Update called vala api.
[stuffkeeper.git] / src / stuffkeeper-interface.gob
blobc6f8b5a9ae2dc23a5c0829aaafe3595402df6ad6
1 requires 2.0.10
3 %h{
4 #include "stuffkeeper-data-backend.h"
5 #include "stuffkeeper-data-schema.h"
6 #include "stuffkeeper-data-tag.h"
7 #include "stuffkeeper-data-item-search.h"
8 #include "stuffkeeper-item-view.h"
9 %}
11 %ph{
12 /* Include gtk */
13 #include <gtk/gtk.h>
14 #include <gdk/gdkkeysyms.h>
15 #include <glib/gi18n.h>
16 #include <config.h>
17 #include "misc.h"
19 /* Include the database */
21 #include "stuffkeeper-data-backend.h"
22 #include "stuffkeeper-edit-schema.h"
23 #include "stuffkeeper-show-item.h"
24 #include "stuffkeeper-item-window.h"
25 #include "stuffkeeper-export-html.h"
26 #include "stuffkeeper-item-window.h"
27 #include "stuffkeeper-plugin-manager.h"
28 #include "stuffkeeper-plugin.h"
30 #include "stuffkeeper-multiple-item-view.h"
34 %ph{
35 #include "revision.h"
36     const gchar *artists[] = {
37         "Jakub Szypulka (http://cubestuff.wordpress.com )",
38         "Tango Project (http://tango.freedesktop.org/ )",
39     NULL};
40     const gchar *authors[] = {
41         "Martijn Koedam (qball) <Qball@Stuffkeeper.org>", 
42         "Barak Korren (ifireball)",
43         "\nTester:",
44         "Greg Fitzgerald",
45         "Rasi <rasi@stuffkeeper.org>",
46     NULL};
48     typedef enum _LPColumnType{
49         LP_ID, 
50         LP_TITLE,
51         LP_SELECTED,
52         LP_ITEM,
53         LP_AMOUNT,
54         LP_NUM_ROWS
55     } LPColumnType;
57     typedef enum _LPType {
58         LP_TYPE_TAG,
59         LP_TYPE_SCHEMA,
60         LP_TYPE_SEARCH
61     }LPType;
64 class Stuffkeeper:Interface from G:Object 
66     private GtkTreeModel        *model_tags         = {NULL};
67     private GtkTreeModel        *model_tags_filter  = {NULL};
68     private GtkTreeModel        *model_items        = {NULL};
69     private GtkTreeModel        *model_schemas      = {NULL};
70     /* search items */
71     private GtkTreeModel        *model_searches     = {NULL};
72     private GtkTreeModel        *model_items_filter = {NULL};
74     public GKeyFile            *config_file        = {NULL};
76     /* Menu */
77     private GtkWidget           *menu               = {NULL};
78     private GtkWidget           *menu_item_add      = {NULL};
79     /**
80      * Treeview 1 & 2
81      */
82     private GtkBuilder            *xml;
83     private GtkWidget           *win;
84     private GtkWidget           *LeftPaneCB;
85     private GtkWidget           *treeview1;
86     private GtkWidget           *treeview2;
87     private GtkTreeViewColumn   *column_lv_pixbuf = {NULL};
88     private GtkCellRenderer     *treeview1_renderer = {NULL};
89     private GtkCellRenderer     *renderer_toggle = {NULL};
90     
91     private GtkWidget           *LeftPane_edit ;
92     private GtkWidget           *AddMenuButton ;
93     private GtkWidget           *search_entry ;
94     private GtkWidget           *hpaned1;
95     private GtkWidget           *vpaned1;
96     private GtkWidget           *item_label;
97     private GtkWidget           *cb_search;
99     private GtkWidget           *item_view_container;
100     private GtkWidget           *show_item_pane_menu_item;
102     private GtkWidget           *menuitem_item_add;
104     private StuffkeeperDataBackend *skdbg = {NULL};
105     private StuffkeeperPluginManager *spm = {NULL};
106     /**
107      * Signals 
108      */
109     /* schema */
110     private gulong signal_schema_added = {0};
111     private gulong signal_schema_changed = {0};
112     private gulong signal_schema_removed = {0};
113     /* tag */
114     private gulong signal_tag_added = {0};
115     private gulong signal_tag_changed = {0};
116     private gulong signal_tag_removed = {0};
117     /* item */
118     private gulong signal_item_added = {0};
119     private gulong signal_item_changed = {0};
120     private gulong signal_item_removed = {0};
122     /* search/filter */
123     private gulong search_timeout = {0};
124     private gulong signal_search_added = {0};
125     private gulong signal_search_changed = {0};
126     private gulong signal_search_removed = {0};
127     /* backend */
128     private gulong signal_backend_locked = {0};
130     private int item_sort_column = {3};
131     private int item_sort_order = {GTK_SORT_DESCENDING};
132     
133     private signal last NONE (POINTER)
134     void item_added_here(self, Stuffkeeper:Data:Item *item (check null type)) 
135     {
136         GtkTreeIter iter;
137         GtkTreePath *path = NULL;
138         GtkTreeModel *store =GTK_TREE_MODEL(self->_priv->model_items_filter);
140         if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
141             StuffkeeperDataItem *found_item = NULL;
142             g_debug("Searching new item in tree\n");
143             do {
144                 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &found_item, -1);
145                 if(found_item == item) {
146                     g_debug("Found new item in tree\n");
147                     path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
148                     break;
149                 }
150             } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
151             if(path) {
152                 g_debug("Moving cursor to new item\n");
153                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(self->_priv->treeview2), path, NULL, FALSE);
154                 gtk_tree_path_free(path);
155             }else {
156                 self_popup_item(self, item);
157             }
158         }
159     }
161     /**
162     * Changes in the GtkTreeModelFilter wrapper, updating the total item label.
163      */
164     private
165     void
166     filter_model_row_inserted(self, GtkTreePath *path, GtkTreeIter *iter, GtkTreeModel  *model)
167     {
168         int num_items = gtk_tree_model_iter_n_children(self->_priv->model_items_filter, NULL);
169         gchar *data = g_strdup_printf("%i", num_items); 
170         gtk_label_set_text(GTK_LABEL(self->_priv->item_label), data);
171         g_free(data);
172     }
174     private
175     void
176     filter_model_row_deleted(self, GtkTreePath *path, GtkTreeModel *model)
177     {
178         int num_items = gtk_tree_model_iter_n_children(self->_priv->model_items_filter, NULL);
179         gchar *data = g_strdup_printf("%i", num_items); 
180         gtk_label_set_text(GTK_LABEL(self->_priv->item_label), data);
181         g_free(data);
182     }
183     /**
184      * Search added
185      */
186     private 
187     void
188     search_changed(self, const SearchField *field, StuffkeeperDataItemSearch *search)
189     {
190         if(!field)
191         {
192             GtkTreeIter iter;
193             GtkTreeModel *model = GTK_TREE_MODEL(self->_priv->model_searches);
194             gint id = stuffkeeper_data_item_search_get_id(search);
195             if(gtk_tree_model_get_iter_first(model, &iter))
196             {
197                 do{
198                     gint oid;
199                     gtk_tree_model_get(model, &iter, 0, &oid, -1);
200                     if(oid == id)
201                     {
202                         gchar *title = stuffkeeper_data_item_search_get_title(search);
203                         gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
204                             LP_TITLE,title,
205                             -1);
206                         g_free(title);
207                     }
208                 }while(gtk_tree_model_iter_next(model, &iter));
209             }
210         }
211         gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
212     }
214     private
215     void
216     search_added(self, StuffkeeperDataItemSearch *search,  StuffkeeperDataBackend *skdb)
217     {
218         GtkTreeIter iter;
219         gchar *title = stuffkeeper_data_item_search_get_title(search);
221         gtk_list_store_insert_with_values(GTK_LIST_STORE(self->_priv->model_searches), &iter, -1,
222                 LP_ID, stuffkeeper_data_item_search_get_id(search),
223                 LP_TITLE, title,
224                 LP_ITEM, search,
225                 -1);
226         g_free(title);
227     }
229     private
230     void 
231     search_removed(self, gint id, StuffkeeperDataBackend *skdb)
232     {
233         GtkTreeIter iter;
234         GtkTreeModel *model = GTK_TREE_MODEL(self->_priv->model_searches);
235         if(gtk_tree_model_get_iter_first(model, &iter))
236         {
237             do{
238                 gint oid;
239                 gtk_tree_model_get(model, &iter, LP_ID, &oid, -1);
240                 if(oid == id)
241                 {
242                     gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
243                     gtk_combo_box_set_active(GTK_COMBO_BOX(self->_priv->cb_search), 0);
244                     return;
245                 }
246             }while(gtk_tree_model_iter_next(model, &iter));
247         }
248     }
251     /**
252      * Keep Schema's GtkListStore up2date
253      */
254     private
255     void 
256     schema_added(self, StuffkeeperDataSchema *schema,StuffkeeperDataBackend *skdb )
257     {
258         GtkTreeIter iter;
259         gchar *title = stuffkeeper_data_schema_get_title(schema);
260         gtk_list_store_insert_with_values(GTK_LIST_STORE(self->_priv->model_schemas), &iter, -1,
261                     LP_ID, stuffkeeper_data_schema_get_id(schema),
262                     LP_TITLE, title,
263                     LP_ITEM, schema,
264                     LP_AMOUNT, stuffkeeper_data_schema_num_items(schema),-1);
267         g_free(title);
269         self_update_all_item_add_menus(self);
270     }
271     private
272     void 
273     schema_changed(self, StuffkeeperDataSchema *schema, StuffkeeperDataBackend *skdb)
274     {
275         GtkTreeIter iter;
276         GtkTreeModel *model = GTK_TREE_MODEL(self->_priv->model_schemas);
277         gint id = stuffkeeper_data_schema_get_id(schema);
278         if(gtk_tree_model_get_iter_first(model, &iter))
279         {
280             do{
281                 gint oid;
282                 gtk_tree_model_get(model, &iter, LP_ID, &oid, -1);
283                 if(oid == id)
284                 {
285                     gchar *title = stuffkeeper_data_schema_get_title(schema);
286                     gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
287                         LP_TITLE,title, 
288                         LP_AMOUNT, stuffkeeper_data_schema_num_items(schema),
289                         -1);
290                     g_free(title);
291                 }
292             }while(gtk_tree_model_iter_next(model, &iter));
293         }
294         /**
295          * If schema add-button prefered schema is this schema, update the tooltip.
296          */
297         if(g_object_get_data(G_OBJECT(self->_priv->AddMenuButton), "schema")  == schema)
298         {
299                gtk_widget_set_tooltip_text(self->_priv->AddMenuButton, stuffkeeper_data_schema_get_title(schema));
300         }
301         self_update_all_item_add_menus(self);
302     }
303     private
304     void 
305     schema_removed(self, gint id, StuffkeeperDataBackend *skdb)
306     {
307         GtkTreeIter iter;
308         GtkTreeModel *model = GTK_TREE_MODEL(self->_priv->model_schemas);
310         if(gtk_tree_model_get_iter_first(model, &iter))
311         {
312             do{
313                 gint oid;
314                 gtk_tree_model_get(model, &iter, LP_ID, &oid, -1);
315                 if(oid == id)
316                 {
317                     gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
318                     break;
319                 }
320             }while(gtk_tree_model_iter_next(model, &iter));
321         }
322         printf("Resetting schema\n" );
323         /* Reset tooltip and item that is added on AddButton */
324         g_object_set_data(G_OBJECT(self->_priv->AddMenuButton), "schema", NULL);
325         gtk_widget_set_tooltip_text(self->_priv->AddMenuButton, "");
326         /* Update both menus */
327         self_update_all_item_add_menus(self);
328     }
330     /**
331      * Keep Tag's GtkListStore up2date
332      */
333     private
334     void 
335     tag_added(StuffkeeperDataBackend *skdb, StuffkeeperDataTag *tag, GtkTreeModel *store)
336     {
337         GtkTreeIter iter;
338         gchar *title = stuffkeeper_data_tag_get_title(tag);
339         gtk_list_store_insert_with_values(GTK_LIST_STORE(store), &iter, -1,
340                     LP_ID, stuffkeeper_data_tag_get_id(tag),
341                     LP_TITLE,title,
342                     LP_ITEM,tag, 
343                     LP_AMOUNT, stuffkeeper_data_tag_num_items(tag),
344                     -1);
345         g_free(title);
346     }
347     private
348     void 
349     tag_changed(StuffkeeperDataBackend *skdb, StuffkeeperDataTag *tag, GtkTreeModel *store)
350     {
351         GtkTreeIter iter;
352         GtkTreeModel *model = GTK_TREE_MODEL(store);
353         gint id = stuffkeeper_data_tag_get_id(tag);
354         if(gtk_tree_model_get_iter_first(model, &iter))
355         {
356             do{
357                 gint oid;
358                 gtk_tree_model_get(model, &iter, LP_ID, &oid, -1);
359                 if(oid == id)
360                 {
361                     gchar *title = stuffkeeper_data_tag_get_title(tag);
362                     gtk_list_store_set(GTK_LIST_STORE(store), &iter, 
363                             LP_TITLE,title, 
364                             LP_AMOUNT, stuffkeeper_data_tag_num_items(tag),
365                             -1);
366                     g_free(title);
367                     return;
368                 }
369             }while(gtk_tree_model_iter_next(model, &iter));
370         }
371     }
372     private
373     void 
374     tag_removed(StuffkeeperDataBackend *skdb, gint id, GtkListStore *store)
375     {
376         GtkTreeIter iter;
377         GtkTreeModel *model = GTK_TREE_MODEL(store);
378         if(gtk_tree_model_get_iter_first(model, &iter))
379         {
380             do{
381                 gint oid;
382                 gtk_tree_model_get(model, &iter, LP_ID, &oid, -1);
383                 if(oid == id)
384                 {
385                     gtk_list_store_remove(store, &iter);
386                     return;
387                 }
388             }while(gtk_tree_model_iter_next(model, &iter));
389         }
390     }
392     /**
393      * Item GtkListStore
394      * Update the gtk-list-store with signals from the backend
395      */
396     private
397     void
398     item_removed(StuffkeeperDataBackend *skdb, gint id,StuffkeeperInterface *self) 
399     {
400         GtkTreeIter iter;
401         GtkListStore *store = GTK_LIST_STORE(self->_priv->model_items);
402         GtkTreeModel *model = GTK_TREE_MODEL(store);
404         if(gtk_tree_model_get_iter_first(model, &iter))
405         {
406             do{
407                 gint oid;
408                 gtk_tree_model_get(model, &iter, 0, &oid, -1);
409                 if(oid == id)
410                 {
411                     gtk_list_store_remove(store, &iter);
412                     return;
413                 }
414             }while(gtk_tree_model_iter_next(model, &iter));
415         }
416     }
417     private
418     void
419     item_added(StuffkeeperDataBackend *skdb, StuffkeeperDataItem *item, StuffkeeperInterface *self) 
420     {
421         GtkTreeIter iter;
422         GtkListStore *store = GTK_LIST_STORE(self->_priv->model_items);
424         gchar *title = stuffkeeper_data_item_get_title(item);
426         gtk_list_store_insert_with_values(GTK_LIST_STORE(store), &iter,-1,
427                     0, stuffkeeper_data_item_get_id(item),
428                     1, title, 
429                     2, item,
430                     3, stuffkeeper_data_item_get_creation_time(item),
431                     4, stuffkeeper_data_schema_get_id(stuffkeeper_data_item_get_schema(item)),
432                     5, stuffkeeper_data_item_get_modification_time(item),
433                     -1);
434         g_free(title);
435     }
436     private
437     void
438     item_changed(StuffkeeperDataBackend *skdb, const gchar *field, StuffkeeperDataItem *item, StuffkeeperInterface *self) 
439     {
440         GtkTreeIter iter;
441         GtkListStore *store = GTK_LIST_STORE(self->_priv->model_items);
442         GtkTreeModel *model = GTK_TREE_MODEL(store);
443         gint id = stuffkeeper_data_item_get_id(item);
444         if(gtk_tree_model_get_iter_first(model, &iter))
445         {
446             do{
447                 gint oid;
448                 gtk_tree_model_get(model, &iter, 0, &oid, -1);
449                 if(oid == id)
450                 {
451                     gchar *title = stuffkeeper_data_item_get_title(item);
452                     gtk_list_store_set(store, &iter, 1,title, 
453                             -1);
455                     g_free(title);
456                     return;
457                 }
458             }while(gtk_tree_model_iter_next(model, &iter));
459         }
460     }
462     private void add_item(self, StuffkeeperDataSchema *schema)
463     {
464         GtkTreeIter iter;
465         StuffkeeperDataItem *item = stuffkeeper_data_backend_new_item(self->_priv->skdbg,schema);
466         /* Set new item tags */
467         if(gtk_tree_model_get_iter_first(self->_priv->model_tags, &iter))
468         {
469             do{
470                 StuffkeeperDataTag *tag = NULL;
471                 gboolean enabled;
472                 gtk_tree_model_get(GTK_TREE_MODEL(self->_priv->model_tags), &iter,2, &enabled, 3,&tag, -1); 
473                 if(enabled)
474                 {
475                     stuffkeeper_data_item_add_tag(item, tag);
476                 }
478             }while(gtk_tree_model_iter_next(self->_priv->model_tags, &iter));
479         }
480         /* signal to other window components that the item was added on this
481          * window */
482         self_item_added_here(self, item);
483     }
484     /**
485      * Add item button clicked 
486      */
487     public void interface_item_add(self,GtkWidget *button)
488     {
489         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
490         if(locked){printf("**ERROR** should not be callable\n");return;}
492         GList *list = stuffkeeper_data_backend_get_schemas(self->_priv->skdbg);
493         /* check if there are schema's */
494         if(list)
495         {
496             StuffkeeperDataSchema *schema = g_object_get_data(G_OBJECT(button), "schema");
497             /* if there is no schema, get the first*/
498             if(schema  == NULL || !STUFFKEEPER_IS_DATA_SCHEMA(schema))
499             {
500                 schema = list->data;
501             }
502             /* Update tooltip with the name of the schema to be added */
503             g_object_set_data(G_OBJECT(self->_priv->AddMenuButton), "schema", list->data);
504             gtk_widget_set_tooltip_text(button, stuffkeeper_data_schema_get_title(schema));
505             self_add_item(self, schema);
506             g_list_free(list);
507         }
508     }
510     private void interface_item_add_menu_button(self, GtkWidget *button)
511     {
512         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
513         if(locked){printf("**ERROR** should not be callable\n");return;}
514         StuffkeeperDataSchema *schema = g_object_get_data(G_OBJECT(button), "schema");
515         if(schema)
516         {
517             self_add_item(self, schema);
518             /* Store last added item. */
519             g_object_set_data(G_OBJECT(self->_priv->AddMenuButton), "schema", schema);
520             /* Set tooltip */
521             gtk_widget_set_tooltip_text(self->_priv->AddMenuButton, stuffkeeper_data_schema_get_title(schema));
522         }
523     }
525     /**
526      * Remove selected item
527      */
528     public void interface_item_remove(self)
529     {
530         if(stuffkeeper_data_backend_get_locked(self->_priv->skdbg)){
531             printf("**ERROR** should not be callable\n");
532             return;
533         }
535         /** Setup a dialog that ask the user if he is sure */
536         GtkWidget *tree = self->_priv->treeview2;
537         GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
538         GtkTreeModel *model = GTK_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(tree)));
539         GtkTreeIter iter;
540         if(gtk_tree_selection_count_selected_rows(selection)>0)
541         {
542             GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(self->_priv->win), 
543                     GTK_DIALOG_DESTROY_WITH_PARENT|// This belongs to the parent, so if the user closes the parent, close it
544                     GTK_DIALOG_MODAL, // It is a warning, it _should_ be modal.
545                     GTK_MESSAGE_WARNING, // It is a warning message.
546                     GTK_BUTTONS_YES_NO, // yes/no question
547                     _("Deleting an entry cannot be undone.\nAre you sure you want to continue?"));
548             if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
549             {
550                 gint id;
551                 GList *node,*list = gtk_tree_selection_get_selected_rows(selection, &model);
552                 for(node = g_list_last(list); node; node = g_list_previous(node))
553                 {
554                     if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)node->data))
555                     {
556                         gtk_tree_model_get(model, &iter ,0,&id, -1);
557                         stuffkeeper_data_backend_remove_item(self->_priv->skdbg, id);
558                     }
559                 }
560                 if(list){
561                     g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
562                     g_list_free (list);
563                 }
564             }
565             gtk_widget_destroy(dialog);
566         }
567     }
568     /**
569      * Clone selectd item
570      */
571     public void interface_item_clone(self)
572     {
573         GtkTreeModel *model;
574         GtkTreeIter iter;
575         GtkTreeSelection *selection;
576         GList *node,*list;
577         if(stuffkeeper_data_backend_get_locked(self->_priv->skdbg)){
578             printf("**ERROR** should not be callable\n");
579             return;
580         }
582         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
583         list = gtk_tree_selection_get_selected_rows(selection, &model);
584         for(node = g_list_first(list); node; node = g_list_next(node))
585         {
586             if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)node->data))
587             {
588                 StuffkeeperDataItem *orig_item, *item; 
589                 gtk_tree_model_get(model, &iter , 2, &orig_item, -1);
590                 item = stuffkeeper_data_backend_clone_item(self->_priv->skdbg, orig_item);
591                 /* signal to other window components that the item was added on this
592                  * window */
593                 self_item_added_here(self, item);
594             }
595         }
596         if(list)
597         {
598             g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
599             g_list_free(list);
600         }
601     }
603     /**
604      * Tag is enabled/disabled
605      */
606     private
607         void 
608         interface_left_pane_toggled(self, gchar *path, GtkCellRendererToggle *renderer)
609         {
610             int type = gtk_combo_box_get_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB));
611             GtkTreeIter iter;
612             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
613             if(type == LP_TYPE_SEARCH)
614             {
615                 gboolean value = !gtk_cell_renderer_toggle_get_active(renderer);
616                 if(value == FALSE)
617                 {
618                     gtk_combo_box_set_active(GTK_COMBO_BOX(self->_priv->cb_search), 0);
619                 }else{
620                     GtkTreeIter iter;
621                     if(gtk_tree_model_get_iter_from_string(model, &iter, path))
622                     {
623                         gtk_combo_box_set_active_iter(GTK_COMBO_BOX(self->_priv->cb_search), &iter);
624                     }
625                 }
626             }
627             else if (type == LP_TYPE_TAG)
628             {
630                 if(gtk_tree_model_get_iter_from_string(model, &iter, path))
631                 {
632                     GtkTreeIter child;
633                     gboolean value = !gtk_cell_renderer_toggle_get_active(renderer);
634                     gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &child, &iter);
636                     gtk_list_store_set(GTK_LIST_STORE(self->_priv->model_tags), &child, LP_SELECTED, value, -1);
637                     /* refilter the items list */
638                     gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
639                 }
641             }
642             else
643             {
644                 if(gtk_tree_model_get_iter_from_string(model, &iter, path))
645                 {
646                     gboolean value = !gtk_cell_renderer_toggle_get_active(renderer);
648                     gtk_list_store_set(GTK_LIST_STORE(model), &iter, LP_SELECTED,value,-1);
650                     /* refilter the items list */
651                     gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
652                 }
653             }
654         }
656     private
657         void interface_item_title_edited
658         (
659          self,
660          gchar               *path,
661          gchar               *new_text,
662          GtkCellRendererText *renderer
663         )
664         {
665             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview2));
666             GtkTreeIter iter;
667             if(gtk_tree_model_get_iter_from_string(model, &iter, path))
668             {
669                 gint id;
670                 StuffkeeperDataItem *item;
671                 gtk_tree_model_get(model, &iter ,0,&id, -1);
672                 item = stuffkeeper_data_backend_get_item(self->_priv->skdbg, id);
673                 if(item)
674                 {
675                     stuffkeeper_data_item_set_title(item, new_text);
676                 }
677             }
678         }
680     private
681         void interface_left_pane_edited 
682         (
683          self,
684          gchar               *path,
685          gchar               *new_text,
686          GtkCellRendererText *renderer
687         )
689         {
690             GtkTreeIter iter;
691             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
692             if(gtk_tree_model_get_iter_from_string(model, &iter, path))
693             {
694                 GObject *item;
696                 gtk_tree_model_get(model, &iter ,LP_ITEM,&item, -1);
698                 if(STUFFKEEPER_IS_DATA_TAG(item)) {
699                     stuffkeeper_data_tag_set_title(STUFFKEEPER_DATA_TAG(item), new_text);
700                 }else if (STUFFKEEPER_IS_DATA_SCHEMA(item)){
701                     stuffkeeper_data_schema_set_title(STUFFKEEPER_DATA_SCHEMA(item), new_text);
702                }else if (STUFFKEEPER_IS_DATA_ITEM_SEARCH(item)){
703                    stuffkeeper_data_item_search_set_title(STUFFKEEPER_DATA_ITEM_SEARCH(item), new_text);
704                 }
705             }
706         }
707     /**
708      * Quit the program
709      */
710     public
711     void quit_program(void)
712     {
713         gtk_main_quit();
714     }
716     public 
717     gboolean 
718     close_window(self)
719     {
720         self_destroy(self);
721         g_object_unref(self);
722         return TRUE;
723     }
724     public
725     void
726     new_window(self)
727     {
728         Self *ski;
729         ski= stuffkeeper_interface_new(self->config_file);
730         stuffkeeper_interface_initialize_interface(ski,self->_priv->skdbg,G_OBJECT(self->_priv->spm));
731     }
733     /**
734      * Filtering the item list
735      */
736     public
737         gboolean 
738         interface_visible_func(GtkTreeModel *model, GtkTreeIter *iter, StuffkeeperInterface *self) 
739         {
740             StuffkeeperDataItem *item;
741             /* Get the item */
742             gtk_tree_model_get(model, iter, 2,&item, -1);
745             if(!item) {
746                 return FALSE;
747             }
748             return self_item_is_visible(self, item);
749         }
750     public
751     gboolean
752     item_is_visible(self, StuffkeeperDataItem *item)
753     {
754         int type = gtk_combo_box_get_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB));
755         const gchar *text = gtk_entry_get_text(GTK_ENTRY(self->_priv->search_entry));
756         GtkTreeModel *model2 = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
757         GtkTreeIter piter;
758         GtkTreeIter iter;
759         /**
760          * Left pane selection filtering
761          * Only when search type is not filter
762          */
763         if(gtk_tree_model_get_iter_first(model2, &piter) && type != LP_TYPE_SEARCH)
764         {
765             int found = -1;
766             do{
767                 GObject *tag;
768                 gboolean sel;
769                 /* get the tag, and if it is selected */
770                 gtk_tree_model_get(model2, &piter,LP_SELECTED,&sel, LP_ITEM,&tag, -1);
772                 if(sel && tag)
773                 {
774                     if(type == LP_TYPE_TAG && !stuffkeeper_data_item_has_tag(item, STUFFKEEPER_DATA_TAG(tag)))
775                     {
776                         return FALSE;
777                     }
778                     /* if viewing types, and it matches mark found */
779                     else if (type == LP_TYPE_SCHEMA && 
780                              stuffkeeper_data_schema_get_id(stuffkeeper_data_item_get_schema(item)) == 
781                              stuffkeeper_data_schema_get_id(STUFFKEEPER_DATA_SCHEMA(tag)))
782                     {
783                         found = 1;
784                     }
785                     /* set that there are items selected */
786                     else if (type == LP_TYPE_SCHEMA && found == -1)
787                     {
788                         found = 0;
789                     }
790                 }
792             }while(gtk_tree_model_iter_next(model2, &piter));
793             /* if viewing types and no selected item matches return FALSE */
794             if(type == LP_TYPE_SCHEMA && found == 0)
795             {
796                 return FALSE;
797             }
798         }
799         /**
800          * Execute filter 
801          */
802         if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_priv->cb_search), &iter))
803         {
804             StuffkeeperDataItemSearch *search;
805             gtk_tree_model_get(self->_priv->model_searches, &iter, LP_ITEM, &search, -1);
806             if(search)
807             {
808                 if(!stuffkeeper_data_item_search_match(search, item))
809                 {
810                     return FALSE;
811                 }
812             }
813         }
814         /**
815          * Search box 
816          */
817         if(strlen(text) > 0)
818         {
819             return stuffkeeper_data_item_has_value(item,text); 
820         }
821         return TRUE;
822     }
823     private
824     gboolean
825     search_entry_changed_timeout(self)
826     {
827         gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
829         self->_priv->search_timeout =0;
830         /* remove it */
831         return FALSE;
832     }
833     private
834         void
835         search_entry_icon_clicked(self,GtkEntryIconPosition pos, GdkEvent *event, GtkEntry *entry)
836     {
837                 if(pos == GTK_ENTRY_ICON_SECONDARY) {
838                         gtk_entry_set_text(entry, "");
839                 }       
840     }
841     
842     public
843     void
844     search_entry_changed(self)
845     {
846         if(self->_priv->search_timeout) {
847             g_source_remove(self->_priv->search_timeout);
848             self->_priv->search_timeout = 0;
849         }
850         self->_priv->search_timeout = g_timeout_add(100,(GSourceFunc)self_search_entry_changed_timeout, self);
851     }
852    
853     private 
854     void
855     schema_edit_button_clicked(self, GtkWidget *button)
856     {
857         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
858         if(locked){printf("**ERROR** should not be callable\n");return;}
860         StuffkeeperDataSchema *schema = g_object_get_data(G_OBJECT(button), "schema");
861         if(schema)
862         {
863             StuffkeeperEditSchema *skes = stuffkeeper_edit_schema_new();
864             stuffkeeper_edit_schema_set_schema(skes, schema);
865         }
866     }
867     private 
868         void
869         interface_background_changed(GtkWidget *widget, GtkStyle *old, GtkWidget *wid)
870         {
871             g_signal_handlers_block_by_func(G_OBJECT(widget), self_interface_background_changed, wid);
872             gtk_widget_modify_bg(wid, GTK_STATE_NORMAL, &(widget->style->light[GTK_STATE_NORMAL]));
873             g_signal_handlers_unblock_by_func(G_OBJECT(widget),self_interface_background_changed, wid);
874         }
876     public
877     void
878     item_pane_checkbox(self,GtkCheckMenuItem *item)
879     {
880         self_interface_item_selection_changed(self, gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2)));
881     }
883    private 
884         void 
885         interface_item_selection_changed (self, GtkTreeSelection *selection)
886         {
888             GtkTreeModel *model;
889             GtkTreeIter iter;
890             GList *list;
891             int selected_items;
892             gboolean show_pane = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(self->_priv->show_item_pane_menu_item));
894             list = gtk_container_get_children(GTK_CONTAINER(self->_priv->item_view_container));
895             if(list)
896             {
897                 GList *node;
898                 for(node = g_list_first(list); node; node = g_list_next(node))
899                 {
900                     gtk_widget_destroy(GTK_WIDGET(node->data));
901                 }
902                 g_list_free(list);
903             }
904             if(!show_pane)
905             {
906                 gtk_widget_hide(self->_priv->item_view_container);
907                 return;
908             }
911             model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview2));
912             selected_items = gtk_tree_selection_count_selected_rows(selection);
913             if( selected_items == 1)
914             {
915                 StuffkeeperDataItem *item;
916                 GList *list = gtk_tree_selection_get_selected_rows(selection, &model);
917                 if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)list->data))
918                 {
919                     gtk_tree_model_get(model, &iter, 2, &item, -1);
920                     if(item)
921                     {
922                         GtkWidget *wid = stuffkeeper_item_view_new(item);
923                         gtk_container_add(GTK_CONTAINER(self->_priv->item_view_container), wid);
924                         gtk_widget_show_all(self->_priv->item_view_container);
925                     }
926                 }
927                 if(list)
928                 {
929                     g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
930                     g_list_free(list);
931                 }
932             }
933             else if ( selected_items > 1) 
934             {
935                 GtkWidget *wid = NULL;
936                 StuffkeeperDataItem *item;
937                 /* Multiple items selected */
938                 GList *list = gtk_tree_selection_get_selected_rows(selection, &model);
939                 GList *mitems = NULL, *liter;
940                 for(liter = g_list_first(list); liter ; liter = g_list_next(liter)){
941                     if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)liter->data))
942                     {
943                         gtk_tree_model_get(model, &iter, 2, &item, -1);
944                         mitems = g_list_prepend(mitems, item);
945                     }
946                 }
947                 if(mitems) mitems = g_list_reverse(mitems);
948                 /* Edit multiple items widget */
949                 wid = (GtkWidget *)stuffkeeper_multiple_item_view_new(self->_priv->skdbg,mitems, NULL);
950                 gtk_container_add(GTK_CONTAINER(self->_priv->item_view_container), wid);
951                 gtk_widget_show_all(self->_priv->item_view_container);
952                 /* cleanup */
953                 if(mitems) { g_list_free(mitems); mitems = NULL;}
956                 if(list)
957                 {
958                     g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
959                     g_list_free(list);
960                 }
961             }
962             else
963             {
964                 GtkWidget *frame = gtk_frame_new(NULL);
965                 GtkWidget *label = gtk_label_new("");
966                 GtkWidget *event = gtk_event_box_new();
967                 GtkWidget *hbox = gtk_hbox_new(FALSE, 6);
968                 GtkWidget *ali = gtk_alignment_new(1.0, 0.5,0,0);
970                 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
971                 g_signal_connect(G_OBJECT(event), "style-set", G_CALLBACK(self_interface_background_changed), event);
972                 gtk_label_set_markup(GTK_LABEL(label), _("<b>No item to preview, select an item from the item list to preview it</b>"));
974                 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
976                 gtk_container_add(GTK_CONTAINER(ali), gtk_image_new_from_icon_name("stuffkeeper", GTK_ICON_SIZE_DIALOG));
977                  gtk_box_pack_start(GTK_BOX(hbox),ali, TRUE, TRUE, 0);               
978                 gtk_box_pack_start(GTK_BOX(hbox),label, TRUE, TRUE, 0);
980                 gtk_container_add(GTK_CONTAINER(frame),hbox);
981                 gtk_container_add(GTK_CONTAINER(event),frame);
982                 gtk_container_add(GTK_CONTAINER(self->_priv->item_view_container), event);
984                 gtk_widget_modify_bg(event, GTK_STATE_NORMAL, &(self->_priv->item_view_container->style->white));
985                 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &(self->_priv->item_view_container->style->black));
986                 gtk_widget_show_all(self->_priv->item_view_container);
987             }
988             return;
989         }
991      /**
992      * Right mouse handling left treeview
993      */
994     /**
995      * Label signals
996      */
997      private
998      void
999      add_tag(self, GtkMenuItem *item)
1000      {
1001          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1002          if(locked){printf("**ERROR** should not be callable\n");return;}
1003          g_signal_handler_block(self->_priv->skdbg,self->_priv->signal_tag_added);
1004          StuffkeeperDataTag *tag = stuffkeeper_data_backend_new_tag(self->_priv->skdbg);
1006          stuffkeeper_data_tag_set_title(tag, _("New Tag"));
1007          if(tag)
1008          {
1009              GtkTreeIter iter;
1010              gtk_list_store_append(GTK_LIST_STORE(self->_priv->model_tags), &iter);
1011              gchar *title = stuffkeeper_data_tag_get_title(tag);
1012              gtk_list_store_set(GTK_LIST_STORE(self->_priv->model_tags), &iter, 
1013                      0, stuffkeeper_data_tag_get_id(tag),
1014                      1,title,
1015                      3,tag, 
1016                      4, stuffkeeper_data_tag_num_items(tag),
1017                      -1);
1019              if(self->_priv->treeview1_renderer)
1020              {
1021                  GtkTreeViewColumn *col = gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview1), 1);
1022                  GtkTreePath *path = gtk_tree_model_get_path(self->_priv->model_tags, &iter);
1023                  gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(self->_priv->treeview1), path, col,self->_priv->treeview1_renderer, TRUE);
1024                  gtk_tree_path_free(path);
1025              }
1026              g_free(title);
1027          }
1028          g_signal_handler_unblock(self->_priv->skdbg,self->_priv->signal_tag_added);
1029      }
1030      private 
1031      void
1032      remove_tag(self, GtkMenuItem *item)
1033      {
1034          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1035          if(locked){printf("**ERROR** should not be callable\n");return;}
1036          GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1037          GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1038          GtkTreeIter iter;
1039          if(gtk_tree_selection_get_selected(selection,&model, &iter))
1040          {
1041              gint items;
1042              gint id;
1043              /* Get id and items */
1044              gtk_tree_model_get(model, &iter,0,&id,4,&items, -1);
1046              if(items == 0)
1047              {
1048                  stuffkeeper_data_backend_remove_tag(self->_priv->skdbg,id);
1049              }
1050          }
1051      }
1052      private 
1053      void
1054      open_tag(self, GtkMenuItem *item)
1055      {
1056          GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1057          GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1058          GtkTreeIter iter;
1059          if(gtk_tree_selection_get_selected(selection,&model, &iter))
1060          {
1061              StuffkeeperDataTag *tag = NULL;
1062              /* Get id and items */
1063              gtk_tree_model_get(model, &iter,3,&tag, -1);
1064              if(tag) {
1065                  gchar *title = stuffkeeper_data_tag_get_title(tag);
1066                  GtkWidget *win = stuffkeeper_item_window_new_tag_list(self->_priv->skdbg, tag,config_file, title);
1067                  g_free(title);
1068                  gtk_widget_show(win);
1069              }
1070          }
1071      }
1074     /* Types */
1076      private
1077      void
1078      add_item_of_type(self, GtkMenuItem *item)
1079      {
1080          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1081          if(locked){printf("**ERROR** should not be callable\n");return;}
1083          GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1084          GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1085          GtkTreeIter iter;
1086          if(gtk_tree_selection_get_selected(selection,&model, &iter))
1087          {
1088             StuffkeeperDataSchema *schema = NULL;
1089              /* Get id and items */
1090              gtk_tree_model_get(model, &iter,LP_ITEM,&schema, -1);
1091             if(schema)
1092             {
1093                 StuffkeeperDataItem *item = stuffkeeper_data_backend_new_item(self->_priv->skdbg,schema);
1094                 if(item)
1095                 {
1096                     /* signal to other window components that the item was added on this
1097                      * window */
1098                     self_item_added_here(self, item);
1099                 }
1100             }
1101         }
1102      }
1103      private
1104      void
1105      add_type(self, GtkMenuItem *item)
1106      {
1107          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1108          if(locked){printf("**ERROR** should not be callable\n");return;}
1110          g_signal_handler_block(self->_priv->skdbg,self->_priv->signal_schema_added);
1111          StuffkeeperDataSchema *schema = stuffkeeper_data_backend_new_schema(self->_priv->skdbg);
1112          stuffkeeper_data_schema_set_title(schema, _("New Schema"));
1113          if(schema)
1114          {
1115              GtkTreeIter iter;
1116              gtk_list_store_append(GTK_LIST_STORE(self->_priv->model_schemas), &iter);
1117              gchar *title = stuffkeeper_data_schema_get_title(schema);
1118              gtk_list_store_set(GTK_LIST_STORE(self->_priv->model_schemas), &iter, 
1119                      0, stuffkeeper_data_schema_get_id(schema),
1120                      1, title,
1121                      3, schema,
1122                      4, stuffkeeper_data_schema_num_items(schema),-1);
1126              if(self->_priv->treeview1_renderer)
1127              {
1128                  GtkTreeViewColumn *col = gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview1), 1);
1129                  GtkTreePath *path = gtk_tree_model_get_path(self->_priv->model_schemas, &iter);
1130                  gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(self->_priv->treeview1), path, col,self->_priv->treeview1_renderer, TRUE);
1131                  gtk_tree_path_free(path);
1132              }
1133          }
1134          g_signal_handler_unblock(self->_priv->skdbg,self->_priv->signal_schema_added);
1135      }
1136      private 
1137      void
1138      remove_type(self, GtkMenuItem *item)
1139      {
1140          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1141          if(locked){printf("**ERROR** should not be callable\n");return;}
1143          GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1144          GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1145          GtkTreeIter iter;
1146          if(gtk_tree_selection_get_selected(selection,&model, &iter))
1147          {
1148              gint items;
1149              gint id;
1150              /* Get id and items */
1151              gtk_tree_model_get(model, &iter,0,&id,4,&items, -1);
1153              if(items == 0)
1154              {
1155                  stuffkeeper_data_backend_remove_schema(self->_priv->skdbg,id);
1156              }
1157          }
1160      }
1161      private 
1162      void
1163      edit_type(self, GtkMenuItem *item)
1164      {
1165          gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1166          if(locked){printf("**ERROR** should not be callable\n");return;}
1168          GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1169          GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1170          GtkTreeIter iter;
1171          if(gtk_tree_selection_get_selected(selection,&model, &iter))
1172          {
1173              StuffkeeperDataSchema *schema;
1174              gtk_tree_model_get(model, &iter, 3, &schema, -1);
1175              if(schema)
1176              {
1177                  StuffkeeperEditSchema *skes = stuffkeeper_edit_schema_new();
1178                  stuffkeeper_edit_schema_set_schema(skes, schema);
1179              }
1180          }
1181      }
1182     
1183     /* right mouse menu item treeview */
1184     public
1185     gboolean 
1186     treeview2_button_press_event(self, GdkEventButton *event, GtkWidget *widget)
1187     {
1188         return self_click_fix(self, event, widget);
1189         return FALSE;
1190     }
1191     private
1192     void
1193     menu_plugin_called(self, GtkWidget *item)
1194     {
1195         StuffkeeperPlugin *plugin = g_object_get_data(G_OBJECT(item), "plugin");
1196         if(plugin)
1197         {
1198             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
1199             GtkWidget *tree = self->_priv->treeview2;
1200             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
1201             GtkTreeIter iter;
1202 //            if(gtk_tree_selection_get_selected(selection, &model, &iter))
1203             if(gtk_tree_selection_count_selected_rows(selection) == 1)
1204             {
1205                 GList *list;
1206                 StuffkeeperDataItem *item;
1208                 list = gtk_tree_selection_get_selected_rows(selection, &model);
1209                 if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)list->data))
1210                 {
1211                     gtk_tree_model_get(model, &iter, 2, &item, -1);
1212                     if(item)
1213                     {
1214                         stuffkeeper_plugin_run_item(STUFFKEEPER_PLUGIN(plugin), item);
1215                         return;
1216                     }
1217                 }
1218                 if(list)
1219                 {
1220                     g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
1221                     g_list_free(list);
1222                 }
1223             }
1224         }
1225     }
1226     private
1227     void
1228     menu_plugin_tag_called(self, GtkWidget *item)
1229     {
1230         StuffkeeperPlugin *plugin = g_object_get_data(G_OBJECT(item), "plugin");
1231         if(plugin)
1232         {
1233             GtkWidget *tree = self->_priv->treeview1;
1234             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1235             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
1236             GtkTreeIter iter;
1237 //            if(gtk_tree_selection_get_selected(selection, &model, &iter))
1238             if(gtk_tree_selection_count_selected_rows(selection) == 1)
1239             {
1240                 GList *list;
1241                 StuffkeeperDataTag *tag;
1243                 list = gtk_tree_selection_get_selected_rows(selection, &model);
1244                 if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)list->data))
1245                 {
1246                     gtk_tree_model_get(model, &iter, 3, &tag, -1);
1247                     if(item)
1248                     {
1249                         stuffkeeper_plugin_run_tag(STUFFKEEPER_PLUGIN(plugin), tag);
1250                         return;
1251                     }
1252                 }
1253                 if(list)
1254                 {
1255                     g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
1256                     g_list_free(list);
1257                 }
1258             }
1259         }
1260     }
1262     public
1263     gboolean 
1264     treeview2_button_release_event(self, GdkEventButton *event, GtkWidget *widget)
1265     {
1266         g_debug("treeview2 buttom release event\n");
1267         if(event->button == 3)
1268         {
1269             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
1270             //GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview2));
1271             if(gtk_tree_selection_count_selected_rows(selection) > 0)
1272             {
1273                 GtkWidget *menu;                
1274                 GtkWidget *menu_item;
1275                 GList *node,*iter;
1276                 /* create menu */
1277                 menu = gtk_menu_new();
1279                 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
1280                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_interface_item_open), self);
1281                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1283                 if(!stuffkeeper_data_backend_get_locked(self->_priv->skdbg))
1284                 {
1285                     menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_REMOVE, NULL);
1286                     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_interface_item_remove), self);
1287                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1288                 }
1290                 if(gtk_tree_selection_count_selected_rows(selection) == 1)
1291                 {
1292                     menu_item = gtk_image_menu_item_new_with_label(_("Export"));
1293                     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU));
1294                     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_export_html_item), self);
1295                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1296                 }
1298                 node = stuffkeeper_plugin_manager_get_loaded_plugins(self->_priv->spm); 
1299                 if(node)
1300                 {
1301                     for(iter = g_list_first(node);iter;iter = g_list_next(iter))
1302                     {
1303                         StuffkeeperPlugin *plugin = iter->data; 
1304                         if(stuffkeeper_plugin_get_plugin_type(plugin)&PLUGIN_ITEM)
1305                         {
1306                             gint width = 16, height=16;
1307                             GdkPixbuf *pb = stuffkeeper_plugin_get_icon(plugin);
1309                             menu_item = gtk_image_menu_item_new_with_label(stuffkeeper_plugin_get_name(plugin));
1310                             if(pb)
1311                             {
1312                                 GdkPixbuf *scale = gdk_pixbuf_scale_simple(pb,width, height, GDK_INTERP_BILINEAR);
1313                                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),gtk_image_new_from_pixbuf(scale));
1314                                 g_object_unref(scale);
1315                             }
1317                             g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_menu_plugin_called), self);
1318                             g_object_set_data(G_OBJECT(menu_item), "plugin", plugin);
1319                             gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1320                         }
1321                     }
1322                     g_list_free(node);
1323                 }
1325                 /* popup the menu */
1326                 gtk_widget_show_all(menu);
1328                 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
1329                 return FALSE;
1330             }
1331         }
1332         return FALSE;
1333     }
1337     /* Right mouse button press */
1338    public
1339     gboolean 
1340     treeview1_button_press_event(self, GdkEventButton *event, GtkWidget *widget)
1341     {
1343         return FALSE;
1344     }
1345     public 
1346     gboolean
1347     treeview1_button_release_event(self, GdkEventButton *event, GtkWidget *widget)
1348     {
1349         if(stuffkeeper_data_backend_get_locked(self->_priv->skdbg))
1350         {
1351             /* no right menu in locked mode */
1352             return FALSE;
1353         }
1356         /* Right mouse click, ignore rest */
1357         if(event->button == 3)
1358         {
1359             int type = gtk_combo_box_get_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB));
1360             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1));
1361             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview1));
1362             GtkTreeIter iter;
1363             GtkWidget *menu;
1364             GtkWidget *menu_item;
1366             g_debug("treeview 1 button press event\n");
1367             /* Create menu */
1368             menu = gtk_menu_new();
1370             if(type == LP_TYPE_TAG)
1371             {
1372                 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
1373                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_open_tag), self);
1374                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1376                 /* Add tag */
1377                 menu_item = gtk_image_menu_item_new_with_label(_("New tag"));
1378                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1379                         gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
1380                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_add_tag), self);
1381                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1382                 if(gtk_tree_selection_get_selected(selection,&model, &iter))
1383                 {
1384                     int items;
1385                     /* Get the number of items */
1386                     gtk_tree_model_get(model, &iter, 4, &items, -1);
1388                     /* no items, then you can delete it*/
1389                     if(items ==  0)
1390                     {
1391                         menu_item = gtk_image_menu_item_new_with_label(_("Remove tag"));
1392                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1393                                 gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
1394                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_remove_tag),self);
1395                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1396                     }
1397                 }
1398                 {
1399                     GList *iter, *node = stuffkeeper_plugin_manager_get_loaded_plugins(self->_priv->spm); 
1400                     if(node)
1401                     {
1402                         for(iter = g_list_first(node);iter;iter = g_list_next(iter))
1403                         {
1404                             StuffkeeperPlugin *plugin = iter->data; 
1405                             if(stuffkeeper_plugin_get_plugin_type(plugin)&PLUGIN_TAG)
1406                             {
1407                                 gint width = 16, height=16;
1408                                 GdkPixbuf *pb = stuffkeeper_plugin_get_icon(plugin);
1409                                 menu_item = gtk_image_menu_item_new_with_label(stuffkeeper_plugin_get_name(plugin));
1410                                 if(pb)
1411                                 {
1412                                     GdkPixbuf *scale = gdk_pixbuf_scale_simple(pb,
1413                                             width, height, GDK_INTERP_BILINEAR);
1414                                     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1415                                             gtk_image_new_from_pixbuf(scale));
1416                                     g_object_unref(scale);
1417                                 }
1419                                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", 
1420                                         G_CALLBACK(self_menu_plugin_tag_called), self);
1421                                 g_object_set_data(G_OBJECT(menu_item), "plugin", plugin);
1422                                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1423                             }
1424                         }
1425                         g_list_free(node);
1426                     }
1427                 }
1429             }
1430             else if (type == LP_TYPE_SCHEMA) 
1431             {
1432                 /* Add item */
1433                 menu_item = gtk_image_menu_item_new_with_label(_("New type"));
1434                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1435                         gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
1436                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_add_type), self);
1437                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1438                 if(gtk_tree_selection_get_selected(selection,&model, &iter))
1439                 {
1440                     int items;
1441                     gchar *temp;
1442                     StuffkeeperDataSchema *schema = NULL;
1443                     /* Get the number of items */
1444                     gtk_tree_model_get(model, &iter, LP_ITEM, &schema, 4, &items, -1);
1447                     /* no items, then you can delete it*/
1448                     if(items ==  0)
1449                     {
1450                         menu_item = gtk_image_menu_item_new_with_label(_("Remove type"));
1451                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1452                                 gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
1453                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_remove_type),self);
1454                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1455                     }
1456                     menu_item = gtk_image_menu_item_new_with_label(_("Edit type"));
1457                     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1458                             gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1459                     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_type),self);
1460                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1463                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1464                     /* add item of this type */
1465                     temp = g_strdup_printf("%s %s %s", _("Add new"), stuffkeeper_data_schema_get_title(schema), _("item"));
1466                     menu_item = gtk_image_menu_item_new_with_label(temp);
1467                     g_free(temp);
1468                     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1469                             gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
1470                     g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_add_item_of_type),self);
1471                     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1472                 }
1474             } else if (type == LP_TYPE_SEARCH)
1475             {
1476                 /* Add item */
1477                 menu_item = gtk_image_menu_item_new_with_label(_("New filter"));
1478                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1479                         gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
1480                 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_new_search), self);
1481                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1482                 if(gtk_tree_selection_get_selected(selection,&model, &iter))
1483                 {
1484                     int id;
1485                     StuffkeeperDataItemSearch *search;
1486                     /* Get the number of items */
1487                     gtk_tree_model_get(model, &iter, 0, &id,3, &search, -1);
1489                     /* no items, then you can delete it*/
1490                     if(id >=  0)
1491                     {
1493                         menu_item = gtk_image_menu_item_new_with_label(_("Remove filter"));
1494                         g_object_set_data(G_OBJECT(menu_item), "search", search);
1495                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1496                                 gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
1497                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_remove_search_menu),self);
1498                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1501                         menu_item = gtk_image_menu_item_new_with_label(_("Edit filter"));
1502                         g_object_set_data(G_OBJECT(menu_item), "search", search);
1503                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), 
1504                                 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1505                         g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_search_menu),self);
1506                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1507                     }
1508                 }
1509             }
1511             /* popup the menu */
1512             gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
1513             /* show the widget */
1514             gtk_widget_show_all(menu);
1515             /* don't pass message */
1516             return TRUE;
1517         }
1518         return FALSE;
1519     }
1522     public
1523         StuffkeeperInterface * 
1524         new(GKeyFile *config_file)
1525         {
1526             GtkAccelGroup *agroup = NULL;
1527             int value,width,height;
1528             GError *error = NULL;
1529             Self *self = g_object_ref_sink(GET_NEW);
1531             self->_priv->xml = gtk_builder_new();
1533             self->config_file = config_file;
1534             gtk_builder_add_from_file(self->_priv->xml, PACKAGE_DATADIR"/stuffkeeper.ui", &error);
1535             if(error)
1536             {
1537                 g_object_unref(self);
1538                 g_debug("Failed top open xml file: %s\n", error->message);
1539                 g_error_free(error);
1540                 return NULL;
1541             }
1542             self->_priv->hpaned1 =  (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "hpaned1");
1543             self->_priv->vpaned1 =  (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "vpaned1");
1544             self->_priv->LeftPaneCB  =(GtkWidget *) gtk_builder_get_object(self->_priv->xml, "LeftPaneCB");
1545             self->_priv->treeview1 = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "treeview1");
1546             self->_priv->treeview2 = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "treeview2");
1548             self->_priv->LeftPane_edit = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "LeftPane_edit");
1549             self->_priv->AddMenuButton = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "AddMenuButton");
1551             self->_priv->item_label = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "item_label");
1552             self->_priv->item_view_container = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "item_view_container");
1553             self->_priv->show_item_pane_menu_item = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "show_item_pane_menu_item");
1554             
1555              self->_priv->cb_search = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "cb_search");
1556             
1557             self->_priv->menuitem_item_add = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_add");
1559             self->_priv->win = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "win");
1561             /* Accel group */
1562             agroup = gtk_accel_group_new();
1563             gtk_window_add_accel_group(GTK_WINDOW(self->_priv->win), agroup);
1565             gtk_widget_hide_on_delete(self->_priv->win);
1567             /**
1568              * Custom search widget, 
1569              */
1570             self->_priv->search_entry = gtk_entry_new();
1571             /* Add clear button */
1572             gtk_entry_set_icon_from_stock(GTK_ENTRY(self->_priv->search_entry),GTK_ENTRY_ICON_SECONDARY, 
1573                             GTK_STOCK_CLEAR);
1574             /* Add find icon */
1575             gtk_entry_set_icon_from_stock(GTK_ENTRY(self->_priv->search_entry),GTK_ENTRY_ICON_PRIMARY, 
1576                             GTK_STOCK_FIND);
1577                         g_signal_connect_swapped(G_OBJECT(self->_priv->search_entry), "icon-release" , 
1578                                                         G_CALLBACK(self_search_entry_icon_clicked), self);
1580             gtk_box_pack_end(GTK_BOX(gtk_builder_get_object(self->_priv->xml,"hbox3")), self->_priv->search_entry, TRUE, TRUE, 0);
1581             g_signal_connect_swapped(G_OBJECT(self->_priv->search_entry), "changed", G_CALLBACK(self_search_entry_changed), self);
1583             gtk_widget_show_all(GTK_WIDGET(self->_priv->search_entry));
1585             gtk_widget_add_accelerator(self->_priv->search_entry, "grab-focus",agroup, GDK_f, GDK_CONTROL_MASK,0);
1587             /* read config */
1589             value = g_key_file_get_integer(self->config_file, "WINDOW", "hpane", &error);
1590             if(error ) {
1591                 g_debug("No valid pane position: %s\n", error->message);
1592                 /* Free error */
1593                 g_error_free(error);
1594                 error = NULL;
1595             }
1596             else if(value > 50)
1597             {
1598                 g_debug("Setting position: %i\n", value);
1599                 gtk_paned_set_position(GTK_PANED(self->_priv->hpaned1), value);
1600             }
1601             /* restore layout */
1603             value = g_key_file_get_integer(self->config_file, "WINDOW", "alternative-layout", &error);
1604             if(error ) {
1605                 g_debug("No valid layout position: %s\n", error->message);
1606                 /* Free error */
1607                 g_error_free(error);
1608                 error = NULL;
1609             }
1610             else
1611             {
1612                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "alternative_layout_cb")), value);
1613                 self_set_alternative_layout(self, value);
1614                 /*
1615                 g_debug("Setting position: %i\n", value);
1616                 gtk_paned_set_position(GTK_PANED(self->_priv->vpaned1), value);
1617                 */
1618             }
1619             /* Restore size and position */
1621             width = g_key_file_get_integer(self->config_file, "WINDOW", "width", &error);
1622             if(error) {
1623                 g_error_free(error);
1624                 error = NULL;
1625             } else {
1626                 height = g_key_file_get_integer(self->config_file, "WINDOW", "height", &error);
1627                 if(error) {
1628                     g_error_free(error);
1629                     error = NULL;
1630                 } else {
1631                     gtk_window_resize(GTK_WINDOW(self->_priv->win), width, height);
1632                 }
1633             }
1634             /* Move window */
1635             width = g_key_file_get_integer(self->config_file, "WINDOW", "x-pos", &error);
1636             if(error) {
1637                 g_error_free(error);
1638                 error = NULL;
1639             } else {
1640                 height = g_key_file_get_integer(self->config_file, "WINDOW", "y-pos", &error);
1641                 if(error) {
1642                     g_error_free(error);
1643                     error = NULL;
1644                 } else {
1645                     gtk_window_move(GTK_WINDOW(self->_priv->win), width, height);
1646                 }
1647             }
1648             /* show pane */
1649             width = g_key_file_get_integer(self->config_file, "WINDOW", "show-item-pane", &error);
1650             if(error) {
1651                 g_error_free(error);
1652                 error = NULL;
1653             } else {
1654                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(self->_priv->show_item_pane_menu_item),width);
1655             }
1657             /* setup treeview */
1658             gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(self->_priv->treeview2), TRUE);
1659             gtk_tree_view_set_enable_search(GTK_TREE_VIEW(self->_priv->treeview2), FALSE);
1662             gtk_builder_connect_signals_full(self->_priv->xml, (GtkBuilderConnectFunc)self____builder_xml_connect_foreach, (gpointer)self);
1663             /* some testing */
1664             gtk_widget_show(self->_priv->win);
1665             /* put this after the show, or it will turn up black, for some oddball reason */
1666             self_interface_item_selection_changed(self, gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2)));
1668             interface_element_add((GtkWidget *)(self));
1670             return self;
1671         }
1673     public
1674     void
1675     left_pane_changed(self, GtkComboBox *box)
1676     {
1677         GtkWidget *entry = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "LeftPaneFilterEntry");
1678         int i = gtk_combo_box_get_active(box);
1680         gtk_tree_view_column_set_visible(self->_priv->column_lv_pixbuf, FALSE);
1681         if(i==0){
1682             gtk_widget_show(entry);
1683             gtk_tree_view_set_model(GTK_TREE_VIEW(self->_priv->treeview1), GTK_TREE_MODEL(self->_priv->model_tags_filter));
1684         }else if (i == 1){
1685             gtk_widget_hide(entry);
1686             gtk_tree_view_column_set_visible(self->_priv->column_lv_pixbuf, TRUE);
1687             gtk_tree_view_set_model(GTK_TREE_VIEW(self->_priv->treeview1), GTK_TREE_MODEL(self->_priv->model_schemas));
1688         }else if ( i == 2) {
1689             gtk_widget_hide(entry);
1690             gtk_tree_view_set_model(GTK_TREE_VIEW(self->_priv->treeview1), GTK_TREE_MODEL(self->_priv->model_searches));
1691         }
1693         /* refilter the items list */
1694         gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
1695     }
1697     public
1698     void
1699     search_type_changed(self, GtkComboBox *box)
1700     {
1701         GtkTreeIter iter, node;
1702         if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_priv->cb_search), &iter))
1703         {
1704             StuffkeeperDataItemSearch *search;
1705             GtkWidget *item = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_filter_remove");
1706             GtkWidget *item1 = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_filter_edit");
1707             gint id;
1708             gtk_tree_model_get(self->_priv->model_searches, &iter,0,&id, 3, &search, -1);
1710             if(id == -1) {
1711                 gtk_widget_set_sensitive(item, FALSE);
1712                 gtk_widget_set_sensitive(item1, FALSE);
1713             } else {
1714                 gtk_widget_set_sensitive(item, TRUE);
1715                 gtk_widget_set_sensitive(item1, TRUE);
1716             }
1717             if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(self->_priv->model_searches), &node)) {
1718                 do{
1719                     gtk_list_store_set(GTK_LIST_STORE(self->_priv->model_searches), &node, 2, FALSE,-1);
1720                 }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(self->_priv->model_searches), &node));
1721             }
1722             gtk_list_store_set(GTK_LIST_STORE(self->_priv->model_searches), &iter, 2, TRUE,-1);
1723         }
1724         /* refilter the items list */
1725         gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter));
1726     }
1728     /* This function sets the right image on the CellRenderer for the pixbuf column.
1729      * Only does it when showing Schema list
1730      */
1731     private
1732     void
1733     interface_lv_get_schema_pixbuf(GtkTreeViewColumn *col, GtkCellRenderer *renderer,GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
1734     {
1735         Self *self = SELF(data);
1736         int type = gtk_combo_box_get_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB));
1737         if(type == LP_TYPE_SCHEMA)
1738         {
1739             StuffkeeperDataSchema *schema;
1740             gtk_tree_model_get(self->_priv->model_schemas, iter, LP_ITEM, &schema, -1);
1741             if(schema)
1742             {
1743                 GdkPixbuf *pb = stuffkeeper_data_schema_get_pixbuf(schema);
1744                 g_object_set(G_OBJECT(renderer), "pixbuf", pb,NULL);
1745             }
1746         }
1747     }
1749     /* Add item menu */
1750     private
1751     void 
1752     update_all_item_add_menus(self) {
1753         self_update_item_add_menu(self, GTK_MENU_SHELL(self->_priv->menu), FALSE);
1754         self_update_item_add_menu(self, GTK_MENU_SHELL(self->_priv->menu_item_add), TRUE);
1755         
1756         
1757         if(g_object_get_data(G_OBJECT(self->_priv->AddMenuButton), "schema") == NULL)
1758         {
1759             GList *list = stuffkeeper_data_backend_get_schemas(self->_priv->skdbg);
1760             if(list)
1761             {
1762                gtk_widget_set_tooltip_text(self->_priv->AddMenuButton, stuffkeeper_data_schema_get_title((StuffkeeperDataSchema *)list->data));
1763                g_object_set_data(G_OBJECT(self->_priv->AddMenuButton), "schema", list->data);
1764                g_list_free(list);
1765             }
1766             else
1767                 gtk_widget_set_tooltip_text(self->_priv->AddMenuButton, "");
1769         }
1770     }
1772     private
1773     void 
1774     update_item_add_menu(self, Gtk:MenuShell *menu, gboolean add_hotkeys)
1775     {
1776         GtkTreeIter iter;
1777         GList *node,*items = NULL;
1779         items = gtk_container_get_children(GTK_CONTAINER(menu));
1780         for(node = items; node;node = g_list_next(node))
1781         {
1782             gtk_widget_destroy(GTK_WIDGET(node->data));
1783         }
1784         if(items)
1785             g_list_free(items);
1787         if(gtk_tree_model_get_iter_first(self->_priv->model_schemas,&iter))
1788         {
1789             gchar *menu_hotkeys = NULL;
1790             gchar **menu_hotkeys_list = NULL;
1791             gchar **menu_hotkey_ptr = NULL;
1793             /* Colon-seperated list of shortcut-prefixes for menu items the
1794              * last item on the list will be repeated for all menu entries
1795              * witout their own items */
1796             if(add_hotkeys) {
1797                 menu_hotkeys = _("_1. :_2. :_3. :_4. :_5. :_6. :_7. :_8. :_9. :_0. :_A. :_B. :_C. :_D. :_E. :_F. :_G. :_H. :_I. :_J. :_K. :_L. :_M. :_M. :_N. :_O. :_P. :_Q. :_R. :_S. :_T. :_U. :_V. :_W. :_X. :_Y. :_Z. :   ");
1798                 menu_hotkeys_list = g_strsplit(menu_hotkeys, ":", -1);
1799                 menu_hotkey_ptr = menu_hotkeys_list;
1800             }
1801             do{
1802                 gchar *title = NULL;
1803                 gchar *menu_entry = NULL;
1804                 GtkWidget *m = NULL;
1805                 StuffkeeperDataSchema *schema = NULL;
1807                 gtk_tree_model_get(self->_priv->model_schemas, &iter, 1, &title,3,&schema, -1);
1808                 if(add_hotkeys) {
1809                     if(title && g_strstr_len(title, -1, "_")) {
1810                         gchar **tsplit;
1811                         /* Need to escape underscores in the title */
1812                         tsplit = g_strsplit(title, "_", -1);
1813                         g_free(title);
1814                         title = g_strjoinv("__",tsplit);
1815                         g_strfreev(tsplit);
1816                     }
1817                     menu_entry = g_strconcat(*menu_hotkey_ptr, (title == NULL)?_("n/a"):title, NULL);
1818                     m=gtk_image_menu_item_new_with_mnemonic(menu_entry);
1819                 } else {
1820                     m=gtk_image_menu_item_new_with_label((title == NULL)?_("n/a"):title);
1821                 }
1822                 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(m), 
1823                     gtk_image_new_from_pixbuf(stuffkeeper_data_schema_get_pixbuf(schema)));
1824                 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), m,-1);
1825                 g_object_set_data(G_OBJECT(m), "schema", schema);
1826                 g_signal_connect_swapped(G_OBJECT(m), "activate", G_CALLBACK(self_interface_item_add_menu_button), self);
1827                 if(title) {
1828                     g_free(title);
1829                 }
1830                 if(menu_entry) {
1831                         g_free(menu_entry);
1832                 }
1833                 if(add_hotkeys && menu_hotkey_ptr[1]) {
1834                     menu_hotkey_ptr++;
1835                 }
1837             } while(gtk_tree_model_iter_next(self->_priv->model_schemas, &iter));
1838             gtk_widget_show_all(GTK_WIDGET(menu));
1839             if(add_hotkeys) {
1840                 g_strfreev(menu_hotkeys_list);
1841             }
1842         }
1843     }
1845     public
1846     void
1847     style_changed(GtkWidget *tree,GtkStyle *old, GtkCellRenderer *renderer)
1848     {
1849         g_debug("style changed\n");
1850         g_object_set(G_OBJECT(renderer), 
1851                     "background-set", TRUE, "background-gdk",&(GTK_WIDGET(tree)->style->bg[GTK_STATE_SELECTED]), 
1852                     "foreground-set", TRUE, "foreground-gdk",&(GTK_WIDGET(tree)->style->fg[GTK_STATE_SELECTED]), 
1853                     NULL);
1854     }
1857     public
1858     void
1859     get_pixbuf(GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
1860     {
1861         StuffkeeperDataItem *item;
1862         StuffkeeperDataSchema *schema;
1863         GdkPixbuf *pb;
1864         gtk_tree_model_get(model, iter, 2, &item, -1); 
1865         schema = stuffkeeper_data_item_get_schema(item);
1866         if(schema)
1867         {
1868             pb = stuffkeeper_data_schema_get_pixbuf(schema);
1869             g_object_set(renderer, "pixbuf", pb,NULL);
1870         }
1871     }
1873     private
1874     void
1875     backend_locked(self, GParamSpec *arg1, StuffkeeperDataBackend *backend)
1876     {
1877         GtkWidget *button = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "toggle_locked");
1878         gboolean value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1879         gboolean locked = stuffkeeper_data_backend_get_locked(backend);
1881         if(value != locked)
1882         {
1883             g_signal_handler_block(self->_priv->skdbg,self->_priv->signal_backend_locked);
1884             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), locked);
1885             g_signal_handler_unblock(self->_priv->skdbg,self->_priv->signal_backend_locked);
1886         }
1888         button = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_view_locked");
1889         value = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(button));
1890         if(value != locked)
1891         {
1892             g_signal_handler_block(self->_priv->skdbg,self->_priv->signal_backend_locked);
1893             gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(button), locked);
1894             g_signal_handler_unblock(self->_priv->skdbg,self->_priv->signal_backend_locked);
1895         }
1897         /* change the interface */
1898         if(locked)
1899         {
1900             g_object_set(G_OBJECT(self->_priv->treeview1_renderer), "editable", FALSE, NULL);
1901             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "toolbar1"));
1902             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_sep"));
1903             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_add"));
1904             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_remove"));
1905             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_clone"));
1906             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_filter"));
1907             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_type_new"));
1908             gtk_widget_hide((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_type_import"));
1909         } else {
1910             g_object_set(G_OBJECT(self->_priv->treeview1_renderer), "editable", TRUE, NULL);
1911             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "toolbar1"));
1912             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_sep"));
1913             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_add"));
1914             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_remove"));
1915             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_item_clone"));
1916             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_filter"));
1917             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_type_new"));
1918             gtk_widget_show((GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_type_import"));
1919         }
1922     }
1923     public
1924     void
1925     menu_backend_locked_toggled(self, GtkCheckMenuItem *item)
1926     {
1927         gboolean value = gtk_check_menu_item_get_active(item);
1928         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1929         if(locked != value)
1930         {
1931             stuffkeeper_data_backend_set_locked(self->_priv->skdbg, value);
1932         }
1933     }
1934     public
1935     void
1936     backend_locked_toggled(self, GtkToggleButton *button)
1937     {
1938         gboolean value = gtk_toggle_button_get_active(button);
1939         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1940         if(locked != value)
1941         {
1942             stuffkeeper_data_backend_set_locked(self->_priv->skdbg, value);
1943         }
1944     }
1946         private 
1947         gboolean click_fix (self, GdkEventButton *event, GtkWidget *tree)
1948     {
1949         GtkTreePath *path = NULL;
1950         if(event->button == 3 && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree), event->x, event->y,&path,NULL,NULL,NULL))
1951         {       
1952             GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1953             if(gtk_tree_selection_path_is_selected(sel, path))
1954             {
1955                 gtk_tree_path_free(path);
1956                 return TRUE;
1958             }
1959         }
1960         if(path) {
1961             gtk_tree_path_free(path);
1962         }
1963         return FALSE;
1964     }
1965     public void left_pane_filter_entry_clear(self, GtkEntryIconPosition pos, GdkEvent *event, GtkEntry *entry)
1966     {
1967         if(pos == GTK_ENTRY_ICON_SECONDARY) {
1968             gtk_entry_set_text(entry, "");
1969         }
1971     }
1972     public void left_pane_filter_changed(self, GtkEditable *editable)
1973     {
1974         gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(self->_priv->model_tags_filter));
1975     }
1976    
1977     /*
1978      * React if the user presses enter in the filter entry. 
1979      * 1 item visible -> open it.
1980      * 2 or more items visible -> do nothing.
1981      * 3 items visible -> ask user to add it as tag.
1982      *
1983      */
1984     public void left_pane_filter_entry_activate(self, GtkEntry *entry)
1985     {
1986         gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
1987         int type = gtk_combo_box_get_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB));
1988         int num_items = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(self->_priv->model_tags_filter), NULL);
1989         if(type != 0) return;
1990         if( num_items == 0) {
1991             if(!locked) {
1992                 GtkWidget * dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(self->_priv->win),
1993                         GTK_DIALOG_DESTROY_WITH_PARENT,
1994                         GTK_MESSAGE_INFO,
1995                         GTK_BUTTONS_OK_CANCEL,
1996                         "Add tag with name: <i>%s</i>?",
1997                         gtk_entry_get_text(GTK_ENTRY(entry)));
1998                 switch(gtk_dialog_run(GTK_DIALOG(dialog)))
1999                 {
2000                     case GTK_RESPONSE_OK:
2001                     {
2002                         StuffkeeperDataTag *tag = stuffkeeper_data_backend_new_tag(self->_priv->skdbg);
2003                         stuffkeeper_data_tag_set_title(tag, gtk_entry_get_text(entry));
2004                     }
2005                     default:
2006                         gtk_widget_destroy(dialog);
2007                         break;
2008                 }
2009             }
2010         }else if (num_items == 1) {
2011             GtkTreeIter iter;
2012             if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(self->_priv->model_tags_filter), &iter))
2013             {
2014                 StuffkeeperDataTag *tag;
2015                 gtk_tree_model_get(GTK_TREE_MODEL(self->_priv->model_tags_filter), &iter,3, &tag, -1);
2016                 if(tag)
2017                 {
2018                     if(tag) {
2019                         GList *items = stuffkeeper_data_tag_get_items(tag);
2020                         if(items) {
2021                             gchar *title = stuffkeeper_data_tag_get_title(tag);
2022                             printf("Window items\n");
2023                             GtkWidget *win = stuffkeeper_item_window_new_multiple(self->_priv->skdbg, items,config_file, title);
2024                             g_free(title);
2025                             gtk_widget_show(win);
2026                             g_list_free(items);
2027                         }
2028                     }
2029                 }
2030             }
2032         }
2035     }
2038     private gboolean left_pane_filter_function(GtkTreeModel *model, GtkTreeIter *iter,gpointer data)
2039     {
2040         Self *self = SELF(data);
2041         gboolean visible = FALSE;
2042         const gchar *data;
2043         gchar *compare = NULL;
2045         GtkEntry *entry = (GtkEntry *)gtk_builder_get_object(self->_priv->xml, "LeftPaneFilterEntry");
2046         if(entry == NULL  || gtk_entry_buffer_get_length (gtk_entry_get_buffer (entry)) == 0)
2047         {
2048             /* if nothing entered, allow everything */
2049             return TRUE;
2050         }
2051         data = gtk_entry_get_text(entry);
2052         gtk_tree_model_get (model, iter, 1, &compare, -1);
2053         if(compare)
2054         {
2055             gchar *asmall = g_utf8_normalize(compare, -1, G_NORMALIZE_ALL);
2056             gchar *bsmall = g_utf8_normalize(data, -1, G_NORMALIZE_ALL);
2057             gchar *alower = g_utf8_casefold(asmall, -1);
2058             gchar *blower = g_utf8_casefold(bsmall, -1);
2060             visible = strstr(alower, blower) != NULL;
2061             g_free(alower);
2062             g_free(blower);
2063             g_free(asmall);
2064             g_free(bsmall);
2065             g_free(compare);
2066         }
2069         return visible;
2070     }
2072     /**
2073      * Initialize the main gui
2074      */
2075     public
2076         void 
2077         initialize_interface(self, StuffkeeperDataBackend *skdb,GObject *spm)
2078         {
2079             GError *error = NULL;
2080             gint value = 0, sort_order;
2081             GList *iter, *node;
2082             GtkTreeViewColumn *column;
2083             GtkCellRenderer *renderer;
2084             GtkTreeSelection *sel;
2085             /**
2086              * StuffkeeperDataBackend
2087              */
2088             self->_priv->skdbg = skdb;
2089             self->_priv->spm = STUFFKEEPER_PLUGIN_MANAGER(spm);
2090             /* locked signal */
2091             self->_priv->signal_backend_locked = g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), "notify::locked", G_CALLBACK(self_backend_locked), self);
2093             /* Setting up backends */
2094             self->_priv->model_schemas = (GtkTreeModel *)gtk_list_store_new(5, G_TYPE_INT,G_TYPE_STRING,G_TYPE_BOOLEAN,G_TYPE_POINTER,G_TYPE_INT);
2095             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_schemas), 1, GTK_SORT_ASCENDING);
2097             /* New Item menus */
2098             self->_priv->menu = gtk_menu_new();
2099             gtk_menu_tool_button_set_menu(GTK_MENU_TOOL_BUTTON(self->_priv->AddMenuButton), (self->_priv->menu));
2100             self->_priv->menu_item_add = gtk_menu_new();
2101             gtk_menu_item_set_submenu(GTK_MENU_ITEM(self->_priv->menuitem_item_add), self->_priv->menu_item_add);
2103             /** Load the schemas*/
2104             node = stuffkeeper_data_backend_get_schemas(self->_priv->skdbg);
2105             for(iter = node;iter;iter = g_list_next(iter))
2106             {
2107                 self_schema_added(self, STUFFKEEPER_DATA_SCHEMA(iter->data), self->_priv->skdbg);
2108             }
2109             if(node) g_list_free(node);
2111             self->_priv->signal_schema_added = g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2112                     "schema-added",   
2113                     G_CALLBACK(self_schema_added),
2114                     self); 
2115             self->_priv->signal_schema_removed =g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2116                     "schema-removed", 
2117                     G_CALLBACK(self_schema_removed),
2118                     self);
2119             self->_priv->signal_schema_changed=g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2120                     "schema-changed", 
2121                     G_CALLBACK(self_schema_changed),
2122                     self);
2127             /* Tags */
2128             self->_priv->model_tags = (GtkTreeModel *)gtk_list_store_new(5, G_TYPE_INT,G_TYPE_STRING,G_TYPE_BOOLEAN,G_TYPE_POINTER,G_TYPE_INT);
2129             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_tags), 1, GTK_SORT_ASCENDING);
2130             /* Setup filtering */
2131             self->_priv->model_tags_filter = (GtkTreeModel *)gtk_tree_model_filter_new(GTK_TREE_MODEL(self->_priv->model_tags),NULL);
2132             gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(self->_priv->model_tags_filter), self_left_pane_filter_function, self, NULL);
2135             /** Load the tags */
2136             node = stuffkeeper_data_backend_get_tags(self->_priv->skdbg);
2137             for(iter = node;iter;iter = g_list_next(iter))
2138             {
2139                 self_tag_added(self->_priv->skdbg, iter->data,self->_priv->model_tags);
2140             }
2141             if(node) g_list_free(node);
2142             /* handle an added tag */
2143             self->_priv->signal_tag_added = g_signal_connect(G_OBJECT(self->_priv->skdbg),
2144                     "tag-added",
2145                     G_CALLBACK(self_tag_added),
2146                     self->_priv->model_tags);
2147              self->_priv->signal_tag_changed = g_signal_connect(G_OBJECT(self->_priv->skdbg),
2148                     "tag-changed",
2149                     G_CALLBACK(self_tag_changed),
2150                     self->_priv->model_tags);
2151               self->_priv->signal_tag_removed = g_signal_connect(G_OBJECT(self->_priv->skdbg),
2152                     "tag-removed",
2153                     G_CALLBACK(self_tag_removed),
2154                     self->_priv->model_tags);
2156             self->_priv->model_items = (GtkTreeModel *)gtk_list_store_new(6, G_TYPE_INT,G_TYPE_STRING,G_TYPE_POINTER,G_TYPE_INT,G_TYPE_INT,G_TYPE_INT);
2157             sort_order = g_key_file_get_integer(self->config_file, "WINDOW", "item-sort-order", &error);
2158             if(error != NULL)
2159             {
2160                 sort_order= GTK_SORT_DESCENDING;
2161                 g_error_free(error);
2162                 error = NULL;
2163             }
2164             else
2165             {
2166                 self->_priv->item_sort_order = sort_order;
2167                 if(sort_order == GTK_SORT_DESCENDING)
2168                 {
2169                     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_descending")),TRUE);
2170                 }else{
2171                     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_ascending")),TRUE);
2172                 }
2173             }
2174             value = g_key_file_get_integer(self->config_file, "WINDOW", "item-sort-column", &error);
2175             if(error == NULL) {
2176                 self->_priv->item_sort_column = value;
2177                 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items), value, sort_order);
2178                 switch(value) {
2179                     case 1:
2180                         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_by_title")),TRUE);
2181                         break;
2182                     case 4:
2183                          gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_by_schema")),TRUE);
2184                         break;
2185                     case 5:
2186                         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_by_modification_time")),TRUE);
2187                         break;
2188                     default:
2189                         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->_priv->xml, "menu_sort_by_creation_time")),TRUE);
2190                         break;
2191                 }
2192             } else {
2193                 g_error_free(error);
2194                 error = NULL;
2195                 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items), 3, sort_order);
2196             }
2197             /** Load the items*/
2198             node = stuffkeeper_data_backend_get_items(self->_priv->skdbg);
2199             stuffkeeper_data_backend_begin_transaction(self->_priv->skdbg);
2200             for(iter = node;iter;iter = g_list_next(iter))
2201             {
2202                 self_item_added(self->_priv->skdbg, STUFFKEEPER_DATA_ITEM(iter->data),self);
2203             }
2204             stuffkeeper_data_backend_end_transaction(self->_priv->skdbg);
2205             if(node) g_list_free(node);
2206             self->_priv->signal_item_added = g_signal_connect(G_OBJECT(self->_priv->skdbg), 
2207                     "item-added",   
2208                     G_CALLBACK(self_item_added),
2209                     self); 
2210             self->_priv->signal_item_removed = g_signal_connect(G_OBJECT(self->_priv->skdbg), 
2211                     "item-removed",
2212                     G_CALLBACK(self_item_removed),
2213                     self);
2214             self->_priv->signal_item_changed = g_signal_connect(G_OBJECT(self->_priv->skdbg), 
2215                     "item-changed", 
2216                     G_CALLBACK(self_item_changed),
2217                     self);
2219             /**
2220              * Searches
2221              */
2222             self->_priv->model_searches = (GtkTreeModel *)gtk_list_store_new(5, G_TYPE_INT,G_TYPE_STRING,G_TYPE_BOOLEAN,G_TYPE_POINTER, G_TYPE_INT);
2224             gtk_combo_box_set_model(GTK_COMBO_BOX(self->_priv->cb_search), self->_priv->model_searches);
2225             {
2226                 GObject* search = stuffkeeper_data_item_search_new_dummy();
2227                 self_search_added(self, STUFFKEEPER_DATA_ITEM_SEARCH(search), self->_priv->skdbg);
2228             }
2229             node = stuffkeeper_data_backend_get_searches(self->_priv->skdbg);
2230             for(iter = node;iter;iter = g_list_next(iter))
2231             {
2232                 self_search_added(self, STUFFKEEPER_DATA_ITEM_SEARCH(iter->data),self->_priv->skdbg);
2233             }
2234             if(node) g_list_free(node);
2235             self->_priv->signal_search_added = g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2236                     "search-added",
2237                     G_CALLBACK(self_search_added),
2238                     self); 
2239             self->_priv->signal_search_removed = g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2240                     "search-removed",
2241                     G_CALLBACK(self_search_removed),
2242                     self);
2243             self->_priv->signal_search_changed = g_signal_connect_swapped(G_OBJECT(self->_priv->skdbg), 
2244                     "search-changed",
2245                     G_CALLBACK(self_search_changed),
2246                     self);
2252             /**
2253              * Items
2254              */
2255             /* A filtered items */
2256             self->_priv->model_items_filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(self->_priv->model_items), NULL);
2257             g_signal_connect_swapped(G_OBJECT(self->_priv->model_items_filter), "row-inserted", G_CALLBACK(self_filter_model_row_inserted), self);
2258             g_signal_connect_swapped(G_OBJECT(self->_priv->model_items_filter), "row-deleted", G_CALLBACK(self_filter_model_row_deleted), self);
2260             renderer = gtk_cell_renderer_pixbuf_new();
2262             gtk_tree_view_insert_column_with_data_func(GTK_TREE_VIEW(self->_priv->treeview2), -1,"test", renderer, 
2263                     self_get_pixbuf, self, NULL);
2265             gtk_tree_view_column_set_sizing(
2266                         GTK_TREE_VIEW_COLUMN(gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview2), 0)), 
2267                         GTK_TREE_VIEW_COLUMN_FIXED);
2268             
2269               gtk_tree_view_column_set_fixed_width(
2271                     GTK_TREE_VIEW_COLUMN(gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview2), 0)), 
2272                     24+gtk_tree_view_column_get_spacing(GTK_TREE_VIEW_COLUMN(gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview2), 0))));
2274             renderer = gtk_cell_renderer_text_new();
2275             gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(self->_priv->treeview2), -1, "items", renderer, "text", 1, NULL);
2276 //            g_object_set(renderer, "editable", TRUE,NULL);
2277             gtk_tree_view_column_set_sizing(
2278                     GTK_TREE_VIEW_COLUMN(gtk_tree_view_get_column(GTK_TREE_VIEW(self->_priv->treeview2), 1)), 
2279                     GTK_TREE_VIEW_COLUMN_FIXED);
2280             g_signal_connect_swapped(G_OBJECT(renderer), "edited", G_CALLBACK(self_interface_item_title_edited), self);
2282             /* Look at the tree */
2283             gtk_tree_view_set_model(GTK_TREE_VIEW(self->_priv->treeview2), GTK_TREE_MODEL(self->_priv->model_items_filter));
2285             /* get changed selection */
2286             sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
2287             g_signal_connect_swapped(G_OBJECT(sel), "changed", G_CALLBACK(self_interface_item_selection_changed), self);
2288             gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
2290             /* Tag list */
2291             gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(self->_priv->model_items_filter), 
2292                     (GtkTreeModelFilterVisibleFunc)self_interface_visible_func, self, NULL);
2296             /* TAGS */
2297             column = gtk_tree_view_column_new();
2299             /* Toggle button  */
2301             self->_priv->renderer_toggle = renderer = gtk_cell_renderer_toggle_new();
2302             gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
2303             gtk_tree_view_column_set_attributes(column, renderer, "active", 2, NULL);
2304             /* handle toggled */
2305             g_signal_connect_swapped(G_OBJECT(renderer), "toggled", G_CALLBACK(self_interface_left_pane_toggled), self);
2308             gtk_tree_view_append_column(GTK_TREE_VIEW(self->_priv->treeview1), column);
2309             /* icon */
2310             self->_priv->column_lv_pixbuf = column = gtk_tree_view_column_new();
2311             renderer = gtk_cell_renderer_pixbuf_new();
2312             gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
2313             gtk_tree_view_column_set_visible(self->_priv->column_lv_pixbuf, FALSE);
2314             gtk_tree_view_append_column(GTK_TREE_VIEW(self->_priv->treeview1), column);
2315             gtk_tree_view_column_set_cell_data_func(column, renderer, self_interface_lv_get_schema_pixbuf, self, NULL);
2316             /* TAGS */
2317             column = gtk_tree_view_column_new();
2318             /* Tag name */
2319             self->_priv->treeview1_renderer = renderer = gtk_cell_renderer_text_new();
2320             gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, TRUE);
2321             gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
2322             g_object_set(renderer, "editable", TRUE,NULL);
2323             g_signal_connect_swapped(G_OBJECT(renderer), "edited", G_CALLBACK(self_interface_left_pane_edited), self);
2325             /* Number of items */
2326             renderer = gtk_cell_renderer_text_new();
2327             g_object_set(G_OBJECT(renderer), 
2328                     "background-set", TRUE, "background-gdk",&(GTK_WIDGET(self->_priv->treeview1)->style->bg[GTK_STATE_SELECTED]), 
2329                     "foreground-set", TRUE, "foreground-gdk",&(GTK_WIDGET(self->_priv->treeview1)->style->fg[GTK_STATE_SELECTED]), 
2330                     NULL);
2331             g_signal_connect(self->_priv->treeview1, "style-set", G_CALLBACK(self_style_changed), renderer);            
2334             gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, FALSE);
2335             gtk_tree_view_column_set_attributes(column, renderer, "text", 4, NULL);
2337             gtk_tree_view_append_column(GTK_TREE_VIEW(self->_priv->treeview1), column);
2339             g_signal_connect_swapped(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview1))),
2340                             "changed", 
2341                             G_CALLBACK(self_treeview1_selection_changed), 
2342                             self);
2344             gtk_combo_box_set_active(GTK_COMBO_BOX(self->_priv->LeftPaneCB), 0);
2347             renderer = gtk_cell_renderer_text_new();
2348             gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(self->_priv->cb_search), renderer, TRUE);
2349             gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(self->_priv->cb_search), renderer, "text", 1);
2351             gtk_combo_box_set_active(GTK_COMBO_BOX(self->_priv->cb_search), 0);
2353             /** initial setup the list */
2355             /* update label */
2356             self_filter_model_row_inserted(self, NULL, NULL, NULL);
2359             /* update lock state */
2360             self_backend_locked(self, NULL, self->_priv->skdbg);
2363             node = stuffkeeper_plugin_manager_get_loaded_plugins(STUFFKEEPER_PLUGIN_MANAGER(spm)); 
2364             if(node){
2365                 GtkWidget *parent = (GtkWidget *)gtk_builder_get_object(self->_priv->xml, "menuitem_tools");
2366                 GtkWidget *menu = gtk_menu_new();
2367                 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent), menu);
2368                 for(iter = node;iter;iter = g_list_next(iter))
2369                 {
2370                     StuffkeeperPlugin *plugin = iter->data; 
2371                     if(stuffkeeper_plugin_get_plugin_type(plugin)&PLUGIN_MENU)
2372                     {
2373                         gint width = 16, height=16;
2374                         GtkWidget *item = gtk_image_menu_item_new_with_label(stuffkeeper_plugin_get_name(plugin));
2375                         GdkPixbuf *pb = stuffkeeper_plugin_get_icon(plugin);
2377                         gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
2378                         if(pb)
2379                         {
2381                             GdkPixbuf *scale = gdk_pixbuf_scale_simple(pb,width, height, GDK_INTERP_BILINEAR);
2382                             gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),gtk_image_new_from_pixbuf(scale));
2383                             g_object_unref(scale);
2384                         }
2385                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
2386                         g_object_set_data(G_OBJECT(item), "plugin",plugin); 
2387                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_tool_activate), self);
2388                     }
2389                 }
2390                 gtk_widget_show_all(menu);
2391             }
2392             if(node)
2393                 g_list_free(node);
2396             gtk_widget_show(self->_priv->win);
2397         }
2398         private
2399         void
2400         tool_activate(self,GtkWidget *item)
2401         {
2402             StuffkeeperPlugin *plugin = g_object_get_data(G_OBJECT(item), "plugin");
2403             if(plugin)
2404             {
2405                 stuffkeeper_plugin_run_menu(STUFFKEEPER_PLUGIN(plugin),self->_priv->skdbg);
2406             }
2407         }
2409         override (G:Object)
2410         void
2411         finalize(G:Object *obj)
2412         {
2413             int value;
2414             Self *self = SELF(obj);
2415             g_debug("** Finalize stuffkeeper interface\n");
2416             if(self->_priv->signal_backend_locked) { 
2417                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_backend_locked);
2418                 self->_priv->signal_backend_locked = 0;
2419             }
2420             if(self->_priv->signal_schema_added) { 
2421                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_schema_added);
2422                 self->_priv->signal_schema_added = 0;
2423             }
2424             if(self->_priv->signal_schema_changed) { 
2425                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_schema_changed);
2426                 self->_priv->signal_schema_changed = 0;
2427             }
2428             if(self->_priv->signal_schema_removed) { 
2429                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_schema_removed);
2430                 self->_priv->signal_schema_removed = 0;
2431             }
2433             if(self->_priv->signal_item_added) { 
2434                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_item_added);
2435                 self->_priv->signal_item_added = 0;
2436             }
2437             if(self->_priv->signal_item_changed) { 
2438                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_item_changed);
2439                 self->_priv->signal_item_changed = 0;
2440             }
2441             if(self->_priv->signal_item_removed) { 
2442                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_item_removed);
2443                 self->_priv->signal_item_removed = 0;
2444             }
2445             if(self->_priv->signal_search_added) { 
2446                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_search_added);
2447                 self->_priv->signal_search_added = 0;
2448             }
2449             if(self->_priv->signal_search_changed) { 
2450                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_search_changed);
2451                 self->_priv->signal_search_changed = 0;
2452             }
2453             if(self->_priv->signal_search_removed) { 
2454                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_search_removed);
2455                 self->_priv->signal_search_removed = 0;
2456             }
2459             if(self->_priv->signal_tag_added) { 
2460                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_tag_added);
2461                 self->_priv->signal_tag_added = 0;
2462             }
2463             if(self->_priv->signal_tag_changed) { 
2464                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_tag_changed);
2465                 self->_priv->signal_tag_changed = 0;
2466             }
2467             if(self->_priv->signal_tag_removed) { 
2468                 g_signal_handler_disconnect(G_OBJECT(self->_priv->skdbg), self->_priv->signal_tag_removed);
2469                 self->_priv->signal_tag_removed = 0;
2470             }
2471             if(self->_priv->search_timeout) {
2472                 g_source_remove(self->_priv->search_timeout);
2473                 self->_priv->search_timeout = 0;
2474             }
2475             value = gtk_paned_get_position(GTK_PANED(self->_priv->hpaned1));
2476             g_key_file_set_integer(self->config_file, "WINDOW", "hpane", value);
2477             self_safe_vpane_position(self);
2478             gtk_window_get_size(GTK_WINDOW(self->_priv->win), &value, NULL);
2479             g_key_file_set_integer(self->config_file, "WINDOW", "width", value);
2480             gtk_window_get_size(GTK_WINDOW(self->_priv->win), NULL, &value);
2481             g_key_file_set_integer(self->config_file, "WINDOW", "height", value);
2482             /* position */
2483             gtk_window_get_position(GTK_WINDOW(self->_priv->win), &value, NULL);
2484             g_key_file_set_integer(self->config_file, "WINDOW", "x-pos", value);
2485             gtk_window_get_position(GTK_WINDOW(self->_priv->win), NULL, &value);
2486             g_key_file_set_integer(self->config_file, "WINDOW", "y-pos", value);
2488             value =  gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(self->_priv->show_item_pane_menu_item));
2489             g_key_file_set_integer(self->config_file, "WINDOW", "show-item-pane", value);
2492             gtk_widget_destroy(self->_priv->win);
2493             
2494             if(self->_priv->xml)
2495             {
2496                 g_object_unref(self->_priv->xml);
2497             }
2499             if(self->_priv->model_schemas)
2500             {
2501                 g_object_unref(self->_priv->model_schemas);
2502                 self->_priv->model_schemas = NULL;
2503             }
2504             PARENT_HANDLER(obj);
2505         }
2506         /**
2507          * Item popup
2508          */
2509         public
2510         void
2511         interface_item_open(self)
2512         {
2513             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
2514             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview2));
2515             GtkTreeIter iter;
2516             if(gtk_tree_selection_count_selected_rows(selection) > 0)
2517             {
2518                 StuffkeeperDataItem *item;
2519                 GList *list, *node;
2520                 list = gtk_tree_selection_get_selected_rows(selection, &model);
2521                 for(node = g_list_first(list); node; node = g_list_next(node))
2522                 {
2523                     if(gtk_tree_model_get_iter(model, &iter, (GtkTreePath*)node->data))
2524                     {
2525                         gtk_tree_model_get(model, &iter, 2, &item, -1);
2526                         if(item)
2527                         {
2528                             self_popup_item(self, item);
2529                         }
2530                     }
2531                 }
2532                 if(list){
2533                     g_list_foreach (list,(GFunc) gtk_tree_path_free, NULL);
2534                     g_list_free (list);
2535                 }
2536             }
2537         }
2539         public 
2540         void
2541         item_row_activated(self, GtkTreePath *path, GtkTreeViewColumn *column, GtkTreeView *view)
2542         {
2544             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self->_priv->treeview2));
2545             GtkTreeIter iter;
2546             g_debug("item row activated\n");
2547             if(gtk_tree_model_get_iter(model,&iter, path)) 
2548             {
2549                 StuffkeeperDataItem *item;
2550                 gtk_tree_model_get(model, &iter, 2, &item, -1);
2551                 if(item)
2552                 {
2553                     self_popup_item(self, item);
2554                 }
2555             }
2556         }
2558         /**
2559          * Popup an item list
2560          * TODO: Check it item is destroyed, and if it is remove the window
2561          */
2562         public
2563         void 
2564         popup_item(self, Stuffkeeper:Data:Item *item)
2565         {
2566             stuffkeeper_item_window_new(self->_priv->skdbg, item,self->config_file);
2568         }
2571         private 
2572         void
2573         dialog_activate_link(GtkAboutDialog *dialog, const gchar *uri, Self *self) 
2574         {
2575             open_url(uri);
2576         }
2577         private 
2578         void
2579         dialog_activate_email(GtkAboutDialog *dialog, const gchar *uri, Self *self) 
2580         {
2581             open_email(uri);
2582         }
2584         public
2585         void
2586         about_dialog(self)
2587         {
2588             GtkWidget *dialog = gtk_about_dialog_new();
2589             GdkPixbuf *pixbuf = NULL;
2590             /* set url handler */
2591             gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc)self_dialog_activate_link,self, NULL);
2592             gtk_about_dialog_set_email_hook((GtkAboutDialogActivateLinkFunc)self_dialog_activate_email,self, NULL);
2593             /* Set config time defines */
2594             gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), PROGRAM_NAME);
2595             if(strlen(revision)>0)
2596             {
2597                 gchar *str = g_strdup_printf("%s\n%s: %s", PROGRAM_VERSION, _("Revision"), revision);
2598                 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog),str);
2599                 g_free(str);
2600             }
2601             else
2602             {
2603                 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), PROGRAM_VERSION);
2604             }
2605             gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), PROGRAM_WEBSITE); 
2607             gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), _("Copyright 2008-2014 Qball Cow"));
2608             gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog),
2609                     _("GNU General Public License"));
2612             pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "stuffkeeper", 64, 0, NULL);
2613             gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog),pixbuf);
2616             gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog),artists);
2617             gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog),authors);
2618             gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG(dialog), _("translator-credits"));
2620             gtk_dialog_run(GTK_DIALOG(dialog));
2621             gtk_widget_destroy(dialog);
2623         }
2624         /** 
2625          * Backup
2626          */
2627         private
2628                 void
2629                 ___builder_xml_connect_foreach(
2630                                 GtkBuilder *builder,
2631                     GObject *object,
2632                     const gchar *signal_name,
2633                     const gchar *handler_name,
2634                     GObject *connect_object,
2635                     GConnectFlags flags,
2636                     gpointer user_data)
2637         {
2638             static GModule * allsymbols = NULL;
2640             if (!allsymbols) allsymbols = g_module_open(NULL, 0);
2641             if (allsymbols) {
2642                 gchar * func_name = g_strdup_printf("stuffkeeper_interface_%s", handler_name);
2643                 GCallback func;
2645                 if (!g_module_symbol(allsymbols, func_name, (gpointer)&func)){
2646                     if (!g_module_symbol(allsymbols, handler_name, (gpointer)&func)) {
2647                         g_warning("could not find signal handler '%s'.", func_name);
2648                         g_free(func_name);
2649                         return;
2650                     }
2651                 }
2652                 g_signal_connect_data(object, signal_name, func, user_data, NULL, G_CONNECT_SWAPPED | flags);
2653                 g_free(func_name);
2654             }
2655         }
2656         public
2657         void
2658         make_backup(self)
2659         {
2660             GError *error = NULL;
2661             gchar *value = NULL;
2662             GtkBuilder *xml = gtk_builder_new();            
2663             GtkWidget *dialog;
2665             gtk_builder_add_from_file(xml, PACKAGE_DATADIR"/backup-dialog.ui",&error);
2666             if(error != NULL) {
2667                 g_error("Failed to open ui description file: %s\n", error->message);
2668                 g_error_free(error);
2669                 return;
2670             }
2672             dialog = (GtkWidget *)gtk_builder_get_object(xml,"dialog_backup");
2673             /* Restore previous location */ 
2674             value = g_key_file_get_string(self->config_file, "BACKUP", "directory", &error);
2675             if(error == NULL) {
2676                 if(value ) {
2677                     gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gtk_builder_get_object(xml, "location_chooser")), value);
2678                     g_free(value);
2679                 }
2680             }else{
2681                 g_error_free(error);
2682                 error = NULL;
2683             }
2685             value = g_key_file_get_string(self->config_file, "BACKUP", "filename", &error);
2686             if(error == NULL) {
2687                 if(value ) {
2688                     gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(xml, "entry_filename")), value);
2689                     g_free(value);
2690                 }
2691             }else{
2692                 g_error_free(error);
2693                 error = NULL;
2694             }
2696             gtk_builder_connect_signals_full(xml, (GtkBuilderConnectFunc)self____builder_xml_connect_foreach, (gpointer)self);
2697             switch(gtk_dialog_run(GTK_DIALOG(dialog)))
2698             {
2699                 case -5:
2700                     {
2701                         gchar *directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gtk_builder_get_object(xml, "location_chooser")));
2702                         GtkWidget *entry = (GtkWidget *)gtk_builder_get_object(xml, "entry_filename"); 
2703                         const gchar *file = gtk_entry_get_text(GTK_ENTRY(entry)); 
2704                         const gchar *source = stuffkeeper_data_backend_get_path(self->_priv->skdbg);
2705                         /* Store for next time */
2706                         g_key_file_set_string(self->config_file, "BACKUP", "directory", directory);
2707                         g_key_file_set_string(self->config_file, "BACKUP", "filename", file);
2709                         if(file)                                                                                      
2710                         {
2711                             gchar *suffix = g_path_get_dirname(directory);
2712                             gchar *exec = g_strdup_printf("tar -cz -C '%s' -f '%s%c%s.tar.gz' '.'",source, directory,G_DIR_SEPARATOR,file);
2713                             g_spawn_command_line_async(exec, NULL);
2714                             g_free(suffix);
2715                             g_free(exec);
2716                             g_free(directory);
2717                         }
2718                     }
2719                 default:
2720                     break;
2721             }
2722             gtk_widget_destroy(dialog);
2723             g_object_unref(xml);
2724         }
2726         public
2727         void
2728         restore_backup(self)
2729         {
2730             GtkWidget *dialog = NULL;
2731             
2732             dialog = gtk_message_dialog_new_with_markup(
2733             GTK_WINDOW(self->_priv->win), 
2734             GTK_DIALOG_DESTROY_WITH_PARENT,
2735             GTK_MESSAGE_WARNING,
2736             GTK_BUTTONS_OK_CANCEL,
2737             _("Restoring from a backup will destroy the current database.\nUse with care."));
2739             switch(gtk_dialog_run(GTK_DIALOG(dialog)))
2740             {
2741                 case GTK_RESPONSE_CANCEL:
2742                     gtk_widget_destroy(dialog);
2743                     return;
2744                 default:
2745                     gtk_widget_destroy(dialog);
2746             }
2749             dialog = gtk_file_chooser_dialog_new("Open archive", 
2750                         NULL, 
2751                         GTK_FILE_CHOOSER_ACTION_OPEN,
2752                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2753                         GTK_STOCK_OPEN, GTK_RESPONSE_OK, 
2754                         NULL);
2755             switch(gtk_dialog_run(GTK_DIALOG(dialog)))
2756             {
2757                 case GTK_RESPONSE_OK:
2758                 {
2759                     const gchar *directory= stuffkeeper_data_backend_get_path(self->_priv->skdbg);
2760                     gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2761                     if(filename)
2762                     {
2763                         gchar *exec = g_strdup_printf("tar -zxf '%s' -C '%s' ",filename, directory);
2764                         gchar *path = g_strdup(stuffkeeper_data_backend_get_path(self->_priv->skdbg));
2765                         stuffkeeper_data_backend_close_yourself(self->_priv->skdbg);
2766                         g_spawn_command_line_sync(exec,NULL, NULL, NULL,NULL);
2767                         g_free(exec);
2768                         g_free(filename);
2769                         stuffkeeper_data_backend_load(self->_priv->skdbg, path);
2772                         g_free(path);
2773                     }
2774                 }
2775                 default:
2776                     break;
2778             }
2779             gtk_widget_destroy(dialog);
2780         }
2783         public
2784         void
2785         reload(self)
2786         {
2787             gchar *path = g_strdup(stuffkeeper_data_backend_get_path(self->_priv->skdbg));
2788             stuffkeeper_data_backend_close_yourself(self->_priv->skdbg);
2789             stuffkeeper_data_backend_load(self->_priv->skdbg, path);
2790             g_free(path);
2791         }
2792         public
2793             void
2794             visit_homepage(self)
2795             {
2796                 open_url(PROGRAM_WEBSITE);
2797             }
2798         public
2799             void
2800             visit_bugtracker(self)
2801             {
2802                 open_url(PROGRAM_BUGTRACKER);
2803             }
2807         /**
2808          * HTML Export 
2809          */
2810         /* Export the whole db */
2811         public
2812         void
2813         export_to_html(self)
2814         {
2815             stuffkeeper_export_html_new_schema(self,self->_priv->skdbg,GTK_LIST_STORE(self->_priv->model_schemas));
2816         }
2818         /* export selected item */
2819         public
2820         void
2821         export_html_item(self)
2822         {
2823             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self->_priv->treeview2));
2824             GtkWidget *tree = self->_priv->treeview2;
2825             GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
2826             GtkTreeIter iter;
2827             if(gtk_tree_selection_count_selected_rows(selection) == 1)
2828             {
2829                 GList *list = gtk_tree_selection_get_selected_rows(selection, &model);
2830                 if(list && gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)list->data))
2831                 {
2832                     StuffkeeperDataItem *item;
2833                     gtk_tree_model_get(model, &iter, 2, &item, -1);
2834                     if(item)
2835                     {
2836                         stuffkeeper_export_html_new(self,self->_priv->skdbg,STUFFKEEPER_DATA_ITEM(item));
2837                         return;
2838                     }
2839                 }
2841                 if(list){
2842                     g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
2843                     g_list_free (list);
2844                 }
2845             }
2846         }
2847         
2848         /**
2849          * Search new 
2850          */
2851         public
2852         void 
2853         new_search(self)
2854         {
2855             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
2856             if(locked){printf("**ERROR** should not be callable\n");return;}
2857             StuffkeeperDataItemSearch *search = stuffkeeper_data_backend_new_search(self->_priv->skdbg);
2858             stuffkeeper_data_item_search_edit_search_gui(search);
2859         }
2861         public
2862         void
2863         remove_search(self)
2864         {
2865             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
2866             if(locked){printf("**ERROR** should not be callable\n");return;}
2867             GtkTreeIter iter;
2868             if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_priv->cb_search), &iter))
2869             {
2870                 StuffkeeperDataItemSearch *search;
2871                 gint id;
2872                 gtk_tree_model_get(self->_priv->model_searches, &iter,0,&id, 3, &search, -1);
2873                 if(search && id != -1)
2874                 {
2875                     stuffkeeper_data_backend_remove_search(self->_priv->skdbg, id);
2876                 }
2877             }
2880         }
2881         public
2882             void
2883         edit_search(self)
2884         {
2885             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
2886             if(locked){printf("**ERROR** should not be callable\n");return;}
2887             GtkTreeIter iter;
2888             if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_priv->cb_search), &iter))
2889             {
2890                 StuffkeeperDataItemSearch *search;
2891                 gint id;
2892                 gtk_tree_model_get(self->_priv->model_searches, &iter,0,&id, 3, &search, -1);
2893                 if(search && id != -1)
2894                 {
2895                     stuffkeeper_data_item_search_edit_search_gui(search);
2896                 }
2897             }
2900         }
2904         public
2905         void
2906         remove_search_menu(self, GtkWidget *menu_item)
2907         {
2908             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
2909             if(locked){printf("**ERROR** should not be callable\n");return;}
2910             StuffkeeperDataItemSearch *search;
2911             search = g_object_get_data(G_OBJECT(menu_item), "search");
2912             if(search) 
2913             {
2914                 gint id = stuffkeeper_data_item_search_get_id(search);
2915                 stuffkeeper_data_backend_remove_search(self->_priv->skdbg, id);
2916             }
2917         }
2918         public
2919         void
2920         edit_search_menu(self,GtkWidget *menu_item)
2921         {
2922             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
2923             if(locked){printf("**ERROR** should not be callable\n");return;}
2924             StuffkeeperDataItemSearch *search;
2925             search = g_object_get_data(G_OBJECT(menu_item), "search");
2926             if(search)
2927             {
2928                 stuffkeeper_data_item_search_edit_search_gui(search);
2929             }
2930         }
2932         private
2933         void
2934         treeview1_selection_changed(self, GtkTreeSelection *selection)
2935         {
2936         }
2937         /**
2938          * Sorting
2939          */
2940         public 
2941             void
2942         sort_item_descending(self,GtkRadioButton *style)
2943         {
2944             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-order", GTK_SORT_DESCENDING);
2945             self->_priv->item_sort_order = GTK_SORT_DESCENDING;
2946             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2947                     self->_priv->item_sort_column,
2948                     self->_priv->item_sort_order);
2949         }
2951         public 
2952             void
2953         sort_item_ascending(self,GtkRadioButton *style)
2954         {
2955             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-order", GTK_SORT_ASCENDING);
2956             self->_priv->item_sort_order = GTK_SORT_ASCENDING;
2957             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2958                     self->_priv->item_sort_column,
2959                     self->_priv->item_sort_order);
2960         }
2961         public 
2962         void
2963         sort_item_by_modification_time(self,GtkRadioButton *style)
2964         {
2965             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-column", 5);
2966             self->_priv->item_sort_column = 5;
2967             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2968                     self->_priv->item_sort_column,
2969                     self->_priv->item_sort_order);
2970         }
2972         public 
2973         void
2974         sort_item_by_creation_time(self,GtkRadioButton *style)
2975         {
2976             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-column", 3);
2977             self->_priv->item_sort_column = 3;
2978             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2979                     self->_priv->item_sort_column,
2980                     self->_priv->item_sort_order);
2981         }
2982         public 
2983         void
2984         sort_item_by_title(self,GtkRadioButton *style)
2985         {
2986             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-column", 1);
2987             self->_priv->item_sort_column = 1;
2988             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2989                     self->_priv->item_sort_column,
2990                     self->_priv->item_sort_order);
2991         }
2992         public 
2993         void
2994         sort_item_by_schema(self,GtkRadioButton *style)
2995         {
2996             g_key_file_set_integer(self->config_file, "WINDOW", "item-sort-column", 4);
2997             self->_priv->item_sort_column = 4;
2998             gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(self->_priv->model_items),
2999                     self->_priv->item_sort_column,
3000                     self->_priv->item_sort_order);
3001         }
3002         /* storing saving schemas */
3003         private
3004         void
3005         schema_style_set(GtkWidget *event, GtkStyle *style, GtkBuilder *xml)
3006         {
3007             GtkWidget *dialog = (GtkWidget *)gtk_builder_get_object(xml,"export_schema_dialog");
3008             GtkWidget *event = (GtkWidget *)gtk_builder_get_object(xml, "eventbox_schema");
3009             GtkWidget *label =  (GtkWidget *)gtk_builder_get_object(xml, "label_title_schema");
3010             gtk_widget_modify_bg(event,
3011                     GTK_STATE_NORMAL, 
3012                     &((dialog)->style->bg[GTK_STATE_SELECTED]));
3013             gtk_widget_modify_text(label,
3014                               GTK_STATE_NORMAL, 
3015                               &((dialog)->style->text[GTK_STATE_SELECTED]));
3016             gtk_widget_modify_fg(label,
3017                     GTK_STATE_NORMAL, 
3018                               &((dialog)->style->fg[GTK_STATE_SELECTED]));
3019             
3020         }
3023         public
3024         void
3025         schema_new(self)
3026         {
3027             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
3028             if(locked){printf("**ERROR** should not be callable\n");return;}
3030             StuffkeeperDataSchema *schema = stuffkeeper_data_backend_new_schema(self->_priv->skdbg);
3031             StuffkeeperEditSchema *skes = stuffkeeper_edit_schema_new();
3032             stuffkeeper_edit_schema_set_schema(skes, schema);
3033         }
3035         public
3036         void
3037         schema_import(self)
3038         {
3039             gboolean locked = stuffkeeper_data_backend_get_locked(self->_priv->skdbg);
3040             if(locked){printf("**ERROR** should not be callable\n");return;}
3042            GtkFileFilter *filter = NULL;
3043             GtkWidget *dialog = gtk_file_chooser_dialog_new(_("Import type"), 
3044                     NULL, 
3045                     GTK_FILE_CHOOSER_ACTION_OPEN,
3046                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3047                     GTK_STOCK_OPEN, GTK_RESPONSE_OK, 
3048                     NULL);
3049             filter = gtk_file_filter_new();
3050             gtk_file_filter_set_name(filter, _("Types files"));
3051             gtk_file_filter_add_pattern(filter, "*.type");
3052             gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
3055             switch(gtk_dialog_run(GTK_DIALOG(dialog)))
3056             {
3057                 case GTK_RESPONSE_OK:
3058                 {
3059                     gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
3060                     stuffkeeper_data_backend_load_from_xml(self->_priv->skdbg,filename);
3061                     g_free(filename);
3062                 }
3063                 default:
3064                     break;
3065             }
3066             gtk_widget_destroy(dialog);
3067         }
3068     
3069         public
3070         void
3071         entry_changed(GtkWidget *entry, GtkWidget *button)
3072         {
3073             const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
3074             if(text[0] == '\0') {
3075                 gtk_widget_set_sensitive(button, FALSE);
3076             } else {
3077                 gtk_widget_set_sensitive(button, TRUE);
3078             }
3079         }
3081         public
3082         void
3083         schema_export(self)
3084         {
3085             GtkCellRenderer *renderer;
3086             GtkWidget *entry, *cb_schema;
3087             GtkBuilder *xml = gtk_builder_new();
3088             GtkWidget *dialog; 
3089             GError *error= NULL;
3090             gtk_builder_add_from_file(xml, PACKAGE_DATADIR"/export-schema-dialog.ui",&error);
3091             if(error) {
3092                 g_error("Failed to open ui file: %s\n", error->message);
3093                 g_error_free(error);
3094                 g_object_unref(xml);
3095                 return;
3096             }
3098             dialog = (GtkWidget *)gtk_builder_get_object(xml,"export_schema_dialog");
3100             g_signal_connect(G_OBJECT(dialog), "style-set", G_CALLBACK(self_schema_style_set),xml);
3102             /* entry */
3103             entry = (GtkWidget *)gtk_builder_get_object(xml, "entry_name");
3104             g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(self_entry_changed),
3105                             (GtkWidget *)gtk_builder_get_object(xml, "save_button1"));
3106             cb_schema = (GtkWidget *)gtk_builder_get_object(xml, "cb_schema");
3108             gtk_combo_box_set_model(GTK_COMBO_BOX(cb_schema), GTK_TREE_MODEL(self->_priv->model_schemas));
3109             gtk_combo_box_set_active(GTK_COMBO_BOX(cb_schema), 0);
3110             renderer = gtk_cell_renderer_text_new();
3111             gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cb_schema),renderer, TRUE);
3112             gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(cb_schema),renderer, "text",1 );
3115             gtk_builder_connect_signals_full(xml, (GtkBuilderConnectFunc)self____builder_xml_connect_foreach, (gpointer)self);
3116             switch(gtk_dialog_run(GTK_DIALOG(dialog)))
3117             {
3118                 case -5:
3119                     {
3120                         GtkTreeIter iter;
3121                         gchar *directory = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gtk_builder_get_object(xml, "fc_directory")));
3122                         const gchar *file = gtk_entry_get_text(GTK_ENTRY(entry)); 
3123                         if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cb_schema),&iter))
3124                         {
3125                             gchar *path = NULL;
3126                             gchar *filename = g_strdup_printf("%s.type", file);
3127                             StuffkeeperDataSchema *schema = NULL;
3128                             /* get model schema */
3129                             gtk_tree_model_get(self->_priv->model_schemas, &iter,3, &schema, -1); 
3130                             /* build path */
3131                             path = g_build_path(G_DIR_SEPARATOR_S, directory, filename,NULL);
3132                             /* save it */
3133                             stuffkeeper_data_schema_save_to_xml(schema,path);
3134                             g_free(path);
3135                             g_free(filename);
3136                         }
3137                         g_free(directory);
3138                     }
3139                 default:
3140                     break;
3141             }
3142             gtk_widget_destroy(dialog);
3143             g_object_unref(xml);
3144         }
3147         /**
3148          * First run 
3149          */
3150         public
3151         void
3152         first_run(self)
3153         {
3154             GDir *dir;
3155             GError *error = NULL;
3156             gchar *path = g_build_path(G_DIR_SEPARATOR_S,PACKAGE_DATADIR, "types",NULL);
3157             /* open the directory */
3158             dir = g_dir_open(path, 0, &error);
3159             if(error)
3160             {
3161                 printf("Error opening: '%s': '%s'\n", path, error->message);
3162                 g_error_free(error);
3163             }
3164             if(dir)
3165             {
3166                 const char *filename = NULL;
3167                 while((filename = g_dir_read_name(dir)))
3168                 {
3169                     gchar *full_path = g_build_path(G_DIR_SEPARATOR_S,PACKAGE_DATADIR, "types",filename,NULL);
3170                     stuffkeeper_data_backend_load_from_xml(self->_priv->skdbg, full_path);
3171                     g_free(full_path);
3172                 }
3173                 g_dir_close(dir);
3174             }
3175             g_free(path);
3176         }
3177         public
3178         void
3179         present(self)
3180         {
3181             gtk_window_present(GTK_WINDOW(self->_priv->win));
3182         }
3185         private
3186         void
3187         safe_vpane_position(self)
3188         {
3189             int value = 0;
3190             if(GTK_IS_HPANED(self->_priv->vpaned1))
3191             {
3192                 value = gtk_paned_get_position(GTK_PANED(self->_priv->vpaned1));
3193                 g_key_file_set_integer(self->config_file, "WINDOW", "vpane-alternative", value);
3194                 printf("store position alternative: %i\n", value);
3195             }
3196             else
3197             {
3198                 value = gtk_paned_get_position(GTK_PANED(self->_priv->vpaned1));
3199                 g_key_file_set_integer(self->config_file, "WINDOW", "vpane", value);
3201                 printf("store position : %i\n", value);
3202             }
3203         }
3204         private
3205         void
3206         set_alternative_layout(self, int active)
3207         {
3208             GError *error = NULL;
3209             int value =0;
3210             if(active && GTK_IS_VPANED(self->_priv->vpaned1))
3211             {
3212                 GtkWidget *p1 = g_object_ref(gtk_paned_get_child1(GTK_PANED(self->_priv->vpaned1)));
3213                 GtkWidget *p2 = g_object_ref(gtk_paned_get_child2(GTK_PANED(self->_priv->vpaned1)));
3214                 gtk_container_remove(GTK_CONTAINER(self->_priv->vpaned1), p1);
3215                 gtk_container_remove(GTK_CONTAINER(self->_priv->vpaned1), p2);
3216                 gtk_widget_destroy(self->_priv->vpaned1);
3217                 self->_priv->vpaned1 = gtk_hpaned_new();
3218                 gtk_paned_add2(GTK_PANED(self->_priv->hpaned1), self->_priv->vpaned1);
3219                 gtk_paned_pack1(GTK_PANED(self->_priv->vpaned1), p1,TRUE, FALSE);
3220                 gtk_paned_pack2(GTK_PANED(self->_priv->vpaned1), p2,TRUE, FALSE);
3221                 g_object_unref(p1);
3222                 g_object_unref(p2);
3223                 gtk_widget_show(self->_priv->vpaned1);
3225                 g_key_file_set_integer(self->config_file, "WINDOW", "alternative-layout", 1);
3227             }else if(!active && GTK_IS_HPANED(self->_priv->vpaned1)){
3229                 GtkWidget *p1 = g_object_ref(gtk_paned_get_child1(GTK_PANED(self->_priv->vpaned1)));
3230                 GtkWidget *p2 = g_object_ref(gtk_paned_get_child2(GTK_PANED(self->_priv->vpaned1)));
3231                 gtk_container_remove(GTK_CONTAINER(self->_priv->vpaned1), p1);
3232                 gtk_container_remove(GTK_CONTAINER(self->_priv->vpaned1), p2);
3233                 gtk_widget_destroy(self->_priv->vpaned1);
3234                 self->_priv->vpaned1 = gtk_vpaned_new();
3235                 gtk_paned_add2(GTK_PANED(self->_priv->hpaned1), self->_priv->vpaned1);
3236                 gtk_paned_pack1(GTK_PANED(self->_priv->vpaned1), p1,TRUE, FALSE);
3237                 gtk_paned_pack2(GTK_PANED(self->_priv->vpaned1), p2,TRUE, FALSE);
3238                 g_object_unref(p1);
3239                 g_object_unref(p2);
3241                 gtk_widget_show(self->_priv->vpaned1);
3243                 g_key_file_set_integer(self->config_file, "WINDOW", "alternative-layout", 0);
3245             }
3246             if(GTK_IS_HPANED(self->_priv->vpaned1)){
3247                 value = g_key_file_get_integer(self->config_file, "WINDOW", "vpane-alternative", &error);
3249                 g_debug("restore position alternative: %i\n", value);
3250             }else{
3251                 value = g_key_file_get_integer(self->config_file, "WINDOW", "vpane", &error);
3253                 g_debug("restore position : %i\n", value);
3254             }
3255             /* Restore pane position */
3256             if(error ) {
3257                 g_debug("No valid vpane position: %s\n", error->message);
3258                 /* Free error */
3259                 g_error_free(error);
3260                 error = NULL;
3261             }
3262             else if(value > 50)
3263             {
3264                 g_debug("Setting position: %i\n", value);
3265                 gtk_paned_set_position(GTK_PANED(self->_priv->vpaned1), value);
3266             }
3268         }
3269         public
3270         void
3271         on_alternative_layout_cb_activate(self, GtkCheckMenuItem *activate)
3272         {
3273             int active = gtk_check_menu_item_get_active(activate);
3275             self_safe_vpane_position(self);
3276             self_set_alternative_layout(self, active);
3278         }
3280         public  
3281         signal last NONE (NONE)
3282         void
3283         destroy(self)
3284         {
3286         }