# HG changeset patch # User nadvornik # Date 1236962721 0 # Node ID 3019f5d3a3c719805a996f80b4754454b255d28f # Parent c449a9344c8e36d109a0c4c2844b988b07c18344 added keyword tree filtering diff -r c449a9344c8e -r 3019f5d3a3c7 src/bar_keywords.c --- a/src/bar_keywords.c Fri Mar 13 12:06:01 2009 +0000 +++ b/src/bar_keywords.c Fri Mar 13 16:45:21 2009 +0000 @@ -116,6 +116,10 @@ GtkTreePath *click_tpath; + gboolean expand_checked; + gboolean collapse_unchecked; + gboolean hide_unchecked; + FileData *fd; gchar *key; }; @@ -150,7 +154,7 @@ string_list_free(list); } -gboolean bar_keyword_tree_expand_if_set(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +gboolean bar_keyword_tree_expand_if_set_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { PaneKeywordsData *pkd = data; gboolean set; @@ -164,15 +168,41 @@ return FALSE; } +gboolean bar_keyword_tree_collapse_if_unset_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + PaneKeywordsData *pkd = data; + gboolean set; + gboolean is_keyword; + + gtk_tree_model_get(model, iter, FILTER_KEYWORD_COLUMN_TOGGLE, &set, + FILTER_KEYWORD_COLUMN_IS_KEYWORD, &is_keyword, -1); + + if (is_keyword && !set && gtk_tree_view_row_expanded(GTK_TREE_VIEW(pkd->keyword_treeview), path)) + { + gtk_tree_view_collapse_row(GTK_TREE_VIEW(pkd->keyword_treeview), path); + } + return FALSE; +} + static void bar_keyword_tree_sync(PaneKeywordsData *pkd) { - GtkTreeModelFilter *store; + GtkTreeModel *model; - store = GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview))); + GtkTreeModel *keyword_tree; + GList *keywords; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model)); - gtk_tree_model_filter_refilter(store); - gtk_tree_model_foreach(GTK_TREE_MODEL(store), bar_keyword_tree_expand_if_set, pkd); - + keywords = keyword_list_pull(pkd->keyword_view); + keyword_show_set_in(GTK_TREE_STORE(keyword_tree), model, keywords); + if (pkd->hide_unchecked) keyword_hide_unset_in(GTK_TREE_STORE(keyword_tree), model, keywords); + string_list_free(keywords); + + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(model)); + + if (pkd->expand_checked) gtk_tree_model_foreach(model, bar_keyword_tree_expand_if_set_cb, pkd); + if (pkd->collapse_unchecked) gtk_tree_model_foreach(model, bar_keyword_tree_collapse_if_unset_cb, pkd); } static void bar_pane_keywords_keyword_update_all(void) @@ -323,6 +353,13 @@ } +gboolean bar_pane_keywords_filter_visible(GtkTreeModel *keyword_tree, GtkTreeIter *iter, gpointer data) +{ + GtkTreeModel *filter = data; + + return !keyword_is_hidden_in(keyword_tree, iter, filter); +} + static void bar_pane_keywords_set_selection(PaneKeywordsData *pkd, gboolean append) { GList *keywords = NULL; @@ -855,9 +892,103 @@ keyword_delete(GTK_TREE_STORE(keyword_tree), &kw_iter); } +static void bar_pane_keywords_hide_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + GtkTreeModel *model; + GtkTreeIter iter; + + GtkTreeModel *keyword_tree; + GtkTreeIter kw_iter; + + if (!pkd->click_tpath) return; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model)); + + if (!gtk_tree_model_get_iter(model, &iter, pkd->click_tpath)) return; + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(model), &kw_iter, &iter); + + keyword_hide_in(GTK_TREE_STORE(keyword_tree), &kw_iter, model); +} + +static void bar_pane_keywords_show_all_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + GtkTreeModel *model; + + GtkTreeModel *keyword_tree; + + pkd->hide_unchecked = FALSE; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model)); + + keyword_show_all_in(GTK_TREE_STORE(keyword_tree), model); + bar_keyword_tree_sync(pkd); +} + +static void bar_pane_keywords_expand_checked_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + gtk_tree_model_foreach(model, bar_keyword_tree_expand_if_set_cb, pkd); +} + +static void bar_pane_keywords_collapse_unchecked_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + gtk_tree_model_foreach(model, bar_keyword_tree_collapse_if_unset_cb, pkd); +} + +static void bar_pane_keywords_hide_unchecked_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + GtkTreeModel *model; + + GtkTreeModel *keyword_tree; + GList *keywords; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)); + keyword_tree = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model)); + + keywords = keyword_list_pull(pkd->keyword_view); + keyword_hide_unset_in(GTK_TREE_STORE(keyword_tree), model, keywords); + string_list_free(keywords); + bar_keyword_tree_sync(pkd); +} + +static void bar_pane_keywords_expand_checked_toggle_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + pkd->expand_checked = !pkd->expand_checked; + bar_keyword_tree_sync(pkd); +} + +static void bar_pane_keywords_collapse_unchecked_toggle_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + pkd->collapse_unchecked = !pkd->collapse_unchecked; + bar_keyword_tree_sync(pkd); +} + +static void bar_pane_keywords_hide_unchecked_toggle_cb(GtkWidget *menu_widget, gpointer data) +{ + PaneKeywordsData *pkd = data; + pkd->hide_unchecked = !pkd->hide_unchecked; + bar_keyword_tree_sync(pkd); +} + static void bar_pane_keywords_menu_popup(GtkWidget *widget, PaneKeywordsData *pkd, gint x, gint y) { GtkWidget *menu; + GtkWidget *item; + GtkWidget *submenu; GtkTreeViewDropPosition pos; if (pkd->click_tpath) gtk_tree_path_free(pkd->click_tpath); @@ -869,8 +1000,6 @@ if (pkd->click_tpath) { /* for the entry */ - GtkWidget *item; - GtkWidget *submenu; gchar *text; gchar *mark; gint i; @@ -884,11 +1013,8 @@ gtk_tree_model_get(model, &iter, FILTER_KEYWORD_COLUMN_NAME, &name, FILTER_KEYWORD_COLUMN_MARK, &mark, -1); - text = g_strdup_printf(_("Edit \"%s\""), name); - menu_item_add_stock(menu, text, GTK_STOCK_EDIT, G_CALLBACK(bar_pane_keywords_edit_dialog_cb), pkd); - g_free(text); - text = g_strdup_printf(_("Delete \"%s\""), name); - menu_item_add_stock(menu, text, GTK_STOCK_DELETE, G_CALLBACK(bar_pane_keywords_delete_cb), pkd); + text = g_strdup_printf(_("Hide \"%s\""), name); + menu_item_add_stock(menu, text, GTK_STOCK_EDIT, G_CALLBACK(bar_pane_keywords_hide_cb), pkd); g_free(text); submenu = gtk_menu_new(); @@ -899,11 +1025,20 @@ g_object_set_data(G_OBJECT(item), "mark", GINT_TO_POINTER(i + 1)); g_free(text); } - text = g_strdup_printf(_("Connect \"%s\" to mark"), name); item = menu_item_add(menu, text, NULL, NULL); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); g_free(text); + + menu_item_add_divider(menu); + + text = g_strdup_printf(_("Edit \"%s\""), name); + menu_item_add_stock(menu, text, GTK_STOCK_EDIT, G_CALLBACK(bar_pane_keywords_edit_dialog_cb), pkd); + g_free(text); + text = g_strdup_printf(_("Delete \"%s\""), name); + menu_item_add_stock(menu, text, GTK_STOCK_DELETE, G_CALLBACK(bar_pane_keywords_delete_cb), pkd); + g_free(text); + if (mark && mark[0]) { @@ -917,6 +1052,23 @@ g_free(name); } /* for the pane */ + + + menu_item_add(menu, _("Expand checked"), G_CALLBACK(bar_pane_keywords_expand_checked_cb), pkd); + menu_item_add(menu, _("Collapse unchecked"), G_CALLBACK(bar_pane_keywords_collapse_unchecked_cb), pkd); + menu_item_add(menu, _("Hide unchecked"), G_CALLBACK(bar_pane_keywords_hide_unchecked_cb), pkd); + menu_item_add(menu, _("Show all"), G_CALLBACK(bar_pane_keywords_show_all_cb), pkd); + + submenu = gtk_menu_new(); + item = menu_item_add(menu, _("On any change"), NULL, NULL); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + + menu_item_add_check(submenu, _("Expand checked"), pkd->expand_checked, G_CALLBACK(bar_pane_keywords_expand_checked_toggle_cb), pkd); + menu_item_add_check(submenu, _("Collapse unchecked"), pkd->collapse_unchecked, G_CALLBACK(bar_pane_keywords_collapse_unchecked_toggle_cb), pkd); + menu_item_add_check(submenu, _("Hide unchecked"), pkd->hide_unchecked, G_CALLBACK(bar_pane_keywords_hide_unchecked_toggle_cb), pkd); + + menu_item_add_divider(menu); + menu_item_add_stock(menu, _("Add keyword"), GTK_STOCK_EDIT, G_CALLBACK(bar_pane_keywords_add_dialog_cb), pkd); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); @@ -986,6 +1138,7 @@ pkd->key = g_strdup(key); + pkd->expand_checked = TRUE; hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP); @@ -1030,6 +1183,10 @@ bar_pane_keywords_filter_modify, pkd, NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(store), + bar_pane_keywords_filter_visible, + store, + NULL); pkd->keyword_treeview = gtk_tree_view_new_with_model(store); g_object_unref(store); diff -r c449a9344c8e -r 3019f5d3a3c7 src/metadata.c --- a/src/metadata.c Fri Mar 13 12:06:01 2009 +0000 +++ b/src/metadata.c Fri Mar 13 16:45:21 2009 +0000 @@ -771,6 +771,7 @@ gchar *mark, *name, *casefold; gboolean is_keyword; + /* do not copy KEYWORD_COLUMN_HIDE_IN, it fully shows the new subtree */ gtk_tree_model_get(GTK_TREE_MODEL(keyword_tree), from, KEYWORD_COLUMN_MARK, &mark, KEYWORD_COLUMN_NAME, &name, KEYWORD_COLUMN_CASEFOLD, &casefold, @@ -805,7 +806,7 @@ void keyword_move_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *to, GtkTreeIter *from) { keyword_copy_recursive(keyword_tree, to, from); - gtk_tree_store_remove(keyword_tree, from); + keyword_delete(keyword_tree, from); } GList *keyword_tree_get_path(GtkTreeModel *keyword_tree, GtkTreeIter *iter_ptr) @@ -898,7 +899,7 @@ { const gchar *kw = work->data; work = work->next; - + casefold_list = g_list_prepend(casefold_list, g_utf8_casefold(kw, -1)); } @@ -1010,15 +1011,122 @@ void keyword_delete(GtkTreeStore *keyword_tree, GtkTreeIter *iter_ptr) { + GList *list; + GtkTreeIter child; + while (gtk_tree_model_iter_children(GTK_TREE_MODEL(keyword_tree), &child, iter_ptr)) + { + keyword_delete(keyword_tree, &child); + } + + meta_data_connect_mark_with_keyword(GTK_TREE_MODEL(keyword_tree), iter_ptr, -1); + + gtk_tree_model_get(GTK_TREE_MODEL(keyword_tree), iter_ptr, KEYWORD_COLUMN_HIDE_IN, &list, -1); + g_list_free(list); + gtk_tree_store_remove(keyword_tree, iter_ptr); } +void keyword_hide_in(GtkTreeStore *keyword_tree, GtkTreeIter *iter, gpointer id) +{ + GList *list; + gtk_tree_model_get(GTK_TREE_MODEL(keyword_tree), iter, KEYWORD_COLUMN_HIDE_IN, &list, -1); + if (!g_list_find(list, id)) + { + list = g_list_prepend(list, id); + gtk_tree_store_set(keyword_tree, iter, KEYWORD_COLUMN_HIDE_IN, list, -1); + } +} + +void keyword_show_in(GtkTreeStore *keyword_tree, GtkTreeIter *iter, gpointer id) +{ + GList *list; + gtk_tree_model_get(GTK_TREE_MODEL(keyword_tree), iter, KEYWORD_COLUMN_HIDE_IN, &list, -1); + list = g_list_remove(list, id); + gtk_tree_store_set(keyword_tree, iter, KEYWORD_COLUMN_HIDE_IN, list, -1); +} + +gboolean keyword_is_hidden_in(GtkTreeModel *keyword_tree, GtkTreeIter *iter, gpointer id) +{ + GList *list; + gtk_tree_model_get(keyword_tree, iter, KEYWORD_COLUMN_HIDE_IN, &list, -1); + return !!g_list_find(list, id); +} + +static gboolean keyword_show_all_in_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + keyword_show_in(GTK_TREE_STORE(model), iter, data); + return FALSE; +} + +void keyword_show_all_in(GtkTreeStore *keyword_tree, gpointer id) +{ + gtk_tree_model_foreach(GTK_TREE_MODEL(keyword_tree), keyword_show_all_in_cb, id); +} + +static void keyword_hide_unset_in_recursive(GtkTreeStore *keyword_tree, GtkTreeIter *iter_ptr, gpointer id, GList *keywords) +{ + GtkTreeIter iter = *iter_ptr; + while (TRUE) + { + if (keyword_get_is_keyword(GTK_TREE_MODEL(keyword_tree), &iter) && + !keyword_tree_is_set(GTK_TREE_MODEL(keyword_tree), &iter, keywords)) + { + keyword_hide_in(keyword_tree, &iter, id); + /* no need to check children of hidden node */ + } + else + { + GtkTreeIter child; + if (gtk_tree_model_iter_children(GTK_TREE_MODEL(keyword_tree), &child, &iter)) + { + keyword_hide_unset_in_recursive(keyword_tree, &child, id, keywords); + } + } + if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(keyword_tree), &iter)) return; + } +} + +void keyword_hide_unset_in(GtkTreeStore *keyword_tree, gpointer id, GList *keywords) +{ + GtkTreeIter iter; + gtk_tree_model_get_iter_first(GTK_TREE_MODEL(keyword_tree), &iter); + keyword_hide_unset_in_recursive(keyword_tree, &iter, id, keywords); +} + +static gboolean keyword_show_set_in_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter_ptr, gpointer data) +{ + GtkTreeIter iter = *iter_ptr; + GList *keywords = data; + gpointer id = keywords->data; + keywords = keywords->next; /* hack */ + if (keyword_tree_is_set(model, &iter, keywords)) + { + while (TRUE) + { + GtkTreeIter parent; + keyword_show_in(GTK_TREE_STORE(model), &iter, id); + if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(keyword_tree), &parent, &iter)) break; + iter = parent; + } + } + return FALSE; +} + +void keyword_show_set_in(GtkTreeStore *keyword_tree, gpointer id, GList *keywords) +{ + /* hack: pass id to keyword_hide_unset_in_cb in the list */ + keywords = g_list_prepend(keywords, id); + gtk_tree_model_foreach(GTK_TREE_MODEL(keyword_tree), keyword_show_set_in_cb, keywords); + keywords = g_list_delete_link(keywords, keywords); +} + + void keyword_tree_new(void) { if (keyword_tree) return; - keyword_tree = gtk_tree_store_new(KEYWORD_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); + keyword_tree = gtk_tree_store_new(KEYWORD_COLUMN_COUNT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER); } diff -r c449a9344c8e -r 3019f5d3a3c7 src/metadata.h --- a/src/metadata.h Fri Mar 13 12:06:01 2009 +0000 +++ b/src/metadata.h Fri Mar 13 16:45:21 2009 +0000 @@ -46,6 +46,7 @@ KEYWORD_COLUMN_NAME, KEYWORD_COLUMN_CASEFOLD, KEYWORD_COLUMN_IS_KEYWORD, + KEYWORD_COLUMN_HIDE_IN, KEYWORD_COLUMN_COUNT }; @@ -74,6 +75,14 @@ void keyword_delete(GtkTreeStore *keyword_tree, GtkTreeIter *iter_ptr); + +void keyword_hide_in(GtkTreeStore *keyword_tree, GtkTreeIter *iter, gpointer id); +void keyword_show_in(GtkTreeStore *keyword_tree, GtkTreeIter *iter, gpointer id); +gboolean keyword_is_hidden_in(GtkTreeModel *keyword_tree, GtkTreeIter *iter, gpointer id); +void keyword_show_all_in(GtkTreeStore *keyword_tree, gpointer id); +void keyword_hide_unset_in(GtkTreeStore *keyword_tree, gpointer id, GList *keywords); +void keyword_show_set_in(GtkTreeStore *keyword_tree, gpointer id, GList *keywords); + void keyword_tree_new_default(void); void keyword_tree_new(void);