[tracker/tracker-needle-improved-tagging: 6/6] WIP
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-needle-improved-tagging: 6/6] WIP
- Date: Mon, 3 Oct 2011 22:18:54 +0000 (UTC)
commit 96b3e47da64b35ea80e001ad18ccfc233fdbbade
Author: Martyn Russell <martyn lanedo com>
Date: Mon Oct 3 23:16:41 2011 +0100
WIP
src/tracker-needle/Makefile.am | 1 +
src/tracker-needle/tracker-needle.ui | 133 +++++-
src/tracker-needle/tracker-taglist.vala | 2 +-
src/tracker-needle/tracker-tags-view.vala | 802 +++++++++++++++++++++++++++++
src/tracker-needle/tracker-view.vala | 17 +-
5 files changed, 929 insertions(+), 26 deletions(-)
---
diff --git a/src/tracker-needle/Makefile.am b/src/tracker-needle/Makefile.am
index 5dbc7eb..bfcc9ce 100644
--- a/src/tracker-needle/Makefile.am
+++ b/src/tracker-needle/Makefile.am
@@ -30,6 +30,7 @@ tracker_needle_SOURCES = \
tracker-result-store.vala \
tracker-stats.vala \
tracker-taglist.vala \
+ tracker-tags-view.vala
tracker-utils.vala \
tracker-needle.vala \
tracker-view.vala
diff --git a/src/tracker-needle/tracker-needle.ui b/src/tracker-needle/tracker-needle.ui
index f0f9142..4a74e3c 100644
--- a/src/tracker-needle/tracker-needle.ui
+++ b/src/tracker-needle/tracker-needle.ui
@@ -1,12 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="liststore_search">
<columns>
<!-- column-name text -->
<column type="gchararray"/>
</columns>
</object>
+ <object class="GtkVBox" id="vbox_tags_view">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Set the tags you want to associate with the %d selected items:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">fill</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="entry_tag">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="changed" handler="tracker_tags_view_entry_tag_changed_cb" swapped="no"/>
+ <signal name="activate" handler="tracker_tags_view_entry_tag_activate_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="button_add">
+ <property name="label">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="tracker_tags_view_button_add_clicked_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_remove">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ <signal name="clicked" handler="tracker_tags_view_button_remove_clicked_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_tags">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">never</property>
+ <child>
+ <object class="GtkTreeView" id="treeview_tags">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="enable_search">False</property>
+ <signal name="row-activated" handler="tracker_tags_view_treeview_tags_row_activated_cb" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
<object class="GtkWindow" id="window_needle">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Desktop Search</property>
@@ -113,6 +233,8 @@
</child>
<child>
<object class="GtkRadioToolButton" id="toolbutton_find_in_all">
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-select-all</property>
<property name="active">True</property>
@@ -166,17 +288,6 @@
<property name="yscale">0</property>
<property name="left_padding">4</property>
<property name="right_padding">4</property>
- <child>
- <object class="GtkComboBoxText" id="comboboxtext_search">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="has_entry">True</property>
- <property name="model">liststore_search</property>
- <accelerator key="s" signal="grab-focus" modifiers="GDK_CONTROL_MASK"/>
- <accelerator key="f" signal="grab-focus" modifiers="GDK_CONTROL_MASK"/>
- </object>
- </child>
</object>
</child>
</object>
diff --git a/src/tracker-needle/tracker-taglist.vala b/src/tracker-needle/tracker-taglist.vala
index c5c9796..6f8c328 100644
--- a/src/tracker-needle/tracker-taglist.vala
+++ b/src/tracker-needle/tracker-taglist.vala
@@ -20,7 +20,7 @@
using Gtk;
public class Tracker.TagList : ScrolledWindow {
- static Sparql.Connection connection;
+ private static Sparql.Connection connection;
private TreeView treeview;
private ListStore store;
private int offset;
diff --git a/src/tracker-needle/tracker-tags-view.vala b/src/tracker-needle/tracker-tags-view.vala
new file mode 100644
index 0000000..d58893b
--- /dev/null
+++ b/src/tracker-needle/tracker-tags-view.vala
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2011, Martyn Russell <martyn lanedo com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+using Gtk;
+using Tracker;
+
+private class TagData {
+ public TrackerTagsView tv;
+ public Cancellable cancellable;
+ public string tag_id;
+ public TreeIter *iter;
+ public int items;
+ public bool update;
+ public bool selected;
+
+ TagData (string tag_id, TreeIter? iter, bool update, bool selected, int items, TrackerTagsView tv) {
+ debug ("Creating tag data");
+
+ self.tv = tv;
+ self.cancellable = new Cancellable ();
+ self.tag_id = tag_id;
+
+ if (iter != null) {
+ self.iter = iter.copy ();
+ } else {
+ self.iter = null;
+ }
+
+ self.items = items;
+ self.update = update;
+ self.selected = selected;
+ }
+
+ ~TagData () {
+ if (cancellable != null) {
+ cancellable.cancel ();
+ cancellable = null;
+ }
+
+ if (iter != null) {
+ iter.free ();
+ }
+ }
+}
+
+private class FindTag {
+ public TrackerTagsView tv;
+ public string tag;
+ public bool found;
+ public TreeIter found_iter;
+
+ FindTag (TrackerTagsView tv, string tag) {
+ self.tv = tv;
+ self.tag = tag;
+ }
+}
+
+[CCode (cname = "TRACKER_UI_DIR")]
+extern static const string UIDIR;
+
+[CCode (cname = "SRCDIR")]
+extern static const string SRCDIR;
+
+public class TrackerTagsView : VBox {
+ private Sparql.Connection connection;
+ private Cancellable cancellable;
+
+ private List<TagData> tag_data_requests;
+ private List<string> files;
+
+ private ListStore store;
+
+ private const string UI_FILE = "tracker-preferences.ui";
+
+ private VBox vbox;
+ private HBox hbox;
+ private Label label;
+ private Entry entry;
+ private Button button_add;
+ private Button button_remove;
+ private ScrolledWindow scrolled_window;
+ private TreeView view;
+
+ enum Col {
+ SELECTION,
+ TAG_ID,
+ TAG_NAME,
+ TAG_COUNT,
+ TAG_COUNT_VALUE,
+ N_COLUMNS
+ }
+
+ enum Selection {
+ INCONSISTENT = -1,
+ FALSE = 0,
+ TRUE = 1
+ }
+
+ TrackerTagsView () {
+ try {
+ connection = Sparql.Connection.get ();
+ } catch (GLib.Error e) {
+ warning ("Could not get Sparql connection: %s", e.message);
+ }
+
+ cancellable = new Cancellable ();
+
+ store = new ListStore (Col.N_COLUMNS,
+ typeof (int), /* Selection type */
+ typeof (string), /* Tag ID */
+ typeof (string), /* Tag Name */
+ typeof (string), /* Tag Count String */
+ typeof (int)); /* Tag Count */
+ }
+
+ ~TrackerTagsView () {
+ if (cancellable != null) {
+ cancellable.cancel ();
+ cancellable = null;
+ }
+
+ if (private->files) {
+ // TODO: finish
+ //nautilus_file_info_list_free (private->files);
+ private->files = null;
+ }
+
+ if (tag_data_requests != null) {
+ tag_data_requests.foreach ((td) => {
+ tag_data_free (td);
+ });
+
+ tag_data_requests = NULL;
+ }
+ }
+
+ private void show_error_dialog (Error e) {
+ string str = e.message != null ? e.message : _("No error was given");
+
+ var msg = new MessageDialog (null,
+ DialogFlags.MODAL,
+ MessageType.ERROR,
+ ButtonsType.CLOSE,
+ "%s",
+ e.message);
+ msg.run ();
+ }
+
+ [CCode (instance_pos = -1)]
+ public void button_remove_clicked_cb (Button source) {
+ debug ("Remove clicked");
+
+// TrackerTagsView *tv;
+// TrackerTagsViewPrivate *private;
+// TagData *td;
+// GtkTreeIter iter;
+// GtkTreeSelection *select;
+// GtkTreeModel *model;
+// gchar *id;
+
+// tv = user_data;
+// private = TRACKER_TAGS_VIEW_GET_PRIVATE (tv);
+
+// select = gtk_tree_view_get_selection (GTK_TREE_VIEW (private->view));
+
+// if (gtk_tree_selection_get_selected (select, &model, &iter)) {
+// gtk_tree_model_get (GTK_TREE_MODEL (private->store), &iter, Col.TAG_ID, &id, -1);
+
+// td = tag_data_new (id, &iter, FALSE, TRUE, 1, tv);
+// private->tag_data_requests =
+// g_list_prepend (private->tag_data_requests, td);
+
+// tags_view_remove_tag (tv, td);
+
+// private->tag_data_requests =
+// g_list_remove (private->tag_data_requests, td);
+// tag_data_free (td);
+// }
+ }
+
+ [CCode (instance_pos = -1)]
+ public void button_add_clicked_cb (Button source) {
+ debug ("Add clicked");
+
+// TrackerTagsView *tv;
+// TrackerTagsViewPrivate *private;
+// const gchar *tag;
+
+// tv = user_data;
+// private = TRACKER_TAGS_VIEW_GET_PRIVATE (tv);
+
+// tag = gtk_entry_get_text (GTK_ENTRY (private->entry));
+// tags_view_add_tag (tv, tag);
+ }
+
+ [CCode (instance_pos = -1)]
+ public void entry_tag_activated_cb (Entry source) {
+ debug ("Entry activated");
+
+// TrackerTagsViewPrivate *private;
+
+// private = TRACKER_TAGS_VIEW_GET_PRIVATE (tv);
+
+// gtk_widget_activate (private->button_add);
+ }
+
+ [CCode (instance_pos = -1)]
+ public void entry_tag_changed_cb (Editable source) {
+ debug ("Entry changed");
+
+// TrackerTagsViewPrivate *private;
+// GtkTreeIter iter;
+// const gchar *tag;
+
+// private = TRACKER_TAGS_VIEW_GET_PRIVATE (tv);
+
+// tag = gtk_entry_get_text (GTK_ENTRY (private->entry));
+
+// if (tag_view_model_find_tag (tv, tag, &iter)) {
+// gtk_widget_set_sensitive (GTK_WIDGET (private->button_add), FALSE);
+// } else {
+// gtk_widget_set_sensitive (GTK_WIDGET (private->button_add),
+// !tracker_is_empty_string (tag));
+// }
+ }
+
+ [CCode (instance_pos = -1)]
+ public void treeview_tags_cell_toggled_cb (CellRendererToggle cell, string path_string, TrackerTagsView tv) {
+ TreePath path;
+
+ // TODO: finish
+ // path = gtk_tree_path_new_from_string (path_string);
+ model_toggle_row (tv, path);
+ // gtk_tree_path_free (path);
+ }
+
+ [CCode (instance_pos = -1)]
+ public void treeview_tags_row_selected_cb (TreeSelection selection) {
+ TreeIter iter;
+ TreeModel model;
+
+ if (selection.get_selected (out model, out iter)) {
+ button_remove.set_sensitive = true;
+ } else {
+ button_remove.set_sensitive = false;
+ }
+ }
+
+ [CCode (instance_pos = -1)]
+ public void treeview_tags_row_activated_cb (TreeView source, TreePath path, TreeViewColumn column) {
+ debug ("Treeview row activated");
+
+ model_toggle_row (user_data, path);
+ }
+
+ [CCode (instance_pos = -1)]
+ private void treeview_tags_toggle_cell_data_func (TreeViewColumn column, Gtk.CellRenderer renderer, TreeModel model, TreeIter iter) {
+ Value inconsistent = { 0 };
+ int selection;
+
+ model.get (iter, Col.SELECTION, out selection, -1);
+ ((Gtk.CellRendererToggle) renderer).set_active (Selection.TRUE == selection);
+
+ g_value_init (&inconsistent, typeof (bool));
+ g_value_set_boolean (&inconsistent, Selection.INCONSISTENT == selection);
+ g_object_set_property (G_OBJECT (cell_renderer), "inconsistent", &inconsistent);
+ }
+
+ private void create_ui (TrackerTagsView tv) {
+ CellRenderer cell_renderer;
+ TreeSelection selection;
+ TreeViewColumn column;
+ string str;
+
+ var builder = new Gtk.Builder ();
+
+ try {
+ debug ("Trying to use UI file:'%s'", SRCDIR + UI_FILE);
+ builder.add_from_file (SRCDIR + UI_FILE);
+ } catch (GLib.Error e) {
+ //now the install location
+ try {
+ debug ("Trying to use UI file:'%s'", UIDIR + UI_FILE);
+ builder.add_from_file (UIDIR + UI_FILE);
+ } catch (GLib.Error e) {
+ var msg = new MessageDialog (null,
+ DialogFlags.MODAL,
+ MessageType.ERROR,
+ ButtonsType.CANCEL,
+ "Failed to load UI file, %s\n",
+ e.message);
+ msg.run ();
+ Gtk.main_quit();
+ }
+ }
+
+ // Get widgets from .ui file
+ vbox = builder.get_object ("vbox_tags") as VBox;
+ label = builder.get_object ("label_tag") as Label;
+ entry = builder.get_object ("entry_tag") as Entry;
+ button_add = builder.get_object ("button_add") as Button;
+ button_remove = builder.get_object ("button_remove") as Button;
+ scrolled_window = builder.get_object ("scrolled_window_tags") as ScrolledWindow;
+ view = builder.get_object ("treeview_tags") as TreeView;
+
+ // TODO: finish
+ //str = g_strdup_printf (dngettext (NULL,
+ // "_Set the tags you want to associate with the %d selected item:",
+ // "_Set the tags you want to associate with the %d selected items:",
+ // g_list_length (private->files)),
+ // g_list_length (private->files));
+
+ Gtk.TreeViewColumn col;
+ Gtk.CellRenderer renderer;
+
+ // List column: Tag
+ renderer = new CellRendererToggle ();
+ renderer.xpad = 5;
+ renderer.ypad = 5;
+ renderer.connect.toggled (cell_toggled_cb, tv);
+ ((Gtk.CellRendererToggle) renderer).set_radio (false);
+
+ col = new Gtk.TreeViewColumn ();
+ col.set_title ("-");
+ col.set_resizable (false);
+ col.set_sizing (Gtk.TreeViewColumnSizing.FIXED);
+ col.set_fixed_width (50);
+ col.pack_start (renderer, false);
+ col.set_cell_data_func (renderer, model_toggle_cell_data_func);
+ view.append_column (col);
+
+ // List column: Name
+ renderer = new CellRendererText ();
+ renderer.xpad = 5;
+ renderer.ypad = 5;
+
+ col = new Gtk.TreeViewColumn ();
+ col.set_title (_("Name"));
+ col.set_resizable (true);
+ col.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
+ col.set_expand (true);
+ col.pack_start (renderer, true);
+ col.add_attribute (renderer, "text", 2);
+
+ view.append_column (col);
+
+ // List coumnn: Count
+ renderer = new CellRendererText ();
+ renderer.xpad = 5;
+ renderer.ypad = 5;
+
+ col = new Gtk.TreeViewColumn ();
+ col.set_title ("-");
+ col.set_resizable (false);
+ col.set_sizing (Gtk.TreeViewColumnSizing.FIXED);
+ col.set_fixed_width (50);
+ col.pack_end (renderer, false);
+ col.add_attribute (renderer, "text", 3);
+
+ view.append_column (col);
+
+ var selection = treeview.get_selection ();
+ selection.changed.connect (model_selection_changed);
+
+ // Get all tags
+ Sparql.Cursor cursor = null;
+
+ try {
+ string query = "SELECT ?urn ?label WHERE { ?urn a nao:Tag ; nao:prefLabel ?label . } ORDER BY ?label";
+
+ cursor = yield connection.query_async (query, null);
+
+ while (yield cursor.next_async ()) {
+ debug ("Clearing tags in store");
+
+ store.clear ();
+
+ debug ("Adding all tags...");
+
+ const string id = cursor.get_string (0);
+ const string label = cursor.get_string (1);
+
+ debug (" Adding tag id:'%s' with label:'%s' to store", id, label);
+
+ TreeIter iter;
+ store.append (out iter);
+
+ store.set (iter,
+ Col.TAG_ID, id,
+ Col.TAG_NAME, label,
+ Col.SELECTION, Selection.FALSE,
+ -1);
+
+ td = new TagData (id, iter, false, true, 1, tv);
+ tag_data_requests += td;
+
+ query_files_for_tag_id (td);
+ }
+ } catch (GLib.Error e) {
+ warning ("Could not run Sparql query: %s", e.message);
+ } finally {
+ }
+
+ vbox.show_all ();
+ }
+
+ private void model_toggle_row (TrackerTagsView tv, TreePath path) {
+ TagData td = null;
+ string f[] = null;
+ TreeIter iter;
+ TreeModel model;
+ string filter, query;
+ string id, tag, tag_escaped;
+ int selection;
+
+ model = view.get_model ();
+
+ if (model.get_iter (out iter, path) == false) {
+ return;
+ }
+
+ model.get (iter,
+ Col.SELECTION, out selection,
+ Col.TAG_ID, out id,
+ Col.TAG_NAME, out tag,
+ -1);
+
+ selection = selection == Selection.FALSE ? Selection.TRUE : Selection.FALSE;
+
+ // TODO: finish
+ //tag_escaped = tracker_tags_escape_sparql_string (tag);
+
+ // TODO: finish
+ // f = tracker_glist_to_string_list_for_nautilus_files (private->files);
+ // filter = tracker_tags_get_filter_string (f, NULL);
+ f = null;
+
+ if (selection) {
+ // NB: ?f is used in filter.
+ query = "INSERT {
+ ?urn nao:hasTag ?label
+ } WHERE {
+ ?urn nie:url ?f .
+ ?label nao:prefLabel %s .
+ %s
+ }".printf (tag_escaped, filter);
+ } else {
+ // NB: ?f is used in filter.
+ query = "DELETE {
+ ?urn nao:hasTag ?label
+ } WHERE {
+ ?urn nie:url ?f .
+ ?label nao:prefLabel %s .
+ %s
+ }".printf (tag_escaped, filter);
+
+ /* Check if there are any files left with this tag and
+ * remove tag if not.
+ */
+ td = new TagData (id, iter, false, true, 1, tv);
+ tag_data_requests.prepend (td);
+
+ query_files_for_tag_id (td);
+ }
+
+ filter = null;
+ tag_escaped = null;
+
+ entry.set_sensitive (false);
+
+ if (connection == null) {
+ warning ("Can't update tags, no SPARQL connection available");
+ return;
+ }
+
+ debug ("Running query:'%s'", query);
+
+ // TODO: Why do we have 2x td parameters here?
+
+ td = new TagData (id, iter, true, selection, 1, tv);
+ tag_data_requests += td;
+
+ try {
+ Sparql.Cursor cursor = null;
+
+ cursor = yield connection.update_async (query, Priority.DEFAULT, td.cancellable);
+
+ debug ("Updated tags");
+ update_tag_data (td);
+ } catch (GLib.Error e) {
+ warning ("Could not run Sparql update query: %s", e.message);
+ show_error_dialog (e);
+ }
+
+ tag_data_requests -= td;
+ td = null;
+
+ entry.set_text ("");
+ entry.set_sensitive (true);
+ }
+
+ private bool find_tag (TrackerTagsView tv, string tag, out TreeIter iter) {
+ TreeView view;
+ TreeModel model;
+ FindTag data;
+
+ if (tag == null || *tag == '\0') {
+ return false;
+ }
+
+ data = new FindTag (tv, tag);
+
+ data.tv = tv;
+ data.tag = tag;
+ data.found = FALSE;
+
+ model = gtk_tree_view_get_model (view);
+
+ model.foreach ((model, path, out iter, data) => {
+ string tag;
+
+ model.get (iter, Col.TAG_NAME, out tag, -1);
+
+ if (tag == null) {
+ return false;
+ }
+
+ if (data->tag != null && strcmp (data->tag, tag) == 0) {
+ data.found = true;
+ data.found_iter = iter;
+ }
+
+ return true;
+ },
+ data);
+
+ if (data.found == true) {
+ iter = data.found_iter;
+ return true;
+ }
+
+ return false;
+ }
+
+ private void remove_tag (TrackerTagsView tv, TagData td) {
+ TagData td_copy;
+ string query;
+
+ if (connection == null) {
+ warning ("Can't remove tag '%s', no SPARQL connection available", td->tag_id);
+ return;
+ }
+
+ query = "DELETE { <%s> a rdfs:Resource }".printf (td.tag_id);
+
+ td_copy = new TagData (td.tag_id, td.iter, td.update, td.selected, td.items, td.tv);
+ tag_data_requests += td_copy;
+
+ try {
+ Sparql.Cursor cursor = null;
+
+ cursor = yield connection.update_async (query, Priority.DEFAULT, td_copy.cancellable);
+
+ if (cursor != null) {
+ yield cursor.next_async ();
+ }
+
+ debug ("Tag removed");
+ store.remove (td_copy.iter);
+ } catch (GLib.Error e) {
+ warning ("Could not run Sparql update query: %s", e.message);
+ show_error_dialog (e);
+ }
+
+ tag_data_requests -= td_copy;
+ td_copy = null;
+ }
+
+ private void add_tag (TrackerTagsView tv, string tag) {
+ TagData td;
+ string query;
+ int files;
+
+ if (connection == null) {
+ warning ("Can't add tag '%s', no SPARQL connection available", tag);
+ return;
+ }
+
+ entry.set_sensitive = false;
+
+ if (files.length > 0) {
+ List<string> files = null;
+ string[] f;
+ string tag_escaped;
+ string filter;
+ uint i;
+
+ query = g_string_new ("");
+
+ // TODO: finish
+ //files = tracker_glist_to_string_list_for_nautilus_files (private->files);
+ //filter = tracker_tags_get_filter_string (files, NULL);
+ tag_escaped = tracker_tags_escape_sparql_string (tag);
+
+ for (List<string> l = files; l != null; l.next ()) {
+ query += "INSERT {
+ _:file a nie:DataObject ;
+ nie:url '%s'
+ } WHERE {
+ OPTIONAL {
+ ?file a nie:DataObject ;
+ nie:url '%s'
+ } .
+ FILTER (!bound(?file))
+ }".printf (files[i], files[i]);
+ }
+
+ query += "INSERT {
+ _:tag a nao:Tag;
+ nao:prefLabel %s .
+ } WHERE {
+ OPTIONAL {
+ ?tag a nao:Tag ;
+ nao:prefLabel %s
+ } .
+ FILTER (!bound(?tag))
+ }
+ INSERT {
+ ?urn nao:hasTag ?label
+ } WHERE {
+ ?urn nie:url ?f .
+ ?label nao:prefLabel %s
+ %s
+ }".printf (tag_escaped, tag_escaped, tag_escaped, filter);
+ } else {
+ // TODO: finish
+ // query = new tracker_tags_add_query (tag);
+ }
+
+ td = new TagData (null, null, false, true, files, tv);
+ tag_data_requests += td;
+
+ try {
+ Sparql.Cursor cursor = null;
+
+ cursor = yield connection.update_async (query, Priority.DEFAULT, td.cancellable);
+
+ debug ("Updated tags");
+ update_tag_data (td);
+
+ } catch (GLib.Error e) {
+ warning ("Could not run Sparql update query: %s", e.message);
+ show_error_dialog (e);
+ }
+
+ tag_data_requests -= td;
+ td = null;
+
+ entry.set_text ("");
+ entry.set_sensitive (true);
+ }
+
+ private void update_tag_data (TagData td) {
+ tag = gtk_entry_get_text (GTK_ENTRY (private->entry));
+
+ if (td.update == false) {
+ TreeIter iter;
+
+ debug ("Setting tag selection state to ON (new)");
+
+ store.append (out iter);
+ store.set (iter,
+ Col.TAG_ID, td.tag_id,
+ Col.TAG_NAME, tag,
+ Col.TAG_COUNT, "%d".printf (td.items),
+ Col.TAG_COUNT_VALUE, td.items,
+ Col.SELECTION, Selection.TRUE,
+ -1);
+ } else if (td.selected == true) {
+ TagData td_copy;
+
+ debug ("Setting tag selection state to ON");
+
+ store.set (td.iter,
+ Col.SELECTION, Selection.TRUE,
+ -1);
+
+ td_copy = new TagData (td.tag_id, td.iter, td.update, td.selected, td.items, td.tv);
+ tag_data_requests += td_copy;
+
+ query_files_for_tag_id (td_copy);
+ } else {
+ TagData *td_copy;
+
+ debug ("Setting tag selection state to FALSE");
+
+ store.set (td.iter,
+ Col.SELECTION, Selection.FALSE,
+ -1);
+
+ td_copy = new TagData (td.tag_id, td.iter, td.update, td.selected, td.items, td.tv);
+ tag_data_requests += td_copy;
+
+ query_files_for_tag_id (td_copy);
+ }
+
+ }
+
+ private void query_files_for_tag_id (TagData td) {
+ string query;
+
+ if (connection == null) {
+ warning ("Can't query files for tag id '%s', no SPARQL connection available", td->tag_id);
+ return;
+ }
+
+ query = "SELECT ?url WHERE { ?urn a rdfs:Resource ; nie:url ?url ; nao:hasTag <%s> . }".printf (td.tag_id);
+
+ try {
+ Sparql.Cursor cursor = null;
+
+ cursor = yield connection.query_async (query, td.cancellable);
+
+ TagData td;
+ Error error = null;
+ string str;
+ uint files_selected, files_with_tag, has_tag_in_selection;
+
+ has_tag_in_selection = 0;
+ files_with_tag = 0;
+ files_selected = files.length ();
+
+ while (yield cursor.next_async ()) {
+ List l;
+ bool equal;
+
+ files_with_tag++;
+
+ for (List l = files, equal = false; l != null && equal == false; l.next ()) {
+ string uri;
+
+ //debug ("--> %s", cursor.get_string (i));
+
+ // TODO: finish
+ // uri = nautilus_file_info_get_uri (NAUTILUS_FILE_INFO (l->data));
+
+ const string str = cursor.get_string (0);
+
+ if (str == null) {
+ continue;
+ }
+
+ equal = strcmp (str, uri) == 0;
+
+ if (equal) {
+ has_tag_in_selection++;
+ }
+ }
+ }
+
+ debug ("Querying files with tag, in selection:%d, in total:%d, selected:%d",
+ has_tag_in_selection, files_with_tag, files_selected);
+
+ if (has_tag_in_selection == 0) {
+ store.set (iter, Col.SELECTION, Selection.FALSE, -1);
+ } else if (files_selected != has_tag_in_selection) {
+ store.set (iter, Col.SELECTION, Selection.INCONSISTENT, -1);
+ } else {
+ store.set (iter, Col.SELECTION, Selection.TRUE, -1);
+ }
+
+ str = "%d".printf (files_with_tag);
+ store.set (iter, Col.TAG_COUNT, str, Col.TAG_COUNT_VALUE, files_with_tag, -1);
+
+ debug ("Tags for file updated");
+ store.remove (td_copy.iter);
+ } catch (GLib.Error e) {
+ warning ("Could not run Sparql query: %s", e.message);
+ show_error_dialog (e);
+ }
+
+ tag_data_requests -= td_copy;
+ td_copy = null;
+ }
+}
+
diff --git a/src/tracker-needle/tracker-view.vala b/src/tracker-needle/tracker-view.vala
index 0c51af3..79fafe6 100644
--- a/src/tracker-needle/tracker-view.vala
+++ b/src/tracker-needle/tracker-view.vala
@@ -452,14 +452,8 @@ public class Tracker.View : ScrolledWindow {
var separator = new SeparatorMenuItem ();
context_menu.append (separator);
- item = new MenuItem.with_mnemonic (_("_Add Tag..."));
- item.activate.connect (context_menu_tag_add_clicked);
- item.sensitive = false;
- context_menu.append (item);
-
- item = new MenuItem.with_mnemonic (_("_Remove Tag..."));
- item.activate.connect (context_menu_tag_remove_clicked);
- item.sensitive = false;
+ item = new MenuItem.with_mnemonic (_("_Tags..."));
+ item.activate.connect (context_menu_tags_clicked);
context_menu.append (item);
context_menu.show_all ();
@@ -522,12 +516,7 @@ public class Tracker.View : ScrolledWindow {
tracker_model_launch_selected_parent_dir (model, path, 1);
}
- private void context_menu_tag_add_clicked () {
- warning ("Not yet implemented");
- }
-
- private void context_menu_tag_remove_clicked () {
+ private void context_menu_tags_clicked () {
warning ("Not yet implemented");
}
-
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]