[geary] Use Popover for Move/Label menu. Bug 767431.



commit 7e446b1580a76e5c9a962dd32a168fcbd493348f
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Mon Jun 20 05:43:07 2016 +0200

    Use Popover for Move/Label menu. Bug 767431.
    
    Signed-off-by: Niels De Graef <nielsdegraef gmail com>

 src/CMakeLists.txt                        |    2 +-
 src/client/components/folder-menu.vala    |   74 ----------------
 src/client/components/folder-popover.vala |  131 +++++++++++++++++++++++++++++
 src/client/components/main-toolbar.vala   |    8 +-
 src/client/components/pill-toolbar.vala   |   21 +++++
 ui/CMakeLists.txt                         |    1 +
 ui/folder-popover.ui                      |   62 ++++++++++++++
 ui/geary.css                              |   10 ++
 8 files changed, 230 insertions(+), 79 deletions(-)
---
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ad1b34f..5335e9e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -332,7 +332,7 @@ client/accounts/login-dialog.vala
 
 client/components/conversation-find-bar.vala
 client/components/count-badge.vala
-client/components/folder-menu.vala
+client/components/folder-popover.vala
 client/components/icon-factory.vala
 client/components/main-toolbar.vala
 client/components/main-window.vala
diff --git a/src/client/components/folder-popover.vala b/src/client/components/folder-popover.vala
new file mode 100644
index 0000000..9b377c8
--- /dev/null
+++ b/src/client/components/folder-popover.vala
@@ -0,0 +1,131 @@
+/* Copyright 2016 Software Freedom Conservancy Inc.
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+[GtkTemplate (ui = "/org/gnome/Geary/folder-popover.ui")]
+public class FolderPopover : Gtk.Popover {
+
+    [GtkChild]
+    private Gtk.SearchEntry search_entry;
+    [GtkChild]
+    private Gtk.ListBox list_box;
+
+    private int filtered_folder_count = 0;
+
+    public signal void folder_selected(Geary.Folder folder);
+
+    public FolderPopover() {
+        list_box.set_filter_func(row_filter);
+        list_box.set_sort_func(row_sort);
+        this.show.connect(() => search_entry.grab_focus());
+        this.hide.connect(() => {
+            search_entry.set_text("");
+            invalidate_filter();
+        });
+    }
+
+    public bool has_folder(Geary.Folder folder) {
+        return get_row_with_folder(folder) != null;
+    }
+
+    public void add_folder(Geary.Folder folder) {
+        // don't allow multiples and don't allow folders that can't be opened (that means they
+        // support almost no operations and have no content)
+        if (has_folder(folder) || folder.properties.is_openable.is_impossible())
+            return;
+
+        // also don't allow local-only or virtual folders, which also have a limited set of
+        // operations
+        if (folder.properties.is_local_only || folder.properties.is_virtual)
+            return;
+
+        list_box.add(build_row(folder));
+        list_box.invalidate_sort();
+    }
+
+    public void enable_disable_folder(Geary.Folder folder, bool sensitive) {
+        Gtk.ListBoxRow row = get_row_with_folder(folder);
+        if (row != null)
+            row.sensitive = sensitive;
+    }
+
+    public void remove_folder(Geary.Folder folder) {
+        Gtk.ListBoxRow row = get_row_with_folder(folder);
+        if (row != null)
+            list_box.remove(row);
+    }
+
+    public Gtk.ListBoxRow? get_row_with_folder(Geary.Folder folder) {
+        Gtk.ListBoxRow result = null;
+        list_box.foreach((row) => {
+            if (row.get_data<Geary.Folder>("folder") == folder)
+                result = row as Gtk.ListBoxRow;
+        });
+        return result;
+    }
+
+    public void clear() {
+        list_box.foreach((row) => list_box.remove(row));
+    }
+
+    private Gtk.ListBoxRow build_row(Geary.Folder folder) {
+        Gtk.ListBoxRow row = new Gtk.ListBoxRow();
+        row.get_style_context().add_class("geary-folder-popover-list-row");
+        row.set_data("folder", folder);
+
+        Gtk.Label label = new Gtk.Label(folder.path.to_string());
+        label.set_halign(Gtk.Align.START);
+        row.add(label);
+
+        return row;
+    }
+
+    [GtkCallback]
+    private void on_row_activated(Gtk.ListBoxRow? row) {
+        if (row != null) {
+            Geary.Folder folder = row.get_data<Geary.Folder>("folder");
+            folder_selected(folder);
+        }
+
+        this.hide();
+    }
+
+    [GtkCallback]
+    private void on_search_entry_activate() {
+        if (filtered_folder_count == 1) {
+            // Don't use get_row_at_index(0), or you will get the first row of the unfiltered list.
+            Gtk.ListBoxRow? row = list_box.get_row_at_y(0);
+            if (row != null)
+                on_row_activated(row);
+        } else if (filtered_folder_count > 0) {
+            list_box.get_row_at_y(0).grab_focus();
+        }
+    }
+
+    [GtkCallback]
+    private void on_search_entry_search_changed() {
+        invalidate_filter();
+    }
+
+    private void invalidate_filter() {
+        filtered_folder_count = 0;
+        list_box.invalidate_filter();
+    }
+
+    private bool row_filter(Gtk.ListBoxRow row) {
+        Gtk.Label label = row.get_child() as Gtk.Label;
+        if (label.label.down().contains(search_entry.text.down())) {
+            filtered_folder_count++;
+            return true;
+        }
+        return false;
+    }
+
+    private int row_sort(Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) {
+        Geary.Folder folder1 = row1.get_data<Geary.Folder>("folder");
+        Geary.Folder folder2 = row2.get_data<Geary.Folder>("folder");
+        return folder1.path.compare_to(folder2.path);
+    }
+}
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
index 01eb8c4..0827a6e 100644
--- a/src/client/components/main-toolbar.vala
+++ b/src/client/components/main-toolbar.vala
@@ -6,8 +6,8 @@
 
 // Draws the main toolbar.
 public class MainToolbar : Gtk.Box {
-    public FolderMenu copy_folder_menu { get; private set; default = new FolderMenu(); }
-    public FolderMenu move_folder_menu { get; private set; default = new FolderMenu(); }
+    public FolderPopover copy_folder_menu { get; private set; default = new FolderPopover(); }
+    public FolderPopover move_folder_menu { get; private set; default = new FolderPopover(); }
     public string account { get; set; }
     public string folder { get; set; }
     public bool show_close_button { get; set; default = false; }
@@ -103,9 +103,9 @@ public class MainToolbar : Gtk.Box {
         insert.clear();
         insert.add(conversation_header.create_menu_button("marker-symbolic", mark_menu,
             GearyController.ACTION_MARK_AS_MENU));
-        insert.add(conversation_header.create_menu_button(rtl ? "tag-rtl-symbolic" : "tag-symbolic",
+        insert.add(conversation_header.create_popover_button(rtl ? "tag-rtl-symbolic" : "tag-symbolic",
             copy_folder_menu, GearyController.ACTION_COPY_MENU));
-        insert.add(conversation_header.create_menu_button("folder-symbolic", move_folder_menu,
+        insert.add(conversation_header.create_popover_button("folder-symbolic", move_folder_menu,
             GearyController.ACTION_MOVE_MENU));
         conversation_header.add_start(conversation_header.create_pill_buttons(insert));
         
diff --git a/src/client/components/pill-toolbar.vala b/src/client/components/pill-toolbar.vala
index 79f4b50..78d911b 100644
--- a/src/client/components/pill-toolbar.vala
+++ b/src/client/components/pill-toolbar.vala
@@ -103,6 +103,27 @@ public interface PillBar : Gtk.Container {
     }
     
     /**
+     * Given an icon, popover, and action, creates a button that triggers the popover and the action.
+     */
+    public virtual Gtk.MenuButton create_popover_button(string? icon_name, Gtk.Popover? popover, string 
action_name) {
+        Gtk.MenuButton b = new Gtk.MenuButton();
+        setup_button(b, icon_name, action_name);
+        b.set_popover(popover);
+        b.clicked.connect(() => popover.show_all());
+
+        if (b.related_action != null) {
+            b.related_action.activate.connect(() => {
+                    b.clicked();
+                });
+            // Null out the action since by connecting it to clicked
+            // above, invoking would cause an infinite loop otherwise.
+            b.related_action = null;
+        }
+
+        return b;
+    }
+
+    /**
      * Given a list of buttons, creates a "pill-style" tool item that can be appended to this
      * toolbar.  Optionally adds spacers "before" and "after" the buttons (those terms depending
      * on Gtk.TextDirection)
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index 9841d61..20efd37 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -10,6 +10,7 @@ set(RESOURCE_LIST
   STRIPBLANKS "composer_accelerators.ui"
   STRIPBLANKS "edit_alternate_emails.glade"
   STRIPBLANKS "find_bar.glade"
+  STRIPBLANKS "folder-popover.ui"
   STRIPBLANKS "login.glade"
   STRIPBLANKS "password-dialog.glade"
   STRIPBLANKS "preferences.glade"
diff --git a/ui/folder-popover.ui b/ui/folder-popover.ui
new file mode 100644
index 0000000..06a0f98
--- /dev/null
+++ b/ui/folder-popover.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.14"/>
+  <template class="FolderPopover" parent="GtkPopover">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox" id="container">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_start">6</property>
+        <property name="margin_end">6</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkSearchEntry" id="search_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="primary_icon_name">edit-find-symbolic</property>
+            <property name="primary_icon_activatable">False</property>
+            <property name="primary_icon_sensitive">False</property>
+            <signal name="activate" handler="on_search_entry_activate" swapped="no"/>
+            <signal name="search_changed" handler="on_search_entry_search_changed" swapped="no"/>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolled">
+            <property name="min_content_width">200</property>
+            <property name="min_content_height">320</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="shadow_type">in</property>
+            <property name="hscrollbar_policy">never</property>
+            <child>
+              <object class="GtkListBox" id="list_box">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="activate_on_single_click">True</property>
+                <signal name="row_activated" handler="on_row_activated" swapped="no"/>
+                <style>
+                  <class name="geary-folder-popover-list"/>
+                </style>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/ui/geary.css b/ui/geary.css
index 88a8e8c..10a0085 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -45,3 +45,13 @@ GtkBox.vertical GtkHeaderBar {
 .geary-titlebar-left:dir(rtl) {
   border-top-left-radius: 0px;
 }
+
+row.geary-folder-popover-list-row {
+  padding: 6px;
+  border-color: @borders;
+  border-style: groove;
+  border-bottom-width: 1px;
+}
+row.geary-folder-popover-list-row > label {
+  color: @theme_text_color;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]