[bijiben] noteTagsDialog Sort tags properly and scroll to new tags



commit 9f2339fb93766a8e2a6d1e0b2f7a9f39d2484b95
Author: Pierre-Yves Luyten <py luyten fr>
Date:   Wed Jan 30 23:38:05 2013 +0100

    noteTagsDialog Sort tags properly and scroll to new tags
    
    https://bugzilla.gnome.org/show_bug.cgi?id=692791
    https://bugzilla.gnome.org/show_bug.cgi?id=692790

 src/bjb-note-tag-dialog.c                         |  118 ++++++++++++++++++---
 src/libbiji/biji-note-obj.c                       |    6 +-
 src/libbiji/biji-tracker.c                        |   67 ++++++++++---
 src/libbiji/biji-tracker.h                        |    6 +-
 src/libbiji/deserializer/biji-lazy-deserializer.c |    3 +-
 5 files changed, 170 insertions(+), 30 deletions(-)
---
diff --git a/src/bjb-note-tag-dialog.c b/src/bjb-note-tag-dialog.c
index f0bd71b..ea6a81d 100644
--- a/src/bjb-note-tag-dialog.c
+++ b/src/bjb-note-tag-dialog.c
@@ -52,12 +52,16 @@ struct _BjbNoteTagDialogPrivate
   // parent
   GtkWindow *window;
 
-  // to create new tag
+  // widgets
   GtkWidget    * entry;
+  GtkTreeView  * view;
 
   // data
   GList *notes;
   GtkListStore *store;
+  
+  // tmp when a new tag added
+  gchar *tag_to_scroll_to;
 };
 
 #define BJB_NOTE_TAG_DIALOG_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BJB_TYPE_NOTE_TAG_DIALOG, BjbNoteTagDialogPrivate))
@@ -91,25 +95,92 @@ append_tag (gchar *tag, BjbNoteTagDialog *self)
                       COL_TAG_NAME ,          tag, -1);
 }
 
-/* Current tags selection & sorting might be improved */
+static gint
+bjb_compare_tag (gconstpointer a, gconstpointer b)
+{
+  gchar *up_a, *up_b;
+  gint retval;
+
+  up_a = g_utf8_strup (a, -1);
+  up_b = g_utf8_strup (b, -1);
+  retval = g_strcmp0 (up_a, up_b);
+
+  g_free (up_a);
+  g_free (up_b);
+  return retval;
+}
+
+/* If true, free the retval with gtk_tree_path_free */
+static gboolean
+bjb_get_path_for_str (GtkTreeModel  *model,
+                      GtkTreePath  **return_value,
+                      gint           column,
+                      gchar         *needle)
+{
+  gboolean retval= FALSE;
+  GtkTreeIter iter;
+  gboolean valid = gtk_tree_model_get_iter_first (model, &iter);
+  *return_value = NULL;
+
+  while (valid)
+  {
+    gchar *cur_str = NULL;
+    gtk_tree_model_get (model, &iter, column, &cur_str, -1);
+
+    if (cur_str)
+    {
+      if (g_strcmp0 (cur_str, needle)==0)
+        *return_value = gtk_tree_model_get_path (model, &iter);
+
+      g_free (cur_str);
+    }
+
+    if (*return_value)
+    {
+      retval = TRUE;
+      break;
+    }
+
+    valid = gtk_tree_model_iter_next (model, &iter);
+  }
+
+  return retval;
+}
+
 static void
 bjb_note_tag_dialog_handle_tags (GObject *source_object,
                                  GAsyncResult *res,
                                  gpointer user_data)
 {
   BjbNoteTagDialog *self = BJB_NOTE_TAG_DIALOG (user_data);
+  BjbNoteTagDialogPrivate *priv = self->priv;
 
   GList *tags;
 
   tags = biji_get_all_tags_finish (source_object, res);
-  tags = g_list_sort (tags, (GCompareFunc) g_strcmp0);
+  tags = g_list_sort (tags, bjb_compare_tag);
 
   g_list_foreach (tags, (GFunc) append_tag, self);
   g_list_free_full (tags, g_free);
+
+  /* If a new tag was added, scroll & free */
+  if (priv->tag_to_scroll_to)
+  {
+    GtkTreePath *path = NULL;
+
+    if (bjb_get_path_for_str (GTK_TREE_MODEL (priv->store), &path,
+                              COL_TAG_NAME, priv->tag_to_scroll_to))
+    {
+      gtk_tree_view_scroll_to_cell (priv->view, path, NULL, TRUE, 0.5, 0.5);
+      gtk_tree_path_free (path);
+    }
+    
+    g_clear_pointer (& (priv->tag_to_scroll_to), g_free);
+  }
 }
 
 static void
-update_tags_model (BjbNoteTagDialog *self)
+update_tags_model_async (BjbNoteTagDialog *self)
 {
   gtk_list_store_clear (self->priv->store);
   biji_get_all_tracker_tags_async (bjb_note_tag_dialog_handle_tags, self);
@@ -163,10 +234,24 @@ on_tag_toggled (GtkCellRendererToggle *cell,
 }
 
 static void
+on_new_tag_added_cb (gpointer user_data)
+{
+  BjbNoteTagDialog *self = user_data;
+  BjbNoteTagDialogPrivate *priv = self->priv;
+
+  priv->tag_to_scroll_to = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry)));
+  g_list_foreach (priv->notes, (GFunc) note_dialog_add_tag, priv->tag_to_scroll_to);
+
+  update_tags_model_async (self);
+  gtk_entry_set_text (GTK_ENTRY (priv->entry), "");
+}
+
+static void
 add_new_tag (BjbNoteTagDialog *self)
 {
-  push_tag_to_tracker ((gchar*) gtk_entry_get_text(GTK_ENTRY(self->priv->entry)));
-  update_tags_model (self);
+  push_tag_to_tracker (gtk_entry_get_text (GTK_ENTRY (self->priv->entry)),
+                       on_new_tag_added_cb,
+                       self );
 }
 
 static void
@@ -231,6 +316,7 @@ bjb_note_tag_dialog_init (BjbNoteTagDialog *self)
   self->priv = priv;
   priv->notes = NULL;
   priv->window = NULL;
+  priv->tag_to_scroll_to = NULL;
 
   gtk_window_set_default_size (GTK_WINDOW (self),
                                BJB_NOTE_TAG_DIALOG_DEFAULT_WIDTH,
@@ -257,7 +343,6 @@ bjb_note_tag_dialog_constructed (GObject *obj)
   BjbNoteTagDialog *self = BJB_NOTE_TAG_DIALOG (obj);
   BjbNoteTagDialogPrivate *priv = self->priv;
   GtkWidget *hbox, *label, *new, *area, *sw, *close;
-  GtkTreeView *treeview;
 
   gtk_window_set_transient_for (GTK_WINDOW (self), priv->window);
 
@@ -287,16 +372,16 @@ bjb_note_tag_dialog_constructed (GObject *obj)
                                   GTK_POLICY_AUTOMATIC,
                                   GTK_POLICY_AUTOMATIC);
 
-  update_tags_model (self);
-  treeview = GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->store)));
+  update_tags_model_async (self);
+  priv->view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->store)));
   g_object_unref (self->priv->store);
 
-  gtk_tree_view_set_rules_hint (treeview, TRUE);
-  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (treeview),
+  gtk_tree_view_set_rules_hint (priv->view, TRUE);
+  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->view),
                                GTK_SELECTION_MULTIPLE);
   
-  add_columns (treeview, self);
-  gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (treeview));
+  add_columns (priv->view, self);
+  gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (priv->view));
 
   gtk_box_pack_start (GTK_BOX (area), sw, TRUE, TRUE,2);
 
@@ -312,6 +397,13 @@ bjb_note_tag_dialog_constructed (GObject *obj)
 static void
 bjb_note_tag_dialog_finalize (GObject *object)
 {
+  BjbNoteTagDialog *self = BJB_NOTE_TAG_DIALOG (object);
+  BjbNoteTagDialogPrivate *priv = self->priv;
+
+  /* no reason, it should have been freed earlier */
+  if (priv->tag_to_scroll_to)
+    g_free (priv->tag_to_scroll_to);
+
   G_OBJECT_CLASS (bjb_note_tag_dialog_parent_class)->finalize (object);
 }
 
diff --git a/src/libbiji/biji-note-obj.c b/src/libbiji/biji-note-obj.c
index f13d665..96e7704 100644
--- a/src/libbiji/biji-note-obj.c
+++ b/src/libbiji/biji-note-obj.c
@@ -594,11 +594,13 @@ biji_note_obj_add_label (BijiNoteObj *note, gchar *label, gboolean on_user_actio
   g_return_val_if_fail (label != NULL, FALSE);
   g_return_val_if_fail (!biji_note_obj_has_label (note, label), FALSE);
 
-  g_hash_table_add (note->priv->labels, label);
+  gchar *tag = g_strdup (label);
+
+  g_hash_table_add (note->priv->labels, tag);
 
   if (on_user_action_cb)
   {
-    push_existing_or_new_tag_to_note (label, note); // Tracker
+    push_existing_or_new_tag_to_note (tag, note); // Tracker
     biji_note_id_set_last_metadata_change_date_now (note->priv->id);
     biji_note_obj_save_note (note);
   }
diff --git a/src/libbiji/biji-tracker.c b/src/libbiji/biji-tracker.c
index fe3d93b..5e84898 100644
--- a/src/libbiji/biji-tracker.c
+++ b/src/libbiji/biji-tracker.c
@@ -17,6 +17,39 @@
 
 #include "biji-tracker.h"
 
+/* To perform something after async tracker query */
+typedef struct {
+
+  /* query, could add the cancellable */
+  gchar *query;
+
+  /* after the query */
+  BijiFunc func;
+  gpointer user_data;
+
+} BijiTrackerFinisher;
+
+static BijiTrackerFinisher *
+biji_tracker_finisher_new (gchar *query, BijiFunc f, gpointer user_data)
+{
+  BijiTrackerFinisher *retval = g_new (BijiTrackerFinisher, 1);
+
+  retval->query = query;
+  retval->func = f;
+  retval->user_data = user_data;
+
+  return retval;
+}
+
+static void
+biji_tracker_finisher_free (BijiTrackerFinisher *f)
+{
+  if (f->query)
+    g_free (f->query);
+
+  g_free (f);
+}
+
 TrackerSparqlConnection *bjb_connection ;
 
 static TrackerSparqlConnection *
@@ -55,7 +88,8 @@ biji_finish_update (GObject *source_object,
 {
   TrackerSparqlConnection *self = TRACKER_SPARQL_CONNECTION (source_object);
   GError *error = NULL;
-  gchar *query = user_data;
+  BijiTrackerFinisher *finisher = user_data;
+  gchar *query = finisher->query;
 
   tracker_sparql_connection_update_finish (self, res, &error);
 
@@ -65,18 +99,24 @@ biji_finish_update (GObject *source_object,
     g_error_free (error);
   }
 
-  g_free (query);
+  /* See if the query has something to perform afterward */
+  if (finisher->func)
+    finisher->func (finisher->user_data);
+
+  biji_tracker_finisher_free (finisher);
 }
 
 static void
-biji_perform_update_async_and_free (gchar *query)
+biji_perform_update_async_and_free (gchar *query, BijiFunc f, gpointer user_data)
 {
+  BijiTrackerFinisher *finisher = biji_tracker_finisher_new (query, f, user_data);
+
   tracker_sparql_connection_update_async (get_connection_singleton(),
                                           query,
                                           0,     // priority
                                           NULL,
                                           biji_finish_update,
-                                          query);
+                                          finisher);
 }
 
 /* Don't worry too much. We just want plain text here */
@@ -204,17 +244,18 @@ biji_get_notes_with_string_or_tag_async (gchar *needle, GAsyncReadyCallback f, g
 }
 
 void 
-push_tag_to_tracker(gchar *tag)
+push_tag_to_tracker (const gchar *tag, BijiFunc afterward, gpointer user_data)
 { 
   gchar *query = g_strdup_printf ("INSERT {_:tag a nao:Tag ; \
   nao:prefLabel '%s' . } \
   WHERE { OPTIONAL {?tag a nao:Tag ; nao:prefLabel '%s'} . \
   FILTER (!bound(?tag)) }",tag,tag);
 
-  biji_perform_update_async_and_free (query) ;
+  biji_perform_update_async_and_free (query, afterward, user_data);
 }
 
-// removes the tag EVEN if files associated.
+/* removes the tag EVEN if files associated.
+ * TODO : afterward */
 void
 remove_tag_from_tracker(gchar *tag)
 {
@@ -222,12 +263,12 @@ remove_tag_from_tracker(gchar *tag)
   gchar *query = g_strdup_printf ("DELETE { ?tag a nao:Tag } \
   WHERE { ?tag nao:prefLabel '%s' }",value);
 
-  biji_perform_update_async_and_free (query);
+  biji_perform_update_async_and_free (query, NULL, NULL);
   g_free (tag);
 }
 
 void
-push_existing_or_new_tag_to_note (gchar *tag,BijiNoteObj *note)
+push_existing_or_new_tag_to_note (gchar *tag, BijiNoteObj *note)
 {
   gchar *url = get_note_url (note);
   gchar *query = g_strdup_printf (
@@ -235,7 +276,7 @@ push_existing_or_new_tag_to_note (gchar *tag,BijiNoteObj *note)
             ?unknown nao:hasTag _:tag} WHERE {?unknown nie:url '%s'}",
             tag, url);
 
-  biji_perform_update_async_and_free (query);
+  biji_perform_update_async_and_free (query, NULL, NULL);
 
   g_free (url);
 }
@@ -249,7 +290,7 @@ remove_tag_from_note (gchar *tag, BijiNoteObj *note)
                     WHERE { ?urn nie:url ?f . ?label nao:prefLabel '%s' .  \
                     FILTER (?f = '%s') }", tag, url);
 
-  biji_perform_update_async_and_free (query);
+  biji_perform_update_async_and_free (query, NULL, NULL);
 
   g_free (url);
 }
@@ -260,7 +301,7 @@ biji_note_delete_from_tracker (BijiNoteObj *note)
   gchar *query = g_strdup_printf ("DELETE { <%s> a rdfs:Resource }",
                                         biji_note_obj_get_path(note));
 
-  biji_perform_update_async_and_free (query);
+  biji_perform_update_async_and_free (query, NULL, NULL);
 }
 
 void
@@ -292,7 +333,7 @@ bijiben_push_note_to_tracker (BijiNoteObj *note)
                            title,
                            content) ;
 
-  biji_perform_update_async_and_free (query);
+  biji_perform_update_async_and_free (query, NULL, NULL);
 
   g_free(title);
   g_free(file);
diff --git a/src/libbiji/biji-tracker.h b/src/libbiji/biji-tracker.h
index 66a8ce3..b6a8952 100644
--- a/src/libbiji/biji-tracker.h
+++ b/src/libbiji/biji-tracker.h
@@ -24,15 +24,19 @@
 
 #include <libbiji/libbiji.h>
 
+/* todo : find this on glib */
+typedef void (*BijiFunc) (gpointer user_data);
+
 /* All notes matching (either content or tag) */
 GList * biji_get_notes_with_strings_or_tag_finish (GObject *source_object, GAsyncResult *res, BijiNoteBook *book);
 void biji_get_notes_with_string_or_tag_async (gchar *needle, GAsyncReadyCallback f, gpointer user_data);
 
 /* Get tags */
 GList * biji_get_all_tags_finish (GObject *source_object, GAsyncResult *res);
+
 void biji_get_all_tracker_tags_async (GAsyncReadyCallback f, gpointer user_data);
 
-void push_tag_to_tracker(gchar *tag);
+void push_tag_to_tracker (const gchar *tag, BijiFunc afterward, gpointer user_data);
 
 void remove_tag_from_tracker(gchar *tag);
 
diff --git a/src/libbiji/deserializer/biji-lazy-deserializer.c b/src/libbiji/deserializer/biji-lazy-deserializer.c
index b9b43b2..13f0ece 100644
--- a/src/libbiji/deserializer/biji-lazy-deserializer.c
+++ b/src/libbiji/deserializer/biji-lazy-deserializer.c
@@ -492,7 +492,8 @@ processNode (BijiLazyDeserializer *self)
     {
       norm = g_string_new (tag);
       g_string_erase (norm,0,16);
-      biji_note_obj_add_label (n, g_string_free (norm, FALSE), FALSE);
+      biji_note_obj_add_label (n, norm->str, FALSE);
+      g_string_free (norm, TRUE);
     }
 
     free (tag);



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