[pan2] https://bugzilla.gnome.org/show_bug.cgi?id=679274



commit 29da552d63e9511338b62ea645915a1ded22b2a8
Author: Heinrich MÃller <henmull src gnome org>
Date:   Mon Jul 9 07:29:02 2012 +0200

    https://bugzilla.gnome.org/show_bug.cgi?id=679274

 pan/gui/header-pane.cc |   12 +-
 pan/gui/task-pane.cc   |  262 +++++++++++++++++++++++++++++++++++++++++++++++-
 pan/gui/task-pane.h    |    8 ++-
 3 files changed, 274 insertions(+), 8 deletions(-)
---
diff --git a/pan/gui/header-pane.cc b/pan/gui/header-pane.cc
index 68e4a29..aecf1e3 100644
--- a/pan/gui/header-pane.cc
+++ b/pan/gui/header-pane.cc
@@ -1783,12 +1783,12 @@ HeaderPane :: create_filter_entry ()
   g_signal_connect (entry, "activate", G_CALLBACK(search_entry_activated), this);
   entry_changed_tag = g_signal_connect (entry, "changed", G_CALLBACK(search_entry_changed), this);
 
-      gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
-                                   GTK_ENTRY_ICON_PRIMARY,
-                                   GTK_STOCK_FIND);
-   gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
-                                  GTK_ENTRY_ICON_SECONDARY,
-                                  GTK_STOCK_CLEAR );
+  gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
+                                 GTK_ENTRY_ICON_PRIMARY,
+                                 GTK_STOCK_FIND);
+  gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
+                                 GTK_ENTRY_ICON_SECONDARY,
+                                 GTK_STOCK_CLEAR );
 
   bool regex = _prefs.get_flag ("use-regex", false);
   GtkWidget * menu = gtk_menu_new ();
diff --git a/pan/gui/task-pane.cc b/pan/gui/task-pane.cc
index 11cdfcc..9a730b4 100644
--- a/pan/gui/task-pane.cc
+++ b/pan/gui/task-pane.cc
@@ -713,6 +713,256 @@ namespace
   }
 }
 
+namespace
+{
+  // the text typed by the user.
+  std::string search_text;
+
+  guint entry_changed_tag (0u);
+  guint activate_soon_tag (0u);
+
+  // AUTHOR, SUBJECT, SUBJECT_OR_AUTHOR, or MESSAGE_ID
+  int search_mode;
+
+  void set_search_entry (GtkWidget * entry, const char * s)
+  {
+    g_signal_handler_block (entry, entry_changed_tag);
+    gtk_entry_set_text (GTK_ENTRY(entry), s);
+    g_signal_handler_unblock (entry, entry_changed_tag);
+  }
+
+  gboolean search_entry_focus_in_cb (GtkWidget     * w,
+                                     GdkEventFocus * ,
+                                     gpointer        )
+  {
+#if !GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_modify_text (w, GTK_STATE_NORMAL, NULL); // resets
+#else
+    gtk_widget_override_color (w, GTK_STATE_FLAG_NORMAL, NULL);
+#endif
+    set_search_entry (w, search_text.c_str());
+    return false;
+  }
+
+  const char * mode_strings [] =
+  {
+    N_("Subject or Author"),
+    N_("Sub or Auth (regex)"),
+    N_("Subject"),
+    N_("Author"),
+    N_("Message-ID"),
+  };
+
+  enum
+  {
+    SUBJECT_OR_AUTHOR=0,
+    SUBJECT_OR_AUTHOR_REGEX=1,
+    SUBJECT=2,
+    AUTHOR=3,
+    MESSAGE_ID=4
+  };
+
+  void refresh_search_entry (GtkWidget * w)
+  {
+    if (search_text.empty() && !gtk_widget_has_focus(w))
+    {
+#if !GTK_CHECK_VERSION(3,0,0)
+      GdkColor c;
+      c.pixel = 0;
+      c.red = c.green = c.blue = 0xAAAA;
+      gtk_widget_modify_text (w, GTK_STATE_NORMAL, &c);
+#else
+      GdkRGBA c;
+      gdk_rgba_parse (&c, "0xAAA");
+      gtk_widget_override_color(w, GTK_STATE_FLAG_NORMAL, &c);
+#endif
+      set_search_entry (w, _(mode_strings[search_mode]));
+    }
+  }
+
+  gboolean search_entry_focus_out_cb (GtkWidget     * w,
+                                      GdkEventFocus * ,
+                                      gpointer        )
+  {
+    refresh_search_entry (w);
+    return false;
+  }
+
+  void search_activate (TaskPane * h)
+  {
+    h->filter (search_text, search_mode);
+  }
+
+  void remove_activate_soon_tag ()
+  {
+    if (activate_soon_tag != 0)
+    {
+      g_source_remove (activate_soon_tag);
+      activate_soon_tag = 0;
+    }
+  }
+
+  void search_entry_activated (GtkEntry *, gpointer h_gpointer)
+  {
+    search_activate (static_cast<TaskPane*>(h_gpointer));
+    remove_activate_soon_tag ();
+  }
+
+  gboolean activated_timeout_cb (gpointer h_gpointer)
+  {
+    search_activate (static_cast<TaskPane*>(h_gpointer));
+    remove_activate_soon_tag ();
+    return false; // remove the source
+  }
+
+  // ensure there's exactly one activation timeout
+  // and that it's set to go off in a half second from now.
+  void bump_activate_soon_tag (TaskPane * h)
+  {
+    remove_activate_soon_tag ();
+    activate_soon_tag = g_timeout_add (500, activated_timeout_cb, h);
+  }
+
+  // when the user changes the filter text,
+  // update our state variable and bump the activate timeout.
+  void search_entry_changed (GtkEditable * e, gpointer h_gpointer)
+  {
+    search_text = gtk_entry_get_text (GTK_ENTRY(e));
+    bump_activate_soon_tag (static_cast<TaskPane*>(h_gpointer));
+    refresh_search_entry (GTK_WIDGET(e));
+  }
+
+  // when the search mode is changed via the menu,
+  // update our state variable and bump the activate timeout.
+  void search_menu_toggled_cb (GtkCheckMenuItem  * menu_item,
+                                gpointer            entry_g)
+  {
+    if (gtk_check_menu_item_get_active  (menu_item))
+    {
+      search_mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(menu_item), "MODE"));
+      refresh_search_entry (GTK_WIDGET(entry_g));
+      TaskPane * h = (TaskPane*) g_object_get_data (G_OBJECT(entry_g), "pane");
+      bump_activate_soon_tag (h);
+    }
+  }
+
+  void entry_icon_release (GtkEntry*, GtkEntryIconPosition icon_pos, GdkEventButton*, gpointer menu)
+  {
+    if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
+      gtk_menu_popup (GTK_MENU(menu), 0, 0, 0, 0, 0, gtk_get_current_event_time());
+  }
+
+  void entry_icon_release_2 (GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEventButton*, gpointer pane_gpointer)
+  {
+    if (icon_pos == GTK_ENTRY_ICON_SECONDARY) {
+      set_search_entry (GTK_WIDGET(entry), "");
+      refresh_search_entry (GTK_WIDGET(entry));
+      search_text.clear ();
+      search_entry_activated (NULL, pane_gpointer);
+    }
+  }
+
+  gboolean filter_visible_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer gdata)
+  {
+
+     if (search_text.empty()) return true;
+
+     Task *task(0);
+     /* Get value from column */
+     gtk_tree_model_get( GTK_TREE_MODEL(model), iter, COL_TASK_POINTER, &task, -1 );
+
+     TaskArticle* ta (dynamic_cast<TaskArticle*>(task));
+
+/*  SUBJECT_OR_AUTHOR=0,
+    SUBJECT_OR_AUTHOR_REGEX=1,
+    SUBJECT=2,
+    AUTHOR=3,
+    MESSAGE_ID=4
+*/
+     if (ta)
+     {
+       std::string s1("");
+       if (search_mode == 0)
+       {
+        s1 = ta->get_article().author.c_str();
+        if (s1.find(search_text) != s1.npos) return true;
+        s1 = ta->get_article().subject.c_str();
+       }
+       if (search_mode == 1)
+       {
+          GRegexCompileFlags cf0((GRegexCompileFlags)0);
+          GRegexMatchFlags mf0((GRegexMatchFlags)0);
+          GRegex* rex = g_regex_new (search_text.c_str(), cf0, mf0, NULL);
+          if (!rex) return false;
+          return g_regex_match (rex, ta->get_article().subject.c_str(), G_REGEX_MATCH_NOTEMPTY, NULL) ||
+                  g_regex_match (rex, ta->get_article().author.c_str(), G_REGEX_MATCH_NOTEMPTY, NULL);
+       }
+       if (search_mode == 2)
+        s1 = ta->get_article().subject.c_str();
+       if (search_mode == 3)
+        s1 = ta->get_article().author.c_str();
+       if (search_mode == 4)
+        s1 = ta->get_article().message_id.c_str();
+
+       if (s1.find(search_text) != s1.npos) return true;
+     }
+
+     return false;
+
+  }
+}
+
+void
+TaskPane :: filter (const std::string& text, int mode)
+{
+  search_text = text;
+  search_mode = mode;
+  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(GTK_TREE_VIEW(_view))));
+}
+
+GtkWidget*
+TaskPane :: create_filter_entry ()
+{
+  GtkWidget * entry = gtk_entry_new ();
+//  _action_manager.disable_accelerators_when_focused (entry);
+  g_object_set_data (G_OBJECT(entry), "pane", this);
+  g_signal_connect (entry, "focus-in-event", G_CALLBACK(search_entry_focus_in_cb), NULL);
+  g_signal_connect (entry, "focus-out-event", G_CALLBACK(search_entry_focus_out_cb), NULL);
+  g_signal_connect (entry, "activate", G_CALLBACK(search_entry_activated), this);
+  entry_changed_tag = g_signal_connect (entry, "changed", G_CALLBACK(search_entry_changed), this);
+
+  gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
+                                 GTK_ENTRY_ICON_PRIMARY,
+                                 GTK_STOCK_FIND);
+  gtk_entry_set_icon_from_stock( GTK_ENTRY( entry ),
+                                 GTK_ENTRY_ICON_SECONDARY,
+                                 GTK_STOCK_CLEAR );
+
+  bool regex = false;//_prefs.get_flag ("use-regex", false);
+  GtkWidget * menu = gtk_menu_new ();
+  if (regex == true )
+    search_mode = 1;
+  else
+    search_mode = 0;
+  GSList * l = 0;
+  for (int i=0, qty=G_N_ELEMENTS(mode_strings); i<qty; ++i) {
+    GtkWidget * w = gtk_radio_menu_item_new_with_label (l, _(mode_strings[i]));
+    l = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM(w));
+    g_object_set_data (G_OBJECT(w), "MODE", GINT_TO_POINTER(i));
+    g_signal_connect (w, "toggled", G_CALLBACK(search_menu_toggled_cb),entry);
+    if (search_mode == i)
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(w), TRUE);
+    gtk_menu_shell_append (GTK_MENU_SHELL(menu), w);
+    gtk_widget_show (w);
+  }
+  g_signal_connect (entry, "icon-release", G_CALLBACK(entry_icon_release), menu);
+  g_signal_connect (entry, "icon-release", G_CALLBACK(entry_icon_release_2), this);
+
+  refresh_search_entry (entry);
+
+  return entry;
+}
+
 TaskPane :: TaskPane (Queue& queue, Prefs& prefs): _queue(queue)
 {
   _root = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -760,7 +1010,6 @@ TaskPane :: TaskPane (Queue& queue, Prefs& prefs): _queue(queue)
   GtkWidget * hbox = gtk_hbox_new (false, PAD);
   w = _status_label = gtk_label_new (0);
   gtk_box_pack_start (GTK_BOX(hbox), w, false, false, PAD_SMALL);
-  gtk_box_pack_start (GTK_BOX(vbox), hbox, false, false, PAD);
 
   _store = gtk_list_store_new (NUM_COLS, G_TYPE_POINTER, G_TYPE_INT);
   _view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(_store));
@@ -785,6 +1034,17 @@ TaskPane :: TaskPane (Queue& queue, Prefs& prefs): _queue(queue)
   add_actions(_view);
   gtk_window_add_accel_group (GTK_WINDOW(_root), gtk_ui_manager_get_accel_group (_uim));
 
+  // search filter
+  gtk_box_pack_start (GTK_BOX(hbox), gtk_vseparator_new(), 0, 0, 0);
+  gtk_box_pack_start (GTK_BOX(hbox), create_filter_entry(), false, false, PAD);
+  GtkTreeModel* initial_model= gtk_tree_view_get_model(GTK_TREE_VIEW( _view ));
+  GtkTreeModel* filter_model = gtk_tree_model_filter_new( initial_model, NULL );
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER ( filter_model ),(GtkTreeModelFilterVisibleFunc) filter_visible_func, NULL, NULL);
+  gtk_tree_view_set_model( GTK_TREE_VIEW( _view ),filter_model);
+  g_object_unref( filter_model );
+
+  gtk_box_pack_start (GTK_BOX(vbox), hbox, false, false, PAD);
+
   w = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(w), GTK_SHADOW_IN);
diff --git a/pan/gui/task-pane.h b/pan/gui/task-pane.h
index 736e495..0ac1efc 100644
--- a/pan/gui/task-pane.h
+++ b/pan/gui/task-pane.h
@@ -94,7 +94,13 @@ namespace pan
       static void get_selected_tasks_foreach (GtkTreeModel*, GtkTreePath*, GtkTreeIter*, gpointer);
       static void online_toggled_cb  (GtkToggleButton*, Queue*);
 
-    public:   /// FIXME, privatize this again...
+    private:
+      GtkWidget* create_filter_entry ();
+
+    public:
+      void filter (const std::string& text, int mode);
+
+    public:
       static void up_clicked_cb      (GtkButton*, TaskPane*);
       static void down_clicked_cb    (GtkButton*, TaskPane*);
       static void top_clicked_cb     (GtkButton*, TaskPane*);



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