73#ifdef GDK_WINDOWING_QUARTZ
76#include <gdk/gdkkeysyms.h>
82#define FLOATING_ENTRY_WIDTH DT_PIXEL_APPLY_DPI(150)
101 gboolean tree_flag, suggestion_flag, sort_count_flag, hide_path_flag,
dttags_flag;
148 GdkModifierType mods, gpointer user_data);
150 GdkModifierType mods, gpointer user_data);
159 static const char *
v[] = {
"lighttable",
"map",
"studio_capture", NULL};
172 const gboolean user_tag = !g_str_has_prefix(path,
"darktable|") || g_str_has_prefix(path,
"darktable|style|");
179 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
180 gtk_tree_selection_unselect_all(selection);
188 GList *rows = gtk_tree_selection_get_selected_rows(selection,
model);
189 gboolean found =
FALSE;
192 found = gtk_tree_model_get_iter(*
model, iter, (GtkTreePath *)rows->data);
193 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
209 GtkTreeIter parent, child = *iter;
210 while(gtk_tree_model_iter_parent(
model, &parent, &child))
214 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
224 gchar *tagname = NULL;
225 gchar *synonyms = NULL;
231 if(synonyms && synonyms[0]) tagname =
dt_util_dstrcat(tagname,
", %s", synonyms);
232 gchar *haystack = g_utf8_strdown(tagname, -1);
233 gchar *needle = g_utf8_strdown(
d->keyword, -1);
234 visible = (g_strrstr(haystack, needle) != NULL);
250 GtkTreeIter parent, child = *iter;
255 while(gtk_tree_model_iter_parent(
model, &parent, &child))
267 if(
d->attached_tree_flag)
270 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
273 if(force &&
d->sort_count_flag)
276 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
279 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore), sort, GTK_SORT_ASCENDING);
287 if(force &&
d->sort_count_flag)
290 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
293 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore), sort, GTK_SORT_ASCENDING);
296 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
301 const char *tagname,
const gboolean needle)
303 gboolean found =
FALSE;
311 gchar *haystack = g_utf8_strdown(path, -1);
312 found = g_strstr_len(haystack, strlen(haystack), tagname) != NULL;
316 found = !g_strcmp0(tagname, path);
318 if(found)
return found;
319 GtkTreeIter child, parent = *iter;
320 if(gtk_tree_model_iter_children(
model, &child, &parent))
329 }
while(gtk_tree_model_iter_next(
model, iter));
335 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
336 GtkTreePath *path = gtk_tree_model_get_path(
model, iter);
337 gtk_tree_view_expand_to_path(
view, path);
338 gtk_tree_view_scroll_to_cell(
view, path, NULL,
TRUE, 0.5, 0.5);
339 gtk_tree_path_free(path);
342 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
343 gtk_tree_selection_select_iter(selection, iter);
349 const gboolean needle,
const gboolean select)
353 char *lt = g_strdup(tagname);
354 char *
t = g_strstrip(lt);
356 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
357 if(gtk_tree_model_get_iter_first(
model, &iter))
368 gchar *needle = g_utf8_strdown(keyword, -1);
378 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
379 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
381 for(; valid &&
i < index -1;
i++)
382 valid = gtk_tree_model_iter_next(
model, &iter);
383 for(; valid; valid = gtk_tree_model_iter_previous(
model, &iter))
397 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
398 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
400 for(; valid &&
i < index;
i++)
401 valid = gtk_tree_model_iter_next(
model, &iter);
402 for(; valid; valid = gtk_tree_model_iter_next(
model, &iter))
424 gboolean no_sel =
FALSE;
427 const gboolean build_tree = which ?
d->tree_flag :
d->attached_tree_flag;
434 view =
d->attached_view;
436 store = build_tree ? GTK_TREE_MODEL(
d->attached_treestore) : GTK_TREE_MODEL(
d->attached_liststore);
441 if(!
d->tree_flag &&
d->suggestion_flag)
445 view =
d->dictionary_view;
446 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
view));
448 store = GTK_TREE_MODEL(
d->dictionary_treestore);
450 store = GTK_TREE_MODEL(
d->dictionary_liststore);
453 gtk_tree_view_set_model(GTK_TREE_VIEW(
view), NULL);
455 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
458 gtk_tree_store_clear(GTK_TREE_STORE(
store));
460 char **last_tokens = NULL;
461 int last_tokens_length = 0;
462 GtkTreeIter last_parent = { 0 };
465 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
467 const gchar *tag = ((
dt_tag_t *)taglist->data)->tag;
470 tokens = g_strsplit(tag,
"|", -1);
474 GtkTreeIter parent = last_parent;
475 const int tokens_length = g_strv_length(tokens);
476 int common_length = 0;
479 while(tokens[common_length] && last_tokens[common_length] &&
480 !g_strcmp0(tokens[common_length], last_tokens[common_length]))
486 for(
int i = common_length;
i < last_tokens_length;
i++)
488 gtk_tree_model_iter_parent(GTK_TREE_MODEL(
store), &parent, &last_parent);
489 last_parent = parent;
495 for(
int i = 0;
i < common_length;
i++)
498 for(
char **token = &tokens[common_length]; *token; token++)
501 gchar *pth2 = g_strdup(pth);
502 pth2[strlen(pth2) - 1] =
'\0';
503 gtk_tree_store_insert(GTK_TREE_STORE(
store), &iter, common_length > 0 ? &parent : NULL, -1);
504 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
507 ((
dt_tag_t *)taglist->data)->id : 0,
510 ((
dt_tag_t *)taglist->data)->count : 0,
516 if(((
dt_tag_t *)taglist->data)->select)
525 if(last_tokens) g_strfreev(last_tokens);
526 last_tokens = tokens;
527 last_parent = parent;
528 last_tokens_length = tokens_length;
531 g_strfreev(last_tokens);
533 if(which &&
d->keyword[0])
537 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
539 else gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
540 g_object_unref(
model);
544 gtk_list_store_clear(GTK_LIST_STORE(
store));
545 if(count > 0 && tags)
547 for (GList *tag = tags; tag; tag = g_list_next(tag))
549 const char *subtag = g_strrstr(((
dt_tag_t *)tag->data)->tag,
"|");
550 gtk_list_store_append(GTK_LIST_STORE(
store), &iter);
551 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
564 if(which &&
d->keyword[0])
568 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
569 g_object_unref(
model);
576 if(!which &&
d->attached_tree_flag)
577 gtk_tree_view_expand_all(GTK_TREE_VIEW(
d->attached_view));
583 GtkTreeModel *
model, GtkTreeIter *iter,
584 gpointer data, gboolean dictionary_view)
595 gtk_tree_model_get(
model, iter,
602 const gboolean hide = dictionary_view ? (
d->tree_flag ?
TRUE :
d->hide_path_flag) :
d->attached_tree_flag;
604 if((dictionary_view && !count) || (!dictionary_view && count <= 1))
606 coltext = g_markup_printf_escaped(istag ?
"%s" :
"<i>%s</i>", hide ?
name : path);
610 coltext = g_markup_printf_escaped(istag ?
"%s (%d)" :
"<i>%s</i> (%d)", hide ?
name : path, count);
612 g_object_set(renderer,
"markup", coltext, NULL);
619 GtkTreeModel *
model, GtkTreeIter *iter,
626 GtkTreeModel *
model, GtkTreeIter *iter,
660 d->collection[0] =
'\0';
672 if(!
d->collection[0])
694 GtkTreeIter child, parent = *iter;
695 if(gtk_tree_model_iter_children(
model, &child, &parent))
701 }
while (gtk_tree_model_iter_next(
model, iter));
708 GtkTreeIter child, parent = *iter;
717 if(gtk_tree_model_iter_children(
model, &child, &parent))
719 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
725 GtkTreeIter child, parent = *iter;
728 if(gtk_tree_model_iter_children(
model, &child, &parent))
734 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
739 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
745 GtkTreeIter child, parent = *iter;
748 if(GTK_IS_TREE_STORE(
model))
750 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
752 if(gtk_tree_model_iter_children(
model, &child, &parent))
757 gtk_list_store_set(GTK_LIST_STORE(
model), &parent,
760 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
767 GtkTreeIter child = *iter;
768 while (gtk_tree_model_iter_parent(
model, parent, &child))
800 if(gtk_tree_model_get_iter_first(
model, &parent))
814 if(gtk_tree_model_get_iter_first(
model, &parent))
817 for (GList *tag = tags; tag; tag = g_list_next(tag))
819 GtkTreeIter iter = parent;
822 if(GTK_IS_TREE_STORE(
model))
824 gtk_tree_store_set(GTK_TREE_STORE(
model), &iter,
830 gtk_list_store_set(GTK_LIST_STORE(
model), &iter,
846 GtkTreeIter child, parent = *iter;
847 gboolean valid =
TRUE;
850 if(gtk_tree_model_iter_children(
model, &child, &parent))
852 GtkTreeIter tobedel = parent;
853 valid = gtk_tree_model_iter_next(
model, &parent);
856 gtk_tree_store_set(GTK_TREE_STORE(
model), &tobedel,
869 gtk_tree_store_remove(GTK_TREE_STORE(
model), &tobedel);
870 }
while (!root && valid);
877 guint pathlen = strlen(path);
878 gboolean valid = gtk_tree_model_get_iter_first(
model, &child);
883 GtkTreeIter tobedel = child;
884 valid = gtk_tree_model_iter_next (
model, &child);
885 if(strlen(path2) >= pathlen)
887 char letter = path2[pathlen];
888 path2[pathlen] =
'\0';
889 if(g_strcmp0(path, path2) == 0)
891 path2[pathlen] = letter;
892 gtk_list_store_remove(GTK_LIST_STORE(
model), &tobedel);
905 if(!
d->tree_flag &&
d->suggestion_flag)
911 : GTK_TREE_MODEL(
d->dictionary_liststore));
919 const gchar *beg = g_strrstr(gtk_entry_get_text(
d->dict_entry),
",");
922 beg = gtk_entry_get_text(
d->dict_entry);
925 if(*beg ==
',') beg++;
926 if(*beg ==
' ') beg++;
928 g_strlcpy(
d->keyword, beg,
sizeof(
d->keyword));
937 if(g_str_has_prefix(tagname, oldtagname))
939 if(strlen(tagname) == strlen(oldtagname))
944 char *subtag = g_strrstr(to->
newtagname,
"|");
945 subtag = (!subtag) ? newtagname : subtag + 1;
955 else if(strlen(tagname) > strlen(oldtagname) && tagname[strlen(oldtagname)] ==
'|')
958 char *newpath = g_strconcat(newtagname, &tagname[strlen(oldtagname)] , NULL);
979 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
980 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
982 if(gtk_tree_model_get_iter_first(
store, &iter))
988 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
995 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
1017 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
1035 const char *buf = (
char *)
params;
1038 gchar **tokens = g_strsplit(buf,
",", 0);
1042 gchar **entry = tokens;
1045 const guint tagid = strtoul(*entry, NULL, 0);
1046 tags = g_list_prepend(tags, GINT_TO_POINTER(tagid));
1054 gboolean change =
FALSE;
1055 for(GList *tag = tags; tag; tag = g_list_next(tag))
1078 GtkTreeModel *
model = NULL;
1079 GList *rows = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(
view), &
model);
1080 for(GList *
r = rows;
r;
r = g_list_next(
r))
1083 if(gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)
r->data))
1087 if(tagid > 0) ids = g_list_prepend(ids, GUINT_TO_POINTER(tagid));
1090 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
1102 gboolean changed =
FALSE;
1103 for(GList *
t = tagids;
t;
t = g_list_next(
t))
1105 const guint tagid = GPOINTER_TO_UINT(
t->data);
1106 if(tagid <= 0)
continue;
1112 g_list_free(affected);
1128 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1129 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1134 if(tagid <= 0)
return;
1145 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
1146 if(gtk_tree_model_get_iter_first(
model, &iter))
1150 GtkTreeIter store_iter;
1151 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1152 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1153 &store_iter, &iter);
1177 g_list_free(tagids);
1184 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1186 GList *tagids = NULL;
1187 if(gtk_tree_model_get_iter_first(
model, &iter))
1194 if(tagid > 0) tagids = g_list_prepend(tagids, GUINT_TO_POINTER(tagid));
1195 }
while(gtk_tree_model_iter_next(
model, &iter));
1198 g_list_free(tagids);
1205 menu = gtk_menu_new();
1208 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1209 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1210 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
1219 menuitem = gtk_menu_item_new_with_label(_(
"attach tag to all"));
1221 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1222 menuitem = gtk_separator_menu_item_new();
1223 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1229 menuitem = gtk_menu_item_new_with_label(sel_cnt > 1 ? _(
"detach tags") : _(
"detach tag"));
1230 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1234 menuitem = gtk_menu_item_new_with_label(_(
"detach all tags"));
1235 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1238 gtk_widget_show_all(GTK_WIDGET(menu));
1240 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
1245 const gchar *path_str, GdkRectangle *background,
1246 GdkRectangle *cell_area, GtkCellRendererState
flags,
1250 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
1251 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1253 if(path && gtk_tree_model_get_iter(
model, &iter, path))
1259 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1264 if(path) gtk_tree_path_free(path);
1271 GtkTreeModel *
model, GtkTreeIter *iter, gpointer data)
1275 g_object_set(renderer,
"icon-name",
"edit-delete-symbolic",
1284 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1285 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1286 GtkTreePath *path = NULL;
1287 const gboolean on_row =
1288 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL);
1290 gboolean valid_tag =
FALSE;
1292 if(on_row && gtk_tree_model_get_iter(
model, &iter, path))
1296 if(event->type == GDK_BUTTON_PRESS && event->button == 3)
1301 if(!gtk_tree_selection_path_is_selected(selection, path))
1303 gtk_tree_selection_unselect_all(selection);
1304 gtk_tree_selection_select_path(selection, path);
1308 gtk_tree_selection_unselect_all(selection);
1310 if(path) gtk_tree_path_free(path);
1315 if(event->type == GDK_2BUTTON_PRESS && event->button == 1 && valid_tag)
1321 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1325 if(path) gtk_tree_path_free(path);
1330 if(event->type == GDK_BUTTON_PRESS && event->button == 1 && on_row && !valid_tag)
1332 gtk_tree_path_free(path);
1336 if(path) gtk_tree_path_free(path);
1346 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1347 if(
key == GDK_KEY_Delete && gtk_tree_selection_count_selected_rows(selection) > 0)
1351 g_list_free(tagids);
1354 if(
key == GDK_KEY_Tab)
1356 gtk_tree_selection_unselect_all(selection);
1357 gtk_widget_grab_focus(GTK_WIDGET(
d->entry));
1360 else if(
key == GDK_KEY_ISO_Left_Tab)
1362 gtk_tree_selection_unselect_all(selection);
1372 const gchar *tag = gtk_entry_get_text(src);
1392 char *tagname = strrchr(
d->last_tag,
',');
1395 tagname ? tagname + 1 :
d->last_tag,
FALSE,
TRUE);
1429 case GDK_KEY_Return:
1432 case GDK_KEY_Escape:
1435 case GDK_KEY_ISO_Left_Tab:
1440 gtk_widget_grab_focus(GTK_WIDGET(
d->attached_view));
1453 if(
position != GTK_ENTRY_ICON_SECONDARY)
return;
1456 gtk_widget_grab_focus(GTK_WIDGET(entry));
1464 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
1465 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1467 if(
d->tree_flag &&
d->keyword[0])
1478 int res = GTK_RESPONSE_YES;
1485 GtkTreeModel *
model = NULL;
1486 GtkTreeView *
view =
d->dictionary_view;
1487 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1496 if(tag_count == 0)
return;
1499 GtkWidget *dialog = gtk_dialog_new_with_buttons( _(
"delete node?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1500 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
1501 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1502 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1504 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1505 gtk_container_add(GTK_CONTAINER(area), vbox);
1506 text = g_strdup_printf(_(
"selected: %s"), tagname);
1507 label = gtk_label_new(text);
1508 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1512 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1513 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be deleted",
"<u>%d</u> tags will be deleted", tag_count), tag_count);
1514 label = gtk_label_new(NULL);
1515 gtk_label_set_markup(GTK_LABEL(label), text);
1516 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1518 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1519 label = gtk_label_new(NULL);
1520 gtk_label_set_markup(GTK_LABEL(label), text);
1521 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1524#ifdef GDK_WINDOWING_QUARTZ
1527 gtk_widget_show_all(dialog);
1529 res = gtk_dialog_run(GTK_DIALOG(dialog));
1530 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1531 gtk_widget_destroy(dialog);
1533 if(
res != GTK_RESPONSE_YES)
1539 GList *tag_family = NULL;
1540 GList *tagged_images = NULL;
1548 GtkTreeIter store_iter;
1549 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1550 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1551 &store_iter, &iter);
1557 g_list_free(tagged_images);
1558 tagged_images = NULL;
1576 GtkTreeModel *
model = NULL;
1577 GtkTreeView *
view =
d->dictionary_view;
1578 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1585 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"create tag"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1586 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1587 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1588 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1590 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1591 gtk_container_add(GTK_CONTAINER(area), vbox);
1594 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1595 label = gtk_label_new(_(
"name: "));
1596 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1599 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1604 GtkTextBuffer *buffer = NULL;
1606 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1608 text = g_strdup_printf(_(
"add to: \"%s\" "), path);
1609 parent = gtk_check_button_new_with_label(text);
1610 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(parent),
TRUE);
1611 gtk_box_pack_end(GTK_BOX(vbox2), parent,
FALSE,
TRUE, 0);
1614 category = gtk_check_button_new_with_label(_(
"category"));
1615 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(category),
FALSE);
1616 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1617 private = gtk_check_button_new_with_label(_(
"private"));
1618 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
private),
FALSE);
1619 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1622 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1623 label = gtk_label_new(_(
"synonyms: "));
1624 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1625 GtkWidget *synonyms = gtk_text_view_new();
1628 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1629 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1630 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1632#ifdef GDK_WINDOWING_QUARTZ
1635 gtk_widget_show_all(dialog);
1637 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1639 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1640 char *message = NULL;
1642 message = _(
"empty tag is not allowed, aborting");
1643 char *new_tagname = NULL;
1644 const gboolean root = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(parent));
1647 new_tagname = g_strdup(path);
1650 else new_tagname = g_strdup(newtag);
1653 message = _(
"tag name already exists. aborting.");
1656 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1657 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1658 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1659 gtk_widget_destroy(warning_dialog);
1660 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1661 gtk_widget_destroy(dialog);
1666 guint new_tagid = 0;
1669 const gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1670 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1672 GtkTextIter start, end;
1673 gtk_text_buffer_get_start_iter(buffer, &start);
1674 gtk_text_buffer_get_end_iter(buffer, &end);
1675 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1676 if(new_tagid && new_synonyms_list && new_synonyms_list[0])
1687 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1688 gtk_widget_destroy(dialog);
1699 char *synonyms_list;
1704 GtkTreeModel *
model = NULL;
1705 GtkTreeView *
view =
d->dictionary_view;
1706 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1711 char *subtag = g_strrstr(tagname,
"|");
1712 if(subtag) subtag = subtag + 1;
1724 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"edit"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1725 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1726 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1727 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1729 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1730 gtk_container_add(GTK_CONTAINER(area), vbox);
1731 text = g_strdup_printf(_(
"selected: %s"), tagname);
1732 label = gtk_label_new(text);
1733 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1737 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1738 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
1739 label = gtk_label_new(NULL);
1740 gtk_label_set_markup(GTK_LABEL(label), text);
1741 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1743 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1744 label = gtk_label_new(NULL);
1745 gtk_label_set_markup(GTK_LABEL(label), text);
1746 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1750 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1751 label = gtk_label_new(_(
"name: "));
1752 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1755 gtk_entry_set_text(GTK_ENTRY(entry), subtag ? subtag : tagname);
1756 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1760 GtkWidget *
private = gtk_check_button_new_with_label(_(
"private"));
1761 GtkTextBuffer *buffer = NULL;
1766 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1768 category = gtk_check_button_new_with_label(_(
"category"));
1770 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1772 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1775 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1776 label = gtk_label_new(_(
"synonyms: "));
1777 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1778 GtkWidget *synonyms = gtk_text_view_new();
1781 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1782 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1783 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1784 if(synonyms_list) gtk_text_buffer_set_text(buffer, synonyms_list, -1);
1787#ifdef GDK_WINDOWING_QUARTZ
1790 gtk_widget_show_all(dialog);
1792 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1794 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1795 if(g_strcmp0(newtag, subtag ? subtag : tagname) != 0)
1798 char *message = NULL;
1800 message = _(
"empty tag is not allowed, aborting");
1801 if(strchr(newtag,
'|') != 0)
1802 message = _(
"'|' character is not allowed for renaming tag.\nto modify the hierarchy use rename path instead. Aborting.");
1805 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1806 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1807 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1808 gtk_widget_destroy(warning_dialog);
1809 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1810 gtk_widget_destroy(dialog);
1816 GList *tag_family = NULL;
1817 GList *tagged_images = NULL;
1820 const int tagname_len = strlen(tagname);
1821 char *new_prefix_tag;
1824 const int subtag_len = strlen(subtag);
1825 const char letter = tagname[tagname_len - subtag_len];
1826 tagname[tagname_len - subtag_len] =
'\0';
1827 new_prefix_tag = g_strconcat(tagname, newtag, NULL);
1828 tagname[tagname_len - subtag_len] = letter;
1831 new_prefix_tag = (
char *)newtag;
1834 gboolean tagname_exists =
FALSE;
1835 for (GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1837 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1841 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1842 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1843 _(
"at least one new tag name (%s) already exists, aborting"), new_tagname);
1844 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1845 gtk_widget_destroy(warning_dialog);
1851 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1852 gtk_widget_destroy(dialog);
1861 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1863 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1869 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1875 GtkSortType sort_order;
1876 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(
store), &sort_column, &sort_order);
1877 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
1879 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), sort_column, sort_order);
1891 g_list_free(tagged_images);
1892 tagged_images = NULL;
1897 gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1898 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1899 GtkTextIter start, end;
1900 gtk_text_buffer_get_start_iter(buffer, &start);
1901 gtk_text_buffer_get_end_iter(buffer, &end);
1902 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1905 GtkTreeIter store_iter;
1906 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1907 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1908 &store_iter, &iter);
1918 if(new_synonyms_list && g_strcmp0(synonyms_list, new_synonyms_list) != 0)
1930 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1931 gtk_widget_destroy(dialog);
1942 gboolean success =
FALSE;
1943 GList *tag_family = NULL;
1944 GList *tagged_images = NULL;
1948 const int tagname_len = strlen(tagname);
1949 gboolean tagname_exists =
FALSE;
1950 for(GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1952 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1962 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_MODAL,
1963 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1964 _(
"at least one new tagname (%s) already exists, aborting."), new_tagname);
1965 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1966 gtk_widget_destroy(warning_dialog);
1973 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1975 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1989 g_list_free(tagged_images);
1990 tagged_images = NULL;
2005 GtkTreeModel *
model = NULL;
2006 GtkTreeView *
view =
d->dictionary_view;
2007 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2016 if(tag_count == 0)
return;
2019 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"change path"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
2020 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
2021 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
2022 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2024 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
2025 gtk_container_add(GTK_CONTAINER(area), vbox);
2026 text = g_strdup_printf(_(
"selected: %s"), tagname);
2027 label = gtk_label_new(text);
2028 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
2032 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
2033 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
2034 label = gtk_label_new(NULL);
2035 gtk_label_set_markup(GTK_LABEL(label), text);
2036 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
2038 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
2039 label = gtk_label_new(NULL);
2040 gtk_label_set_markup(GTK_LABEL(label), text);
2041 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
2046 gtk_entry_set_text(GTK_ENTRY(entry), tagname);
2047 gtk_box_pack_start(GTK_BOX(vbox), entry,
FALSE,
TRUE, 0);
2049#ifdef GDK_WINDOWING_QUARTZ
2052 gtk_widget_show_all(dialog);
2054 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
2056 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
2057 if(g_strcmp0(newtag, tagname) == 0)
2059 char *message = NULL;
2061 message = _(
"empty tag is not allowed, aborting");
2062 if(strchr(newtag,
'|') == &newtag[0] || strchr(newtag,
'|') == &newtag[strlen(newtag)-1] || strstr(newtag,
"||"))
2063 message = _(
"'|' misplaced, empty tag is not allowed, aborting");
2066 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
2067 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
2068 gtk_dialog_run(GTK_DIALOG(warning_dialog));
2069 gtk_widget_destroy(warning_dialog);
2070 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2071 gtk_widget_destroy(dialog);
2078 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2079 gtk_widget_destroy(dialog);
2088 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2089 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2111 if(
d->collection[0])
2116 d->collection[0] =
'\0';
2124 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2125 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2130 gtk_entry_set_text(
d->dict_entry, tag);
2132 gtk_entry_grab_focus_without_selecting(
d->dict_entry);
2141 const guint nb = g_list_length(tagids);
2144 guint img_count = 0;
2145 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2148 if(img_count > 0 ||
dt_conf_get_bool(
"plugins/lighttable/tagging/ask_before_delete_tag"))
2151 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"delete tag?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
2152 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
2153 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
2154 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2155 gchar *text = g_strdup_printf(ngettext(
"do you really want to delete %d tag?\n%d image is assigned these tags!",
2156 "do you really want to delete %d tags?\n%d images are assigned these tags!",
2157 img_count), nb, img_count);
2159 gtk_container_set_border_width(GTK_CONTAINER(area), 8);
2160 gtk_container_add(GTK_CONTAINER(area), label);
2162#ifdef GDK_WINDOWING_QUARTZ
2165 gtk_widget_show_all(dialog);
2166 const int res = gtk_dialog_run(GTK_DIALOG(dialog));
2167 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2168 gtk_widget_destroy(dialog);
2170 if(
res != GTK_RESPONSE_YES)
return;
2173 GList *affected = NULL;
2174 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2176 const guint tagid = GPOINTER_TO_UINT(
t->data);
2192 g_list_free(affected);
2201 g_list_free(tagids);
2211 GtkTreeModel *
model = NULL;
2212 GtkTreeView *
view =
d->dictionary_view;
2213 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2232 GtkTreeIter iter, child;
2233 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2234 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2235 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
2236 if(sel_cnt == 0)
return;
2244 menuitem = gtk_menu_item_new_with_label(_(
"delete tags"));
2246 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2247 gtk_widget_show_all(GTK_WIDGET(menu));
2248 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2255 gtk_tree_model_get(
model, &iter,
2259 if(
d->tree_flag || !
d->suggestion_flag)
2261 menuitem = gtk_menu_item_new_with_label(_(
"create tag..."));
2262 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2267 menuitem = gtk_menu_item_new_with_label(_(
"delete tag"));
2268 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2272 if(gtk_tree_model_iter_children(
model, &child, &iter))
2274 menuitem = gtk_menu_item_new_with_label(_(
"delete node"));
2275 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2279 menuitem = gtk_menu_item_new_with_label(_(
"edit..."));
2280 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2287 menuitem = gtk_menu_item_new_with_label(_(
"change path..."));
2288 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2292 if(
d->tree_flag && !tagid)
2294 menuitem = gtk_separator_menu_item_new();
2295 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2297 menuitem = gtk_menu_item_new_with_label(_(
"set as a tag"));
2298 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2302 if(!
d->suggestion_flag)
2304 menuitem = gtk_separator_menu_item_new();
2305 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2308 menuitem = gtk_menu_item_new_with_label(_(
"copy to entry"));
2310 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2312 if(
d->collection[0])
2314 char *collection = g_malloc(4096);
2316 if(g_strcmp0(
d->collection, collection) == 0)
d->collection[0] =
'\0';
2319 if(count ||
d->collection[0])
2321 menuitem = gtk_separator_menu_item_new();
2322 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2325 menuitem = gtk_menu_item_new_with_label(_(
"go to tag collection"));
2327 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2329 if(
d->collection[0])
2331 menuitem = gtk_menu_item_new_with_label(_(
"go back to work"));
2333 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2336 gtk_widget_show_all(GTK_WIDGET(menu));
2338 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2347 const int button_pressed = (
event->type == GDK_BUTTON_PRESS) ? event->button : 0;
2348 const gboolean shift_pressed =
dt_modifier_is(event->state, GDK_SHIFT_MASK);
2352 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2353 GtkTreePath *path = NULL;
2355 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
2359 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
2361 gtk_tree_model_get_iter(
model, &iter, path);
2363 gtk_tree_model_get(
model, &iter,
2369 d->drag.tagname = tagname;
2370 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
2371 d->drag.path = path;
2372 if(
d->drag.lastpath) gtk_tree_path_free(
d->drag.lastpath);
2373 d->drag.lastpath = NULL;
2379 if(!gtk_tree_selection_path_is_selected(selection, path))
2381 gtk_tree_selection_unselect_all(selection);
2382 gtk_tree_selection_select_path(selection, path);
2385 gtk_tree_path_free(path);
2390 gtk_tree_selection_select_path(selection, path);
2391 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
TRUE);
2392 gtk_tree_path_free(path);
2396 gtk_tree_path_free(path);
2406 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2407 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2413 GtkTreePath *path = gtk_tree_model_get_path(
model, &iter);
2420 gtk_tree_view_collapse_all(GTK_TREE_VIEW(
view));
2422 gtk_tree_view_collapse_row(GTK_TREE_VIEW(
view), path);
2429 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
2437 gtk_tree_path_free(path);
2439 if(event->keyval == GDK_KEY_Tab)
2441 gtk_tree_selection_unselect_all(selection);
2444 else if(event->keyval == GDK_KEY_ISO_Left_Tab)
2446 gtk_tree_selection_unselect_all(selection);
2447 gtk_widget_grab_focus(GTK_WIDGET(
d->dict_entry));
2457 GtkTreePath *path = NULL;
2459 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
x, y, &path, NULL, NULL, NULL))
2461 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
2463 if(gtk_tree_model_get_iter(
model, &iter, path))
2468 char *synonyms = NULL;
2475 gchar *text = g_strdup_printf(_(
"%s"), tagname);
2477 text =
dt_util_dstrcat(text,
"synonyms: %s", (synonyms && synonyms[0]) ? synonyms :
" - ");
2478 gtk_tooltip_set_text(
tooltip, text);
2487 gtk_tree_path_free(path);
2497 last_dirname = g_get_home_dir();
2501 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2502 _(
"select a keyword file"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
2503 _(
"_import"), _(
"_cancel"));
2505 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2506 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
FALSE);
2508 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2510 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2511 char *dirname = g_path_get_dirname(filename);
2512 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2519 g_object_unref(filechooser);
2525 GDateTime *now = g_date_time_new_now_local();
2526 char *export_filename = g_date_time_format(now,
"darktable_tags_%F_%H-%M.txt");
2530 last_dirname = g_get_home_dir();
2534 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2535 _(
"select file to export to"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SAVE,
2536 _(
"_export"), _(
"_cancel"));
2538 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(filechooser),
TRUE);
2539 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2540 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), export_filename);
2542 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2544 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2545 char *dirname = g_path_get_dirname(filename);
2546 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2553 g_date_time_unref(now);
2555 g_object_unref(filechooser);
2561 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2565 d->suggestion_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2566 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_suggestion_button),
d->suggestion_flag);
2568 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_tree_button),
d->tree_flag);
2572 if(
model == GTK_TREE_MODEL(
d->dictionary_listfilter))
2574 g_object_ref(
model);
2575 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2576 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2577 gtk_list_store_clear(GTK_LIST_STORE(
store));
2578 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_treefilter));
2579 g_object_unref(
d->dictionary_treefilter);
2581 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
FALSE);
2585 if(
model == GTK_TREE_MODEL(
d->dictionary_treefilter))
2587 g_object_ref(
model);
2588 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2589 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2590 gtk_tree_store_clear(GTK_TREE_STORE(
store));
2591 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_listfilter));
2592 g_object_unref(
d->dictionary_listfilter);
2594 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
TRUE);
2599 gtk_drag_source_set(GTK_WIDGET(
d->dictionary_view), GDK_BUTTON1_MASK,
2602 gtk_drag_source_unset(GTK_WIDGET(
d->dictionary_view));
2604 d->sort_count_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/listsortedbycount");
2609 d->hide_path_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/hidehierarchy");
2611 d->attached_tree_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/attached_treeview");
2615 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->dttags_check),
d->dttags_flag);
2623 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2632 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/treeview");
2644 return (count_b - count_a);
2655 const gboolean sort = g_strcmp0(tag_a, tag_b);
2669 for(
char *letter = tag_a; *letter; letter++)
2670 if(*letter ==
'|') *letter =
'\1';
2673 tag_a = g_strdup(
"");
2677 for(
char *letter = tag_b; *letter; letter++)
2678 if(*letter ==
'|') *letter =
'\1';
2681 tag_b = g_strdup(
"");
2683 const gboolean sort = g_strcmp0(tag_a, tag_b);
2713 d->dttags_flag = gtk_toggle_button_get_active(source);
2742 if(!
d->collection_tags)
return;
2743 g_hash_table_remove_all(
d->collection_tags);
2746 for(GList *
t = tags;
t;
t = g_list_next(
t))
2750 g_hash_table_add(
d->collection_tags, g_strdup(tag->tag));
2762 GtkEditable *e = (GtkEditable *)gtk_entry_completion_get_entry(completion);
2764 if(!GTK_IS_EDITABLE(e))
2769 const gint cur_pos = gtk_editable_get_position(e);
2770 const gboolean onLastTag = (g_strstr_len(&
key[cur_pos], -1,
",") == NULL);
2776 GtkTreeModel *
model = gtk_entry_completion_get_model(completion);
2777 const int column = gtk_entry_completion_get_text_column(completion);
2779 if(gtk_tree_model_get_column_type(
model, column) != G_TYPE_STRING)
2784 const gchar *lastTag = g_strrstr(
key,
",");
2795 gtk_tree_model_get(
model, iter, column, &tag, -1);
2799 if(lastTag[0] ==
'\0')
2801 res = (
d &&
d->collection_tags && tag) ? g_hash_table_contains(
d->collection_tags, tag) :
FALSE;
2808 char *normalized = g_utf8_normalize(tag, -1, G_NORMALIZE_ALL);
2811 char *casefold = g_utf8_casefold(normalized, -1);
2814 res = g_strstr_len(casefold, -1, lastTag) != NULL;
2833 if(!
d->drag.root)
return;
2834 GtkTreeModel *
model = GTK_TREE_MODEL(
d->dictionary_treestore);
2836 gtk_tree_model_get_iter_first(
model, &iter);
2840 gtk_tree_store_remove(
d->dictionary_treestore, &iter);
2848 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2852 cairo_surface_t *row_pix = gtk_tree_view_create_row_drag_icon(tree,
d->drag.path);
2858 gtk_drag_set_icon_surface(context, row_pix);
2859 cairo_surface_destroy(row_pix);
2860 gtk_tree_path_free(
d->drag.path);
2861 d->drag.path = NULL;
2862 d->drag.tag_source =
TRUE;
2870 gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data),
2875 GtkSelectionData *selection_data, guint target_type, guint time,
2879 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2881 g_signal_stop_emission_by_name(tree,
"drag-data-received");
2882 gboolean success =
FALSE;
2886 GtkTreePath *path = NULL;
2887 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2890 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2893 gtk_tree_model_get_iter(
model, &iter, path);
2896 const gboolean root = (
name &&
name[0] ==
'\0');
2897 char *
leave = g_strrstr(
d->drag.tagname,
"|");
2904 gtk_tree_path_free(path);
2910 GtkTreePath *path = NULL;
2911 const int imgs_nb = gtk_selection_data_get_length(selection_data) /
sizeof(uint32_t);
2912 if(imgs_nb && gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2914 const uint32_t *imgt = (uint32_t *)gtk_selection_data_get_data(selection_data);
2916 for(
int i = 0;
i < imgs_nb;
i++)
2918 imgs = g_list_prepend(imgs, GINT_TO_POINTER(imgt[
i]));
2920 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2922 gtk_tree_model_get_iter(
model, &iter, path);
2933 gtk_tree_path_free(path);
2937 gtk_drag_finish(context, success,
FALSE, time);
2943 if(
d->drag.lastpath)
2945 gtk_tree_view_expand_row(
d->dictionary_view,
d->drag.lastpath,
FALSE);
2953 if(
d->drag.scroll_timeout)
2955 GdkRectangle visible;
2956 gtk_tree_view_get_visible_rect(
d->dictionary_view, &visible);
2958 gtk_tree_view_convert_bin_window_to_tree_coords(
d->dictionary_view,
2959 0, 0, NULL, &top_ty);
2962 if(
d->drag.tag_source && !
d->drag.root &&
d->drag.last_y < 5 && top_ty < 1)
2965 gtk_tree_store_prepend(
d->dictionary_treestore, &iter, NULL);
2966 gtk_tree_store_set(
d->dictionary_treestore, &iter,
2975 d->drag.root =
TRUE;
2977 else if(
d->drag.root &&
d->drag.last_y >= 20)
2980 if(
d->drag.last_y < 5)
2983 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty - 25 < 0 ? 0 : top_ty - 25);
2985 else if(
d->drag.last_y > visible.height - 5)
2987 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty + 25);
2997 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2998 GtkTreePath *path = NULL;
3000 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
3002 if(
IS_NULL_PTR(
d->drag.lastpath) || ((
d->drag.lastpath) && gtk_tree_path_compare(
d->drag.lastpath, path) != 0))
3004 GtkTreeViewColumn *col = gtk_tree_view_get_column(
d->dictionary_view, 0);
3005 const int sel_width = gtk_tree_view_column_get_width(col);
3008 if(!gtk_tree_view_row_expanded(tree, path))
3013 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3014 gtk_tree_selection_select_path(selection, path);
3016 if(
d->drag.scroll_timeout == 0)
3025 if(
d->drag.lastpath)
3026 gtk_tree_path_free(
d->drag.lastpath);
3027 d->drag.lastpath = path;
3037 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3038 gtk_tree_selection_unselect_all(selection);
3039 if(
d->drag.scroll_timeout)
3040 g_source_remove(
d->drag.scroll_timeout);
3041 d->drag.scroll_timeout = 0;
3042 d->drag.tag_source =
FALSE;
3050 gtk_widget_show_all(
d->manage_window);
3051 gtk_window_present(GTK_WINDOW(
d->manage_window));
3058 if(!
d->tree_flag &&
d->suggestion_flag)
3065 dt_conf_set_int(
"plugins/lighttable/tagging/confidence", gtk_spin_button_get_value_as_int(spin));
3072 dt_conf_set_int(
"plugins/lighttable/tagging/nb_recent_tags", gtk_spin_button_get_value_as_int(spin));
3087 self->
data = (
void *)
d;
3097 GtkTreeModel *
model;
3098 GtkListStore *liststore;
3099 GtkTreeStore *treestore;
3100 GtkTreeViewColumn *col;
3101 GtkCellRenderer *renderer;
3112 gtk_widget_set_valign(
d->attached_view_combo, GTK_ALIGN_CENTER);
3113 gtk_widget_set_tooltip_text(
d->attached_view_combo,
3114 _(
"show the attached tags as a flat list or as a hierarchical tree"));
3116 gtk_box_pack_start(hbox,
d->attached_view_combo,
TRUE,
TRUE, 0);
3124 gtk_widget_set_valign(
d->sort_combo, GTK_ALIGN_CENTER);
3125 gtk_widget_set_tooltip_text(
d->sort_combo, _(
"sort the tags by name or by image count"));
3126 g_signal_connect(G_OBJECT(
d->sort_combo),
"value-changed", G_CALLBACK(
_sort_combo_changed), self);
3127 gtk_box_pack_start(hbox,
d->sort_combo,
TRUE,
TRUE, 0);
3129 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3135 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
3136 view = GTK_TREE_VIEW(gtk_tree_view_new());
3140 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3141 d->attached_view =
view;
3142 gtk_tree_view_set_enable_search(
view,
FALSE);
3143 gtk_tree_view_set_headers_visible(
view,
FALSE);
3145 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3152 d->attached_liststore = liststore;
3155 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3158 d->attached_treestore = treestore;
3159 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3162 col = gtk_tree_view_column_new();
3163 gtk_tree_view_append_column(
view, col);
3164 renderer = gtk_cell_renderer_text_new();
3165 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3166 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3168 gtk_tree_view_column_set_expand(col,
TRUE);
3169 gtk_tree_view_set_expander_column(
view, col);
3172 col = gtk_tree_view_column_new();
3173 gtk_tree_view_append_column(
view, col);
3175 g_object_set(renderer,
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
3176 gtk_tree_view_column_pack_end(col, renderer,
FALSE);
3180 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3181 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(liststore));
3184 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"attached tags,"
3185 "\nclick the trash icon, press Delete or double-click to detach"
3186 "\nselect several tags and right-click to detach them in bulk,"
3187 "\npress Tab to give the focus to entry,"
3188 "\nctrl-wheel scroll to resize the window"));
3193#define NEW_TOGGLE_BUTTON(paint, callback, tooltip, action) \
3194 button = dtgtk_togglebutton_new(paint, 0, NULL); \
3195 gtk_widget_set_tooltip_text(button, tooltip); \
3196 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, TRUE, 0); \
3197 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), self); \
3201 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
FALSE,
TRUE, 0);
3204 gtk_box_reorder_child(GTK_BOX(self->
widget), GTK_WIDGET(box), 1);
3208 w = gtk_entry_new();
3210 gtk_entry_set_text(GTK_ENTRY(w),
"");
3211 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3213 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"enter or pick a tag, Enter to attach"));
3214 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3215 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3216 g_signal_connect(G_OBJECT(w),
"icon-release", G_CALLBACK(
_entry_clear_icon), self);
3217 gtk_box_pack_start(hbox, w,
TRUE,
TRUE, 0);
3218 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3219 d->entry = GTK_ENTRY(w);
3223 gtk_widget_set_tooltip_text(
d->validate_button, _(
"attach this tag to the selected images"));
3224 gtk_box_pack_end(GTK_BOX(hbox),
d->validate_button,
FALSE,
TRUE, 0);
3226 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3234 GtkEntryCompletion *completion = gtk_entry_completion_new();
3235 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3237 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3238 gtk_entry_completion_set_popup_completion(completion,
TRUE);
3239 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3240 gtk_entry_completion_set_minimum_key_length(completion, 1);
3241 g_signal_connect(G_OBJECT(completion),
"match-selected",
3244 gtk_entry_set_completion(
d->entry, completion);
3245 g_object_unref(completion);
3247 g_object_unref(
d->completion_store);
3252 g_signal_connect(G_OBJECT(
d->entry),
"key-press-event", G_CALLBACK(
_enter_key_pressed), self);
3255 d->manage_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3256#ifdef GDK_WINDOWING_QUARTZ
3259 gtk_window_set_title(GTK_WINDOW(
d->manage_window), _(
"manage tags"));
3260 gtk_window_set_transient_for(GTK_WINDOW(
d->manage_window), GTK_WINDOW(
dt_gui_main_window()));
3263 g_signal_connect(G_OBJECT(
d->manage_window),
"delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
3267 gtk_container_add(GTK_CONTAINER(
d->manage_window), GTK_WIDGET(box));
3270 w = gtk_entry_new();
3272 gtk_entry_set_text(GTK_ENTRY(w),
"");
3273 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3274 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"type to filter the tag dictionary below"));
3275 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3276 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3277 g_signal_connect(G_OBJECT(w),
"icon-release", G_CALLBACK(
_entry_clear_icon), self);
3278 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3279 g_signal_connect(G_OBJECT(w),
"changed", G_CALLBACK(
_tag_name_changed), (gpointer)self);
3280 d->dict_entry = GTK_ENTRY(w);
3281 gtk_box_pack_start(box, w,
FALSE,
TRUE, 0);
3284 view = GTK_TREE_VIEW(gtk_tree_view_new());
3288 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3289 d->dictionary_view =
view;
3290 gtk_tree_view_set_enable_search(
view,
FALSE);
3291 gtk_tree_view_set_headers_visible(
view,
FALSE);
3293 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3300 d->dictionary_liststore = liststore;
3301 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
3303 d->dictionary_listfilter = GTK_TREE_MODEL_FILTER(
model);
3305 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3308 d->dictionary_treestore = treestore;
3309 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(treestore), NULL);
3311 d->dictionary_treefilter = GTK_TREE_MODEL_FILTER(
model);
3313 col = gtk_tree_view_column_new();
3314 gtk_tree_view_append_column(
view, col);
3315 renderer = gtk_cell_renderer_text_new();
3316 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3317 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3319 gtk_tree_view_set_expander_column(
view, col);
3321 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3322 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"tag dictionary,"
3323 "\nright-click to create, edit, delete tags,"
3324 "\nselect several tags and right-click to delete them in bulk,"
3325 "\nshift+click to fully expand the selected tag,"
3326 "\nctrl-scroll to resize the window"));
3330 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(
d->dictionary_listfilter));
3331 g_object_unref(
d->dictionary_listfilter);
3332 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3338 d->drag.path = NULL;
3339 d->drag.tagname = NULL;
3340 d->drag.scroll_timeout = 0;
3341 d->drag.expand_timeout = 0;
3343 d->drag.tag_source =
FALSE;
3344 gtk_drag_dest_set(GTK_WIDGET(
d->dictionary_view), GTK_DEST_DEFAULT_ALL,
3346 g_signal_connect(
d->dictionary_view,
"drag-data-get", G_CALLBACK(
_event_dnd_get), self);
3347 g_signal_connect(
d->dictionary_view,
"drag-data-received", G_CALLBACK(
_event_dnd_received), self);
3348 g_signal_connect_after(
d->dictionary_view,
"drag-begin", G_CALLBACK(
_event_dnd_begin), self);
3349 g_signal_connect_after(
d->dictionary_view,
"drag-end", G_CALLBACK(
_event_dnd_end), self);
3350 g_signal_connect(
d->dictionary_view,
"drag-motion", G_CALLBACK(
_event_dnd_motion), self);
3357 gtk_box_pack_start(hbox,
d->new_button,
TRUE,
TRUE, 0);
3360 gtk_box_pack_start(hbox,
d->import_button,
TRUE,
TRUE, 0);
3363 gtk_box_pack_start(hbox,
d->export_button,
TRUE,
TRUE, 0);
3366 _(
"toggle list / tree view"), N_(
"tree"));
3368 _(
"toggle list with / without suggestion"), N_(
"suggestion"));
3370 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3379 GtkWidget *lbl = gtk_label_new(_(
"suggested tags level of confidence"));
3380 gtk_widget_set_halign(lbl, GTK_ALIGN_START);
3381 gtk_widget_set_hexpand(lbl,
TRUE);
3382 GtkWidget *spin = gtk_spin_button_new_with_range(0, 100, 1);
3383 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
dt_conf_get_int(
"plugins/lighttable/tagging/confidence"));
3384 gtk_widget_set_tooltip_text(spin, _(
"level of confidence to include a tag in the suggestions list:"
3385 "\n0: all associated tags, 99: 99% matching tags,"
3386 "\n100: only the recently-used tags (faster)"));
3388 gtk_grid_attach(GTK_GRID(grid), lbl, 0, 0, 1, 1);
3389 gtk_grid_attach(GTK_GRID(grid), spin, 1, 0, 1, 1);
3391 GtkWidget *lbl2 = gtk_label_new(_(
"number of recently attached tags"));
3392 gtk_widget_set_halign(lbl2, GTK_ALIGN_START);
3393 gtk_widget_set_hexpand(lbl2,
TRUE);
3394 GtkWidget *spin2 = gtk_spin_button_new_with_range(-1, 1000, 1);
3395 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin2),
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags"));
3396 gtk_widget_set_tooltip_text(spin2, _(
"number of recently attached tags shown in the suggestions list"
3397 "\n(-1 disables the recent-tags list)"));
3399 gtk_grid_attach(GTK_GRID(grid), lbl2, 0, 1, 1, 1);
3400 gtk_grid_attach(GTK_GRID(grid), spin2, 1, 1, 1, 1);
3402 gtk_box_pack_start(box, grid,
FALSE,
FALSE, 0);
3406 d->dttags_check = gtk_check_button_new_with_label(_(
"Show system tags"));
3407 gtk_widget_set_tooltip_text(
d->dttags_check, _(
"show the tags automatically attached by Ansel (names starting with “Ansel|”)"));
3410 gtk_box_pack_start(GTK_BOX(self->
widget),
d->dttags_check,
FALSE,
TRUE, 0);
3412#undef NEW_TOGGLE_BUTTON
3424 d->collection = g_malloc(4096);
3425 d->collection_tags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
3437 _(
"Opens the quick tagging entry"));
3440 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3441 _(
"Re-applies the last used tag"));
3445 _(
"Opens the quick tagging entry"));
3448 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3449 _(
"Re-applies the last used tag"));
3475 if(
d->manage_window) gtk_widget_destroy(
d->manage_window);
3476 if(
d->collection_tags) g_hash_table_destroy(
d->collection_tags);
3478 if(
d->attached_liststore) g_object_unref(
d->attached_liststore);
3479 if(
d->attached_treestore) g_object_unref(
d->attached_treestore);
3485 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
3497 case GDK_KEY_Escape:
3498 g_list_free(
d->floating_tag_imgs);
3499 d->floating_tag_imgs = NULL;
3500 gtk_widget_destroy(
d->floating_tag_window);
3505 case GDK_KEY_Return:
3507 const gchar *tag = gtk_entry_get_text(GTK_ENTRY(entry));
3510 g_list_free(
d->floating_tag_imgs);
3511 d->floating_tag_imgs = NULL;
3520 gtk_widget_destroy(
d->floating_tag_window);
3532 gtk_widget_destroy(GTK_WIDGET(user_data));
3541 GdkModifierType mods, gpointer user_data)
3568 GdkModifierType mods, gpointer user_data)
3574 dt_control_log(_(
"tag shortcut is not active with tag tree view. please switch to list view"));
3583 gdk_window_get_origin(gtk_widget_get_window(center), &px, &py);
3585 w = gdk_window_get_width(gtk_widget_get_window(center));
3586 h = gdk_window_get_height(gtk_widget_get_window(center));
3599 d->floating_tag_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3600#ifdef GDK_WINDOWING_QUARTZ
3604 gtk_widget_set_can_focus(
d->floating_tag_window,
TRUE);
3605 gtk_window_set_decorated(GTK_WINDOW(
d->floating_tag_window),
FALSE);
3606 gtk_window_set_type_hint(GTK_WINDOW(
d->floating_tag_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
3607 gtk_window_set_transient_for(GTK_WINDOW(
d->floating_tag_window), GTK_WINDOW(
window));
3608 gtk_widget_set_opacity(
d->floating_tag_window, 0.8);
3609 gtk_window_move(GTK_WINDOW(
d->floating_tag_window),
x, y);
3614 gtk_widget_add_events(entry, GDK_FOCUS_CHANGE_MASK);
3616 GtkEntryCompletion *completion = gtk_entry_completion_new();
3617 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3619 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3620 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3621 gtk_entry_completion_set_minimum_key_length(completion, 0);
3622 g_signal_connect(G_OBJECT(completion),
"match-selected",
3625 gtk_entry_set_completion(GTK_ENTRY(entry), completion);
3627 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
3628 gtk_container_add(GTK_CONTAINER(
d->floating_tag_window), entry);
3632 gtk_widget_show_all(
d->floating_tag_window);
3633 gtk_widget_grab_focus(entry);
3634 gtk_window_present(GTK_WINDOW(
d->floating_tag_window));
3641 const int length =
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags");
3642 if(length == -1)
return length;
3643 else if(length >= 10/2)
return length * 2;
3659 char *
p = (
char *)list;
3661 for(;*
p !=
'\0';
p++)
3669 char *list2 = g_strdup(list);
3672 p = g_strrstr(list2,
"','");
3684 GtkWidget *mi = gtk_menu_item_new_with_label(_(
"manage tags..."));
3686 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3692 d->last_tag = g_strdup(tagnames);
3704 for(GList *tag = ntags; tag; tag = g_list_next(tag))
3706 char *escaped = sqlite3_mprintf(
"%q", (
char *)tag->data);
3707 GList *found = g_list_find_custom(tags, escaped, (GCompareFunc)g_strcmp0);
3710 tags = g_list_remove_link(tags, found);
3715 tags = g_list_prepend(tags, g_strdup(escaped));
3716 sqlite3_free(escaped);
3724 if(g_list_length(tags) > nb_recent)
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
Build the accel path of feature under scope.
void dt_accels_new_action_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, GtkWidget *target_widget, GtkAccelGroup *accel_group, const gchar *action_scope, const gchar *action_name, guint key_val, GdkModifierType accel_mods, const gboolean lock, const char *description)
Register a new shortcut for a generic action, setting up its path, default keys and accel group....
void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data)
Recursively remove all accels for all shortcuts containing path. This is unneeded for accels attached...
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
Handle default and user-set shortcuts (accelerators)
GList * dt_act_on_get_images()
GtkWidget * dt_gui_main_window(void)
struct dt_accels_t * dt_gui_get_accels(void)
GtkWidget * dt_gui_center_widget(void)
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
void dt_bauhaus_combobox_set_selected_text_align(GtkWidget *widget, const dt_bauhaus_combobox_alignment_t text_align)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
@ DT_BAUHAUS_COMBOBOX_ALIGN_RIGHT
void dt_collection_deserialize(const char *buf)
int dt_collection_serialize(char *buf, int bufsize)
dt_collection_properties_t
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
void dt_image_synch_xmps(const GList *img)
void dt_image_synch_xmp(const int selected)
int32_t dt_control_get_mouse_over_id()
void dt_control_log(const char *msg,...)
void leave(dt_view_t *self)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
void dt_gui_refocus_parent(GtkWindow *parent)
GtkTreeStore * store
its model, owned by the view
GtkWidget * view
the tree view
static const GtkTargetEntry target_list_tags_dest[]
static const guint n_targets_tags
static const guint n_targets_tags_dest
static const GtkTargetEntry target_list_tags[]
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
GtkCellRenderer * dtgtk_cell_renderer_button_new(void)
void dt_gui_textview_set_padding(GtkTextView *textview)
Apply the standard recessed-input text padding to a GtkTextView.
static const dt_iop_drawlayer_params_t * params
void dt_lib_cancel_postponed_update(dt_lib_module_t *mod)
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
void dt_lib_queue_postponed_update(dt_lib_module_t *mod, void(*update_fn)(dt_lib_module_t *self))
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_mipmap_buffer_dsc_flags flags
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
void dt_osx_disallow_fullscreen(GtkWidget *widget)
struct dt_selection_t * dt_selection_get_global(void)
int dt_selection_get_length(struct dt_selection_t *selection)
GList * dt_selection_get_list(struct dt_selection_t *selection)
void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE
This signal is raised when mouse hovers over image thumbs both on lighttable and in the filmstrip....
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
const float uint32_t state[4]
GtkWidget * floating_tag_window
GtkWidget * manage_window
GtkListStore * attached_liststore
GList * floating_tag_imgs
GtkWidget * toggle_suggestion_button
GtkTreeStore * attached_treestore
GtkWidget * export_button
GtkWidget * attached_view_combo
GtkTreeModelFilter * dictionary_listfilter
GHashTable * collection_tags
gboolean attached_tree_flag
GtkTreeView * attached_view
static void _lib_tagging_redraw_callback(gpointer instance, dt_lib_module_t *self)
static gboolean _attached_key_pressed(GtkWidget *view, GdkEventKey *event, dt_lib_module_t *self)
static gint _sort_tree_tag_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, dt_lib_module_t *self)
static gint _sort_tree_count_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, dt_lib_module_t *self)
static void _export_button_clicked(GtkButton *button, dt_lib_module_t *self)
static void _entry_clear_icon(GtkEntry *entry, const GtkEntryIconPosition position, GdkEvent *event, dt_lib_module_t *self)
static void _entry_clear_suppressed(GtkEntry *entry, dt_lib_module_t *self)
void gui_reset(dt_lib_module_t *self)
static gboolean _enter_key_pressed(GtkWidget *entry, GdkEventKey *event, dt_lib_module_t *self)
int set_params(dt_lib_module_t *self, const void *params, int size)
static void _lib_tagging_tags_changed_callback(gpointer instance, dt_lib_module_t *self)
static GList * _selected_tagids(GtkTreeView *view)
static gboolean _dnd_scroll_timeout(dt_lib_module_t *self)
static gboolean _select_previous_user_attached_tag(const int index, GtkTreeView *view)
static void _pop_menu_dictionary_delete_node(GtkWidget *menuitem, dt_lib_module_t *self)
void * get_params(dt_lib_module_t *self, int *size)
static void _tree_tagname_show(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data, gboolean dictionary_view)
void set_preferences(void *menu, dt_lib_module_t *self)
static void _pop_menu_attached_detach(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _find_tag_iter_tagname(GtkTreeModel *model, GtkTreeIter *iter, const char *tagname, const gboolean needle)
static gint _sort_tree_path_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, dt_lib_module_t *self)
static void _toggle_tree_button_callback(GtkToggleButton *source, dt_lib_module_t *self)
static gboolean _set_matching_tag_visibility(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, dt_lib_module_t *self)
static void _update_sel_on_tree(GtkTreeModel *model)
static void _sort_combo_changed(GtkWidget *combo, dt_lib_module_t *self)
static void _validate_button_clicked(GtkButton *button, dt_lib_module_t *self)
static gboolean _row_tooltip_setup(GtkWidget *treeview, gint x, gint y, gboolean kb_mode, GtkTooltip *tooltip, dt_lib_module_t *self)
static gboolean _dictionary_key_pressed(GtkWidget *view, GdkEventKey *event, dt_lib_module_t *self)
static void _refresh_collection_tags(dt_lib_module_t *self)
static gboolean _update_tag_name_per_name(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, dt_tag_op_t *to)
static void _event_dnd_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, const guint target_type, const guint time, dt_lib_module_t *self)
static void _new_button_clicked(GtkButton *button, dt_lib_module_t *self)
static void _dnd_clear_root(dt_lib_module_t *self)
static void _tag_name_changed(GtkEntry *entry, dt_lib_module_t *self)
static gboolean _lib_tagging_tag_redo_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType mods, gpointer user_data)
Re-apply the most recent tag expression to the current target images.
static void _detach_tagids(GList *tagids, dt_lib_module_t *self)
static void _update_attached_count(const int tagid, GtkTreeView *view, const gboolean tree_flag)
#define NEW_TOGGLE_BUTTON(paint, callback, tooltip, action)
static void _unselect_all_in_view(GtkTreeView *view)
static void _import_button_clicked(GtkButton *button, dt_lib_module_t *self)
static void _pop_menu_dictionary_change_path(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _tree_reveal_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void _size_recent_tags_list()
static void _propagate_sel_to_parents(GtkTreeModel *model, GtkTreeIter *iter)
static void _update_layout(dt_lib_module_t *self)
static void _create_tag_from_entry(dt_lib_module_t *self, GtkEntry *src)
static void _pop_menu_dictionary_delete_selected(GtkWidget *menuitem, dt_lib_module_t *self)
static void _tree_tagname_show_attached(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
void gui_cleanup(dt_lib_module_t *self)
static void _attached_delete_icon_show(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
static void _pop_menu_dictionary_edit_tag(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _select_next_user_attached_tag(const int index, GtkTreeView *view)
static void _show_manage_window(GtkMenuItem *menuitem, dt_lib_module_t *self)
static void _pop_menu_attached_attach_to_all(GtkWidget *menuitem, dt_lib_module_t *self)
static void _pop_menu_dictionary(GtkWidget *treeview, GdkEventButton *event, dt_lib_module_t *self)
static void _set_keyword(dt_lib_module_t *self)
static void _reset_sel_on_path_full(GtkTreeModel *model, GtkTreeIter *iter, const gboolean root)
static void _dttags_check_toggled(GtkToggleButton *source, dt_lib_module_t *self)
static void _sort_attached_list(dt_lib_module_t *self, gboolean force)
static void _event_dnd_begin(GtkWidget *widget, GdkDragContext *context, dt_lib_module_t *self)
static void _recent_tags_changed(GtkSpinButton *spin, dt_lib_module_t *self)
static void _show_keyword_on_view(GtkTreeView *view, const char *keyword, const gboolean select)
static gboolean _apply_rename_path(GtkWidget *dialog, const char *tagname, const char *newtag, dt_lib_module_t *self)
static void _calculate_sel_on_tree(GtkTreeModel *model, GtkTreeIter *iter)
static void _lib_selection_changed_callback(gpointer instance, dt_lib_module_t *self)
static void _find_root_iter_iter(GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent)
void init_presets(dt_lib_module_t *self)
static void _pop_menu_dictionary_goto_collection_back(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _completion_match_func(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data)
static void _pop_menu_dictionary_set_as_tag(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _is_user_tag(GtkTreeModel *model, GtkTreeIter *iter)
static void _pop_menu_dictionary_create_tag(GtkWidget *menuitem, dt_lib_module_t *self)
static void _attached_view_combo_changed(GtkWidget *combo, dt_lib_module_t *self)
static void _show_tag_on_view(GtkTreeView *view, const char *tagname, const gboolean needle, const gboolean select)
static void _confidence_changed(GtkSpinButton *spin, dt_lib_module_t *self)
static void _init_treeview(dt_lib_module_t *self, const int which)
static void _collection_updated_callback(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, dt_lib_module_t *self)
uint32_t container(dt_lib_module_t *self)
static void _postponed_update(dt_lib_module_t *self)
@ DT_LIB_TAGGING_COL_SYNONYM
@ DT_LIB_TAGGING_NUM_COLS
@ DT_LIB_TAGGING_COL_VISIBLE
@ DT_LIB_TAGGING_COL_PATH
@ DT_LIB_TAGGING_COL_COUNT
@ DT_LIB_TAGGING_COL_FLAGS
#define FLOATING_ENTRY_WIDTH
static void _reset_sel_on_path(GtkTreeModel *model, GtkTreeIter *iter, const gboolean root)
static void _pop_menu_attached_detach_all(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _selection_get_first(GtkTreeSelection *selection, GtkTreeModel **model, GtkTreeIter *iter)
static void _delete_tagids(GList *tagids, dt_lib_module_t *self)
static int _get_recent_tags_list_length()
static void _refresh_suggestions(dt_lib_module_t *self)
static void _toggle_suggestion_button_callback(GtkToggleButton *source, dt_lib_module_t *self)
static void _event_dnd_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, dt_lib_module_t *self)
static void _tree_selection_changed(GtkTreeSelection *treeselection, gpointer data)
static void _event_dnd_end(GtkWidget *widget, GdkDragContext *context, dt_lib_module_t *self)
static void _pop_menu_dictionary_goto_tag_collection(GtkWidget *menuitem, dt_lib_module_t *self)
void gui_init(dt_lib_module_t *self)
static gboolean _lib_tagging_tag_key_press(GtkWidget *entry, GdkEventKey *event, dt_lib_module_t *self)
static gboolean _lib_tagging_tag_show_accel(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType mods, gpointer user_data)
Open the floating quick-tag entry used by the historical tagging shortcut, now registered in the acti...
static void _delete_tree_path(GtkTreeModel *model, GtkTreeIter *iter, gboolean root, gboolean tree)
const char ** views(dt_lib_module_t *self)
static gboolean _lib_tagging_tag_destroy(GtkWidget *widget, GdkEvent *event, gpointer user_data)
static void _calculate_sel_on_path(GtkTreeModel *model, GtkTreeIter *iter, const gboolean root)
static gboolean _attached_delete_icon_activated(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *treeview, const gchar *path_str, GdkRectangle *background, GdkRectangle *cell_area, GtkCellRendererState flags, gpointer user_data)
static void _tree_tagname_show_dictionary(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
static gboolean _click_on_view_dictionary(GtkWidget *view, GdkEventButton *event, dt_lib_module_t *self)
static gboolean _dnd_expand_timeout(dt_lib_module_t *self)
static void _raise_signal_tag_changed(dt_lib_module_t *self)
static void _save_last_tag_used(const char *tags, dt_lib_tagging_t *d)
static gboolean _event_dnd_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, dt_lib_module_t *self)
static void _pop_menu_attached(GtkWidget *treeview, GdkEventButton *event, dt_lib_module_t *self)
static void _pop_menu_dictionary_copy_tag(GtkWidget *menuitem, dt_lib_module_t *self)
static gboolean _find_tag_iter_tagid(GtkTreeModel *model, GtkTreeIter *iter, const gint tagid)
static void _update_atdetach_buttons(dt_lib_module_t *self)
static void _sort_dictionary_list(dt_lib_module_t *self, gboolean force)
static void _show_iter_on_view(GtkTreeView *view, GtkTreeIter *iter, const gboolean select)
static gboolean _click_on_view_attached(GtkWidget *view, GdkEventButton *event, dt_lib_module_t *self)
gboolean dt_tagging_completion_match_selected(GtkEntryCompletion *completion, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
void dt_tagging_completion_refresh(GtkListStore *store)
void dt_tagging_entry_clear(GtkEntry *entry, GCallback key_handler, gpointer user_data)
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER