154#include <gio/gunixmounts.h>
156#ifdef GDK_WINDOWING_QUARTZ
163#define PARAM_STRING_SIZE 256
278static void tag_changed(gpointer instance, gpointer self);
325static const char *
const OP_TOKENS[] = {
"",
"<",
"<=",
">",
">=",
"<>" };
326static const char *
const OP_LABELS[] = {
"=",
"<",
"≤",
">",
"≥",
"≠" };
327#define COLLECT_N_OPS ((int)G_N_ELEMENTS(OP_TOKENS))
333 *
value = text ? text :
"";
335 if(g_str_has_prefix(text,
"<="))
340 else if(g_str_has_prefix(text,
">="))
345 else if(g_str_has_prefix(text,
"<>"))
350 else if(g_str_has_prefix(text,
"<"))
355 else if(g_str_has_prefix(text,
">"))
360 else if(g_str_has_prefix(text,
"="))
365 while(**
value ==
' ') (*value)++;
379 static const char *
v[] = {
"lighttable",
"map",
"print", NULL };
394 const int old_version,
int *new_version,
size_t *new_size)
396 if(old_version == 1 || old_version == 2)
409#define CLEAR_PARAMS(r) \
411 memset(¶ms, 0, sizeof(params)); \
413 params.rule[0].mode = 0; \
414 params.rule[0].item = r; \
417 GDateTime *now = g_date_time_new_now_local();
418 char *datetime_today = g_date_time_format(now,
"%Y:%m:%d");
419 GDateTime *gdt = g_date_time_add_days(now, -1);
420 char *datetime_24hrs = g_date_time_format(gdt,
"> %Y:%m:%d %H:%M");
421 g_date_time_unref(gdt);
422 gdt = g_date_time_add_days(now, -30);
423 char *datetime_30d = g_date_time_format(gdt,
"> %Y:%m:%d");
424 g_date_time_unref(gdt);
425 g_date_time_unref(now);
475 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/item%1d",
n);
482 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/item%1d",
n);
489 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/mode%1d",
n);
496 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/mode%1d",
n);
503 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/recursive%1d",
n);
510 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/recursive%1d",
n);
517 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/string%1d",
n);
524 s[strlen(s) - 1] =
'\0';
534 snprintf(
k,
sizeof(
k),
"plugins/lighttable/collect/string%1d",
n);
543 const char *val = gtk_entry_get_text(GTK_ENTRY(dr->
text));
548 s = g_strconcat(
OP_TOKENS[idx], val, NULL);
560 const gboolean folders_visible =
d->folders_controls && gtk_widget_get_visible(
d->folders_controls);
573 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
574 g_signal_handlers_block_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
581 gtk_combo_box_set_active(GTK_COMBO_BOX(dr->
op_combo), idx);
582 gtk_entry_set_text(GTK_ENTRY(dr->
text), val);
586 gtk_entry_set_text(GTK_ENTRY(dr->
text), text);
589 gtk_editable_set_position(GTK_EDITABLE(dr->
text), -1);
592 g_signal_handlers_unblock_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
593 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
613 d->has_last_folders =
TRUE;
616 d->has_last_folders =
FALSE;
638 return d->rule +
d->active_rule;
644 d->active_rule = CLAMP(
d->active_rule, 0,
d->nb_rules - 1);
653 for(
int i = 0;
i <
n;
i++)
661 && !g_str_has_suffix(s,
"*") && !g_str_has_suffix(s,
"%"))
663 gchar *s2 = g_strconcat(s,
"*", NULL);
677 void *
p = malloc(*
size);
685 for(uint32_t
i = 0;
i <
p->rules;
i++)
732#define ADD_COLLECT_ENTRY(value) \
733 dt_bauhaus_combobox_add_full(w, dt_collection_name(value), DT_BAUHAUS_COMBOBOX_ALIGN_RIGHT, \
734 GUINT_TO_POINTER(value + 1), NULL, TRUE)
745 gchar *setting = g_strdup_printf(
"plugins/lighttable/metadata/%s_flag", name_);
774#undef ADD_COLLECT_ENTRY
784 for(; *list; list++) length++;
794 char **tokens = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
797 if(!(g_ascii_isalpha(tokens[0][0]) && tokens[0][strlen(tokens[0]) - 1] ==
':'))
804 const unsigned int size = g_strv_length(tokens);
805 result = malloc(
sizeof(
char *) *
size);
806 for(
unsigned int i = 0;
i <
size;
i++) result[
i] = tokens[
i + 1];
839 gchar *folded = g_utf8_casefold(tag, -1);
840 const size_t len = strlen(folded);
841 char *result = g_malloc(len + 2);
842 if(!g_strcmp0(tag, _(
"not tagged")))
844 else if(g_str_has_prefix(tag,
"darktable|"))
848 memcpy(result + 1, folded, len + 1);
849 for(
char *iter = result + 1; *iter; iter++)
850 if(*iter ==
'|') *iter =
'\1';
856 GtkTreeIter *iter, gpointer data)
862 g_object_set(renderer,
"text",
name, NULL);
865 gchar *coltext = g_strdup_printf(
"%s (%d)",
name, count);
866 g_object_set(renderer,
"text", coltext, NULL);
877 gboolean visible =
FALSE;
878 gboolean was_visible;
881 gchar *haystack = g_utf8_strdown(str, -1);
889 gchar *
operator, * number, *number2;
893 const float nb1 = g_strtod(number, NULL);
894 const float nb2 = g_strtod(haystack, NULL);
895 if(
operator&& strcmp(
operator,
">") == 0)
896 visible = (nb2 > nb1);
897 else if(
operator&& strcmp(
operator,
">=") == 0)
898 visible = (nb2 >= nb1);
899 else if(
operator&& strcmp(
operator,
"<") == 0)
900 visible = (nb2 < nb1);
901 else if(
operator&& strcmp(
operator,
"<=") == 0)
902 visible = (nb2 <= nb1);
903 else if(
operator&& strcmp(
operator,
"<>") == 0)
904 visible = (nb1 != nb2);
905 else if(
operator&& number2 && strcmp(
operator,
"[]") == 0)
907 const float nb3 = g_strtod(number2, NULL);
908 visible = (nb2 >= nb1 && nb2 <= nb3);
911 visible = (nb1 == nb2);
920 for(
const GList *l = list; l; l = g_list_next(l))
922 const char *
name = (
char *)l->data;
923 if((visible = (g_strrstr(haystack,
name + (
name[0] ==
'%')) != NULL)))
break;
929 if(needle[0] ==
'%') needle++;
933 visible = (strchr(haystack, needle[0]) != NULL);
935 visible = (g_strrstr(haystack, needle) != NULL);
940 if(visible != was_visible)
951 if(g_str_has_suffix(needle,
"%")) needle[strlen(needle) - 1] =
'\0';
952 if(g_str_has_suffix(haystack,
"%")) haystack[strlen(haystack) - 1] =
'\0';
955 if(g_str_has_suffix(needle,
"*")) needle[strlen(needle) - 1] =
'\0';
956 if(g_str_has_suffix(needle,
"|")) needle[strlen(needle) - 1] =
'\0';
957 if(g_str_has_suffix(haystack,
"|")) haystack[strlen(haystack) - 1] =
'\0';
961 if(g_str_has_suffix(needle,
"*")) needle[strlen(needle) - 1] =
'\0';
962 if(g_str_has_suffix(needle,
"/")) needle[strlen(needle) - 1] =
'\0';
963 if(g_str_has_suffix(haystack,
"/")) haystack[strlen(haystack) - 1] =
'\0';
967 if(g_str_has_suffix(needle,
":")) needle[strlen(needle) - 1] =
'\0';
968 if(g_str_has_suffix(haystack,
":")) haystack[strlen(haystack) - 1] =
'\0';
977 gboolean cur_state, visible;
984 gchar *haystack = g_utf8_strdown(str, -1),
985 *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
987 visible = (g_strrstr(haystack, needle) != NULL);
999 GtkTreeIter parent, child = *iter;
1002 while(gtk_tree_model_iter_parent(
model, &parent, &child))
1024 for(
const char *
p = s;
p && *
p &&
n < 14;
p++)
1025 if(g_ascii_isdigit(*
p)) digits[
n++] = *
p;
1026 while(
n < 14) digits[
n++] = pad;
1028 return g_ascii_strtoull(digits, NULL, 10);
1044 const guint64 node_lo =
_date_key(str,
'0');
1045 const guint64 node_hi =
_date_key(str,
'9');
1047 const gboolean visible = (node_hi >=
r->lo) && (node_lo <= r->hi);
1052static gboolean
list_select(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1059 gchar *haystack = g_utf8_strdown(str, -1);
1060 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
1061 if(strcmp(haystack, needle) == 0)
1063 gtk_tree_selection_select_path(gtk_tree_view_get_selection(
d->view), path);
1064 gtk_tree_view_scroll_to_cell(
d->view, path, NULL,
FALSE, 0.2, 0);
1072static gboolean
range_select(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1078 gchar *haystack = g_utf8_strdown(str, -1);
1079 gchar *needle = range->
path1 ? g_utf8_strdown(range->
stop, -1) : g_utf8_strdown(range->
start, -1);
1080 if(strcmp(haystack, needle) == 0)
1084 range->
path2 = gtk_tree_path_copy(path);
1091 range->
path1 = gtk_tree_path_copy(path);
1099static gboolean
tree_expand(GtkTreeModel *
model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1103 gchar *str = NULL, *txt = NULL;
1104 gboolean startwildcard =
FALSE, expanded =
FALSE;
1107 gchar *haystack = g_utf8_strdown(str, -1);
1108 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
1109 gchar *txt2 = g_utf8_strdown(txt, -1);
1116 if(g_str_has_prefix(needle,
"%")) startwildcard =
TRUE;
1119 if(reveal && g_strrstr(txt2, needle) != NULL)
1121 gtk_tree_view_expand_to_path(
d->view, path);
1125 if(strlen(needle) == 0)
1129 else if(strcmp(haystack, needle) == 0)
1131 gtk_tree_view_expand_to_path(
d->view, path);
1132 gtk_tree_selection_select_path(gtk_tree_view_get_selection(
d->view), path);
1133 gtk_tree_view_scroll_to_cell(
d->view, path, NULL,
FALSE, 0.2, 0);
1136 else if(startwildcard && g_strrstr(haystack, needle + 1) != NULL)
1138 gtk_tree_view_expand_to_path(
d->view, path);
1143 gtk_tree_view_expand_to_path(
d->view, path);
1160 GtkTreeIter child, iter;
1162 while(gtk_tree_model_iter_n_children(
model, level > 0 ? &iter : NULL) > 0)
1172 if(!gtk_tree_model_iter_parent(
model, &child, &iter)) level = 0;
1177 if(gtk_tree_model_iter_n_children(
model, level > 0 ? &iter : NULL) != 1)
break;
1178 gtk_tree_model_iter_children(
model, &child, level > 0 ? &iter : NULL);
1182 if(level <= 0)
return NULL;
1184 if(gtk_tree_model_iter_n_children(
model, &iter) == 0 && gtk_tree_model_iter_parent(
model, &child, &iter))
1185 return gtk_tree_model_get_path(
model, &child);
1186 return gtk_tree_model_get_path(
model, &iter);
1195 GtkTreeModel *filter = gtk_tree_model_filter_new(
model, path);
1196 gtk_tree_path_free(path);
1206 GHashTable *set = (GHashTable *)data;
1207 GtkTreeModel *
model = gtk_tree_view_get_model(
view);
1209 if(gtk_tree_model_get_iter(
model, &it, path))
1213 if(
p) g_hash_table_add(set,
p);
1228 if(
p && g_hash_table_contains(c->set,
p)) gtk_tree_view_expand_to_path(c->d->view, path);
1239 return g_strsplit(
name,
"|", -1);
1247 GtkTreeIter parent, child = *leaf;
1248 while(gtk_tree_model_iter_parent(
model, &parent, &child))
1260 GtkTreeIter *uncategorized, guint *index,
int count)
1262 if(strchr(
name,
'|') != NULL)
return FALSE;
1264 char *next_name = g_strdup(next_name_raw ? next_name_raw :
"");
1265 if(strlen(next_name) >= strlen(
name) + 1 && next_name[strlen(
name)] ==
'|') next_name[strlen(
name)] =
'\0';
1266 const gboolean leaf_toplevel = g_strcmp0(next_name,
name) && g_strcmp0(
name, _(
"not tagged"));
1268 if(!leaf_toplevel)
return FALSE;
1270 if(!uncategorized->stamp)
1292 GList *sorted_names = NULL;
1294 for(GList *
v = values;
v;
v = g_list_next(
v))
1301 char *name_folded = g_utf8_casefold(
name, -1);
1302 char *name_folded_slash = g_strconcat(name_folded, G_DIR_SEPARATOR_S, NULL);
1303 collate_key = g_utf8_collate_key_for_filename(name_folded_slash, -1);
1315 sorted_names = g_list_prepend(sorted_names, tuple);
1320 if(!
dt_conf_get_bool(
"plugins/collect/descending")) sorted_names = g_list_reverse(sorted_names);
1321 return sorted_names;
1328 gboolean no_uncategorized,
const char *format_separator)
1331 GtkTreeIter uncategorized = { 0 };
1332 char **last_tokens = NULL;
1333 int last_tokens_length = 0;
1334 GtkTreeIter last_parent = { 0 };
1337 for(GList *names = sorted_names; names; names = g_list_next(names))
1341 const int count = tuple->
count;
1342 const int status = tuple->
status;
1345 const char *next_name = names->next ? ((
name_key_tuple_t *)names->next->data)->name : NULL;
1352 GtkTreeIter parent = last_parent;
1354 int common_length = 0;
1357 while(tokens[common_length] && last_tokens[common_length]
1358 && !g_strcmp0(tokens[common_length], last_tokens[common_length]))
1360 for(
int i = common_length;
i < last_tokens_length;
i++)
1362 gtk_tree_model_iter_parent(
model, &parent, &last_parent);
1363 last_parent = parent;
1371 for(
int i = 0;
i < common_length;
i++) pth =
dt_util_dstrcat(pth, format_separator, tokens[
i]);
1373 for(
char **token = &tokens[common_length]; *token; token++)
1379 gchar *pth2 = g_strdup(pth);
1380 pth2[strlen(pth2) - 1] =
'\0';
1381 const gboolean leaf = !*(token + 1);
1382 gtk_tree_store_insert_with_values(
store, &iter, common_length > 0 ? &parent : NULL, 0,
1398 if(last_tokens) g_strfreev(last_tokens);
1399 last_tokens = tokens;
1400 last_parent = parent;
1401 last_tokens_length = tokens_length;
1403 g_strfreev(last_tokens);
1411 char *format_separator =
"";
1416 format_separator =
"%s" G_DIR_SEPARATOR_S;
1420 format_separator =
"%s|";
1428 format_separator =
"%s:";
1434 GtkTreeModel *
model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
d->treefilter));
1435 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(
model), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1436 GTK_SORT_ASCENDING);
1438 GHashTable *saved_expanded = NULL;
1440 if(
d->view_rule != property)
1443 saved_expanded = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1446 g_object_ref(
model);
1447 g_object_unref(
d->treefilter);
1448 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view), NULL);
1449 gtk_tree_store_clear(GTK_TREE_STORE(
model));
1450 gtk_widget_hide(GTK_WIDGET(
d->view));
1462 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->view));
1463 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1465 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view),
d->treefilter);
1466 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
1467 gtk_widget_show_all(GTK_WIDGET(
d->view));
1469 g_object_unref(
model);
1470 d->view_rule = property;
1479 GRegex *regex = g_regex_new(
"^\\s*\\[\\s*(.*)\\s*;\\s*(.*)\\s*\\]\\s*$", 0, 0, NULL);
1480 GMatchInfo *match_info;
1481 g_regex_match_full(regex, gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1, 0, 0, &match_info, NULL);
1482 if(g_match_info_get_match_count(match_info) == 3)
1485 range->
start = g_match_info_fetch(match_info, 2);
1486 range->
stop = g_match_info_fetch(match_info, 1);
1488 g_match_info_free(match_info);
1489 g_regex_unref(regex);
1504 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(
d->view));
1509 gtk_tree_view_expand_all(
d->view);
1511 gtk_tree_view_collapse_all(
d->view);
1512 else if(saved_expanded)
1517 if(saved_expanded) g_hash_table_destroy(saved_expanded);
1522 gtk_tree_model_foreach(
d->treefilter, (GtkTreeModelForeachFunc)
range_select, range);
1524 gtk_tree_selection_select_range(gtk_tree_view_get_selection(
d->view), range->
path1, range->
path2);
1527 gtk_tree_path_free(range->
path1);
1528 gtk_tree_path_free(range->
path2);
1532 gtk_tree_model_foreach(
d->treefilter, (GtkTreeModelForeachFunc)
tree_expand, dr);
1543 GtkTreeModel *
model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(
d->listfilter));
1544 if(
d->view_rule != property)
1547 g_object_unref(
d->listfilter);
1548 g_object_ref(
model);
1549 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view), NULL);
1550 gtk_list_store_clear(GTK_LIST_STORE(
model));
1551 gtk_widget_hide(GTK_WIDGET(
d->view));
1554 for(GList *
v = values;
v;
v = g_list_next(
v))
1563 gchar *text = g_strdup(
value);
1565 while(!g_utf8_validate(ptr, -1, (
const gchar **)&ptr)) ptr[0] =
'?';
1566 gchar *escaped_text = g_markup_escape_text(text, -1);
1568 gtk_list_store_append(GTK_LIST_STORE(
model), &iter);
1582 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
d->view));
1584 gtk_tree_selection_set_mode(selection, multi ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
1586 gtk_tree_view_set_model(GTK_TREE_VIEW(
d->view),
d->listfilter);
1587 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
1588 gtk_widget_show_all(GTK_WIDGET(
d->view));
1589 g_object_unref(
model);
1590 d->view_rule = property;
1603 gchar *needle = g_utf8_strdown(gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1);
1604 if(g_str_has_suffix(needle,
"%")) needle[strlen(needle) - 1] =
'\0';
1610 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(
d->view));
1614 GRegex *regex = g_regex_new(
"^\\s*\\[\\s*(.*)\\s*;\\s*(.*)\\s*\\]\\s*$", 0, 0, NULL);
1615 GMatchInfo *match_info;
1616 g_regex_match_full(regex, gtk_entry_get_text(GTK_ENTRY(dr->
text)), -1, 0, 0, &match_info, NULL);
1617 const int match_count = g_match_info_get_match_count(match_info);
1618 if(match_count == 3)
1621 range->
start = g_match_info_fetch(match_info, 1);
1622 range->
stop = g_match_info_fetch(match_info, 2);
1623 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
range_select, range);
1625 gtk_tree_selection_select_range(gtk_tree_view_get_selection(
d->view), range->
path1, range->
path2);
1628 gtk_tree_path_free(range->
path1);
1629 gtk_tree_path_free(range->
path2);
1633 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
list_select, dr);
1634 g_match_info_free(match_info);
1635 g_regex_unref(regex);
1638 gtk_tree_model_foreach(
d->listfilter, (GtkTreeModelForeachFunc)
list_select, dr);
1662 gchar *
n = g_strconcat(text,
"|%", NULL);
1668 gchar *
n = g_strconcat(text,
"*", NULL);
1686 gboolean descending =
FALSE;
1701 GtkTreeModel *
model = NULL;
1702 GtkTreeSelection *selection = gtk_tree_view_get_selection(
view);
1703 const int n_selected = gtk_tree_selection_count_selected_rows(selection);
1704 if(n_selected < 1)
return;
1706 GList *sels = gtk_tree_selection_get_selected_rows(selection, &
model);
1707 GtkTreePath *path1 = (GtkTreePath *)sels->data;
1708 if(!gtk_tree_model_get_iter(
model, &iter, path1))
1710 g_list_free_full(sels, (GDestroyNotify)gtk_tree_path_free);
1720 gboolean order_request =
FALSE;
1724 if(text && strlen(text) > 0)
1730 GtkTreePath *path2 = (GtkTreePath *)g_list_last(sels)->data;
1731 if(gtk_tree_model_get_iter(
model, &iter2, path2))
1736 ? g_strdup_printf(
"[%s;%s]", text2, text)
1737 : g_strdup_printf(
"[%s;%s]", text, text2);
1750 if(gtk_tree_model_iter_has_child(
model, &iter))
1758 g_list_free_full(sels, (GDestroyNotify)gtk_tree_path_free);
1760 g_signal_handlers_block_matched(active_rule->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
1761 gtk_entry_set_text(GTK_ENTRY(active_rule->
text), text);
1762 gtk_editable_set_position(GTK_EDITABLE(active_rule->
text), -1);
1763 g_signal_handlers_unblock_matched(active_rule->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
1813 GtkTreeModel *
model = NULL;
1814 GList *paths = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(
d->view), &
model);
1816 for(GList *l = paths; l; l = g_list_next(l))
1819 if(gtk_tree_model_get_iter(
model, &it, (GtkTreePath *)l->data))
1826 g_list_free_full(paths, (GDestroyNotify)gtk_tree_path_free);
1827 return g_list_reverse(
out);
1834 GHashTable *seen = g_hash_table_new(g_direct_hash, g_direct_equal);
1836 for(GList *l = rows; l; l = g_list_next(l))
1842 for(GList *
i = ids;
i;
i = g_list_next(
i))
1843 if(!g_hash_table_contains(seen,
i->data))
1845 g_hash_table_add(seen,
i->data);
1846 out = g_list_prepend(
out,
i->data);
1850 g_hash_table_destroy(seen);
1851 return g_list_reverse(
out);
1855static gboolean
_confirm(
const char *title,
const char *message)
1858 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
1859 GTK_BUTTONS_YES_NO,
"%s", message);
1860 gtk_window_set_title(GTK_WINDOW(dialog), title);
1861#ifdef GDK_WINDOWING_QUARTZ
1864 const gint res = gtk_dialog_run(GTK_DIALOG(dialog));
1865 gtk_widget_destroy(dialog);
1866 return res == GTK_RESPONSE_YES;
1869static gchar *
_ask_text(
const char *title,
const char *initial)
1873 = gtk_dialog_new_with_buttons(title, GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, _(
"_cancel"),
1874 GTK_RESPONSE_CANCEL, _(
"_ok"), GTK_RESPONSE_ACCEPT, NULL);
1875 GtkWidget *area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1877 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1878 if(initial) gtk_entry_set_text(GTK_ENTRY(entry), initial);
1879 gtk_box_pack_start(GTK_BOX(area), entry,
TRUE,
TRUE, 0);
1880 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1882 gtk_widget_show_all(dialog);
1883#ifdef GDK_WINDOWING_QUARTZ
1886 gchar *result = NULL;
1887 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1889 const gchar *
t = gtk_entry_get_text(GTK_ENTRY(entry));
1890 if(
t && *
t) result = g_strdup(
t);
1892 gtk_widget_destroy(dialog);
1908 g_list_free(imgids);
1915 const int n = g_list_length(rows);
1916 const gboolean single = (
n == 1);
1919 GtkFileChooserNative *
fc = gtk_file_chooser_native_new(
1920 single ? _(
"select the new location of this folder") : _(
"select the new parent folder"), GTK_WINDOW(win),
1921 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, _(
"_open"), _(
"_cancel"));
1922 if(single && first->
path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(
fc), first->
path);
1924 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(
fc)) == GTK_RESPONSE_ACCEPT)
1926 gchar *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(
fc));
1927 gchar *chosen = g_filename_from_uri(uri, NULL, NULL);
1931 for(GList *l = rows; l; l = g_list_next(l))
1939 gchar *base = g_path_get_basename(
r->path);
1940 gchar *dest = g_build_filename(chosen, base, NULL);
1960 const int n = g_list_length(rows);
1961 gchar *msg = g_strdup_printf(ngettext(
"Delete %d tag and detach it from all images?",
1962 "Delete %d tags and detach them from all images?",
n),
1964 const gboolean ok =
_confirm(_(
"delete tags"), msg);
1968 for(GList *l = rows; l; l = g_list_next(l))
1986 gchar *newname =
_ask_text(_(
"rename tag"),
r->path);
2017 const int n = g_list_length(
p->imgids);
2018 const float total = (
n > 0) ? (
float)(
n * (
max + 1)) : 1.0f;
2023 const int32_t imgid = GPOINTER_TO_INT(l->data);
2102 const collect_action_t *act = g_object_get_data(G_OBJECT(mi),
"collect-action");
2104 if(rows) act->
run(
d, rows);
2110 const int property =
d->view_rule;
2111 const int n = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(
d->view));
2116 for(
size_t i = 0;
i < G_N_ELEMENTS(
ACTIONS);
i++)
2119 if(!act->
enabled(property,
n))
continue;
2120 if(!act->
multi &&
n > 1)
continue;
2122 g_object_set_data(G_OBJECT(mi),
"collect-action", (gpointer)act);
2124 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2129 gtk_widget_show_all(menu);
2130 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2133 gtk_widget_destroy(menu);
2146 const int n = g_list_length(imgs);
2147 gchar *msg = g_strdup_printf(ngettext(
"Physically move %d image to\n%s ?\n\nFiles are moved on disk.",
2148 "Physically move %d images to\n%s ?\n\nFiles are moved on disk.",
n),
2150 const gboolean ok =
_confirm(_(
"move images"), msg);
2152 if(!ok)
return FALSE;
2157 const int32_t filmid = film.
id;
2166 for(GList *l = imgs; l; l = g_list_next(l))
2167 if(
dt_image_move(GPOINTER_TO_INT(l->data), filmid) != -1) moved++;
2184 if(!tagid)
return FALSE;
2209 const int imgs_nb = gtk_selection_data_get_length(sel) / (int)
sizeof(uint32_t);
2210 if(imgs_nb <= 0)
return FALSE;
2212 GtkTreePath *path = NULL;
2213 if(!gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
return FALSE;
2215 GtkTreeModel *
model = gtk_tree_view_get_model(tree);
2217 gboolean ok =
FALSE;
2218 if(gtk_tree_model_get_iter(
model, &iter, path))
2220 const uint32_t *imgt = (
const uint32_t *)gtk_selection_data_get_data(sel);
2222 for(
int i = 0;
i < imgs_nb;
i++) imgs = g_list_prepend(imgs, GINT_TO_POINTER((
int)imgt[
i]));
2224 gchar *rowpath = NULL;
2230 gtk_tree_path_free(path);
2247 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2248 GtkTreePath *path = NULL;
2250 && gtk_tree_view_get_path_at_pos(tree,
x, y, &path, NULL, NULL, NULL))
2252 gtk_tree_view_set_drag_dest_row(tree, path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
2253 gtk_tree_path_free(path);
2254 gdk_drag_status(context, GDK_ACTION_MOVE, time);
2258 gtk_tree_view_set_drag_dest_row(tree, NULL, 0);
2259 gdk_drag_status(context, 0, time);
2266 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), NULL, 0);
2270 GtkSelectionData *selection_data, guint target_type, guint time,
2273 GtkTreeView *tree = GTK_TREE_VIEW(widget);
2274 g_signal_stop_emission_by_name(tree,
"drag-data-received");
2275 gtk_tree_view_set_drag_dest_row(tree, NULL, 0);
2279 d->suppress_row_activated =
TRUE;
2283 gtk_drag_finish(context, success,
FALSE, time);
2290 if(event->button != 3 || event->type != GDK_BUTTON_PRESS)
return FALSE;
2293 GtkTreeView *
view = GTK_TREE_VIEW(treeview);
2294 GtkTreeSelection *sel = gtk_tree_view_get_selection(
view);
2298 GtkTreePath *path = NULL;
2299 if(gtk_tree_view_get_path_at_pos(
view, (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL) && path)
2301 if(!gtk_tree_selection_path_is_selected(sel, path))
2303 gtk_tree_selection_unselect_all(sel);
2304 gtk_tree_selection_select_path(sel, path);
2306 gtk_tree_path_free(path);
2310 if(gtk_tree_selection_count_selected_rows(sel) < 1)
return FALSE;
2324 if(
d->suppress_row_activated)
return;
2326 GdkEvent *ev = gtk_get_current_event();
2330 = (ev && (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE))
2331 ? (GdkEventButton *)ev
2334 if(ev) gdk_event_free(ev);
2340 gtk_tree_view_scroll_to_cell(
view, path, NULL,
TRUE, 0.0, 0.0);
2351 gtk_widget_set_tooltip_text(dr->
text, _(
"use <, <=, >, >=, <>, =, [;] as operators"));
2353 gtk_widget_set_tooltip_text(dr->
text, _(
"use <, <=, >, >=, <>, =, [;] as operators\n"
2354 "star rating: 0-5\n"
2355 "rejected images: -1"));
2357 gtk_widget_set_tooltip_text(dr->
text,
2358 _(
"use <, <=, >, >=, <>, =, [;] as operators\n"
2359 "type dates in the form: YYYY:MM:DD hh:mm:ss.sss (only the year is mandatory)"));
2362 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard and `,' to separate values"));
2365 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard\n"
2366 "click to include hierarchy + sub-hierarchies (suffix `*')\n"
2367 "shift+click to include only the current hierarchy (no suffix)\n"
2368 "ctrl+click to include only sub-hierarchies (suffix `|%')"));
2371 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard\n"
2372 "click to include location + sub-locations (suffix `*')\n"
2373 "shift+click to include only the current location (no suffix)\n"
2374 "ctrl+click to include only sub-locations (suffix `|%')"));
2377 gtk_widget_set_tooltip_text(dr->
text,
2378 _(
"use `%' as wildcard and append `*' to match sub-folders"));
2381 gtk_widget_set_tooltip_text(dr->
text, _(
"use `%' as wildcard"));
2383 gchar *tip = gtk_widget_get_tooltip_text(dr->
text);
2384 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
combo), tip);
2398 c->active_rule = dr->
num;
2411 c->active_rule = dr->
num;
2416 const gboolean transferable
2420 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2421 gtk_entry_set_text(GTK_ENTRY(dr->
text),
"");
2422 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2426 g_signal_handlers_block_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
2427 gtk_combo_box_set_active(GTK_COMBO_BOX(dr->
op_combo), 0);
2428 g_signal_handlers_unblock_matched(dr->
op_combo, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_op_changed, NULL);
2434 if(c->folders_controls && gtk_widget_get_visible(c->folders_controls))
2447 dr->
reveal = transferable;
2474 GtkTreeModel *
model = gtk_tree_view_get_model(GTK_TREE_VIEW(c->view));
2475 if(gtk_tree_model_iter_n_children(
model, NULL) == 1)
2478 if(gtk_tree_model_get_iter_first(
model, &iter))
2482 g_signal_handlers_block_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2483 gtk_entry_set_text(GTK_ENTRY(dr->
text), text);
2484 gtk_editable_set_position(GTK_EDITABLE(dr->
text), -1);
2485 g_signal_handlers_unblock_matched(dr->
text, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
entry_changed, NULL);
2518 const gboolean desc = gtk_toggle_button_get_active(b);
2521 gtk_widget_queue_draw(GTK_WIDGET(b));
2538 dt_conf_set_int(
"show_folder_levels", (
int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)));
2545 dt_conf_set_bool(
"plugins/lighttable/tagging/no_uncategorized", gtk_toggle_button_get_active(b));
2567 const dt_lib_collect_mode_t mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"menuitem_mode"));
2573 c->active_rule = active;
2581 const int num = dr->
num + 1;
2582 if(num < MAX_RULES && num > 0)
2583 _rule_set_mode(num, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem),
"menuitem_mode")));
2596 if(c->active_rule >= active - 1) c->active_rule = active - 2;
2623 if(event->button != 1)
return FALSE;
2629 mi = gtk_menu_item_new_with_label(_(
"clear this rule"));
2630 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2631 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_clear), dr);
2633 if(dr->
num == active - 1)
2635 mi = gtk_menu_item_new_with_label(_(
"narrow down search"));
2637 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2638 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2640 mi = gtk_menu_item_new_with_label(_(
"add more images"));
2642 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2643 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2645 mi = gtk_menu_item_new_with_label(_(
"exclude images"));
2647 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2648 g_signal_connect(G_OBJECT(mi),
"activate", G_CALLBACK(
menuitem_mode), dr);
2650 else if(dr->
num < active - 1)
2652 mi = gtk_menu_item_new_with_label(_(
"change to: and"));
2654 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2657 mi = gtk_menu_item_new_with_label(_(
"change to: or"));
2659 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2662 mi = gtk_menu_item_new_with_label(_(
"change to: except"));
2664 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
2668 gtk_widget_show_all(GTK_WIDGET(menu));
2669 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
2711 gtk_button_set_label(GTK_BUTTON(dr->
button),
"-");
2712 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule"));
2716 gtk_button_set_label(GTK_BUTTON(dr->
button),
"+");
2717 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule or add new rules"));
2725 gtk_widget_set_tooltip_text(GTK_WIDGET(dr->
button), _(
"clear this rule"));
2733 gtk_widget_set_no_show_all(
d->rule[
i].hbox,
TRUE);
2734 gtk_widget_hide(
d->rule[
i].hbox);
2736 gtk_widget_set_no_show_all(
d->folders_controls,
TRUE);
2737 gtk_widget_hide(
d->folders_controls);
2738 gtk_widget_set_no_show_all(
d->collections_controls,
TRUE);
2739 gtk_widget_hide(
d->collections_controls);
2740 gtk_widget_set_no_show_all(
d->raw_box,
TRUE);
2741 gtk_widget_hide(
d->raw_box);
2742 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
FALSE);
2743 gtk_widget_show(GTK_WIDGET(
d->view));
2760 if(
d->has_last_folders)
2762 item =
d->last_folders_item;
2777 gtk_widget_set_no_show_all(
d->rule[0].hbox,
FALSE);
2778 gtk_widget_show_all(
d->rule[0].hbox);
2779 gtk_widget_show(
d->rule[0].combo);
2780 gtk_widget_hide(
d->rule[0].button);
2781 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[0].text), _(
"Search a folder..."));
2785 gtk_widget_set_no_show_all(
d->folders_controls,
FALSE);
2786 gtk_widget_show_all(
d->folders_controls);
2789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->sort_dir), desc);
2797 gtk_spin_button_set_value(GTK_SPIN_BUTTON(
d->folder_levels),
2815 gtk_widget_set_no_show_all(
d->rule[0].hbox,
FALSE);
2816 gtk_widget_show_all(
d->rule[0].hbox);
2817 gtk_widget_hide(
d->rule[0].combo);
2818 gtk_widget_hide(
d->rule[0].button);
2819 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[0].text), _(
"Search a collection..."));
2823 gtk_widget_set_no_show_all(
d->collections_controls,
FALSE);
2824 gtk_widget_show_all(
d->collections_controls);
2825 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->no_uncategorized),
2833 gtk_widget_set_no_show_all(
d->raw_box,
FALSE);
2834 gtk_widget_show_all(
d->raw_box);
2835 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->raw_check), raw);
2840 gtk_entry_set_text(GTK_ENTRY(
d->raw_entry), s ? s :
"");
2842 gtk_widget_show(
d->raw_entry);
2843 gtk_widget_set_no_show_all(GTK_WIDGET(
d->view),
TRUE);
2844 gtk_widget_hide(GTK_WIDGET(
d->view));
2849 gtk_widget_hide(
d->raw_entry);
2850 for(
int i = 0;
i <=
d->active_rule;
i++)
2854 gtk_widget_set_no_show_all(
d->rule[
i].hbox,
FALSE);
2855 gtk_widget_show_all(
d->rule[
i].hbox);
2856 gtk_widget_show(
d->rule[
i].combo);
2857 gtk_widget_show(
d->rule[
i].button);
2859 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->rule[
i].text), _(
"Search..."));
2871 if(gtk_toggle_button_get_active(b))
2914 if(
d->view_rule != -1)
return;
2928 g_signal_handlers_block_matched(
d->notebook, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_on_tab_switch, NULL);
2929 gtk_notebook_set_current_page(GTK_NOTEBOOK(
d->notebook), tab);
2930 g_signal_handlers_unblock_matched(
d->notebook, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
_on_tab_switch, NULL);
2950 gboolean refresh =
TRUE;
2954 for(
int i = 0;
i <=
d->active_rule;
i++)
2987 gboolean uses_tag =
FALSE;
2988 for(
int i = 0;
i <
d->nb_rules;
i++)
3008static void geotag_changed(gpointer instance, GList *imgs,
const int locid, gpointer self)
3067 self->
data = (
void *)
d;
3078 dt_ui_notebook_page(GTK_NOTEBOOK(
d->notebook), _(
"Folders"), _(
"Browse and manage the folders known to Ansel"));
3080 dt_ui_notebook_page(GTK_NOTEBOOK(
d->notebook), _(
"Queries"), _(
"Build arbitrary collections"));
3081 gtk_widget_show_all(
d->notebook);
3082 gtk_box_pack_start(GTK_BOX(self->
widget),
d->notebook,
TRUE,
TRUE, 0);
3083 gtk_notebook_set_scrollable(GTK_NOTEBOOK(
d->notebook),
TRUE);
3084 g_signal_connect(G_OBJECT(
d->notebook),
"switch_page", G_CALLBACK(
_on_tab_switch), self);
3091 d->rule[
i].lib_collect = (
void *)
d;
3094 d->rule[
i].hbox = GTK_WIDGET(box);
3095 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
3096 gtk_widget_set_name(GTK_WIDGET(box),
"lib-dtbutton");
3101 g_signal_connect(G_OBJECT(
d->rule[
i].combo),
"value-changed", G_CALLBACK(
combo_changed),
d->rule +
i);
3102 gtk_box_pack_start(box,
d->rule[
i].combo,
FALSE,
FALSE, 0);
3105 gtk_box_pack_start(box, GTK_WIDGET(hbox),
FALSE,
FALSE, 0);
3108 d->rule[
i].op_combo = gtk_combo_box_text_new();
3110 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(
d->rule[
i].op_combo),
OP_LABELS[o]);
3111 gtk_combo_box_set_active(GTK_COMBO_BOX(
d->rule[
i].op_combo), 0);
3112 gtk_widget_set_no_show_all(
d->rule[
i].op_combo,
TRUE);
3113 gtk_widget_set_tooltip_text(
d->rule[
i].op_combo, _(
"comparison operator"));
3114 g_signal_connect(G_OBJECT(
d->rule[
i].op_combo),
"changed", G_CALLBACK(
_op_changed),
d->rule +
i);
3115 gtk_box_pack_start(hbox,
d->rule[
i].op_combo,
FALSE,
FALSE, 0);
3119 d->rule[
i].text = w;
3120 gtk_widget_add_events(w, GDK_FOCUS_CHANGE_MASK | GDK_KEY_PRESS_MASK);
3121 gtk_entry_set_placeholder_text(GTK_ENTRY(w), _(
"Search..."));
3122 g_signal_connect(G_OBJECT(w),
"focus-in-event", G_CALLBACK(
_entry_focus_in),
d->rule +
i);
3123 g_signal_connect(G_OBJECT(w),
"changed", G_CALLBACK(
entry_changed),
d->rule +
i);
3124 g_signal_connect(G_OBJECT(w),
"activate", G_CALLBACK(
entry_activated),
d->rule +
i);
3125 gtk_widget_set_name(GTK_WIDGET(w),
"lib-collect-entry");
3126 gtk_box_pack_start(hbox, w,
TRUE,
TRUE, 0);
3127 gtk_entry_set_width_chars(GTK_ENTRY(w), 5);
3129 d->rule[
i].button = gtk_button_new();
3130 gtk_widget_set_events(
d->rule[
i].button, GDK_BUTTON_PRESS_MASK);
3133 gtk_box_pack_start(hbox,
d->rule[
i].button,
FALSE,
FALSE, 0);
3138 d->recursive_check = gtk_check_button_new_with_label(_(
"include sub-folders"));
3141 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->recursive_check),
FALSE);
3143 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->recursive_check,
FALSE,
FALSE, 0);
3151 gtk_widget_set_valign(
d->sort_by, GTK_ALIGN_CENTER);
3152 g_signal_connect(G_OBJECT(
d->sort_by),
"value-changed", G_CALLBACK(
_sort_by_changed),
d);
3153 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->sort_by,
TRUE,
TRUE, 0);
3157 gtk_widget_set_tooltip_text(
d->sort_dir, _(
"toggle ascending / descending order"));
3159 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->sort_dir,
FALSE,
FALSE, 0);
3161 d->folder_levels = gtk_spin_button_new_with_range(1, 5, 1);
3162 gtk_widget_set_tooltip_text(
d->folder_levels,
3163 _(
"number of folder levels to show in film-roll names, from the right"));
3165 gtk_box_pack_start(GTK_BOX(
d->folders_controls),
d->folder_levels,
FALSE,
FALSE, 0);
3166 gtk_box_pack_start(GTK_BOX(self->
widget),
d->folders_controls,
FALSE,
FALSE, 0);
3170 d->no_uncategorized = gtk_check_button_new_with_label(_(
"no 'uncategorized' group"));
3171 gtk_widget_set_tooltip_text(
d->no_uncategorized,
3172 _(
"do not group childless tags under an 'uncategorized' entry"));
3174 gtk_box_pack_start(GTK_BOX(
d->collections_controls),
d->no_uncategorized,
FALSE,
FALSE, 0);
3175 gtk_box_pack_start(GTK_BOX(self->
widget),
d->collections_controls,
FALSE,
FALSE, 0);
3179 d->raw_check = gtk_check_button_new_with_label(_(
"edit as raw SQL"));
3180 g_signal_connect(G_OBJECT(
d->raw_check),
"toggled", G_CALLBACK(
_raw_toggled),
d);
3181 gtk_box_pack_start(GTK_BOX(
d->raw_box),
d->raw_check,
FALSE,
FALSE, 0);
3182 d->raw_entry = gtk_entry_new();
3183 gtk_entry_set_placeholder_text(GTK_ENTRY(
d->raw_entry),
3184 _(
"SQL WHERE expression, e.g. iso > 800 AND lens LIKE '%50mm%'"));
3187 gtk_box_pack_start(GTK_BOX(
d->raw_box),
d->raw_entry,
FALSE,
FALSE, 0);
3191 GtkTreeView *
view = GTK_TREE_VIEW(gtk_tree_view_new());
3193 gtk_tree_view_set_headers_visible(
view,
FALSE);
3194 gtk_tree_view_set_activate_on_single_click(
view,
TRUE);
3195 gtk_widget_set_can_focus(GTK_WIDGET(
view),
TRUE);
3211 GtkTreeViewColumn *col = gtk_tree_view_column_new();
3212 gtk_tree_view_append_column(
view, col);
3213 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
3214 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
3215 gtk_tree_view_column_set_cell_data_func(col, renderer,
tree_count_show, NULL, NULL);
3217 g_object_set(renderer,
"strikethrough",
TRUE,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE, (gchar *)0);
3220 GtkTreeModel *listmodel = GTK_TREE_MODEL(
3222 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT));
3223 d->listfilter = gtk_tree_model_filter_new(listmodel, NULL);
3226 GtkTreeModel *treemodel = GTK_TREE_MODEL(
3228 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INT));
3229 d->treefilter = gtk_tree_model_filter_new(treemodel, NULL);
3231 g_object_unref(treemodel);
3235 gtk_box_pack_start(GTK_BOX(self->
widget),
3247 d->vmonitor = g_volume_monitor_get();
3248 g_signal_connect(G_OBJECT(
d->vmonitor),
"mount-changed", G_CALLBACK(
_mount_changed), self);
3249 g_signal_connect(G_OBJECT(
d->vmonitor),
"mount-added", G_CALLBACK(
_mount_changed), self);
3251 d->vmonitor = g_unix_mount_monitor_get();
3252 g_signal_connect(G_OBJECT(
d->vmonitor),
"mounts-changed", G_CALLBACK(
_mount_changed), self);
3285 g_object_unref(
d->treefilter);
3286 g_object_unref(
d->listfilter);
3287 g_object_unref(
d->vmonitor);
void dt_bauhaus_combobox_clear(GtkWidget *widget)
void dt_bauhaus_combobox_set_selected_text_align(GtkWidget *widget, const dt_bauhaus_combobox_alignment_t text_align)
gboolean dt_bauhaus_combobox_set_from_value(GtkWidget *widget, int value)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_combobox_add_full(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align, gpointer data, void(free_func)(void *data), gboolean sensitive)
gpointer dt_bauhaus_combobox_get_data(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
static void get_properties(dt_lib_collect_rule_t *dr)
static gboolean _confirm(const char *title, const char *message)
void gui_reset(dt_lib_module_t *self)
int set_params(dt_lib_module_t *self, const void *params, int size)
static void _set_tooltip(dt_lib_collect_rule_t *dr)
static void _hide_all_widgets(dt_lib_collect_t *d)
static gboolean tree_expand(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void metadata_changed(gpointer instance, int type, gpointer self)
static void _folder_levels_changed(GtkWidget *spin, dt_lib_collect_t *d)
void * get_params(dt_lib_module_t *self, int *size)
static void _collect_expanded_cb(GtkTreeView *view, GtkTreePath *path, gpointer data)
static int _rule_get_mode(int n)
@ DT_LIB_COLLECT_COL_TOOLTIP
@ DT_LIB_COLLECT_COL_COUNT
@ DT_LIB_COLLECT_COL_UNREACHABLE
@ DT_LIB_COLLECT_NUM_COLS
@ DT_LIB_COLLECT_COL_FONT
@ DT_LIB_COLLECT_COL_INDEX
@ DT_LIB_COLLECT_COL_PATH
@ DT_LIB_COLLECT_COL_TEXT
@ DT_LIB_COLLECT_COL_VISIBLE
static void _view_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, dt_lib_collect_t *d)
void * legacy_params(struct dt_lib_module_t *self, const void *const old_params, const size_t old_params_size, const int old_version, int *new_version, size_t *new_size)
static void _populate_collect_combo(GtkWidget *w)
static void _mount_changed(GUnixMountMonitor *monitor, dt_lib_module_t *self)
static void geotag_changed(gpointer instance, GList *imgs, const int locid, gpointer self)
#define PARAM_STRING_SIZE
static const char * UNCATEGORIZED_TAG
static void _free_row(gpointer p)
static int _rules_count()
static GList * _collect_sorted_tree_names(int property, int rule)
static void menuitem_clear(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static void get_number_of_rules(dt_lib_collect_t *d)
static void _view_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time, dt_lib_collect_t *d)
static void _action_activate(GtkMenuItem *mi, dt_lib_collect_t *d)
static void _sort_dir_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static void _on_tab_switch(GtkNotebook *nb, GtkWidget *page, guint page_num, dt_lib_module_t *self)
static void _raw_entry_activated(GtkWidget *entry, dt_lib_collect_t *d)
static void _raw_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static char ** _split_tree_name(int property, const char *name)
static void _configure_tab(dt_lib_collect_t *d, dt_collect_tab_t tab)
static void _view_row_activated(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, dt_lib_collect_t *d)
static void _rule_set_mode(int n, int mode)
static int32_t _prerender_job(dt_job_t *job)
static void _split_operator(const char *text, int *op_idx, const char **value)
static gboolean item_is_tree(int item)
static gboolean _drop_move_to_folder(dt_lib_collect_t *d, const char *folder, GList *imgs)
static void tag_changed(gpointer instance, gpointer self)
static gboolean _view_button_pressed(GtkWidget *treeview, GdkEventButton *event, dt_lib_collect_t *d)
static gboolean _en_tags(int property, int n)
static void _build_tree_store(GtkTreeStore *store, int property, GList *sorted_names, gboolean no_uncategorized, const char *format_separator)
static gboolean list_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static int string_array_length(char **list)
static gboolean item_is_tag(int item)
static gboolean _view_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, dt_lib_collect_t *d)
static void _lib_collect_gui_update(dt_lib_module_t *self)
static gboolean _rule_get_recursive(int n)
static void _force_refresh(dt_lib_collect_t *d)
static void _op_changed(GtkWidget *w, dt_lib_collect_rule_t *dr)
static gboolean _view_popup_menu(GtkWidget *treeview, dt_lib_collect_t *d)
static void _combo_as_view_toggle(GtkWidget *combo)
static gboolean tree_match_string(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
void gui_cleanup(dt_lib_module_t *self)
static void _populate_list(dt_lib_collect_rule_t *dr)
static void row_activated(GtkTreeView *view, GtkTreePath *path, GdkEventButton *event, dt_lib_collect_t *d)
static void tree_count_show(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
static void _show_context_menu(dt_lib_collect_t *d, GdkEventButton *event)
static gboolean _drop_attach_tag(dt_lib_collect_t *d, const char *tagpath, GList *imgs)
static GList * _selected_rows(dt_lib_collect_t *d)
static char * tag_collate_key(char *tag)
static const char *const OP_LABELS[]
static gboolean _do_drop(dt_lib_collect_t *d, GtkTreeView *tree, gint x, gint y, GtkSelectionData *sel)
static void _act_tags_remove(dt_lib_collect_t *d, GList *rows)
static void _no_uncategorized_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static gboolean _clear_suppress_row_activated(gpointer d)
static gboolean _combo_set_active_collection(GtkWidget *combo, const int property)
static void _lib_collect_update_params(dt_lib_collect_t *d)
static gint sort_folder_tag(gconstpointer a, gconstpointer b)
static void _rule_set_recursive(int n, gboolean recursive)
static void menuitem_mode_change(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static void entry_activated(GtkWidget *entry, dt_lib_collect_rule_t *dr)
static gboolean item_is_folder(int item)
void init_presets(dt_lib_module_t *self)
static void _rules_set_count(int n)
static GList * _rows_to_imgids(int property, GList *rows, gboolean recursive)
static void _act_folders_remove(dt_lib_collect_t *d, GList *rows)
static void _combo_as_collections(GtkWidget *combo)
static void _view_row_expanded(GtkTreeView *view, GtkTreeIter *iter, GtkTreePath *path, dt_lib_collect_t *d)
static void _prerender_free(void *p)
static dt_lib_collect_t * get_collect(dt_lib_collect_rule_t *r)
#define ADD_COLLECT_ENTRY(value)
uint32_t container(dt_lib_module_t *self)
static gboolean _entry_focus_in(GtkWidget *w, GdkEventFocus *event, dt_lib_collect_rule_t *dr)
static int is_time_property(int property)
static dt_lib_module_t * _self()
static gboolean _restore_expanded_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void set_properties(dt_lib_collect_rule_t *dr)
static void entry_changed(GtkEntry *entry, dt_lib_collect_rule_t *dr)
static void _act_tag_rename(dt_lib_collect_t *d, GList *rows)
static void filmrolls_removed(gpointer instance, gpointer self)
static const collect_action_t ACTIONS[]
static gboolean range_select(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static void menuitem_mode(GtkMenuItem *menuitem, dt_lib_collect_rule_t *dr)
static int _rule_get_item(int n)
static void collection_updated(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, gpointer self)
static void preferences_changed(gpointer instance, gpointer self)
static void _act_folders_relocate(dt_lib_collect_t *d, GList *rows)
static void _rule_set_item(int n, int item)
static gboolean popup_button_callback(GtkWidget *widget, GdkEventButton *event, dt_lib_collect_rule_t *dr)
void gui_init(dt_lib_module_t *self)
static GtkTreeModel * _create_filtered_model(GtkTreeModel *model, dt_lib_collect_rule_t *dr)
static void _rule_set_string(int n, const char *s)
static void _commit_colllection()
const char ** views(dt_lib_module_t *self)
static gboolean _maybe_file_uncategorized(GtkTreeStore *store, const char *name, const char *next_name_raw, GtkTreeIter *uncategorized, guint *index, int count)
static gboolean list_select(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean _en_folders(int property, int n)
static void combo_changed(GtkWidget *combo, dt_lib_collect_rule_t *dr)
static void tree_set_visibility(GtkTreeModel *model, gpointer data)
static void _set_rule_button(dt_lib_collect_rule_t *dr, gboolean last, gboolean active)
static gchar * _rule_get_string(int n)
static gchar * _ask_text(const char *title, const char *initial)
static dt_lib_collect_rule_t * get_active_rule(dt_lib_collect_t *d)
static void filmrolls_updated(gpointer instance, gpointer self)
static void _strip_recursion_marker(gchar *needle, gchar *haystack, int property)
static void _act_prerender(dt_lib_collect_t *d, GList *rows)
static gboolean _en_any(int property, int n)
static void _commit_quiet()
static void _update_op_combo(dt_lib_collect_rule_t *dr)
static void _recursive_toggled(GtkToggleButton *b, dt_lib_collect_t *d)
static const char *const OP_TOKENS[]
static gboolean item_is_numeric(int item)
static GtkTreePath * _folders_root_collapse_path(GtkTreeModel *model)
static gboolean tree_range_visible(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean tree_reveal_func(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
static gboolean _en_tag_single(int property, int n)
static void update_view(dt_lib_collect_rule_t *dr)
static gboolean _en_folders_lighttable(int property, int n)
static void free_tuple(gpointer data)
static void _propagate_count_to_ancestors(GtkTreeStore *store, GtkTreeIter *leaf, int count)
static gboolean _adopt_tag_order(const char *text, int *order)
static void _sort_by_changed(GtkWidget *combo, dt_lib_collect_t *d)
static void _combo_as_full(GtkWidget *combo)
static char ** split_path(const char *path)
static guint64 _date_key(const char *s, char pad)
static int _combo_get_active_collection(GtkWidget *combo)
static gchar * _decorate_hierarchy(gchar *text, GdkEventButton *event)
static void _populate_tree(dt_lib_collect_rule_t *dr)
@ DT_LIB_COLLECT_MODE_AND_NOT
@ DT_LIB_COLLECT_MODE_AND
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
void dt_collection_set_query_flags(const dt_collection_t *collection, dt_collection_query_flags_t flags)
void dt_collection_memory_update()
void dt_collection_split_operator_number(const gchar *input, char **number1, char **number2, char **operator)
GList * dt_collection_get_images_for_rule(const dt_collection_properties_t property, const char *text, gboolean recursive)
void dt_collection_set_tag_id(dt_collection_t *collection, const uint32_t tagid)
void dt_collection_name_value_free(gpointer value)
GList * dt_collection_get_property_values(const dt_collection_properties_t property, const int rule)
dt_collection_properties_t
@ DT_COLLECTION_PROP_EXPOSURE
@ DT_COLLECTION_PROP_MODULE
@ DT_COLLECTION_PROP_RATING
@ DT_COLLECTION_PROP_QUERY
@ DT_COLLECTION_PROP_TIME
@ DT_COLLECTION_PROP_METADATA
@ DT_COLLECTION_PROP_GROUPING
@ DT_COLLECTION_PROP_FILMROLL
@ DT_COLLECTION_PROP_LENS
@ DT_COLLECTION_PROP_CAMERA
@ DT_COLLECTION_PROP_LOCAL_COPY
@ DT_COLLECTION_PROP_GEOTAGGING
@ DT_COLLECTION_PROP_FILENAME
@ DT_COLLECTION_PROP_COLORLABEL
@ DT_COLLECTION_PROP_UNDEF
@ DT_COLLECTION_PROP_ORDER
@ DT_COLLECTION_PROP_FOLDERS
@ DT_COLLECTION_PROP_APERTURE
@ DT_COLLECTION_PROP_IMPORT_TIMESTAMP
@ DT_COLLECTION_PROP_FOCAL_LENGTH
@ DT_COLLECTION_PROP_EXPORT_TIMESTAMP
@ DT_COLLECTION_PROP_CHANGE_TIMESTAMP
@ DT_COLLECTION_PROP_HISTORY
@ DT_COLLECTION_PROP_PRINT_TIMESTAMP
#define DT_COLLECTION_ORDER_FLAG
#define COLLECTION_QUERY_FULL
@ DT_COLLECTION_CHANGE_RELOAD
@ DT_COLLECTION_CHANGE_NEW_QUERY
@ DT_COLLECTION_SORT_FILENAME
@ DT_COLLECTION_SORT_NONE
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
int32_t dt_image_move(const int32_t imgid, const int32_t filmid)
const char * dt_image_film_roll_name(const char *path)
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)
gchar * dt_conf_get_string(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)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
gboolean dt_control_remove_images()
uint32_t view(const dt_view_t *self)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
void void void gboolean dt_gui_widgets_suppressed(void)
static const dt_aligned_pixel_simd_t value
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_internal[]
static const guint n_targets_internal
void dtgtk_cairo_paint_sortby(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dt_film_init(dt_film_t *film)
void dt_film_relocate(const char *old_path, const char *new_path)
int dt_film_new(dt_film_t *film, const char *directory)
int32_t dt_film_get_id(const char *folder)
void dt_film_set_folder_status()
void dt_film_cleanup(dt_film_t *film)
GtkWidget * dt_ui_notebook_page(GtkNotebook *notebook, const char *text, const char *tooltip)
GtkNotebook * dt_ui_notebook_new()
void dt_gui_refocus_center()
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....
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
dt_job_state_t dt_control_job_get_state(_dt_job_t *job)
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void * dt_control_job_get_params(const _dt_job_t *job)
void dt_control_job_set_progress(dt_job_t *job, double value)
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
gboolean dt_handle_dialog_enter(GtkWidget *widget, GdkEventKey *event, gpointer data)
void dt_lib_presets_add(const char *name, const char *plugin_name, const int32_t version, const void *params, const int32_t params_size, gboolean readonly)
float *const restrict const size_t k
void dt_mipmap_get_cache_filename(char path[PATH_MAX], const dt_mipmap_cache_t *cache, dt_mipmap_size_t mip, const int32_t imgid)
void dt_mimap_cache_evict(dt_mipmap_cache_t *cache, const int32_t imgid)
#define dt_mipmap_cache_get(A, B, C, D, E, F)
#define dt_mipmap_cache_release(A, B)
void dt_osx_disallow_fullscreen(GtkWidget *widget)
void dt_selection_select_list(struct dt_selection_t *selection, const GList *const l)
void dt_selection_clear(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_METADATA_CHANGED
This signal is raised when metadata status (shown/hidden) or value has changed.
@ DT_SIGNAL_IMAGES_ORDER_CHANGE
This signal is raised to request image order change.
@ DT_SIGNAL_FILMROLLS_CHANGED
This signal is raised when a filmroll is deleted/changed but not imported.
@ DT_SIGNAL_GEOTAG_CHANGED
This signal is raised when a geotag is added/deleted/changed
@ DT_SIGNAL_PREFERENCES_CHANGE
This signal is raised after preferences have been changed no parameters no return.
@ DT_SIGNAL_FILMROLLS_REMOVED
This signal is raised only when a filmroll is removed.
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
@ 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]
gboolean(* enabled)(int property, int n)
void(* run)(dt_lib_collect_t *d, GList *rows)
dt_mipmap_size_t max_size
struct dt_gui_gtk_t * gui
struct dt_collection_t * collection
struct dt_mipmap_cache_t * mipmap_cache
struct dt_selection_t * selection
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_view_manager_t * view_manager
struct dt_control_t * control
dt_lib_collect_params_rule_t rule[10]
GtkWidget * recursive_check
struct dt_lib_collect_params_t * params
GtkWidget * collections_controls
GtkTreeModel * treefilter
dt_lib_collect_rule_t rule[10]
GtkTreeModel * listfilter
GtkWidget * no_uncategorized
GtkWidget * folder_levels
gchar * last_folders_string
GUnixMountMonitor * vmonitor
gboolean has_last_folders
gboolean last_folders_recursive
GtkWidget * folders_controls
gboolean suppress_row_activated
struct dt_view_manager_t::@69 proxy
struct dt_lib_module_t *void(* update)(struct dt_lib_module_t *)
struct dt_view_manager_t::@69::@71 module_collect
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)
gboolean dt_util_test_image_file(const char *filename)
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER