67#ifdef GDK_WINDOWING_QUARTZ
70#include <gdk/gdkkeysyms.h>
73#define FLOATING_ENTRY_WIDTH DT_PIXEL_APPLY_DPI(150)
92 gboolean tree_flag, suggestion_flag, sort_count_flag, hide_path_flag,
dttags_flag;
138 GdkModifierType mods, gpointer user_data);
140 GdkModifierType mods, gpointer user_data);
149 static const char *
v[] = {
"lighttable",
"map", NULL};
162 const gboolean user_tag = !g_str_has_prefix(path,
"darktable|") || g_str_has_prefix(path,
"darktable|style|");
169 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
170 gtk_tree_selection_unselect_all(selection);
178 GList *rows = gtk_tree_selection_get_selected_rows(selection,
model);
179 gboolean found =
FALSE;
182 found = gtk_tree_model_get_iter(*
model, iter, (GtkTreePath *)rows->data);
183 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
199 GtkTreeIter parent, child = *iter;
200 while(gtk_tree_model_iter_parent(
model, &parent, &child))
204 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
214 gchar *tagname = NULL;
215 gchar *synonyms = NULL;
221 if(synonyms && synonyms[0]) tagname =
dt_util_dstrcat(tagname,
", %s", synonyms);
222 gchar *haystack = g_utf8_strdown(tagname, -1);
223 gchar *needle = g_utf8_strdown(
d->keyword, -1);
224 visible = (g_strrstr(haystack, needle) != NULL);
240 GtkTreeIter parent, child = *iter;
245 while(gtk_tree_model_iter_parent(
model, &parent, &child))
257 if(
d->attached_tree_flag)
260 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
263 if(force &&
d->sort_count_flag)
266 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
269 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->attached_liststore), sort, GTK_SORT_ASCENDING);
277 if(force &&
d->sort_count_flag)
280 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore),
DT_TAG_SORT_NAME_ID, GTK_SORT_ASCENDING);
283 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_liststore), sort, GTK_SORT_ASCENDING);
286 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
d->dictionary_treestore),
DT_TAG_SORT_PATH_ID, GTK_SORT_ASCENDING);
291 const char *tagname,
const gboolean needle)
293 gboolean found =
FALSE;
301 gchar *haystack = g_utf8_strdown(path, -1);
302 found = g_strstr_len(haystack, strlen(haystack), tagname) != NULL;
306 found = !g_strcmp0(tagname, path);
308 if(found)
return found;
309 GtkTreeIter child, parent = *iter;
310 if(gtk_tree_model_iter_children(
model, &child, &parent))
319 }
while(gtk_tree_model_iter_next(
model, iter));
325 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
326 GtkTreePath *path = gtk_tree_model_get_path(
model, iter);
327 gtk_tree_view_expand_to_path(
view, path);
328 gtk_tree_view_scroll_to_cell(
view, path, NULL,
TRUE, 0.5, 0.5);
329 gtk_tree_path_free(path);
332 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
333 gtk_tree_selection_select_iter(selection, iter);
339 const gboolean needle,
const gboolean select)
343 char *lt = g_strdup(tagname);
344 char *
t = g_strstrip(lt);
346 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
347 if(gtk_tree_model_get_iter_first(
model, &iter))
358 gchar *needle = g_utf8_strdown(keyword, -1);
368 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
369 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
371 for(; valid &&
i < index -1;
i++)
372 valid = gtk_tree_model_iter_next(
model, &iter);
373 for(; valid; valid = gtk_tree_model_iter_previous(
model, &iter))
387 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
388 gboolean valid = gtk_tree_model_get_iter_first(
model, &iter);
390 for(; valid &&
i < index;
i++)
391 valid = gtk_tree_model_iter_next(
model, &iter);
392 for(; valid; valid = gtk_tree_model_iter_next(
model, &iter))
414 gboolean no_sel =
FALSE;
417 const gboolean build_tree = which ?
d->tree_flag :
d->attached_tree_flag;
424 view =
d->attached_view;
426 store = build_tree ? GTK_TREE_MODEL(
d->attached_treestore) : GTK_TREE_MODEL(
d->attached_liststore);
431 if(!
d->tree_flag &&
d->suggestion_flag)
435 view =
d->dictionary_view;
436 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
view));
438 store = GTK_TREE_MODEL(
d->dictionary_treestore);
440 store = GTK_TREE_MODEL(
d->dictionary_liststore);
443 gtk_tree_view_set_model(GTK_TREE_VIEW(
view), NULL);
445 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
448 gtk_tree_store_clear(GTK_TREE_STORE(
store));
450 char **last_tokens = NULL;
451 int last_tokens_length = 0;
452 GtkTreeIter last_parent = { 0 };
455 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
457 const gchar *tag = ((
dt_tag_t *)taglist->data)->tag;
460 tokens = g_strsplit(tag,
"|", -1);
464 GtkTreeIter parent = last_parent;
465 const int tokens_length = g_strv_length(tokens);
466 int common_length = 0;
469 while(tokens[common_length] && last_tokens[common_length] &&
470 !g_strcmp0(tokens[common_length], last_tokens[common_length]))
476 for(
int i = common_length;
i < last_tokens_length;
i++)
478 gtk_tree_model_iter_parent(GTK_TREE_MODEL(
store), &parent, &last_parent);
479 last_parent = parent;
485 for(
int i = 0;
i < common_length;
i++)
488 for(
char **token = &tokens[common_length]; *token; token++)
491 gchar *pth2 = g_strdup(pth);
492 pth2[strlen(pth2) - 1] =
'\0';
493 gtk_tree_store_insert(GTK_TREE_STORE(
store), &iter, common_length > 0 ? &parent : NULL, -1);
494 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
497 ((
dt_tag_t *)taglist->data)->id : 0,
500 ((
dt_tag_t *)taglist->data)->count : 0,
506 if(((
dt_tag_t *)taglist->data)->select)
515 if(last_tokens) g_strfreev(last_tokens);
516 last_tokens = tokens;
517 last_parent = parent;
518 last_tokens_length = tokens_length;
521 g_strfreev(last_tokens);
523 if(which &&
d->keyword[0])
527 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
529 else gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
530 g_object_unref(
model);
534 gtk_list_store_clear(GTK_LIST_STORE(
store));
535 if(count > 0 && tags)
537 for (GList *tag = tags; tag; tag = g_list_next(tag))
539 const char *subtag = g_strrstr(((
dt_tag_t *)tag->data)->tag,
"|");
540 gtk_list_store_append(GTK_LIST_STORE(
store), &iter);
541 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
554 if(which &&
d->keyword[0])
558 gtk_tree_view_set_model(GTK_TREE_VIEW(
view),
model);
559 g_object_unref(
model);
566 if(!which &&
d->attached_tree_flag)
567 gtk_tree_view_expand_all(GTK_TREE_VIEW(
d->attached_view));
573 GtkTreeModel *
model, GtkTreeIter *iter,
574 gpointer data, gboolean dictionary_view)
585 gtk_tree_model_get(
model, iter,
592 const gboolean hide = dictionary_view ? (
d->tree_flag ?
TRUE :
d->hide_path_flag) :
d->attached_tree_flag;
594 if((dictionary_view && !count) || (!dictionary_view && count <= 1))
596 coltext = g_markup_printf_escaped(istag ?
"%s" :
"<i>%s</i>", hide ?
name : path);
600 coltext = g_markup_printf_escaped(istag ?
"%s (%d)" :
"<i>%s</i> (%d)", hide ?
name : path, count);
602 g_object_set(renderer,
"markup", coltext, NULL);
609 GtkTreeModel *
model, GtkTreeIter *iter,
616 GtkTreeModel *
model, GtkTreeIter *iter,
649 d->collection[0] =
'\0';
661 if(!
d->collection[0])
683 GtkTreeIter child, parent = *iter;
684 if(gtk_tree_model_iter_children(
model, &child, &parent))
690 }
while (gtk_tree_model_iter_next(
model, iter));
697 GtkTreeIter child, parent = *iter;
706 if(gtk_tree_model_iter_children(
model, &child, &parent))
708 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
714 GtkTreeIter child, parent = *iter;
717 if(gtk_tree_model_iter_children(
model, &child, &parent))
723 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
728 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
734 GtkTreeIter child, parent = *iter;
737 if(GTK_IS_TREE_STORE(
model))
739 gtk_tree_store_set(GTK_TREE_STORE(
model), &parent,
741 if(gtk_tree_model_iter_children(
model, &child, &parent))
746 gtk_list_store_set(GTK_LIST_STORE(
model), &parent,
749 }
while (!root && gtk_tree_model_iter_next(
model, &parent));
756 GtkTreeIter child = *iter;
757 while (gtk_tree_model_iter_parent(
model, parent, &child))
789 if(gtk_tree_model_get_iter_first(
model, &parent))
803 if(gtk_tree_model_get_iter_first(
model, &parent))
806 for (GList *tag = tags; tag; tag = g_list_next(tag))
808 GtkTreeIter iter = parent;
811 if(GTK_IS_TREE_STORE(
model))
813 gtk_tree_store_set(GTK_TREE_STORE(
model), &iter,
819 gtk_list_store_set(GTK_LIST_STORE(
model), &iter,
835 GtkTreeIter child, parent = *iter;
836 gboolean valid =
TRUE;
839 if(gtk_tree_model_iter_children(
model, &child, &parent))
841 GtkTreeIter tobedel = parent;
842 valid = gtk_tree_model_iter_next(
model, &parent);
845 gtk_tree_store_set(GTK_TREE_STORE(
model), &tobedel,
858 gtk_tree_store_remove(GTK_TREE_STORE(
model), &tobedel);
859 }
while (!root && valid);
866 guint pathlen = strlen(path);
867 gboolean valid = gtk_tree_model_get_iter_first(
model, &child);
872 GtkTreeIter tobedel = child;
873 valid = gtk_tree_model_iter_next (
model, &child);
874 if(strlen(path2) >= pathlen)
876 char letter = path2[pathlen];
877 path2[pathlen] =
'\0';
878 if(g_strcmp0(path, path2) == 0)
880 path2[pathlen] = letter;
881 gtk_list_store_remove(GTK_LIST_STORE(
model), &tobedel);
894 if(!
d->tree_flag &&
d->suggestion_flag)
900 : GTK_TREE_MODEL(
d->dictionary_liststore));
908 const gchar *beg = g_strrstr(gtk_entry_get_text(
d->dict_entry),
",");
911 beg = gtk_entry_get_text(
d->dict_entry);
914 if(*beg ==
',') beg++;
915 if(*beg ==
' ') beg++;
917 g_strlcpy(
d->keyword, beg,
sizeof(
d->keyword));
926 if(g_str_has_prefix(tagname, oldtagname))
928 if(strlen(tagname) == strlen(oldtagname))
933 char *subtag = g_strrstr(to->
newtagname,
"|");
934 subtag = (!subtag) ? newtagname : subtag + 1;
944 else if(strlen(tagname) > strlen(oldtagname) && tagname[strlen(oldtagname)] ==
'|')
947 char *newpath = g_strconcat(newtagname, &tagname[strlen(oldtagname)] , NULL);
968 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
969 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
971 if(gtk_tree_model_get_iter_first(
store, &iter))
977 gtk_tree_store_set(GTK_TREE_STORE(
store), &iter,
984 gtk_list_store_set(GTK_LIST_STORE(
store), &iter,
1006 for(GList *taglist = tags; taglist; taglist = g_list_next(taglist))
1013 *
size = strlen(params);
1014 params[*
size-1]=
'\0';
1024 const char *buf = (
char *)params;
1027 gchar **tokens = g_strsplit(buf,
",", 0);
1031 gchar **entry = tokens;
1034 const guint tagid = strtoul(*entry, NULL, 0);
1035 tags = g_list_prepend(tags, GINT_TO_POINTER(tagid));
1043 gboolean change =
FALSE;
1044 for(GList *tag = tags; tag; tag = g_list_next(tag))
1067 GtkTreeModel *
model = NULL;
1068 GList *rows = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(
view), &
model);
1069 for(GList *
r = rows;
r;
r = g_list_next(
r))
1072 if(gtk_tree_model_get_iter(
model, &iter, (GtkTreePath *)
r->data))
1076 if(tagid > 0) ids = g_list_prepend(ids, GUINT_TO_POINTER(tagid));
1079 g_list_free_full(rows, (GDestroyNotify)gtk_tree_path_free);
1090 gboolean changed =
FALSE;
1091 for(GList *
t = tagids;
t;
t = g_list_next(
t))
1093 const guint tagid = GPOINTER_TO_UINT(
t->data);
1094 if(tagid <= 0)
continue;
1100 g_list_free(affected);
1116 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1117 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1122 if(tagid <= 0)
return;
1133 model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
1134 if(gtk_tree_model_get_iter_first(
model, &iter))
1138 GtkTreeIter store_iter;
1139 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1140 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1141 &store_iter, &iter);
1165 g_list_free(tagids);
1172 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1174 GList *tagids = NULL;
1175 if(gtk_tree_model_get_iter_first(
model, &iter))
1182 if(tagid > 0) tagids = g_list_prepend(tagids, GUINT_TO_POINTER(tagid));
1183 }
while(gtk_tree_model_iter_next(
model, &iter));
1186 g_list_free(tagids);
1193 menu = gtk_menu_new();
1196 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1197 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->attached_view));
1198 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
1207 menuitem = gtk_menu_item_new_with_label(_(
"attach tag to all"));
1209 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1210 menuitem = gtk_separator_menu_item_new();
1211 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1217 menuitem = gtk_menu_item_new_with_label(sel_cnt > 1 ? _(
"detach tags") : _(
"detach tag"));
1218 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1222 menuitem = gtk_menu_item_new_with_label(_(
"detach all tags"));
1223 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1226 gtk_widget_show_all(GTK_WIDGET(menu));
1228 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
1233 const gchar *path_str, GdkRectangle *background,
1234 GdkRectangle *cell_area, GtkCellRendererState
flags,
1238 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
1239 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1241 if(path && gtk_tree_model_get_iter(
model, &iter, path))
1247 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1252 if(path) gtk_tree_path_free(path);
1259 GtkTreeModel *
model, GtkTreeIter *iter, gpointer data)
1263 g_object_set(renderer,
"icon-name",
"edit-delete-symbolic",
1272 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1273 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->attached_view));
1274 GtkTreePath *path = NULL;
1275 const gboolean on_row =
1276 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL);
1278 gboolean valid_tag =
FALSE;
1280 if(on_row && gtk_tree_model_get_iter(
model, &iter, path))
1284 if(event->type == GDK_BUTTON_PRESS && event->button == 3)
1289 if(!gtk_tree_selection_path_is_selected(selection, path))
1291 gtk_tree_selection_unselect_all(selection);
1292 gtk_tree_selection_select_path(selection, path);
1296 gtk_tree_selection_unselect_all(selection);
1298 if(path) gtk_tree_path_free(path);
1303 if(event->type == GDK_2BUTTON_PRESS && event->button == 1 && valid_tag)
1309 GList *one = g_list_prepend(NULL, GUINT_TO_POINTER(tagid));
1313 if(path) gtk_tree_path_free(path);
1318 if(event->type == GDK_BUTTON_PRESS && event->button == 1 && on_row && !valid_tag)
1320 gtk_tree_path_free(path);
1324 if(path) gtk_tree_path_free(path);
1334 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1335 if(
key == GDK_KEY_Delete && gtk_tree_selection_count_selected_rows(selection) > 0)
1339 g_list_free(tagids);
1342 if(
key == GDK_KEY_Tab)
1344 gtk_tree_selection_unselect_all(selection);
1345 gtk_widget_grab_focus(GTK_WIDGET(
d->entry));
1348 else if(
key == GDK_KEY_ISO_Left_Tab)
1350 gtk_tree_selection_unselect_all(selection);
1360 const gchar *tag = gtk_entry_get_text(src);
1373 gtk_entry_set_text(src,
"");
1381 char *tagname = strrchr(
d->last_tag,
',');
1384 tagname ? tagname + 1 :
d->last_tag,
FALSE,
TRUE);
1400 case GDK_KEY_Return:
1403 case GDK_KEY_Escape:
1406 case GDK_KEY_ISO_Left_Tab:
1410 gtk_entry_set_text(GTK_ENTRY(entry),
"");
1411 gtk_widget_grab_focus(GTK_WIDGET(
d->attached_view));
1426 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
1427 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1429 if(
d->tree_flag &&
d->keyword[0])
1440 int res = GTK_RESPONSE_YES;
1447 GtkTreeModel *
model = NULL;
1448 GtkTreeView *
view =
d->dictionary_view;
1449 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1458 if(tag_count == 0)
return;
1461 GtkWidget *dialog = gtk_dialog_new_with_buttons( _(
"delete node?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1462 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
1463 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1464 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1466 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1467 gtk_container_add(GTK_CONTAINER(area), vbox);
1468 text = g_strdup_printf(_(
"selected: %s"), tagname);
1469 label = gtk_label_new(text);
1470 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1474 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1475 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be deleted",
"<u>%d</u> tags will be deleted", tag_count), tag_count);
1476 label = gtk_label_new(NULL);
1477 gtk_label_set_markup(GTK_LABEL(label), text);
1478 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1480 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1481 label = gtk_label_new(NULL);
1482 gtk_label_set_markup(GTK_LABEL(label), text);
1483 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1486#ifdef GDK_WINDOWING_QUARTZ
1489 gtk_widget_show_all(dialog);
1491 res = gtk_dialog_run(GTK_DIALOG(dialog));
1492 gtk_widget_destroy(dialog);
1493 if(res != GTK_RESPONSE_YES)
1499 GList *tag_family = NULL;
1500 GList *tagged_images = NULL;
1508 GtkTreeIter store_iter;
1509 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1510 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1511 &store_iter, &iter);
1517 g_list_free(tagged_images);
1518 tagged_images = NULL;
1534 GtkTreeModel *
model = NULL;
1535 GtkTreeView *
view =
d->dictionary_view;
1536 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1543 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"create tag"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1544 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1545 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1546 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1548 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1549 gtk_container_add(GTK_CONTAINER(area), vbox);
1552 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1553 label = gtk_label_new(_(
"name: "));
1554 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1557 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1562 GtkTextBuffer *buffer = NULL;
1564 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1566 text = g_strdup_printf(_(
"add to: \"%s\" "), path);
1567 parent = gtk_check_button_new_with_label(text);
1568 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(parent),
TRUE);
1569 gtk_box_pack_end(GTK_BOX(vbox2), parent,
FALSE,
TRUE, 0);
1572 category = gtk_check_button_new_with_label(_(
"category"));
1573 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(category),
FALSE);
1574 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1575 private = gtk_check_button_new_with_label(_(
"private"));
1576 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
private),
FALSE);
1577 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1580 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1581 label = gtk_label_new(_(
"synonyms: "));
1582 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1583 GtkWidget *synonyms = gtk_text_view_new();
1586 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1587 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1588 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1590#ifdef GDK_WINDOWING_QUARTZ
1593 gtk_widget_show_all(dialog);
1595 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1597 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1598 char *message = NULL;
1600 message = _(
"empty tag is not allowed, aborting");
1601 char *new_tagname = NULL;
1602 const gboolean root = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(parent));
1605 new_tagname = g_strdup(path);
1608 else new_tagname = g_strdup(newtag);
1611 message = _(
"tag name already exists. aborting.");
1614 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1615 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1616 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1617 gtk_widget_destroy(warning_dialog);
1618 gtk_widget_destroy(dialog);
1622 guint new_tagid = 0;
1625 const gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1626 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1628 GtkTextIter start, end;
1629 gtk_text_buffer_get_start_iter(buffer, &start);
1630 gtk_text_buffer_get_end_iter(buffer, &end);
1631 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1632 if(new_tagid && new_synonyms_list && new_synonyms_list[0])
1641 gtk_widget_destroy(dialog);
1651 char *synonyms_list;
1656 GtkTreeModel *
model = NULL;
1657 GtkTreeView *
view =
d->dictionary_view;
1658 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1663 char *subtag = g_strrstr(tagname,
"|");
1664 if(subtag) subtag = subtag + 1;
1676 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"edit"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1677 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1678 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1679 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1681 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1682 gtk_container_add(GTK_CONTAINER(area), vbox);
1683 text = g_strdup_printf(_(
"selected: %s"), tagname);
1684 label = gtk_label_new(text);
1685 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1689 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1690 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
1691 label = gtk_label_new(NULL);
1692 gtk_label_set_markup(GTK_LABEL(label), text);
1693 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1695 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1696 label = gtk_label_new(NULL);
1697 gtk_label_set_markup(GTK_LABEL(label), text);
1698 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1702 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1703 label = gtk_label_new(_(
"name: "));
1704 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1707 gtk_entry_set_text(GTK_ENTRY(entry), subtag ? subtag : tagname);
1708 gtk_box_pack_end(GTK_BOX(box), entry,
TRUE,
TRUE, 0);
1712 GtkWidget *
private = gtk_check_button_new_with_label(_(
"private"));
1713 GtkTextBuffer *buffer = NULL;
1718 gtk_box_pack_start(GTK_BOX(vbox), vbox2,
FALSE,
TRUE, 0);
1720 category = gtk_check_button_new_with_label(_(
"category"));
1722 gtk_box_pack_end(GTK_BOX(vbox2), category,
FALSE,
TRUE, 0);
1724 gtk_box_pack_end(GTK_BOX(vbox2),
private,
FALSE,
TRUE, 0);
1727 gtk_box_pack_end(GTK_BOX(vbox), box,
TRUE,
TRUE, 0);
1728 label = gtk_label_new(_(
"synonyms: "));
1729 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1730 GtkWidget *synonyms = gtk_text_view_new();
1733 gtk_box_pack_end(GTK_BOX(box), synonyms,
TRUE,
TRUE, 0);
1734 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(synonyms), GTK_WRAP_WORD);
1735 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(synonyms));
1736 if(synonyms_list) gtk_text_buffer_set_text(buffer, synonyms_list, -1);
1739#ifdef GDK_WINDOWING_QUARTZ
1742 gtk_widget_show_all(dialog);
1744 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1746 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1747 if(g_strcmp0(newtag, subtag ? subtag : tagname) != 0)
1750 char *message = NULL;
1752 message = _(
"empty tag is not allowed, aborting");
1753 if(strchr(newtag,
'|') != 0)
1754 message = _(
"'|' character is not allowed for renaming tag.\nto modify the hierarchy use rename path instead. Aborting.");
1757 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1758 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
1759 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1760 gtk_widget_destroy(warning_dialog);
1761 gtk_widget_destroy(dialog);
1766 GList *tag_family = NULL;
1767 GList *tagged_images = NULL;
1770 const int tagname_len = strlen(tagname);
1771 char *new_prefix_tag;
1774 const int subtag_len = strlen(subtag);
1775 const char letter = tagname[tagname_len - subtag_len];
1776 tagname[tagname_len - subtag_len] =
'\0';
1777 new_prefix_tag = g_strconcat(tagname, newtag, NULL);
1778 tagname[tagname_len - subtag_len] = letter;
1781 new_prefix_tag = (
char *)newtag;
1784 gboolean tagname_exists =
FALSE;
1785 for (GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1787 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1791 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
1792 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1793 _(
"at least one new tag name (%s) already exists, aborting"), new_tagname);
1794 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1795 gtk_widget_destroy(warning_dialog);
1801 gtk_widget_destroy(dialog);
1809 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1811 char *new_tagname = g_strconcat(new_prefix_tag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1817 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1823 GtkSortType sort_order;
1824 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(
store), &sort_column, &sort_order);
1825 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
1827 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
store), sort_column, sort_order);
1837 g_list_free(tagged_images);
1838 tagged_images = NULL;
1843 gint new_flags = ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(category)) ?
DT_TF_CATEGORY : 0) |
1844 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
private)) ?
DT_TF_PRIVATE : 0));
1845 GtkTextIter start, end;
1846 gtk_text_buffer_get_start_iter(buffer, &start);
1847 gtk_text_buffer_get_end_iter(buffer, &end);
1848 gchar *new_synonyms_list = gtk_text_buffer_get_text(buffer, &start, &end,
FALSE);
1851 GtkTreeIter store_iter;
1852 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
1853 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(
model),
1854 &store_iter, &iter);
1864 if(new_synonyms_list && g_strcmp0(synonyms_list, new_synonyms_list) != 0)
1876 gtk_widget_destroy(dialog);
1886 gboolean success =
FALSE;
1887 GList *tag_family = NULL;
1888 GList *tagged_images = NULL;
1892 const int tagname_len = strlen(tagname);
1893 gboolean tagname_exists =
FALSE;
1894 for(GList *taglist = tag_family; taglist && !tagname_exists; taglist = g_list_next(taglist))
1896 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1906 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_MODAL,
1907 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1908 _(
"at least one new tagname (%s) already exists, aborting."), new_tagname);
1909 gtk_dialog_run(GTK_DIALOG(warning_dialog));
1910 gtk_widget_destroy(warning_dialog);
1917 for (GList *taglist = tag_family; taglist; taglist = g_list_next(taglist))
1919 char *new_tagname = g_strconcat(newtag, &((
dt_tag_t *)taglist->data)->tag[tagname_len], NULL);
1931 g_list_free(tagged_images);
1932 tagged_images = NULL;
1947 GtkTreeModel *
model = NULL;
1948 GtkTreeView *
view =
d->dictionary_view;
1949 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
1958 if(tag_count == 0)
return;
1961 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"change path"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
1962 _(
"cancel"), GTK_RESPONSE_NONE, _(
"save"), GTK_RESPONSE_YES, NULL);
1963 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
1964 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1966 gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
1967 gtk_container_add(GTK_CONTAINER(area), vbox);
1968 text = g_strdup_printf(_(
"selected: %s"), tagname);
1969 label = gtk_label_new(text);
1970 gtk_box_pack_start(GTK_BOX(vbox), label,
FALSE,
TRUE, 0);
1974 gtk_box_pack_start(GTK_BOX(vbox), box,
FALSE,
TRUE, 0);
1975 text = g_strdup_printf(ngettext(
"<u>%d</u> tag will be updated",
"<u>%d</u> tags will be updated", tag_count), tag_count);
1976 label = gtk_label_new(NULL);
1977 gtk_label_set_markup(GTK_LABEL(label), text);
1978 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1980 text = g_strdup_printf(ngettext(
"<u>%d</u> image will be updated",
"<u>%d</u> images will be updated", img_count), img_count);
1981 label = gtk_label_new(NULL);
1982 gtk_label_set_markup(GTK_LABEL(label), text);
1983 gtk_box_pack_start(GTK_BOX(box), label,
FALSE,
TRUE, 0);
1988 gtk_entry_set_text(GTK_ENTRY(entry), tagname);
1989 gtk_box_pack_start(GTK_BOX(vbox), entry,
FALSE,
TRUE, 0);
1991#ifdef GDK_WINDOWING_QUARTZ
1994 gtk_widget_show_all(dialog);
1996 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES)
1998 const char *newtag = gtk_entry_get_text(GTK_ENTRY(entry));
1999 if(g_strcmp0(newtag, tagname) == 0)
2001 char *message = NULL;
2003 message = _(
"empty tag is not allowed, aborting");
2004 if(strchr(newtag,
'|') == &newtag[0] || strchr(newtag,
'|') == &newtag[strlen(newtag)-1] || strstr(newtag,
"||"))
2005 message = _(
"'|' misplaced, empty tag is not allowed, aborting");
2008 GtkWidget *warning_dialog = gtk_message_dialog_new(GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
2009 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
"%s", message);
2010 gtk_dialog_run(GTK_DIALOG(warning_dialog));
2011 gtk_widget_destroy(warning_dialog);
2012 gtk_widget_destroy(dialog);
2018 gtk_widget_destroy(dialog);
2026 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2027 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2049 if(
d->collection[0])
2054 d->collection[0] =
'\0';
2062 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2063 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2068 gtk_entry_set_text(
d->dict_entry, tag);
2070 gtk_entry_grab_focus_without_selecting(
d->dict_entry);
2078 const guint nb = g_list_length(tagids);
2081 guint img_count = 0;
2082 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2085 if(img_count > 0 ||
dt_conf_get_bool(
"plugins/lighttable/tagging/ask_before_delete_tag"))
2088 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"delete tag?"), GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT,
2089 _(
"cancel"), GTK_RESPONSE_NONE, _(
"delete"), GTK_RESPONSE_YES, NULL);
2090 gtk_window_set_default_size(GTK_WINDOW(dialog), 300, -1);
2091 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2092 gchar *text = g_strdup_printf(ngettext(
"do you really want to delete %d tag?\n%d image is assigned these tags!",
2093 "do you really want to delete %d tags?\n%d images are assigned these tags!",
2094 img_count), nb, img_count);
2096 gtk_container_set_border_width(GTK_CONTAINER(area), 8);
2097 gtk_container_add(GTK_CONTAINER(area), label);
2099#ifdef GDK_WINDOWING_QUARTZ
2102 gtk_widget_show_all(dialog);
2103 const int res = gtk_dialog_run(GTK_DIALOG(dialog));
2104 gtk_widget_destroy(dialog);
2105 if(res != GTK_RESPONSE_YES)
return;
2108 GList *affected = NULL;
2109 for(GList *
t = tagids;
t;
t = g_list_next(
t))
2111 const guint tagid = GPOINTER_TO_UINT(
t->data);
2127 g_list_free(affected);
2136 g_list_free(tagids);
2146 GtkTreeModel *
model = NULL;
2147 GtkTreeView *
view =
d->dictionary_view;
2148 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2165 GtkTreeIter iter, child;
2166 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2167 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->dictionary_view));
2168 const gint sel_cnt = gtk_tree_selection_count_selected_rows(selection);
2169 if(sel_cnt == 0)
return;
2177 menuitem = gtk_menu_item_new_with_label(_(
"delete tags"));
2179 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2180 gtk_widget_show_all(GTK_WIDGET(menu));
2181 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2188 gtk_tree_model_get(
model, &iter,
2192 if(
d->tree_flag || !
d->suggestion_flag)
2194 menuitem = gtk_menu_item_new_with_label(_(
"create tag..."));
2195 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2200 menuitem = gtk_menu_item_new_with_label(_(
"delete tag"));
2201 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2205 if(gtk_tree_model_iter_children(
model, &child, &iter))
2207 menuitem = gtk_menu_item_new_with_label(_(
"delete node"));
2208 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2212 menuitem = gtk_menu_item_new_with_label(_(
"edit..."));
2213 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2220 menuitem = gtk_menu_item_new_with_label(_(
"change path..."));
2221 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2225 if(
d->tree_flag && !tagid)
2227 menuitem = gtk_separator_menu_item_new();
2228 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2230 menuitem = gtk_menu_item_new_with_label(_(
"set as a tag"));
2231 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2235 if(!
d->suggestion_flag)
2237 menuitem = gtk_separator_menu_item_new();
2238 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2241 menuitem = gtk_menu_item_new_with_label(_(
"copy to entry"));
2243 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2245 if(
d->collection[0])
2247 char *collection = g_malloc(4096);
2249 if(g_strcmp0(
d->collection, collection) == 0)
d->collection[0] =
'\0';
2252 if(count ||
d->collection[0])
2254 menuitem = gtk_separator_menu_item_new();
2255 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2258 menuitem = gtk_menu_item_new_with_label(_(
"go to tag collection"));
2260 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2262 if(
d->collection[0])
2264 menuitem = gtk_menu_item_new_with_label(_(
"go back to work"));
2266 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
2269 gtk_widget_show_all(GTK_WIDGET(menu));
2271 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2280 const int button_pressed = (
event->type == GDK_BUTTON_PRESS) ? event->button : 0;
2281 const gboolean shift_pressed =
dt_modifier_is(event->state, GDK_SHIFT_MASK);
2285 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2286 GtkTreePath *path = NULL;
2288 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(
view), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
2292 GtkTreeModel *
model = gtk_tree_view_get_model(
d->dictionary_view);
2294 gtk_tree_model_get_iter(
model, &iter, path);
2296 gtk_tree_model_get(
model, &iter,
2302 d->drag.tagname = tagname;
2303 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
2304 d->drag.path = path;
2305 if(
d->drag.lastpath) gtk_tree_path_free(
d->drag.lastpath);
2306 d->drag.lastpath = NULL;
2312 if(!gtk_tree_selection_path_is_selected(selection, path))
2314 gtk_tree_selection_unselect_all(selection);
2315 gtk_tree_selection_select_path(selection, path);
2318 gtk_tree_path_free(path);
2323 gtk_tree_selection_select_path(selection, path);
2324 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
TRUE);
2325 gtk_tree_path_free(path);
2329 gtk_tree_path_free(path);
2339 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2340 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
view));
2341 gboolean res =
FALSE;
2346 GtkTreePath *path = gtk_tree_model_get_path(
model, &iter);
2353 gtk_tree_view_collapse_all(GTK_TREE_VIEW(
view));
2355 gtk_tree_view_collapse_row(GTK_TREE_VIEW(
view), path);
2362 gtk_tree_view_expand_row(GTK_TREE_VIEW(
view), path,
2370 gtk_tree_path_free(path);
2372 if(event->keyval == GDK_KEY_Tab)
2374 gtk_tree_selection_unselect_all(selection);
2377 else if(event->keyval == GDK_KEY_ISO_Left_Tab)
2379 gtk_tree_selection_unselect_all(selection);
2380 gtk_widget_grab_focus(GTK_WIDGET(
d->dict_entry));
2389 gboolean res =
FALSE;
2390 GtkTreePath *path = NULL;
2392 if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
x, y, &path, NULL, NULL, NULL))
2394 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
2396 if(gtk_tree_model_get_iter(
model, &iter, path))
2401 char *synonyms = NULL;
2408 gchar *text = g_strdup_printf(_(
"%s"), tagname);
2410 text =
dt_util_dstrcat(text,
"synonyms: %s", (synonyms && synonyms[0]) ? synonyms :
" - ");
2411 gtk_tooltip_set_text(
tooltip, text);
2420 gtk_tree_path_free(path);
2430 last_dirname = g_get_home_dir();
2434 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2435 _(
"select a keyword file"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_OPEN,
2436 _(
"_import"), _(
"_cancel"));
2438 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2439 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser),
FALSE);
2441 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2443 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2444 char *dirname = g_path_get_dirname(filename);
2445 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2452 g_object_unref(filechooser);
2458 GDateTime *now = g_date_time_new_now_local();
2459 char *export_filename = g_date_time_format(now,
"darktable_tags_%F_%H-%M.txt");
2463 last_dirname = g_get_home_dir();
2467 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
2468 _(
"select file to export to"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SAVE,
2469 _(
"_export"), _(
"_cancel"));
2471 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(filechooser),
TRUE);
2472 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), last_dirname);
2473 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filechooser), export_filename);
2475 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
2477 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
2478 char *dirname = g_path_get_dirname(filename);
2479 dt_conf_set_string(
"plugins/lighttable/tagging/last_import_export_location", dirname);
2486 g_date_time_unref(now);
2488 g_object_unref(filechooser);
2494 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(
d->dictionary_view));
2498 d->suggestion_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2499 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_suggestion_button),
d->suggestion_flag);
2501 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->toggle_tree_button),
d->tree_flag);
2505 if(
model == GTK_TREE_MODEL(
d->dictionary_listfilter))
2507 g_object_ref(
model);
2508 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2509 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2510 gtk_list_store_clear(GTK_LIST_STORE(
store));
2511 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_treefilter));
2512 g_object_unref(
d->dictionary_treefilter);
2514 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
FALSE);
2518 if(
model == GTK_TREE_MODEL(
d->dictionary_treefilter))
2520 g_object_ref(
model);
2521 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), NULL);
2522 GtkTreeModel *
store = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
model));
2523 gtk_tree_store_clear(GTK_TREE_STORE(
store));
2524 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->dictionary_view), GTK_TREE_MODEL(
d->dictionary_listfilter));
2525 g_object_unref(
d->dictionary_listfilter);
2527 gtk_widget_set_sensitive(GTK_WIDGET(
d->toggle_suggestion_button),
TRUE);
2532 gtk_drag_source_set(GTK_WIDGET(
d->dictionary_view), GDK_BUTTON1_MASK,
2535 gtk_drag_source_unset(GTK_WIDGET(
d->dictionary_view));
2537 d->sort_count_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/listsortedbycount");
2542 d->hide_path_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/hidehierarchy");
2544 d->attached_tree_flag =
dt_conf_get_bool(
"plugins/lighttable/tagging/attached_treeview");
2548 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->dttags_check),
d->dttags_flag);
2556 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/nosuggestion");
2565 const gboolean new_state = !
dt_conf_get_bool(
"plugins/lighttable/tagging/treeview");
2577 return (count_b - count_a);
2588 const gboolean sort = g_strcmp0(tag_a, tag_b);
2602 for(
char *letter = tag_a; *letter; letter++)
2603 if(*letter ==
'|') *letter =
'\1';
2606 tag_a = g_strdup(
"");
2610 for(
char *letter = tag_b; *letter; letter++)
2611 if(*letter ==
'|') *letter =
'\1';
2614 tag_b = g_strdup(
"");
2616 const gboolean sort = g_strcmp0(tag_a, tag_b);
2646 d->dttags_flag = gtk_toggle_button_get_active(source);
2655 gtk_entry_set_text(
d->entry,
"");
2656 gtk_entry_set_text(
d->dict_entry,
"");
2674 if(!
d->completion_store)
return;
2675 gtk_list_store_clear(
d->completion_store);
2678 for(GList *
t = tags;
t;
t = g_list_next(
t))
2683 gtk_list_store_append(
d->completion_store, &iter);
2694 if(!
d->collection_tags)
return;
2695 g_hash_table_remove_all(
d->collection_tags);
2698 for(GList *
t = tags;
t;
t = g_list_next(
t))
2702 g_hash_table_add(
d->collection_tags, g_strdup(tag->tag));
2709 const int column = gtk_entry_completion_get_text_column(completion);
2712 if(gtk_tree_model_get_column_type(
model, column) != G_TYPE_STRING)
return TRUE;
2714 GtkEditable *e = (GtkEditable *)gtk_entry_completion_get_entry(completion);
2715 if(!GTK_IS_EDITABLE(e))
2720 gtk_tree_model_get(
model, iter, column, &tag, -1);
2722 gint cut_off, cur_pos = gtk_editable_get_position(e);
2724 gchar *currentText = gtk_editable_get_chars(e, 0, -1);
2725 const gchar *lastTag = g_strrstr(currentText,
",");
2732 cut_off = (int)(g_utf8_strlen(currentText, -1) - g_utf8_strlen(lastTag, -1))+1;
2736 gtk_editable_delete_text(e, cut_off, cur_pos);
2738 gtk_editable_insert_text(e, tag, -1, &cur_pos);
2739 gtk_editable_set_position(e, cur_pos);
2747 gboolean res =
FALSE;
2751 GtkEditable *e = (GtkEditable *)gtk_entry_completion_get_entry(completion);
2753 if(!GTK_IS_EDITABLE(e))
2758 const gint cur_pos = gtk_editable_get_position(e);
2759 const gboolean onLastTag = (g_strstr_len(&
key[cur_pos], -1,
",") == NULL);
2765 GtkTreeModel *
model = gtk_entry_completion_get_model(completion);
2766 const int column = gtk_entry_completion_get_text_column(completion);
2768 if(gtk_tree_model_get_column_type(
model, column) != G_TYPE_STRING)
2773 const gchar *lastTag = g_strrstr(
key,
",");
2784 gtk_tree_model_get(
model, iter, column, &tag, -1);
2788 if(lastTag[0] ==
'\0')
2790 res = (
d &&
d->collection_tags && tag) ? g_hash_table_contains(
d->collection_tags, tag) :
FALSE;
2797 char *normalized = g_utf8_normalize(tag, -1, G_NORMALIZE_ALL);
2800 char *casefold = g_utf8_casefold(normalized, -1);
2803 res = g_strstr_len(casefold, -1, lastTag) != NULL;
2822 if(!
d->drag.root)
return;
2823 GtkTreeModel *
model = GTK_TREE_MODEL(
d->dictionary_treestore);
2825 gtk_tree_model_get_iter_first(
model, &iter);
2829 gtk_tree_store_remove(
d->dictionary_treestore, &iter);
2837 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2841 cairo_surface_t *row_pix = gtk_tree_view_create_row_drag_icon(tree,
d->drag.path);
2847 gtk_drag_set_icon_surface(context, row_pix);
2848 cairo_surface_destroy(row_pix);
2849 gtk_tree_path_free(
d->drag.path);
2850 d->drag.path = NULL;
2851 d->drag.tag_source =
TRUE;
2859 gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data),
2864 GtkSelectionData *selection_data, guint target_type, guint time,
2868 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2870 g_signal_stop_emission_by_name(tree,
"drag-data-received");
2871 gboolean success =
FALSE;
2875 GtkTreePath *path = NULL;
2876 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2879 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2882 gtk_tree_model_get_iter(
model, &iter, path);
2885 const gboolean root = (
name &&
name[0] ==
'\0');
2886 char *
leave = g_strrstr(
d->drag.tagname,
"|");
2893 gtk_tree_path_free(path);
2899 GtkTreePath *path = NULL;
2900 const int imgs_nb = gtk_selection_data_get_length(selection_data) /
sizeof(uint32_t);
2901 if(imgs_nb && gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2903 const uint32_t *imgt = (uint32_t *)gtk_selection_data_get_data(selection_data);
2905 for(
int i = 0;
i < imgs_nb;
i++)
2907 imgs = g_list_prepend(imgs, GINT_TO_POINTER(imgt[
i]));
2909 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2911 gtk_tree_model_get_iter(
model, &iter, path);
2922 gtk_tree_path_free(path);
2926 gtk_drag_finish(context, success,
FALSE, time);
2932 if(
d->drag.lastpath)
2934 gtk_tree_view_expand_row(
d->dictionary_view,
d->drag.lastpath,
FALSE);
2942 if(
d->drag.scroll_timeout)
2944 GdkRectangle visible;
2945 gtk_tree_view_get_visible_rect(
d->dictionary_view, &visible);
2947 gtk_tree_view_convert_bin_window_to_tree_coords(
d->dictionary_view,
2948 0, 0, NULL, &top_ty);
2951 if(
d->drag.tag_source && !
d->drag.root &&
d->drag.last_y < 5 && top_ty < 1)
2954 gtk_tree_store_prepend(
d->dictionary_treestore, &iter, NULL);
2955 gtk_tree_store_set(
d->dictionary_treestore, &iter,
2964 d->drag.root =
TRUE;
2966 else if(
d->drag.root &&
d->drag.last_y >= 20)
2969 if(
d->drag.last_y < 5)
2972 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty - 25 < 0 ? 0 : top_ty - 25);
2974 else if(
d->drag.last_y > visible.height - 5)
2976 gtk_tree_view_scroll_to_point(
d->dictionary_view, 0, top_ty + 25);
2986 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2987 GtkTreePath *path = NULL;
2989 if(gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2991 if(
IS_NULL_PTR(
d->drag.lastpath) || ((
d->drag.lastpath) && gtk_tree_path_compare(
d->drag.lastpath, path) != 0))
2993 GtkTreeViewColumn *col = gtk_tree_view_get_column(
d->dictionary_view, 0);
2994 const int sel_width = gtk_tree_view_column_get_width(col);
2997 if(!gtk_tree_view_row_expanded(tree, path))
3002 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3003 gtk_tree_selection_select_path(selection, path);
3005 if(
d->drag.scroll_timeout == 0)
3014 if(
d->drag.lastpath)
3015 gtk_tree_path_free(
d->drag.lastpath);
3016 d->drag.lastpath = path;
3026 GtkTreeSelection *selection = gtk_tree_view_get_selection(
d->dictionary_view);
3027 gtk_tree_selection_unselect_all(selection);
3028 if(
d->drag.scroll_timeout)
3029 g_source_remove(
d->drag.scroll_timeout);
3030 d->drag.scroll_timeout = 0;
3031 d->drag.tag_source =
FALSE;
3039 gtk_widget_show_all(
d->manage_window);
3040 gtk_window_present(GTK_WINDOW(
d->manage_window));
3047 if(!
d->tree_flag &&
d->suggestion_flag)
3054 dt_conf_set_int(
"plugins/lighttable/tagging/confidence", gtk_spin_button_get_value_as_int(spin));
3061 dt_conf_set_int(
"plugins/lighttable/tagging/nb_recent_tags", gtk_spin_button_get_value_as_int(spin));
3067static void _entry_clear_icon(GtkEntry *entry, GtkEntryIconPosition pos, GdkEvent *event, gpointer user_data)
3069 if(pos == GTK_ENTRY_ICON_SECONDARY) gtk_entry_set_text(entry,
"");
3082 self->
data = (
void *)
d;
3092 GtkTreeModel *
model;
3093 GtkListStore *liststore;
3094 GtkTreeStore *treestore;
3095 GtkTreeViewColumn *col;
3096 GtkCellRenderer *renderer;
3107 gtk_widget_set_valign(
d->attached_view_combo, GTK_ALIGN_CENTER);
3108 gtk_widget_set_tooltip_text(
d->attached_view_combo,
3109 _(
"show the attached tags as a flat list or as a hierarchical tree"));
3111 gtk_box_pack_start(hbox,
d->attached_view_combo,
TRUE,
TRUE, 0);
3119 gtk_widget_set_valign(
d->sort_combo, GTK_ALIGN_CENTER);
3120 gtk_widget_set_tooltip_text(
d->sort_combo, _(
"sort the tags by name or by image count"));
3121 g_signal_connect(G_OBJECT(
d->sort_combo),
"value-changed", G_CALLBACK(
_sort_combo_changed), self);
3122 gtk_box_pack_start(hbox,
d->sort_combo,
TRUE,
TRUE, 0);
3124 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3130 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
3131 view = GTK_TREE_VIEW(gtk_tree_view_new());
3135 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3136 d->attached_view =
view;
3137 gtk_tree_view_set_enable_search(
view,
FALSE);
3138 gtk_tree_view_set_headers_visible(
view,
FALSE);
3140 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3147 d->attached_liststore = liststore;
3150 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3153 d->attached_treestore = treestore;
3154 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3157 col = gtk_tree_view_column_new();
3158 gtk_tree_view_append_column(
view, col);
3159 renderer = gtk_cell_renderer_text_new();
3160 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3161 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3163 gtk_tree_view_column_set_expand(col,
TRUE);
3164 gtk_tree_view_set_expander_column(
view, col);
3167 col = gtk_tree_view_column_new();
3168 gtk_tree_view_append_column(
view, col);
3170 g_object_set(renderer,
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
3171 gtk_tree_view_column_pack_end(col, renderer,
FALSE);
3175 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3176 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(liststore));
3179 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"attached tags,"
3180 "\nclick the trash icon, press Delete or double-click to detach"
3181 "\nselect several tags and right-click to detach them in bulk,"
3182 "\npress Tab to give the focus to entry,"
3183 "\nctrl-wheel scroll to resize the window"));
3188#define NEW_TOGGLE_BUTTON(paint, callback, tooltip, action) \
3189 button = dtgtk_togglebutton_new(paint, 0, NULL); \
3190 gtk_widget_set_tooltip_text(button, tooltip); \
3191 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, TRUE, 0); \
3192 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), self); \
3196 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
FALSE,
TRUE, 0);
3199 gtk_box_reorder_child(GTK_BOX(self->
widget), GTK_WIDGET(box), 1);
3203 w = gtk_entry_new();
3205 gtk_entry_set_text(GTK_ENTRY(w),
"");
3206 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3208 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"enter or pick a tag, Enter to attach"));
3209 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3210 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3211 g_signal_connect(G_OBJECT(w),
"icon-press", G_CALLBACK(
_entry_clear_icon), NULL);
3212 gtk_box_pack_start(hbox, w,
TRUE,
TRUE, 0);
3213 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3214 g_signal_connect(G_OBJECT(w),
"key-press-event", G_CALLBACK(
_enter_key_pressed), (gpointer)self);
3215 d->entry = GTK_ENTRY(w);
3219 gtk_widget_set_tooltip_text(
d->validate_button, _(
"attach this tag to the selected images"));
3220 gtk_box_pack_end(GTK_BOX(hbox),
d->validate_button,
FALSE,
TRUE, 0);
3222 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3230 GtkEntryCompletion *completion = gtk_entry_completion_new();
3231 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3233 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3234 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3235 gtk_entry_completion_set_minimum_key_length(completion, 1);
3236 g_signal_connect(G_OBJECT(completion),
"match-selected", G_CALLBACK(
_match_selected_func), self);
3238 gtk_entry_set_completion(
d->entry, completion);
3239 g_object_unref(completion);
3241 g_object_unref(
d->completion_store);
3244 d->manage_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3245#ifdef GDK_WINDOWING_QUARTZ
3248 gtk_window_set_title(GTK_WINDOW(
d->manage_window), _(
"manage tags"));
3252 g_signal_connect(G_OBJECT(
d->manage_window),
"delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
3256 gtk_container_add(GTK_CONTAINER(
d->manage_window), GTK_WIDGET(box));
3259 w = gtk_entry_new();
3261 gtk_entry_set_text(GTK_ENTRY(w),
"");
3262 gtk_entry_set_width_chars(GTK_ENTRY(w), 0);
3263 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"type to filter the tag dictionary below"));
3264 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY,
"edit-clear-symbolic");
3265 gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w), GTK_ENTRY_ICON_SECONDARY, _(
"clear entry"));
3266 g_signal_connect(G_OBJECT(w),
"icon-press", G_CALLBACK(
_entry_clear_icon), NULL);
3267 gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK);
3268 g_signal_connect(G_OBJECT(w),
"changed", G_CALLBACK(
_tag_name_changed), (gpointer)self);
3269 d->dict_entry = GTK_ENTRY(w);
3270 gtk_box_pack_start(box, w,
FALSE,
TRUE, 0);
3273 view = GTK_TREE_VIEW(gtk_tree_view_new());
3277 gtk_box_pack_start(box, w,
TRUE,
TRUE, 0);
3278 d->dictionary_view =
view;
3279 gtk_tree_view_set_enable_search(
view,
FALSE);
3280 gtk_tree_view_set_headers_visible(
view,
FALSE);
3282 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3289 d->dictionary_liststore = liststore;
3290 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
3292 d->dictionary_listfilter = GTK_TREE_MODEL_FILTER(
model);
3294 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
3297 d->dictionary_treestore = treestore;
3298 model = gtk_tree_model_filter_new(GTK_TREE_MODEL(treestore), NULL);
3300 d->dictionary_treefilter = GTK_TREE_MODEL_FILTER(
model);
3302 col = gtk_tree_view_column_new();
3303 gtk_tree_view_append_column(
view, col);
3304 renderer = gtk_cell_renderer_text_new();
3305 g_object_set(renderer,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3306 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3308 gtk_tree_view_set_expander_column(
view, col);
3310 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(
view), GTK_SELECTION_MULTIPLE);
3311 gtk_widget_set_tooltip_text(GTK_WIDGET(
view), _(
"tag dictionary,"
3312 "\nright-click to create, edit, delete tags,"
3313 "\nselect several tags and right-click to delete them in bulk,"
3314 "\nshift+click to fully expand the selected tag,"
3315 "\nctrl-scroll to resize the window"));
3319 gtk_tree_view_set_model(
view, GTK_TREE_MODEL(
d->dictionary_listfilter));
3320 g_object_unref(
d->dictionary_listfilter);
3321 g_object_set(G_OBJECT(
view),
"has-tooltip",
TRUE, NULL);
3327 d->drag.path = NULL;
3328 d->drag.tagname = NULL;
3329 d->drag.scroll_timeout = 0;
3330 d->drag.expand_timeout = 0;
3332 d->drag.tag_source =
FALSE;
3333 gtk_drag_dest_set(GTK_WIDGET(
d->dictionary_view), GTK_DEST_DEFAULT_ALL,
3335 g_signal_connect(
d->dictionary_view,
"drag-data-get", G_CALLBACK(
_event_dnd_get), self);
3336 g_signal_connect(
d->dictionary_view,
"drag-data-received", G_CALLBACK(
_event_dnd_received), self);
3337 g_signal_connect_after(
d->dictionary_view,
"drag-begin", G_CALLBACK(
_event_dnd_begin), self);
3338 g_signal_connect_after(
d->dictionary_view,
"drag-end", G_CALLBACK(
_event_dnd_end), self);
3339 g_signal_connect(
d->dictionary_view,
"drag-motion", G_CALLBACK(
_event_dnd_motion), self);
3346 gtk_box_pack_start(hbox,
d->new_button,
TRUE,
TRUE, 0);
3349 gtk_box_pack_start(hbox,
d->import_button,
TRUE,
TRUE, 0);
3352 gtk_box_pack_start(hbox,
d->export_button,
TRUE,
TRUE, 0);
3355 _(
"toggle list / tree view"), N_(
"tree"));
3357 _(
"toggle list with / without suggestion"), N_(
"suggestion"));
3359 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
TRUE, 0);
3368 GtkWidget *lbl = gtk_label_new(_(
"suggested tags level of confidence"));
3369 gtk_widget_set_halign(lbl, GTK_ALIGN_START);
3370 gtk_widget_set_hexpand(lbl,
TRUE);
3371 GtkWidget *spin = gtk_spin_button_new_with_range(0, 100, 1);
3372 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin),
dt_conf_get_int(
"plugins/lighttable/tagging/confidence"));
3373 gtk_widget_set_tooltip_text(spin, _(
"level of confidence to include a tag in the suggestions list:"
3374 "\n0: all associated tags, 99: 99% matching tags,"
3375 "\n100: only the recently-used tags (faster)"));
3377 gtk_grid_attach(GTK_GRID(grid), lbl, 0, 0, 1, 1);
3378 gtk_grid_attach(GTK_GRID(grid), spin, 1, 0, 1, 1);
3380 GtkWidget *lbl2 = gtk_label_new(_(
"number of recently attached tags"));
3381 gtk_widget_set_halign(lbl2, GTK_ALIGN_START);
3382 gtk_widget_set_hexpand(lbl2,
TRUE);
3383 GtkWidget *spin2 = gtk_spin_button_new_with_range(-1, 1000, 1);
3384 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin2),
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags"));
3385 gtk_widget_set_tooltip_text(spin2, _(
"number of recently attached tags shown in the suggestions list"
3386 "\n(-1 disables the recent-tags list)"));
3388 gtk_grid_attach(GTK_GRID(grid), lbl2, 0, 1, 1, 1);
3389 gtk_grid_attach(GTK_GRID(grid), spin2, 1, 1, 1, 1);
3391 gtk_box_pack_start(box, grid,
FALSE,
FALSE, 0);
3395 d->dttags_check = gtk_check_button_new_with_label(_(
"Show system tags"));
3396 gtk_widget_set_tooltip_text(
d->dttags_check, _(
"show the tags automatically attached by Ansel (names starting with “Ansel|”)"));
3399 gtk_box_pack_start(GTK_BOX(self->
widget),
d->dttags_check,
FALSE,
TRUE, 0);
3401#undef NEW_TOGGLE_BUTTON
3413 d->collection = g_malloc(4096);
3414 d->collection_tags = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
3425 N_(
"Tag"), GDK_KEY_t, GDK_CONTROL_MASK,
FALSE,
3426 _(
"Opens the quick tagging entry"));
3429 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3430 _(
"Re-applies the last used tag"));
3433 N_(
"Tag"), GDK_KEY_t, GDK_CONTROL_MASK,
FALSE,
3434 _(
"Opens the quick tagging entry"));
3437 N_(
"Redo last tag"), GDK_KEY_t, GDK_MOD1_MASK,
FALSE,
3438 _(
"Re-applies the last used tag"));
3464 if(
d->manage_window) gtk_widget_destroy(
d->manage_window);
3465 if(
d->collection_tags) g_hash_table_destroy(
d->collection_tags);
3467 if(
d->attached_liststore) g_object_unref(
d->attached_liststore);
3468 if(
d->attached_treestore) g_object_unref(
d->attached_treestore);
3474 if(
d->drag.path) gtk_tree_path_free(
d->drag.path);
3486 case GDK_KEY_Escape:
3487 g_list_free(
d->floating_tag_imgs);
3488 d->floating_tag_imgs = NULL;
3489 gtk_widget_destroy(
d->floating_tag_window);
3494 case GDK_KEY_Return:
3496 const gchar *tag = gtk_entry_get_text(GTK_ENTRY(entry));
3499 g_list_free(
d->floating_tag_imgs);
3500 d->floating_tag_imgs = NULL;
3507 gtk_widget_destroy(
d->floating_tag_window);
3519 gtk_widget_destroy(GTK_WIDGET(user_data));
3528 GdkModifierType mods, gpointer user_data)
3553 GdkModifierType mods, gpointer user_data)
3559 dt_control_log(_(
"tag shortcut is not active with tag tree view. please switch to list view"));
3568 gdk_window_get_origin(gtk_widget_get_window(center), &px, &py);
3570 w = gdk_window_get_width(gtk_widget_get_window(center));
3571 h = gdk_window_get_height(gtk_widget_get_window(center));
3584 d->floating_tag_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3585#ifdef GDK_WINDOWING_QUARTZ
3589 gtk_widget_set_can_focus(
d->floating_tag_window,
TRUE);
3590 gtk_window_set_decorated(GTK_WINDOW(
d->floating_tag_window),
FALSE);
3591 gtk_window_set_type_hint(GTK_WINDOW(
d->floating_tag_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
3592 gtk_window_set_transient_for(GTK_WINDOW(
d->floating_tag_window), GTK_WINDOW(window));
3593 gtk_widget_set_opacity(
d->floating_tag_window, 0.8);
3594 gtk_window_move(GTK_WINDOW(
d->floating_tag_window),
x, y);
3599 gtk_widget_add_events(entry, GDK_FOCUS_CHANGE_MASK);
3601 GtkEntryCompletion *completion = gtk_entry_completion_new();
3602 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(
d->completion_store));
3604 gtk_entry_completion_set_inline_completion(completion,
TRUE);
3605 gtk_entry_completion_set_popup_set_width(completion,
FALSE);
3606 gtk_entry_completion_set_minimum_key_length(completion, 0);
3607 g_signal_connect(G_OBJECT(completion),
"match-selected", G_CALLBACK(
_match_selected_func), self);
3609 gtk_entry_set_completion(GTK_ENTRY(entry), completion);
3611 gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
3612 gtk_container_add(GTK_CONTAINER(
d->floating_tag_window), entry);
3616 gtk_widget_show_all(
d->floating_tag_window);
3617 gtk_widget_grab_focus(entry);
3618 gtk_window_present(GTK_WINDOW(
d->floating_tag_window));
3625 const int length =
dt_conf_get_int(
"plugins/lighttable/tagging/nb_recent_tags");
3626 if(length == -1)
return length;
3627 else if(length >= 10/2)
return length * 2;
3643 char *
p = (
char *)list;
3645 for(;*
p !=
'\0';
p++)
3653 char *list2 = g_strdup(list);
3656 p = g_strrstr(list2,
"','");
3668 GtkWidget *mi = gtk_menu_item_new_with_label(_(
"manage tags..."));
3670 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
3676 d->last_tag = g_strdup(tagnames);
3688 for(GList *tag = ntags; tag; tag = g_list_next(tag))
3690 char *escaped = sqlite3_mprintf(
"%q", (
char *)tag->data);
3691 GList *found = g_list_find_custom(tags, escaped, (GCompareFunc)g_strcmp0);
3694 tags = g_list_remove_link(tags, found);
3699 tags = g_list_prepend(tags, g_strdup(escaped));
3700 sqlite3_free(escaped);
3708 if(g_list_length(tags) > nb_recent)
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
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_new_action_shortcut(dt_accels_t *accels, gboolean(*action_callback)(GtkAccelGroup *group, GObject *acceleratable, guint keyval, GdkModifierType mods, gpointer user_data), gpointer data, 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....
GList * dt_act_on_get_images()
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
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_collection_deserialize(const char *buf)
int dt_collection_serialize(char *buf, int bufsize)
dt_collection_properties_t
void dt_image_synch_xmps(const GList *img)
void dt_image_synch_xmp(const int selected)
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)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
int32_t dt_control_get_mouse_over_id()
void dt_control_log(const char *msg,...)
void leave(dt_view_t *self)
uint32_t view(const dt_view_t *self)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
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[]
void dtgtk_cairo_paint_treelist(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_check_mark(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_plus_simple(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
void dt_gui_textview_set_padding(GtkTextView *textview)
Apply the standard recessed-input text padding to a GtkTextView.
GtkWidget * dt_ui_scroll_wrap(GtkWidget *w, gint min_size, char *config_str, dt_ui_resize_mode_t mode)
Wrap a scrollable content widget in a recessed, vertically resizable scrolled window.
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
GtkWidget * dt_ui_center(dt_ui_t *ui)
get the center drawable widget
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
GtkCellRenderer * dtgtk_cell_renderer_button_new(void)
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))
dt_mipmap_buffer_dsc_flags flags
void dt_osx_disallow_fullscreen(GtkWidget *widget)
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,...)
@ 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)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
struct dt_gui_gtk_t * gui
struct dt_selection_t * selection
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
GtkAccelGroup * map_accels
GtkAccelGroup * lighttable_accels
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)
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 _entry_clear_icon(GtkEntry *entry, GtkEntryIconPosition pos, GdkEvent *event, gpointer user_data)
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 _refresh_completion_store(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 gboolean _match_selected_func(GtkEntryCompletion *completion, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
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)
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