72#ifdef GDK_WINDOWING_QUARTZ
75#include <gdk/gdkkeysyms.h>
81#define FLOATING_ENTRY_WIDTH DT_PIXEL_APPLY_DPI(150)
100 gboolean tree_flag, suggestion_flag, sort_count_flag, hide_path_flag,
dttags_flag;
146 GdkModifierType mods, gpointer user_data);
148 GdkModifierType mods, gpointer user_data);
157 static const char *
v[] = {
"lighttable",
"map",
"studio_capture", NULL};
170 const gboolean user_tag = !g_str_has_prefix(path,
"darktable|") || g_str_has_prefix(path,
"darktable|style|");
177 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
178 gtk_tree_selection_unselect_all(selection);
186 GList *rows = gtk_tree_selection_get_selected_rows(selection,
model);
187 gboolean found =
FALSE;
190 found = gtk_tree_model_get_iter(*
model, iter, (GtkTreePath *)rows->data);
191 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
207 GtkTreeIter parent, child = *iter;
208 while(gtk_tree_model_iter_parent(
model, &parent, &child))
212 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
222 gchar *tagname = NULL;
223 gchar *synonyms = NULL;
229 if(synonyms && synonyms[0]) tagname =
dt_util_dstrcat(tagname,
", %s", synonyms);
230 gchar *haystack = g_utf8_strdown(tagname, -1);
231 gchar *needle = g_utf8_strdown(
d->keyword, -1);
232 visible = (g_strrstr(haystack, needle) != NULL);
248 GtkTreeIter parent, child = *iter;
253 while(gtk_tree_model_iter_parent(
model, &parent, &child))
265 if(
d->attached_tree_flag)
268 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
271 if(force &&
d->sort_count_flag)
274 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
277 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore), sort, GTK_SORT_ASCENDING);
285 if(force &&
d->sort_count_flag)
288 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
291 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore), sort, GTK_SORT_ASCENDING);
294 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
299 const char *tagname,
const gboolean needle)
301 gboolean found =
FALSE;
309 gchar *haystack = g_utf8_strdown(path, -1);
310 found = g_strstr_len(haystack, strlen(haystack), tagname) != NULL;
314 found = !g_strcmp0(tagname, path);
316 if(found)
return found;
317 GtkTreeIter child, parent = *iter;
318 if(gtk_tree_model_iter_children(
model, &child, &parent))
327 }
while(gtk_tree_model_iter_next(
model, iter));
333 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
334 GtkTreePath *path = gtk_tree_model_get_path(
model, iter);
335 gtk_tree_view_expand_to_path(
view, path);
336 gtk_tree_view_scroll_to_cell(
view, path, NULL,
TRUE, 0.5, 0.5);
337 gtk_tree_path_free(path);
340 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
341 gtk_tree_selection_select_iter(selection, iter);
347 const gboolean needle,
const gboolean select)
351 char *lt = g_strdup(tagname);
352 char *
t = g_strstrip(lt);
354 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
355 if(gtk_tree_model_get_iter_first(
model, &iter))
366 gchar *needle = g_utf8_strdown(keyword, -1);
376 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
377 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
379 for(; valid &&
i < index -1;
i++)
380 valid = gtk_tree_model_iter_next(
model, &iter);
381 for(; valid; valid = gtk_tree_model_iter_previous(
model, &iter))
395 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
396 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
398 for(; valid &&
i < index;
i++)
399 valid = gtk_tree_model_iter_next(
model, &iter);
400 for(; valid; valid = gtk_tree_model_iter_next(
model, &iter))
422 gboolean no_sel =
FALSE;
425 const gboolean build_tree = which ?
d->tree_flag :
d->attached_tree_flag;
432 view =
d->attached_view;
434 store = build_tree ? GTK_TREE_MODEL(
d->attached_treestore) : GTK_TREE_MODEL(
d->attached_liststore);
439 if(!
d->tree_flag &&
d->suggestion_flag)
443 view =
d->dictionary_view;
444 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
view));
446 store = GTK_TREE_MODEL(
d->dictionary_treestore);
448 store = GTK_TREE_MODEL(
d->dictionary_liststore);
451 gtk_tree_view_set_model(GTK_TREE_VIEW(
view), NULL);
453 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
456 gtk_tree_store_clear(GTK_TREE_STORE(
store));
458 char **last_tokens = NULL;
459 int last_tokens_length = 0;
460 GtkTreeIter last_parent = { 0 };
463 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
465 const gchar *tag = ((
dt_tag_t *)taglist->data)->tag;
468 tokens = g_strsplit(tag,
"|", -1);
472 GtkTreeIter parent = last_parent;
473 const int tokens_length = g_strv_length(tokens);
474 int common_length = 0;
477 while(tokens[common_length] && last_tokens[common_length] &&
478 !g_strcmp0(tokens[common_length], last_tokens[common_length]))
484 for(
int i = common_length;
i < last_tokens_length;
i++)
486 gtk_tree_model_iter_parent(GTK_TREE_MODEL(
store), &parent, &last_parent);
487 last_parent = parent;
493 for(
int i = 0;
i < common_length;
i++)
496 for(
char **token = &tokens[common_length]; *token; token++)
499 gchar *pth2 = g_strdup(pth);
500 pth2[strlen(pth2) - 1] =
'\0';
501 gtk_tree_store_insert(GTK_TREE_STORE(
store), &iter, common_length > 0 ? &parent : NULL, -1);
502 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
505 ((
dt_tag_t *)taglist->data)->id : 0,
508 ((
dt_tag_t *)taglist->data)->count : 0,
514 if(((
dt_tag_t *)taglist->data)->select)
523 if(last_tokens) g_strfreev(last_tokens);
524 last_tokens = tokens;
525 last_parent = parent;
526 last_tokens_length = tokens_length;
529 g_strfreev(last_tokens);
531 if(which &&
d->keyword[0])
535 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
537 else gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
538 g_object_unref(
model);
542 gtk_list_store_clear(GTK_LIST_STORE(
store));
543 if(count > 0 && tags)
545 for (GList *tag = tags; tag; tag = g_list_next(tag))
547 const char *subtag = g_strrstr(((
dt_tag_t *)tag->data)->tag,
"|");
548 gtk_list_store_append(GTK_LIST_STORE(
store), &iter);
549 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
562 if(which &&
d->keyword[0])
566 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
567 g_object_unref(
model);
574 if(!which &&
d->attached_tree_flag)
575 gtk_tree_view_expand_all(GTK_TREE_VIEW(
d->attached_view));
581 GtkTreeModel *
model, GtkTreeIter *iter,
582 gpointer data, gboolean dictionary_view)
593 gtk_tree_model_get(
model, iter,
600 const gboolean hide = dictionary_view ? (
d->tree_flag ?
TRUE :
d->hide_path_flag) :
d->attached_tree_flag;
602 if((dictionary_view && !count) || (!dictionary_view && count <= 1))
604 coltext = g_markup_printf_escaped(istag ?
"%s" :
"<i>%s</i>", hide ?
name : path);
608 coltext = g_markup_printf_escaped(istag ?
"%s (%d)" :
"<i>%s</i> (%d)", hide ?
name : path, count);
610 g_object_set(renderer,
"markup", coltext, NULL);
617 GtkTreeModel *
model, GtkTreeIter *iter,
624 GtkTreeModel *
model, GtkTreeIter *iter,
658 d->collection[0] =
'\0';
670 if(!
d->collection[0])
692 GtkTreeIter child, parent = *iter;
693 if(gtk_tree_model_iter_children(
model, &child, &parent))
699 }
while (gtk_tree_model_iter_next(
model, iter));
706 GtkTreeIter child, parent = *iter;
715 if(gtk_tree_model_iter_children(
model, &child, &parent))
717 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
723 GtkTreeIter child, parent = *iter;
726 if(gtk_tree_model_iter_children(
model, &child, &parent))
732 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
737 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
743 GtkTreeIter child, parent = *iter;
746 if(GTK_IS_TREE_STORE(
model))
748 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
750 if(gtk_tree_model_iter_children(
model, &child, &parent))
755 gtk_list_store_set(GTK_LIST_STORE(
model), &parent,
758 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
765 GtkTreeIter child = *iter;
766 while (gtk_tree_model_iter_parent(
model, parent, &child))
798 if(gtk_tree_model_get_iter_first(
model, &parent))
812 if(gtk_tree_model_get_iter_first(
model, &parent))
815 for (GList *tag = tags; tag; tag = g_list_next(tag))
817 GtkTreeIter iter = parent;
820 if(GTK_IS_TREE_STORE(
model))
822 gtk_tree_store_set(GTK_TREE_STORE(
model), &iter,
828 gtk_list_store_set(GTK_LIST_STORE(
model), &iter,
844 GtkTreeIter child, parent = *iter;
845 gboolean valid =
TRUE;
848 if(gtk_tree_model_iter_children(
model, &child, &parent))
850 GtkTreeIter tobedel = parent;
851 valid = gtk_tree_model_iter_next(
model, &parent);
854 gtk_tree_store_set(GTK_TREE_STORE(
model), &tobedel,
867 gtk_tree_store_remove(GTK_TREE_STORE(
model), &tobedel);
868 }
while (!root && valid);
875 guint pathlen = strlen(path);
876 gboolean valid = gtk_tree_model_get_iter_first(
model, &child);
881 GtkTreeIter tobedel = child;
882 valid = gtk_tree_model_iter_next (
model, &child);
883 if(strlen(path2) >= pathlen)
885 char letter = path2[pathlen];
886 path2[pathlen] =
'\0';
887 if(g_strcmp0(path, path2) == 0)
889 path2[pathlen] = letter;
890 gtk_list_store_remove(GTK_LIST_STORE(
model), &tobedel);
903 if(!
d->tree_flag &&
d->suggestion_flag)
909 : GTK_TREE_MODEL(
d->dictionary_liststore));
917 const gchar *beg = g_strrstr(gtk_entry_get_text(
d->dict_entry),
",");
920 beg = gtk_entry_get_text(
d->dict_entry);
923 if(*beg ==
',') beg++;
924 if(*beg ==
' ') beg++;
926 g_strlcpy(
d->keyword, beg,
sizeof(
d->keyword));
935 if(g_str_has_prefix(tagname, oldtagname))
937 if(strlen(tagname) == strlen(oldtagname))
942 char *subtag = g_strrstr(to->
newtagname,
"|");
943 subtag = (!subtag) ? newtagname : subtag + 1;
953 else if(strlen(tagname) > strlen(oldtagname) && tagname[strlen(oldtagname)] ==
'|')
956 char *newpath = g_strconcat(newtagname, &tagname[strlen(oldtagname)] , NULL);
977 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
978 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
980 if(gtk_tree_model_get_iter_first(
store, &iter))
986 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
993 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
1008 char *params = NULL;
1015 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
1022 *
size = strlen(params);
1023 params[*
size-1]=
'\0';
1033 const char *buf = (
char *)params;
1036 gchar **tokens = g_strsplit(buf,
",", 0);
1040 gchar **entry = tokens;
1043 const guint tagid = strtoul(*entry, NULL, 0);
1044 tags = g_list_prepend(tags, GINT_TO_POINTER(tagid));
1052 gboolean change =
FALSE;
1053 for(GList *tag = tags; tag; tag = g_list_next(tag))
1076 GtkTreeModel *
model = NULL;
1077 GList *rows = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(
view), &
model);
1078 for(GList *
r = rows;
r;
r = g_list_next(
r))
1081 if(gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)
r->data))
1085 if(tagid > 0) ids = g_list_prepend(ids, GUINT_TO_POINTER(tagid));
1088 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
1100 gboolean changed =
FALSE;
1101 for(GList *
t = tagids;
t;
t = g_list_next(
t))
1103 const guint tagid = GPOINTER_TO_UINT(
t->data);
1104 if(tagid <= 0)
continue;
1110 g_list_free(affected);
1126 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1127 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1132 if(tagid <= 0)
return;
1143 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
1144 if(gtk_tree_model_get_iter_first(
model, &iter))
1148 GtkTreeIter store_iter;
1149 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1150 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1151 &store_iter, &iter);
1175 g_list_free(tagids);
1182 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1184 GList *tagids = NULL;
1185 if(gtk_tree_model_get_iter_first(
model, &iter))
1192 if(tagid > 0) tagids = g_list_prepend(tagids, GUINT_TO_POINTER(tagid));
1193 }
while(gtk_tree_model_iter_next(
model, &iter));
1196 g_list_free(tagids);
1203 menu = gtk_menu_new();
1206 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1207 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1208 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
1217 menuitem = gtk_menu_item_new_with_label(_(
"attach tag to all"));
1219 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1220 menuitem = gtk_separator_menu_item_new();
1221 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1227 menuitem = gtk_menu_item_new_with_label(sel_cnt > 1 ? _(
"detach tags") : _(
"detach tag"));
1228 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1232 menuitem = gtk_menu_item_new_with_label(_(
"detach all tags"));
1233 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1236 gtk_widget_show_all(GTK_WIDGET(menu));
1238 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
1243 const gchar *path_str, GdkRectangle *background,
1244 GdkRectangle *cell_area, GtkCellRendererState
flags,
1248 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
1249 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1251 if(path && gtk_tree_model_get_iter(
model, &iter, path))
1257 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1262 if(path) gtk_tree_path_free(path);
1269 GtkTreeModel *
model, GtkTreeIter *iter, gpointer data)
1273 g_object_set(renderer,
"icon-name",
"edit-delete-symbolic",
1282 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1283 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1284 GtkTreePath *path = NULL;
1285 const gboolean on_row =
1286 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL);
1288 gboolean valid_tag =
FALSE;
1290 if(on_row && gtk_tree_model_get_iter(
model, &iter, path))
1294 if(event->type == GDK_BUTTON_PRESS && event->button == 3)
1299 if(!gtk_tree_selection_path_is_selected(selection, path))
1301 gtk_tree_selection_unselect_all(selection);
1302 gtk_tree_selection_select_path(selection, path);
1306 gtk_tree_selection_unselect_all(selection);
1308 if(path) gtk_tree_path_free(path);
1313 if(event->type == GDK_2BUTTON_PRESS && event->button == 1 && valid_tag)
1319 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1323 if(path) gtk_tree_path_free(path);
1328 if(event->type == GDK_BUTTON_PRESS && event->button == 1 && on_row && !valid_tag)
1330 gtk_tree_path_free(path);
1334 if(path) gtk_tree_path_free(path);
1344 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1345 if(
key == GDK_KEY_Delete && gtk_tree_selection_count_selected_rows(selection) > 0)
1349 g_list_free(tagids);
1352 if(
key == GDK_KEY_Tab)
1354 gtk_tree_selection_unselect_all(selection);
1355 gtk_widget_grab_focus(GTK_WIDGET(
d->entry));
1358 else if(
key == GDK_KEY_ISO_Left_Tab)
1360 gtk_tree_selection_unselect_all(selection);
1370 const gchar *tag = gtk_entry_get_text(src);
1390 char *tagname = strrchr(
d->last_tag,
',');
1393 tagname ? tagname + 1 :
d->last_tag,
FALSE,
TRUE);
1427 case GDK_KEY_Return:
1430 case GDK_KEY_Escape:
1433 case GDK_KEY_ISO_Left_Tab:
1438 gtk_widget_grab_focus(GTK_WIDGET(
d->attached_view));
1451 if(
position != GTK_ENTRY_ICON_SECONDARY)
return;
1454 gtk_widget_grab_focus(GTK_WIDGET(entry));
1462 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
1463 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1465 if(
d->tree_flag &&
d->keyword[0])
1476 int res = GTK_RESPONSE_YES;
1483 GtkTreeModel *
model = NULL;
1484 GtkTreeView *
view =
d->dictionary_view;
1485 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1494 if(tag_count == 0)
return;
1497 GtkWidget *dialog = gtk_dialog_new_with_buttons( _(
"delete node?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1498 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
1499 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1500 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1502 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1503 gtk_container_add(GTK_CONTAINER(area), vbox);
1504 text = g_strdup_printf(_(
"selected: %s"), tagname);
1505 label = gtk_label_new(text);
1506 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1510 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1511 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be deleted",
"<u>%d</u> tags will be deleted", tag_count), tag_count);
1512 label = gtk_label_new(NULL);
1513 gtk_label_set_markup(GTK_LABEL(label), text);
1514 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1516 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1517 label = gtk_label_new(NULL);
1518 gtk_label_set_markup(GTK_LABEL(label), text);
1519 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1522#ifdef GDK_WINDOWING_QUARTZ
1525 gtk_widget_show_all(dialog);
1527 res = gtk_dialog_run(GTK_DIALOG(dialog));
1528 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1529 gtk_widget_destroy(dialog);
1531 if(
res != GTK_RESPONSE_YES)
1537 GList *tag_family = NULL;
1538 GList *tagged_images = NULL;
1546 GtkTreeIter store_iter;
1547 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1548 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1549 &store_iter, &iter);
1555 g_list_free(tagged_images);
1556 tagged_images = NULL;
1574 GtkTreeModel *
model = NULL;
1575 GtkTreeView *
view =
d->dictionary_view;
1576 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1583 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"create tag"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1584 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1585 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1586 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1588 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1589 gtk_container_add(GTK_CONTAINER(area), vbox);
1592 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1593 label = gtk_label_new(_(
"name: "));
1594 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1597 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1602 GtkTextBuffer *buffer = NULL;
1604 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1606 text = g_strdup_printf(_(
"add to: \"%s\" "), path);
1607 parent = gtk_check_button_new_with_label(text);
1608 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(parent),
TRUE);
1609 gtk_box_pack_end(GTK_BOX(vbox2), parent,
FALSE,
TRUE, 0);
1612 category = gtk_check_button_new_with_label(_(
"category"));
1613 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(category),
FALSE);
1614 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1615 private = gtk_check_button_new_with_label(_(
"private"));
1616 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
private),
FALSE);
1617 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1620 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1621 label = gtk_label_new(_(
"synonyms: "));
1622 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1623 GtkWidget *synonyms = gtk_text_view_new();
1626 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1627 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1628 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1630#ifdef GDK_WINDOWING_QUARTZ
1633 gtk_widget_show_all(dialog);
1635 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1637 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1638 char *message = NULL;
1640 message = _(
"empty tag is not allowed, aborting");
1641 char *new_tagname = NULL;
1642 const gboolean root = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(parent));
1645 new_tagname = g_strdup(path);
1648 else new_tagname = g_strdup(newtag);
1651 message = _(
"tag name already exists. aborting.");
1654 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1655 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1656 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1657 gtk_widget_destroy(warning_dialog);
1658 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1659 gtk_widget_destroy(dialog);
1664 guint new_tagid = 0;
1667 const gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1668 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1670 GtkTextIter start, end;
1671 gtk_text_buffer_get_start_iter(buffer, &start);
1672 gtk_text_buffer_get_end_iter(buffer, &end);
1673 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1674 if(new_tagid && new_synonyms_list && new_synonyms_list[0])
1685 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1686 gtk_widget_destroy(dialog);
1697 char *synonyms_list;
1702 GtkTreeModel *
model = NULL;
1703 GtkTreeView *
view =
d->dictionary_view;
1704 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1709 char *subtag = g_strrstr(tagname,
"|");
1710 if(subtag) subtag = subtag + 1;
1722 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"edit"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1723 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1724 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1725 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1727 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1728 gtk_container_add(GTK_CONTAINER(area), vbox);
1729 text = g_strdup_printf(_(
"selected: %s"), tagname);
1730 label = gtk_label_new(text);
1731 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1735 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1736 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
1737 label = gtk_label_new(NULL);
1738 gtk_label_set_markup(GTK_LABEL(label), text);
1739 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1741 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1742 label = gtk_label_new(NULL);
1743 gtk_label_set_markup(GTK_LABEL(label), text);
1744 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1748 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1749 label = gtk_label_new(_(
"name: "));
1750 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1753 gtk_entry_set_text(GTK_ENTRY(entry), subtag ? subtag : tagname);
1754 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1758 GtkWidget *
private = gtk_check_button_new_with_label(_(
"private"));
1759 GtkTextBuffer *buffer = NULL;
1764 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1766 category = gtk_check_button_new_with_label(_(
"category"));
1768 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1770 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1773 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1774 label = gtk_label_new(_(
"synonyms: "));
1775 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1776 GtkWidget *synonyms = gtk_text_view_new();
1779 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1780 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1781 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1782 if(synonyms_list) gtk_text_buffer_set_text(buffer, synonyms_list, -1);
1785#ifdef GDK_WINDOWING_QUARTZ
1788 gtk_widget_show_all(dialog);
1790 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1792 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1793 if(g_strcmp0(newtag, subtag ? subtag : tagname) != 0)
1796 char *message = NULL;
1798 message = _(
"empty tag is not allowed, aborting");
1799 if(strchr(newtag,
'|') != 0)
1800 message = _(
"'|' character is not allowed for renaming tag.\nto modify the hierarchy use rename path instead. Aborting.");
1803 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1804 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1805 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1806 gtk_widget_destroy(warning_dialog);
1807 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1808 gtk_widget_destroy(dialog);
1814 GList *tag_family = NULL;
1815 GList *tagged_images = NULL;
1818 const int tagname_len = strlen(tagname);
1819 char *new_prefix_tag;
1822 const int subtag_len = strlen(subtag);
1823 const char letter = tagname[tagname_len - subtag_len];
1824 tagname[tagname_len - subtag_len] =
'\0';
1825 new_prefix_tag = g_strconcat(tagname, newtag, NULL);
1826 tagname[tagname_len - subtag_len] = letter;
1829 new_prefix_tag = (
char *)newtag;
1832 gboolean tagname_exists =
FALSE;
1833 for (GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1835 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1839 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1840 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1841 _(
"at least one new tag name (%s) already exists, aborting"), new_tagname);
1842 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1843 gtk_widget_destroy(warning_dialog);
1849 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1850 gtk_widget_destroy(dialog);
1859 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1861 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1867 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1873 GtkSortType sort_order;
1874 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(
store), &sort_column, &sort_order);
1875 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
1877 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), sort_column, sort_order);
1889 g_list_free(tagged_images);
1890 tagged_images = NULL;
1895 gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1896 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1897 GtkTextIter start, end;
1898 gtk_text_buffer_get_start_iter(buffer, &start);
1899 gtk_text_buffer_get_end_iter(buffer, &end);
1900 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1903 GtkTreeIter store_iter;
1904 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1905 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1906 &store_iter, &iter);
1916 if(new_synonyms_list && g_strcmp0(synonyms_list, new_synonyms_list) != 0)
1928 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
1929 gtk_widget_destroy(dialog);
1940 gboolean success =
FALSE;
1941 GList *tag_family = NULL;
1942 GList *tagged_images = NULL;
1946 const int tagname_len = strlen(tagname);
1947 gboolean tagname_exists =
FALSE;
1948 for(GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1950 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1960 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_MODAL,
1961 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1962 _(
"at least one new tagname (%s) already exists, aborting."), new_tagname);
1963 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1964 gtk_widget_destroy(warning_dialog);
1971 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1973 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1987 g_list_free(tagged_images);
1988 tagged_images = NULL;
2003 GtkTreeModel *
model = NULL;
2004 GtkTreeView *
view =
d->dictionary_view;
2005 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2014 if(tag_count == 0)
return;
2017 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"change path"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
2018 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
2019 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
2020 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2022 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
2023 gtk_container_add(GTK_CONTAINER(area), vbox);
2024 text = g_strdup_printf(_(
"selected: %s"), tagname);
2025 label = gtk_label_new(text);
2026 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
2030 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
2031 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
2032 label = gtk_label_new(NULL);
2033 gtk_label_set_markup(GTK_LABEL(label), text);
2034 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
2036 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
2037 label = gtk_label_new(NULL);
2038 gtk_label_set_markup(GTK_LABEL(label), text);
2039 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
2044 gtk_entry_set_text(GTK_ENTRY(entry), tagname);
2045 gtk_box_pack_start(GTK_BOX(vbox), entry,
FALSE,
TRUE, 0);
2047#ifdef GDK_WINDOWING_QUARTZ
2050 gtk_widget_show_all(dialog);
2052 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
2054 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
2055 if(g_strcmp0(newtag, tagname) == 0)
2057 char *message = NULL;
2059 message = _(
"empty tag is not allowed, aborting");
2060 if(strchr(newtag,
'|') == &newtag[0] || strchr(newtag,
'|') == &newtag[strlen(newtag)-1] || strstr(newtag,
"||"))
2061 message = _(
"'|' misplaced, empty tag is not allowed, aborting");
2064 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
2065 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
2066 gtk_dialog_run(GTK_DIALOG(warning_dialog));
2067 gtk_widget_destroy(warning_dialog);
2068 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2069 gtk_widget_destroy(dialog);
2076 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2077 gtk_widget_destroy(dialog);
2086 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2087 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2109 if(
d->collection[0])
2114 d->collection[0] =
'\0';
2122 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2123 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2128 gtk_entry_set_text(
d->dict_entry, tag);
2130 gtk_entry_grab_focus_without_selecting(
d->dict_entry);
2139 const guint nb = g_list_length(tagids);
2142 guint img_count = 0;
2143 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2146 if(img_count > 0 ||
dt_conf_get_bool(
"plugins/lighttable/tagging/ask_before_delete_tag"))
2149 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"delete tag?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
2150 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
2151 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
2152 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2153 gchar *text = g_strdup_printf(ngettext(
"do you really want to delete %d tag?\n%d image is assigned these tags!",
2154 "do you really want to delete %d tags?\n%d images are assigned these tags!",
2155 img_count), nb, img_count);
2157 gtk_container_set_border_width(GTK_CONTAINER(area), 8);
2158 gtk_container_add(GTK_CONTAINER(area), label);
2160#ifdef GDK_WINDOWING_QUARTZ
2163 gtk_widget_show_all(dialog);
2164 const int res = gtk_dialog_run(GTK_DIALOG(dialog));
2165 GtkWindow *dialog_parent = gtk_window_get_transient_for(GTK_WINDOW(dialog));
2166 gtk_widget_destroy(dialog);
2168 if(
res != GTK_RESPONSE_YES)
return;
2171 GList *affected = NULL;
2172 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2174 const guint tagid = GPOINTER_TO_UINT(
t->data);
2190 g_list_free(affected);
2199 g_list_free(tagids);
2209 GtkTreeModel *
model = NULL;
2210 GtkTreeView *
view =
d->dictionary_view;
2211 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2230 GtkTreeIter iter, child;
2231 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2232 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2233 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
2234 if(sel_cnt == 0)
return;
2242 menuitem = gtk_menu_item_new_with_label(_(
"delete tags"));
2244 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2245 gtk_widget_show_all(GTK_WIDGET(menu));
2246 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2253 gtk_tree_model_get(
model, &iter,
2257 if(
d->tree_flag || !
d->suggestion_flag)
2259 menuitem = gtk_menu_item_new_with_label(_(
"create tag..."));
2260 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2265 menuitem = gtk_menu_item_new_with_label(_(
"delete tag"));
2266 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2270 if(gtk_tree_model_iter_children(
model, &child, &iter))
2272 menuitem = gtk_menu_item_new_with_label(_(
"delete node"));
2273 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2277 menuitem = gtk_menu_item_new_with_label(_(
"edit..."));
2278 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2285 menuitem = gtk_menu_item_new_with_label(_(
"change path..."));
2286 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2290 if(
d->tree_flag && !tagid)
2292 menuitem = gtk_separator_menu_item_new();
2293 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2295 menuitem = gtk_menu_item_new_with_label(_(
"set as a tag"));
2296 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2300 if(!
d->suggestion_flag)
2302 menuitem = gtk_separator_menu_item_new();
2303 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2306 menuitem = gtk_menu_item_new_with_label(_(
"copy to entry"));
2308 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2310 if(
d->collection[0])
2312 char *collection = g_malloc(4096);
2314 if(g_strcmp0(
d->collection, collection) == 0)
d->collection[0] =
'\0';
2317 if(count ||
d->collection[0])
2319 menuitem = gtk_separator_menu_item_new();
2320 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2323 menuitem = gtk_menu_item_new_with_label(_(
"go to tag collection"));
2325 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2327 if(
d->collection[0])
2329 menuitem = gtk_menu_item_new_with_label(_(
"go back to work"));
2331 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2334 gtk_widget_show_all(GTK_WIDGET(menu));
2336 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2345 const int button_pressed = (
event->type == GDK_BUTTON_PRESS) ? event->button : 0;
2346 const gboolean shift_pressed =
dt_modifier_is(event->state, GDK_SHIFT_MASK);
2350 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2351 GtkTreePath *path = NULL;
2353 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
2357 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
2359 gtk_tree_model_get_iter(
model, &iter, path);
2361 gtk_tree_model_get(
model, &iter,
2367 d->drag.tagname = tagname;
2368 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
2369 d->drag.path = path;
2370 if(
d->drag.lastpath) gtk_tree_path_free(
d->drag.lastpath);
2371 d->drag.lastpath = NULL;
2377 if(!gtk_tree_selection_path_is_selected(selection, path))
2379 gtk_tree_selection_unselect_all(selection);
2380 gtk_tree_selection_select_path(selection, path);
2383 gtk_tree_path_free(path);
2388 gtk_tree_selection_select_path(selection, path);
2389 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
TRUE);
2390 gtk_tree_path_free(path);
2394 gtk_tree_path_free(path);
2404 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2405 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2411 GtkTreePath *path = gtk_tree_model_get_path(
model, &iter);
2418 gtk_tree_view_collapse_all(GTK_TREE_VIEW(
view));
2420 gtk_tree_view_collapse_row(GTK_TREE_VIEW(
view), path);
2427 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
2435 gtk_tree_path_free(path);
2437 if(event->keyval == GDK_KEY_Tab)
2439 gtk_tree_selection_unselect_all(selection);
2442 else if(event->keyval == GDK_KEY_ISO_Left_Tab)
2444 gtk_tree_selection_unselect_all(selection);
2445 gtk_widget_grab_focus(GTK_WIDGET(
d->dict_entry));
2455 GtkTreePath *path = NULL;
2457 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
x, y, &path, NULL, NULL, NULL))
2459 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
2461 if(gtk_tree_model_get_iter(
model, &iter, path))
2466 char *synonyms = NULL;
2473 gchar *text = g_strdup_printf(_(
"%s"), tagname);
2475 text =
dt_util_dstrcat(text,
"synonyms: %s", (synonyms && synonyms[0]) ? synonyms :
" - ");
2476 gtk_tooltip_set_text(
tooltip, text);
2485 gtk_tree_path_free(path);
2495 last_dirname = g_get_home_dir();
2499 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2500 _(
"select a keyword file"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
2501 _(
"_import"), _(
"_cancel"));
2503 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2504 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
FALSE);
2506 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2508 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2509 char *dirname = g_path_get_dirname(filename);
2510 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2517 g_object_unref(filechooser);
2523 GDateTime *now = g_date_time_new_now_local();
2524 char *export_filename = g_date_time_format(now,
"darktable_tags_%F_%H-%M.txt");
2528 last_dirname = g_get_home_dir();
2532 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2533 _(
"select file to export to"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SAVE,
2534 _(
"_export"), _(
"_cancel"));
2536 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(filechooser),
TRUE);
2537 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2538 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), export_filename);
2540 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2542 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2543 char *dirname = g_path_get_dirname(filename);
2544 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2551 g_date_time_unref(now);
2553 g_object_unref(filechooser);
2559 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2563 d->suggestion_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2564 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_suggestion_button),
d->suggestion_flag);
2566 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_tree_button),
d->tree_flag);
2570 if(
model == GTK_TREE_MODEL(
d->dictionary_listfilter))
2572 g_object_ref(
model);
2573 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2574 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2575 gtk_list_store_clear(GTK_LIST_STORE(
store));
2576 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_treefilter));
2577 g_object_unref(
d->dictionary_treefilter);
2579 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
FALSE);
2583 if(
model == GTK_TREE_MODEL(
d->dictionary_treefilter))
2585 g_object_ref(
model);
2586 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2587 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2588 gtk_tree_store_clear(GTK_TREE_STORE(
store));
2589 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_listfilter));
2590 g_object_unref(
d->dictionary_listfilter);
2592 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
TRUE);
2597 gtk_drag_source_set(GTK_WIDGET(
d->dictionary_view), GDK_BUTTON1_MASK,
2600 gtk_drag_source_unset(GTK_WIDGET(
d->dictionary_view));
2602 d->sort_count_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/listsortedbycount");
2607 d->hide_path_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/hidehierarchy");
2609 d->attached_tree_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/attached_treeview");
2613 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->dttags_check),
d->dttags_flag);
2621 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2630 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/treeview");
2642 return (count_b - count_a);
2653 const gboolean sort = g_strcmp0(tag_a, tag_b);
2667 for(
char *letter = tag_a; *letter; letter++)
2668 if(*letter ==
'|') *letter =
'\1';
2671 tag_a = g_strdup(
"");
2675 for(
char *letter = tag_b; *letter; letter++)
2676 if(*letter ==
'|') *letter =
'\1';
2679 tag_b = g_strdup(
"");
2681 const gboolean sort = g_strcmp0(tag_a, tag_b);
2711 d->dttags_flag = gtk_toggle_button_get_active(source);
2740 if(!
d->collection_tags)
return;
2741 g_hash_table_remove_all(
d->collection_tags);
2744 for(GList *
t = tags;
t;
t = g_list_next(
t))
2748 g_hash_table_add(
d->collection_tags, g_strdup(tag->tag));
2760 GtkEditable *e = (GtkEditable *)gtk_entry_completion_get_entry(completion);
2762 if(!GTK_IS_EDITABLE(e))
2767 const gint cur_pos = gtk_editable_get_position(e);
2768 const gboolean onLastTag = (g_strstr_len(&
key[cur_pos], -1,
",") == NULL);
2774 GtkTreeModel *
model = gtk_entry_completion_get_model(completion);
2775 const int column = gtk_entry_completion_get_text_column(completion);
2777 if(gtk_tree_model_get_column_type(
model, column) != G_TYPE_STRING)
2782 const gchar *lastTag = g_strrstr(
key,
",");
2793 gtk_tree_model_get(
model, iter, column, &tag, -1);
2797 if(lastTag[0] ==
'\0')
2799 res = (
d &&
d->collection_tags && tag) ? g_hash_table_contains(
d->collection_tags, tag) :
FALSE;
2806 char *normalized = g_utf8_normalize(tag, -1, G_NORMALIZE_ALL);
2809 char *casefold = g_utf8_casefold(normalized, -1);
2812 res = g_strstr_len(casefold, -1, lastTag) != NULL;
2831 if(!
d->drag.root)
return;
2832 GtkTreeModel *
model = GTK_TREE_MODEL(
d->dictionary_treestore);
2834 gtk_tree_model_get_iter_first(
model, &iter);
2838 gtk_tree_store_remove(
d->dictionary_treestore, &iter);
2846 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2850 cairo_surface_t *row_pix = gtk_tree_view_create_row_drag_icon(tree,
d->drag.path);
2856 gtk_drag_set_icon_surface(context, row_pix);
2857 cairo_surface_destroy(row_pix);
2858 gtk_tree_path_free(
d->drag.path);
2859 d->drag.path = NULL;
2860 d->drag.tag_source =
TRUE;
2868 gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data),
2873 GtkSelectionData *selection_data, guint target_type, guint time,
2877 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2879 g_signal_stop_emission_by_name(tree,
"drag-data-received");
2880 gboolean success =
FALSE;
2884 GtkTreePath *path = NULL;
2885 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2888 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2891 gtk_tree_model_get_iter(
model, &iter, path);
2894 const gboolean root = (
name &&
name[0] ==
'\0');
2895 char *
leave = g_strrstr(
d->drag.tagname,
"|");
2902 gtk_tree_path_free(path);
2908 GtkTreePath *path = NULL;
2909 const int imgs_nb = gtk_selection_data_get_length(selection_data) /
sizeof(uint32_t);
2910 if(imgs_nb && gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2912 const uint32_t *imgt = (uint32_t *)gtk_selection_data_get_data(selection_data);
2914 for(
int i = 0;
i < imgs_nb;
i++)
2916 imgs = g_list_prepend(imgs, GINT_TO_POINTER(imgt[
i]));
2918 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2920 gtk_tree_model_get_iter(
model, &iter, path);
2931 gtk_tree_path_free(path);
2935 gtk_drag_finish(context, success,
FALSE, time);
2941 if(
d->drag.lastpath)
2943 gtk_tree_view_expand_row(
d->dictionary_view,
d->drag.lastpath,
FALSE);
2951 if(
d->drag.scroll_timeout)
2953 GdkRectangle visible;
2954 gtk_tree_view_get_visible_rect(
d->dictionary_view, &visible);
2956 gtk_tree_view_convert_bin_window_to_tree_coords(
d->dictionary_view,
2957 0, 0, NULL, &top_ty);
2960 if(
d->drag.tag_source && !
d->drag.root &&
d->drag.last_y < 5 && top_ty < 1)
2963 gtk_tree_store_prepend(
d->dictionary_treestore, &iter, NULL);
2964 gtk_tree_store_set(
d->dictionary_treestore, &iter,
2973 d->drag.root =
TRUE;
2975 else if(
d->drag.root &&
d->drag.last_y >= 20)
2978 if(
d->drag.last_y < 5)
2981 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty - 25 < 0 ? 0 : top_ty - 25);
2983 else if(
d->drag.last_y > visible.height - 5)
2985 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty + 25);
2995 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2996 GtkTreePath *path = NULL;
2998 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
3000 if(
IS_NULL_PTR(
d->drag.lastpath) || ((
d->drag.lastpath) && gtk_tree_path_compare(
d->drag.lastpath, path) != 0))
3002 GtkTreeViewColumn *col = gtk_tree_view_get_column(
d->dictionary_view, 0);
3003 const int sel_width = gtk_tree_view_column_get_width(col);
3006 if(!gtk_tree_view_row_expanded(tree, path))
3011 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3012 gtk_tree_selection_select_path(selection, path);
3014 if(
d->drag.scroll_timeout == 0)
3023 if(
d->drag.lastpath)
3024 gtk_tree_path_free(
d->drag.lastpath);
3025 d->drag.lastpath = path;
3035 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3036 gtk_tree_selection_unselect_all(selection);
3037 if(
d->drag.scroll_timeout)
3038 g_source_remove(
d->drag.scroll_timeout);
3039 d->drag.scroll_timeout = 0;
3040 d->drag.tag_source =
FALSE;
3048 gtk_widget_show_all(
d->manage_window);
3049 gtk_window_present(GTK_WINDOW(
d->manage_window));
3056 if(!
d->tree_flag &&
d->suggestion_flag)
3063 dt_conf_set_int(
"plugins/lighttable/tagging/confidence", gtk_spin_button_get_value_as_int(spin));
3070 dt_conf_set_int(
"plugins/lighttable/tagging/nb_recent_tags", gtk_spin_button_get_value_as_int(spin));
3085 self->
data = (
void *)
d;
3095 GtkTreeModel *
model;
3096 GtkListStore *liststore;
3097 GtkTreeStore *treestore;
3098 GtkTreeViewColumn *col;
3099 GtkCellRenderer *renderer;
3110 gtk_widget_set_valign(
d->attached_view_combo, GTK_ALIGN_CENTER);
3111 gtk_widget_set_tooltip_text(
d->attached_view_combo,
3112 _(
"show the attached tags as a flat list or as a hierarchical tree"));
3114 gtk_box_pack_start(hbox,
d->attached_view_combo,
TRUE,
TRUE, 0);
3122 gtk_widget_set_valign(
d->sort_combo, GTK_ALIGN_CENTER);
3123 gtk_widget_set_tooltip_text(
d->sort_combo, _(
"sort the tags by name or by image count"));
3124 g_signal_connect(G_OBJECT(
d->sort_combo),
"value-changed", G_CALLBACK(
_sort_combo_changed), self);
3125 gtk_box_pack_start(hbox,
d->sort_combo,
TRUE,
TRUE, 0);
3127 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3133 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
3134 view = GTK_TREE_VIEW(gtk_tree_view_new());
3138 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3139 d->attached_view =
view;
3140 gtk_tree_view_set_enable_search(
view,
FALSE);
3141 gtk_tree_view_set_headers_visible(
view,
FALSE);
3143 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3150 d->attached_liststore = liststore;
3153 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3156 d->attached_treestore = treestore;
3157 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3160 col = gtk_tree_view_column_new();
3161 gtk_tree_view_append_column(
view, col);
3162 renderer = gtk_cell_renderer_text_new();
3163 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3164 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3166 gtk_tree_view_column_set_expand(col,
TRUE);
3167 gtk_tree_view_set_expander_column(
view, col);
3170 col = gtk_tree_view_column_new();
3171 gtk_tree_view_append_column(
view, col);
3173 g_object_set(renderer,
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
3174 gtk_tree_view_column_pack_end(col, renderer,
FALSE);
3178 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3179 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(liststore));
3182 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"attached tags,"
3183 "\nclick the trash icon, press Delete or double-click to detach"
3184 "\nselect several tags and right-click to detach them in bulk,"
3185 "\npress Tab to give the focus to entry,"
3186 "\nctrl-wheel scroll to resize the window"));
3191#define NEW_TOGGLE_BUTTON(paint, callback, tooltip, action) \
3192 button = dtgtk_togglebutton_new(paint, 0, NULL); \
3193 gtk_widget_set_tooltip_text(button, tooltip); \
3194 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, TRUE, 0); \
3195 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), self); \
3199 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
FALSE,
TRUE, 0);
3202 gtk_box_reorder_child(GTK_BOX(self->
widget), GTK_WIDGET(box), 1);
3206 w = gtk_entry_new();
3208 gtk_entry_set_text(GTK_ENTRY(w),
"");
3209 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3211 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"enter or pick a tag, Enter to attach"));
3212 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3213 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3214 g_signal_connect(G_OBJECT(w),
"icon-release", G_CALLBACK(
_entry_clear_icon), self);
3215 gtk_box_pack_start(hbox, w,
TRUE,
TRUE, 0);
3216 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3217 d->entry = GTK_ENTRY(w);
3221 gtk_widget_set_tooltip_text(
d->validate_button, _(
"attach this tag to the selected images"));
3222 gtk_box_pack_end(GTK_BOX(hbox),
d->validate_button,
FALSE,
TRUE, 0);
3224 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3232 GtkEntryCompletion *completion = gtk_entry_completion_new();
3233 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3235 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3236 gtk_entry_completion_set_popup_completion(completion,
TRUE);
3237 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3238 gtk_entry_completion_set_minimum_key_length(completion, 1);
3239 g_signal_connect(G_OBJECT(completion),
"match-selected",
3242 gtk_entry_set_completion(
d->entry, completion);
3243 g_object_unref(completion);
3245 g_object_unref(
d->completion_store);
3250 g_signal_connect(G_OBJECT(
d->entry),
"key-press-event", G_CALLBACK(
_enter_key_pressed), self);
3253 d->manage_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3254#ifdef GDK_WINDOWING_QUARTZ
3257 gtk_window_set_title(GTK_WINDOW(
d->manage_window), _(
"manage tags"));
3258 gtk_window_set_transient_for(GTK_WINDOW(
d->manage_window), GTK_WINDOW(
dt_gui_main_window()));
3261 g_signal_connect(G_OBJECT(
d->manage_window),
"delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
3265 gtk_container_add(GTK_CONTAINER(
d->manage_window), GTK_WIDGET(box));
3268 w = gtk_entry_new();
3270 gtk_entry_set_text(GTK_ENTRY(w),
"");
3271 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3272 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"type to filter the tag dictionary below"));
3273 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3274 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3275 g_signal_connect(G_OBJECT(w),
"icon-release", G_CALLBACK(
_entry_clear_icon), self);
3276 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3277 g_signal_connect(G_OBJECT(w),
"changed", G_CALLBACK(
_tag_name_changed), (gpointer)self);
3278 d->dict_entry = GTK_ENTRY(w);
3279 gtk_box_pack_start(box, w,
FALSE,
TRUE, 0);
3282 view = GTK_TREE_VIEW(gtk_tree_view_new());
3286 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3287 d->dictionary_view =
view;
3288 gtk_tree_view_set_enable_search(
view,
FALSE);
3289 gtk_tree_view_set_headers_visible(
view,
FALSE);
3291 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3298 d->dictionary_liststore = liststore;
3299 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
3301 d->dictionary_listfilter = GTK_TREE_MODEL_FILTER(
model);
3303 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3306 d->dictionary_treestore = treestore;
3307 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(treestore), NULL);
3309 d->dictionary_treefilter = GTK_TREE_MODEL_FILTER(
model);
3311 col = gtk_tree_view_column_new();
3312 gtk_tree_view_append_column(
view, col);
3313 renderer = gtk_cell_renderer_text_new();
3314 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3315 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3317 gtk_tree_view_set_expander_column(
view, col);
3319 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3320 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"tag dictionary,"
3321 "\nright-click to create, edit, delete tags,"
3322 "\nselect several tags and right-click to delete them in bulk,"
3323 "\nshift+click to fully expand the selected tag,"
3324 "\nctrl-scroll to resize the window"));
3328 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(
d->dictionary_listfilter));
3329 g_object_unref(
d->dictionary_listfilter);
3330 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3336 d->drag.path = NULL;
3337 d->drag.tagname = NULL;
3338 d->drag.scroll_timeout = 0;
3339 d->drag.expand_timeout = 0;
3341 d->drag.tag_source =
FALSE;
3342 gtk_drag_dest_set(GTK_WIDGET(
d->dictionary_view), GTK_DEST_DEFAULT_ALL,
3344 g_signal_connect(
d->dictionary_view,
"drag-data-get", G_CALLBACK(
_event_dnd_get), self);
3345 g_signal_connect(
d->dictionary_view,
"drag-data-received", G_CALLBACK(
_event_dnd_received), self);
3346 g_signal_connect_after(
d->dictionary_view,
"drag-begin", G_CALLBACK(
_event_dnd_begin), self);
3347 g_signal_connect_after(
d->dictionary_view,
"drag-end", G_CALLBACK(
_event_dnd_end), self);
3348 g_signal_connect(
d->dictionary_view,
"drag-motion", G_CALLBACK(
_event_dnd_motion), self);
3355 gtk_box_pack_start(hbox,
d->new_button,
TRUE,
TRUE, 0);
3358 gtk_box_pack_start(hbox,
d->import_button,
TRUE,
TRUE, 0);
3361 gtk_box_pack_start(hbox,
d->export_button,
TRUE,
TRUE, 0);
3364 _(
"toggle list / tree view"), N_(
"tree"));
3366 _(
"toggle list with / without suggestion"), N_(
"suggestion"));
3368 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3377 GtkWidget *lbl = gtk_label_new(_(
"suggested tags level of confidence"));
3378 gtk_widget_set_halign(lbl, GTK_ALIGN_START);
3379 gtk_widget_set_hexpand(lbl,
TRUE);
3380 GtkWidget *spin = gtk_spin_button_new_with_range(0, 100, 1);
3381 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
dt_conf_get_int(
"plugins/lighttable/tagging/confidence"));
3382 gtk_widget_set_tooltip_text(spin, _(
"level of confidence to include a tag in the suggestions list:"
3383 "\n0: all associated tags, 99: 99% matching tags,"
3384 "\n100: only the recently-used tags (faster)"));
3386 gtk_grid_attach(GTK_GRID(grid), lbl, 0, 0, 1, 1);
3387 gtk_grid_attach(GTK_GRID(grid), spin, 1, 0, 1, 1);
3389 GtkWidget *lbl2 = gtk_label_new(_(
"number of recently attached tags"));
3390 gtk_widget_set_halign(lbl2, GTK_ALIGN_START);
3391 gtk_widget_set_hexpand(lbl2,
TRUE);
3392 GtkWidget *spin2 = gtk_spin_button_new_with_range(-1, 1000, 1);
3393 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin2),
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags"));
3394 gtk_widget_set_tooltip_text(spin2, _(
"number of recently attached tags shown in the suggestions list"
3395 "\n(-1 disables the recent-tags list)"));
3397 gtk_grid_attach(GTK_GRID(grid), lbl2, 0, 1, 1, 1);
3398 gtk_grid_attach(GTK_GRID(grid), spin2, 1, 1, 1, 1);
3400 gtk_box_pack_start(box, grid,
FALSE,
FALSE, 0);
3404 d->dttags_check = gtk_check_button_new_with_label(_(
"Show system tags"));
3405 gtk_widget_set_tooltip_text(
d->dttags_check, _(
"show the tags automatically attached by Ansel (names starting with “Ansel|”)"));
3408 gtk_box_pack_start(GTK_BOX(self->
widget),
d->dttags_check,
FALSE,
TRUE, 0);
3410#undef NEW_TOGGLE_BUTTON
3422 d->collection = g_malloc(4096);
3423 d->collection_tags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
3435 _(
"Opens the quick tagging entry"));
3438 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3439 _(
"Re-applies the last used tag"));
3443 _(
"Opens the quick tagging entry"));
3446 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3447 _(
"Re-applies the last used tag"));
3473 if(
d->manage_window) gtk_widget_destroy(
d->manage_window);
3474 if(
d->collection_tags) g_hash_table_destroy(
d->collection_tags);
3476 if(
d->attached_liststore) g_object_unref(
d->attached_liststore);
3477 if(
d->attached_treestore) g_object_unref(
d->attached_treestore);
3483 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
3495 case GDK_KEY_Escape:
3496 g_list_free(
d->floating_tag_imgs);
3497 d->floating_tag_imgs = NULL;
3498 gtk_widget_destroy(
d->floating_tag_window);
3503 case GDK_KEY_Return:
3505 const gchar *tag = gtk_entry_get_text(GTK_ENTRY(entry));
3508 g_list_free(
d->floating_tag_imgs);
3509 d->floating_tag_imgs = NULL;
3518 gtk_widget_destroy(
d->floating_tag_window);
3530 gtk_widget_destroy(GTK_WIDGET(user_data));
3539 GdkModifierType mods, gpointer user_data)
3566 GdkModifierType mods, gpointer user_data)
3572 dt_control_log(_(
"tag shortcut is not active with tag tree view. please switch to list view"));
3581 gdk_window_get_origin(gtk_widget_get_window(center), &px, &py);
3583 w = gdk_window_get_width(gtk_widget_get_window(center));
3584 h = gdk_window_get_height(gtk_widget_get_window(center));
3597 d->floating_tag_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3598#ifdef GDK_WINDOWING_QUARTZ
3602 gtk_widget_set_can_focus(
d->floating_tag_window,
TRUE);
3603 gtk_window_set_decorated(GTK_WINDOW(
d->floating_tag_window),
FALSE);
3604 gtk_window_set_type_hint(GTK_WINDOW(
d->floating_tag_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
3605 gtk_window_set_transient_for(GTK_WINDOW(
d->floating_tag_window), GTK_WINDOW(
window));
3606 gtk_widget_set_opacity(
d->floating_tag_window, 0.8);
3607 gtk_window_move(GTK_WINDOW(
d->floating_tag_window),
x, y);
3612 gtk_widget_add_events(entry, GDK_FOCUS_CHANGE_MASK);
3614 GtkEntryCompletion *completion = gtk_entry_completion_new();
3615 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3617 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3618 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3619 gtk_entry_completion_set_minimum_key_length(completion, 0);
3620 g_signal_connect(G_OBJECT(completion),
"match-selected",
3623 gtk_entry_set_completion(GTK_ENTRY(entry), completion);
3625 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
3626 gtk_container_add(GTK_CONTAINER(
d->floating_tag_window), entry);
3630 gtk_widget_show_all(
d->floating_tag_window);
3631 gtk_widget_grab_focus(entry);
3632 gtk_window_present(GTK_WINDOW(
d->floating_tag_window));
3639 const int length =
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags");
3640 if(length == -1)
return length;
3641 else if(length >= 10/2)
return length * 2;
3657 char *
p = (
char *)list;
3659 for(;*
p !=
'\0';
p++)
3667 char *list2 = g_strdup(list);
3670 p = g_strrstr(list2,
"','");
3682 GtkWidget *mi = gtk_menu_item_new_with_label(_(
"manage tags..."));
3684 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3690 d->last_tag = g_strdup(tagnames);
3702 for(GList *tag = ntags; tag; tag = g_list_next(tag))
3704 char *escaped = sqlite3_mprintf(
"%q", (
char *)tag->data);
3705 GList *found = g_list_find_custom(tags, escaped, (GCompareFunc)g_strcmp0);
3708 tags = g_list_remove_link(tags, found);
3713 tags = g_list_prepend(tags, g_strdup(escaped));
3714 sqlite3_free(escaped);
3722 if(g_list_length(tags) > nb_recent)
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
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.
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)
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 _entry_clear_suppressed(GtkEntry *entry)
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)
void dt_tagging_entry_clear(GtkEntry *entry)
gboolean dt_tagging_completion_match_selected(GtkEntryCompletion *completion, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
void dt_tagging_completion_refresh(GtkListStore *store)
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