GtkTreePath *click_tpath;
+ gboolean expand_checked;
+ gboolean collapse_unchecked;
+ gboolean hide_unchecked;
+
FileData *fd;
gchar *key;
};
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;
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;
- gtk_tree_model_filter_refilter(store);
- gtk_tree_model_foreach(GTK_TREE_MODEL(store), bar_keyword_tree_expand_if_set, pkd);
-
+ 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_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)
}
+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;
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);
if (pkd->click_tpath)
{
/* for the entry */
- GtkWidget *item;
- GtkWidget *submenu;
gchar *text;
gchar *mark;
gint i;
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();
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])
{
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);
pkd->key = g_strdup(key);
+ pkd->expand_checked = TRUE;
hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP);
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);
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,
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)
{
const gchar *kw = work->data;
work = work->next;
-
+
casefold_list = g_list_prepend(casefold_list, g_utf8_casefold(kw, -1));
}
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);
}