46#ifdef GDK_WINDOWING_QUARTZ
52#include <librsvg/rsvg.h>
62#include <librsvg/rsvg-cairo.h>
185 gboolean valid =
FALSE;
187 valid = !
import->scan_state->closing &&
import->scan_state->generation ==
import->generation;
195 gtk_label_set_text(GTK_LABEL(widget), label);
208 const char *
extension = g_strrstr(pathname,
".");
220 gchar *pathname = g_file_get_path(document);
228 if(pathname && g_file_test(pathname, G_FILE_TEST_IS_REGULAR) &&
dt_import_passes_filter(import->filter_type, pathname))
230 import->files = g_list_prepend(import->files, pathname);
234 else if(pathname && g_file_test(pathname, G_FILE_TEST_IS_DIR))
244 gchar *path = g_file_get_path(
folder);
246 path ? path :
"?",
error->message);
249 import->scan_errors++;
257 GError *
error = NULL;
258 GFileEnumerator *files
259 = g_file_enumerate_children(
folder, G_FILE_ATTRIBUTE_STANDARD_NAME
"," G_FILE_ATTRIBUTE_STANDARD_TYPE,
260 G_FILE_QUERY_INFO_NONE, NULL, &
error);
270 GError *iter_error = NULL;
271 while(g_file_enumerator_iterate(files, NULL, &file, NULL, &iter_error))
280 g_object_unref(files);
294 g_object_unref(files);
305 GVfs *vfs = g_vfs_get_default();
306 for(GSList *uri = selection; uri; uri = g_slist_next(uri))
308 GFile *file = g_vfs_get_file_for_uri(vfs, (
const char *)uri->data);
310 g_object_unref(file);
313 import->files = g_list_sort(import->files, (GCompareFunc) g_strcmp0);
326 import->elements = (
import->files) ? g_list_length(import->files) : 0;
342 import->scan_errors);
345 else if(import->files)
348 import->files = NULL;
370 uint32_t generation = 0;
372 if(
d->scan_state->closing)
377 d->scan_state->generation++;
378 generation =
d->scan_state->generation;
384 dt_import_t *
import = dt_import_init(d, generation);
399 if(!filename || !g_file_test(filename, G_FILE_TEST_IS_REGULAR))
return NULL;
401 GdkPixbuf *pixbuf = NULL;
402 uint8_t *buffer = NULL;
405 char *mime_type = NULL;
406 const char *
const extension = g_strrstr(filename,
".");
418 const float ratio = ((float)th_height) / ((float)th_width);
422 th_width * th_height * 3 *
sizeof(uint8_t),
427 for(
size_t k = 0;
k < th_width * th_height;
k++)
429 const float alpha = buffer[
k * 4 + 3] > 0 ? buffer[
k * 4 + 3] / 255.0f : 1.0f;
430 rgb[
k * 3] = CLAMP((
int)roundf((buffer[
k * 4] / 255.0f * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
431 rgb[
k * 3 + 1] = CLAMP((
int)roundf((buffer[
k * 4 + 1] / 255.0f * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
432 rgb[
k * 3 + 2] = CLAMP((
int)roundf((buffer[
k * 4 + 2] / 255.0f * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
436 GdkPixbuf *tmp = gdk_pixbuf_new_from_data(
rgb, 0,
FALSE, 8, th_width, th_height,
437 th_width * 3 *
sizeof(uint8_t), NULL, NULL);
440 pixbuf = gdk_pixbuf_scale_simple(tmp, roundf((
float)
width / ratio),
height, GDK_INTERP_HYPER);
452 const gboolean use_internal_loader = !(file_type &
DT_IMAGE_RAW);
454 if(use_internal_loader)
464 const size_t pixels = (size_t)mipbuf.
width * mipbuf.
height;
468 const float *
const in = (
const float *
const)mipbuf.
buf;
470 for(
size_t k = 0;
k < pixels;
k++)
472 const float alpha = in[
k * 4 + 3] > 0.0f ?
CLAMPF(in[
k * 4 + 3], 0.0f, 1.0f) : 1.0f;
473 rgb[
k * 3] = CLAMP((
int)roundf((
CLAMPF(in[
k * 4], 0.0f, 1.0f) * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
474 rgb[
k * 3 + 1] = CLAMP((
int)roundf((
CLAMPF(in[
k * 4 + 1], 0.0f, 1.0f) * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
475 rgb[
k * 3 + 2] = CLAMP((
int)roundf((
CLAMPF(in[
k * 4 + 2], 0.0f, 1.0f) * alpha + (1.0f - alpha)) * 255.0f), 0, 255);
479 mipbuf.
width * 3 *
sizeof(uint8_t), NULL, NULL);
482 const float ratio = (float)mipbuf.
height / (
float)mipbuf.
width;
483 pixbuf = gdk_pixbuf_scale_simple(tmp, roundf((
float)
width / ratio),
height, GDK_INTERP_HYPER);
497 pixbuf = gdk_pixbuf_new_from_file_at_size(filename,
width,
height, NULL);
502 GdkPixbuf *tmp = pixbuf;
504 tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
506 tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
508 tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
510 if(pixbuf != tmp) g_object_unref(pixbuf);
525 else if(strstr(basedir,
"$(") != NULL)
557 GtkAllocation allocation;
558 gtk_widget_get_allocation(widget, &allocation);
565 gchar *text = g_strdup_printf(
"*.%s",
extension);
566 gchar *TEXT = g_utf8_strup(text, -1);
567 gtk_file_filter_add_pattern(filter, text);
568 gtk_file_filter_add_pattern(filter, TEXT);
580 GtkFileFilter *filter;
586 const int n_lists =
sizeof(lists) /
sizeof(lists[0]);
589 filter = gtk_file_filter_new();
590 gtk_file_filter_set_name(filter, _(
"All image files"));
591 for(
int l = 0; l < n_lists; l++)
592 for(
const char *
const *
i = lists[l]; *
i;
i++)
595 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
598 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(file_chooser), filter);
599 d->filter_all = filter;
602 filter = gtk_file_filter_new();
603 gtk_file_filter_set_name(filter, _(
"Raw image files"));
604 for(
int l = 0; l < n_lists; l++)
605 for(
const char *
const *
i = lists[l]; *
i;
i++)
607 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
608 d->filter_raw = filter;
611 filter = gtk_file_filter_new();
612 gtk_file_filter_set_name(filter, _(
"Raster image files"));
613 for(
int l = 0; l < n_lists; l++)
614 for(
const char *
const *
i = lists[l]; *
i;
i++)
617 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
618 d->filter_raster = filter;
622 const char *label,
const GtkAlign align,
const gboolean fixed_width,
623 const gboolean full_width)
627 gtk_label_set_max_width_chars(GTK_LABEL(w), 25);
629 gtk_label_set_ellipsize(GTK_LABEL(w), PANGO_ELLIPSIZE_END);
630 gtk_grid_attach(GTK_GRID(grid), w, column,
row, full_width ? 2 : 1, 1);
631 gtk_label_set_xalign(GTK_LABEL(w), align);
632 gtk_widget_set_halign(w, align);
633 gtk_label_set_line_wrap(GTK_LABEL(w),
TRUE);
639 GtkWidget *w = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
640 gtk_grid_attach(GTK_GRID(grid), w, 0,
row, length, 1);
654 GError *
error = NULL;
655 GFileInfo *info = g_file_query_info(file,
656 G_FILE_ATTRIBUTE_STANDARD_NAME
","
657 G_FILE_ATTRIBUTE_TIME_MODIFIED,
658 G_FILE_QUERY_INFO_NONE, NULL, &
error);
665 const guint64 datetime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
669 g_object_unref(info);
681 if(
d->closing)
return;
682 gchar *uri = gtk_file_chooser_get_preview_uri(file_chooser);
685 gtk_file_chooser_set_preview_widget_active(file_chooser,
FALSE);
689 GVfs *vfs = g_vfs_get_default();
690 GFile *in = g_vfs_get_file_for_uri(vfs, (
const char *)uri);
691 char *filename = g_file_get_path(in);
693 gboolean have_file = (!
IS_NULL_PTR(filename)) && g_file_test(filename, G_FILE_TEST_IS_REGULAR);
694 gtk_file_chooser_set_preview_widget_active(file_chooser, have_file);
700 const char *
const extension = g_strrstr(filename,
".");
704 d->path_file = g_strdup(filename);
727 gtk_image_set_from_pixbuf(GTK_IMAGE(
d->preview), pixbuf);
728 if(pixbuf) g_object_unref(pixbuf);
731 gtk_widget_show_all(
d->preview);
746 gchar *basename = g_file_get_basename(in);
750 const gboolean is_in_lib = (is_path_in_lib > -1) || (is_metadata_in_lib > -1);
756 if(is_path_in_lib > -1)
757 imgid = is_path_in_lib;
758 else if(is_metadata_in_lib > -1)
759 imgid = is_metadata_in_lib;
761 char path[512] = { 0 };
778 gchar *exposure_field = g_strdup_printf(
"%.0f ISO - f/%.1f - %s", img->
exif_iso, img->
exif_aperture, exposure);
798 gchar *path = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(file_chooser));
806 gtk_label_set_markup(
807 GTK_LABEL(
d->help_string),
808 _(
"<i>The files will be copied to the selected destination. You can rename them in batch below:</i>"));
810 gtk_label_set_markup(
811 GTK_LABEL(
d->help_string),
812 _(
"<i>The files will stay at their original location</i>"));
823 gtk_label_set_text(GTK_LABEL(
d->test_path), _(
"No copy."));
828 const char *date = gtk_entry_get_text(GTK_ENTRY(
d->datetime));
829 GList *file = g_list_prepend(NULL, g_strdup(
d->path_file));
839 gtk_label_set_text(GTK_LABEL(
d->test_path), _(
"Choose a file to see the result..."));
849 .base_folder = basedir,
857 gboolean free_after =
FALSE;
874 gchar * cut = g_strdup(g_strrstr(basedir, G_DIR_SEPARATOR_S));
875 gchar *fake_path = g_strdup(g_strrstr(_path, cut));
882 if(fake_path && fake_path[0] != 0)
885 gtk_label_set_text(GTK_LABEL(
d->test_path), _(
"Can't build a valid path."));
904 switch(
d->last_filter_type)
907 text = g_strdup(_(
"No raw file selected"));
910 text = g_strdup(_(
"No raster file selected"));
913 text = g_strdup(_(
"No file selected"));
919 switch(
d->last_filter_type)
922 text = g_strdup_printf(_(
"%i raw files selected"), elements);
925 text = g_strdup_printf(_(
"%i raster files selected"), elements);
928 text = g_strdup_printf(_(
"%i files selected"), elements);
935 gchar *warning = g_strdup_printf(ngettext(
" -- %u folder could not be scanned (permission denied?)",
936 " -- %u folders could not be scanned (permission denied?)",
937 scan_errors), scan_errors);
938 gchar *combined = g_strconcat(text, warning, NULL);
947static void _filelist_changed_callback(gpointer instance, GList *files, guint elements, guint finished, guint scan_errors, gpointer user_data)
963 switch(
d->last_filter_type)
966 fmt = _(
"Detection in progress... (%i raw files found so far)");
969 fmt = _(
"Detection in progress... (%i raster files found so far)");
972 fmt = _(
"Detection in progress... (%i files found so far)");
981 if(
d->closing)
return;
982 gtk_label_set_text(GTK_LABEL(
d->selected_files), _(
"Detecting candidate files for import..."));
986 if(
d->selection_scan_timeout_id > 0) g_source_remove(
d->selection_scan_timeout_id);
1005 if(
d->closing)
return G_SOURCE_REMOVE;
1007 return G_SOURCE_REMOVE;
1012 gboolean
state = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
1014 gtk_widget_set_visible(GTK_WIDGET(
d->grid),
state);
1015 gtk_widget_set_visible(GTK_WIDGET(
d->test_path),
state);
1028 dt_conf_set_string(
"session/base_directory_pattern", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(self)));
1034 dt_conf_set_string(
"session/sub_directory_pattern", gtk_entry_get_text(GTK_ENTRY(widget)));
1040 dt_conf_set_string(
"session/filename_pattern", gtk_entry_get_text(GTK_ENTRY(widget)));
1046 guint year, month,
day;
1047 gtk_calendar_get_date(calendar, &year, &month, &
day);
1048 GTimeZone *tz = g_time_zone_new_local();
1051 GDateTime *datetime = g_date_time_new(tz, year, month + 1,
day, 0, 0, 0.);
1052 g_time_zone_unref(tz);
1053 gchar *date = g_date_time_format(datetime,
"%F");
1054 gtk_entry_set_text(GTK_ENTRY(entry), date);
1056 g_date_time_unref(datetime);
1062 const char *date = gtk_entry_get_text(entry);
1069 gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_SECONDARY,
"dialog-error");
1070 gtk_entry_set_icon_tooltip_text(entry, GTK_ENTRY_ICON_SECONDARY,
1071 _(
"Date should follow the ISO 8601 format, like :\n"
1073 "YYYY-MM-DD HH:mm\n"
1074 "YYYY-MM-DD HH:mm:ss\n"
1075 "YYYY-MM-DDTHH:mm:ss"));
1080 gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_SECONDARY,
"");
1081 gtk_entry_set_icon_tooltip_text(entry, GTK_ENTRY_ICON_SECONDARY,
"");
1084 gtk_entry_set_icon_from_icon_name(entry, GTK_ENTRY_ICON_PRIMARY, NULL);
1092 if(g_file_test(gtk_file_chooser_get_filename(chooser), G_FILE_TEST_IS_REGULAR)
1095 gtk_dialog_response(dialog, GTK_RESPONSE_ACCEPT);
1109static void _process_file_list(gpointer instance, GList *files,
int elements, gboolean finished, guint scan_errors, gpointer user_data)
1111 if(!finished)
return;
1127 .elements = elements,
1153 case GTK_RESPONSE_ACCEPT:
1155 if(
d->selection_scan_timeout_id > 0)
1157 g_source_remove(
d->selection_scan_timeout_id);
1158 d->selection_scan_timeout_id = 0;
1173 case GTK_RESPONSE_CANCEL:
1186 d->dialog = gtk_dialog_new_with_buttons
1187 ( _(
"Ansel - Open pictures"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
1188 _(
"Cancel"), GTK_RESPONSE_CANCEL,
1189 _(
"Import"), GTK_RESPONSE_ACCEPT,
1193#ifdef GDK_WINDOWING_QUARTZ
1200 gtk_window_set_position(GTK_WINDOW(
d->dialog), GTK_WIN_POS_CENTER_ON_PARENT);
1203 gtk_window_set_default_size(GTK_WINDOW(
d->dialog),
1206 gtk_window_set_modal(GTK_WINDOW(
d->dialog),
FALSE);
1210 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(
d->dialog));
1211 g_signal_connect(
d->dialog,
"check-resize", G_CALLBACK(
_resize_dialog), NULL);
1214 d->grid = gtk_grid_new();
1215 GtkGrid *grid = GTK_GRID(
d->grid);
1218 gtk_grid_set_column_homogeneous(grid,
FALSE);
1219 gtk_grid_set_row_homogeneous(grid,
FALSE);
1223 gtk_box_pack_start(GTK_BOX(content), rbox,
TRUE,
TRUE, 0);
1226 d->file_chooser = gtk_file_chooser_widget_new(GTK_FILE_CHOOSER_ACTION_OPEN);
1227 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(
d->file_chooser),
TRUE);
1228 gtk_file_chooser_set_use_preview_label(GTK_FILE_CHOOSER(
d->file_chooser),
FALSE);
1229 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(
d->file_chooser),
1231 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(
d->file_chooser),
FALSE);
1232 gtk_box_pack_start(GTK_BOX(rbox),
d->file_chooser,
TRUE,
TRUE, 0);
1233 g_signal_connect(G_OBJECT(
d->file_chooser),
"current-folder-changed", G_CALLBACK(
_update_directory), NULL);
1234 g_signal_connect(G_OBJECT(
d->file_chooser),
"file-activated", G_CALLBACK(
_file_activated), GTK_DIALOG(
d->dialog));
1235 g_signal_connect(G_OBJECT(
d->file_chooser),
"selection-changed", G_CALLBACK(
_selection_changed),
d);
1236 g_signal_connect(G_OBJECT(
d->file_chooser),
"update-preview", G_CALLBACK(
update_preview_cb),
d);
1243 gtk_widget_set_halign(toolbox, GTK_ALIGN_END);
1245 GtkWidget *select_all = gtk_button_new_with_label(_(
"Select all"));
1246 gtk_box_pack_start(GTK_BOX(toolbox), select_all,
FALSE,
FALSE, 0);
1249 GtkWidget *select_none = gtk_button_new_with_label(_(
"Select none"));
1250 gtk_box_pack_start(GTK_BOX(toolbox), select_none,
FALSE,
FALSE, 0);
1253 GtkWidget *select_new = gtk_button_new_with_label(_(
"Select new"));
1254 gtk_box_pack_start(GTK_BOX(toolbox), select_new,
FALSE,
FALSE, 0);
1256 gtk_widget_set_tooltip_text(select_new,
1257 _(
"Selecting new files targets pictures that have never been added to the library. "
1258 "The lookup is done by searching for the original filename and date/time. "
1259 "It can detect files existing at another path, under a different name. "
1260 "False-positive can arise if two pictures have been taken at the same time with the same name."));
1262 d->selected_files = gtk_label_new(
"");
1263 gtk_box_pack_start(GTK_BOX(toolbox),
d->selected_files,
FALSE,
FALSE, 0);
1265 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(
d->file_chooser), toolbox);
1271 d->preview = gtk_image_new();
1273 gtk_box_pack_start(GTK_BOX(preview_box),
d->preview,
TRUE,
FALSE, 0);
1276 d->exif = gtk_grid_new();
1288 GtkWidget *imported_label = gtk_label_new(_(
"Imported:"));
1291 _(
"Images already in the library will not be imported again, selected or not. "
1292 "Remove them from the library first, or use the menu "
1293 "`Run \342\206\222 Resynchronize library and XMP` to update the local database from distant XMP.\n\n"
1294 "Ansel indexes images by their filename and parent folder (full path), "
1295 "not by their content. Therefore, renaming or moving images on the filesystem, "
1296 "or changing the mounting point of their external drive will make them "
1297 "look like new (unknown) images.\n\n"
1298 "If an XMP file is present alongside images, it will be imported as well, "
1299 "including the metadata and settings stored in it. If it is not what you want, "
1300 "you can reset metadata in the lighttable."));
1301 gtk_widget_set_halign(imported_label, GTK_ALIGN_END);
1302 gtk_grid_attach(GTK_GRID(
d->exif), GTK_WIDGET(help_box_inlib), 0,
EXIF_INLIB_FIELD, 1, 1);
1313 gtk_label_set_ellipsize(GTK_LABEL(
d->exif_info[
EXIF_PATH_FIELD]), PANGO_ELLIPSIZE_MIDDLE);
1315 gtk_box_pack_start(GTK_BOX(preview_box),
d->exif,
TRUE,
TRUE, 0);
1316 gtk_widget_show_all(
d->exif);
1318 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(
d->file_chooser), preview_box);
1322 GtkWidget *file_handling = gtk_label_new(
"");
1323 gtk_label_set_markup(GTK_LABEL(file_handling), _(
"<b>File handling</b>"));
1324 gtk_box_pack_start(GTK_BOX(files), GTK_WIDGET(file_handling),
FALSE,
FALSE, 0);
1327 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(
copy), NULL, _(
"Add to library"));
1328 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(
copy), NULL, _(
"Copy to disk"));
1330 gtk_box_pack_start(GTK_BOX(files), GTK_WIDGET(
copy),
FALSE,
FALSE, 0);
1333 d->help_string = gtk_label_new(
"");
1335 gtk_box_pack_start(GTK_BOX(files), GTK_WIDGET(
d->help_string),
FALSE,
FALSE, 0);
1337 gtk_box_pack_start(GTK_BOX(rbox), GTK_WIDGET(files),
FALSE,
FALSE, 0);
1340 GtkWidget *calendar_label = gtk_label_new(_(
"Project date"));
1341 gtk_widget_set_halign(calendar_label, GTK_ALIGN_START);
1342 d->datetime = gtk_entry_new();
1344 gtk_entry_set_width_chars(GTK_ENTRY(
d->datetime), 20);
1348 GDateTime *now = g_date_time_new_now_local();
1349 gchar *now_string = g_date_time_format(now,
"%F");
1350 gtk_entry_set_text(GTK_ENTRY(
d->datetime), now_string);
1354 GtkWidget *calendar = gtk_calendar_new();
1356 gtk_calendar_select_month(GTK_CALENDAR(calendar), g_date_time_get_month(now) - 1, g_date_time_get_year(now));
1357 const guint
day = g_date_time_get_day_of_month(now);
1358 gtk_calendar_select_day(GTK_CALENDAR(calendar),
day);
1359 gtk_calendar_mark_day(GTK_CALENDAR(calendar),
day);
1360 GtkBox *box_calendar =
attach_popover(
d->datetime,
"appointment-new-symbolic", calendar);
1361 g_signal_connect(G_OBJECT(calendar),
"day-selected", G_CALLBACK(
_update_date),
d->datetime);
1364 g_date_time_unref(now);
1370 gtk_widget_set_hexpand(jobcode,
TRUE);
1371 g_signal_connect(G_OBJECT(jobcode),
"changed", G_CALLBACK(
_jobcode_changed),
d);
1373 GtkWidget *jobcode_label = gtk_label_new(_(
"Jobcode"));
1374 gtk_widget_set_halign(jobcode_label, GTK_ALIGN_START);
1376 GtkWidget *base_label = gtk_label_new(_(
"Base directory of all projects"));
1377 gtk_widget_set_halign(base_label, GTK_ALIGN_START);
1379 GtkWidget *dir_label = gtk_label_new(_(
"Project directory naming pattern"));
1380 gtk_widget_set_halign(dir_label, GTK_ALIGN_START);
1382 GtkWidget *file_label = gtk_label_new(_(
"File naming pattern"));
1383 gtk_widget_set_halign(file_label, GTK_ALIGN_START);
1386 = gtk_file_chooser_button_new(_(
"Select a base directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
1387 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(base_dir),
1390 gtk_widget_set_hexpand(base_dir,
TRUE);
1392 GtkWidget *sep1 = gtk_label_new(G_DIR_SEPARATOR_S);
1393 GtkWidget *sep2 = gtk_label_new(G_DIR_SEPARATOR_S);
1395 GtkWidget *project_dir = gtk_entry_new();
1398 gtk_widget_set_hexpand(project_dir,
TRUE);
1400 gtk_widget_set_tooltip_text(project_dir, _(
"Start typing `$(` to see available variables through auto-completion"));
1406 gtk_widget_set_hexpand(file,
TRUE);
1410 GtkWidget *pattern_label = gtk_label_new(_(
"Pattern result"));
1411 gtk_widget_set_halign(pattern_label, GTK_ALIGN_START);
1413 d->test_path = gtk_label_new(_(
"Choose a file to see the result..."));
1414 gtk_widget_set_halign(
d->test_path, GTK_ALIGN_START);
1415 gtk_label_set_line_wrap(GTK_LABEL(
d->test_path),
TRUE);
1416 gtk_label_set_max_width_chars(GTK_LABEL(
d->test_path), 60);
1425 gtk_grid_attach(grid, calendar_label, 0,
row, 1, 1);
1426 gtk_grid_attach(grid, jobcode_label, 2,
row, 1, 1);
1427 gtk_grid_attach(grid, pattern_label, 4,
row, 1, 1);
1431 gtk_grid_attach(grid, GTK_WIDGET(box_calendar), 0,
row, 1, 1);
1432 gtk_grid_attach(grid, jobcode, 2,
row, 1, 1);
1433 gtk_grid_attach(grid,
d->test_path, 4,
row, 1, 1);
1441 gtk_grid_attach(grid, base_label, 0,
row, 1, 1);
1442 gtk_grid_attach(grid, dir_label, 2,
row, 1, 1);
1443 gtk_grid_attach(grid, file_label, 4,
row, 1, 1);
1447 gtk_grid_attach(grid, base_dir, 0,
row, 1, 1);
1448 gtk_grid_attach(grid, sep1, 1,
row, 1, 1);
1449 gtk_grid_attach(grid, project_dir, 2,
row, 1, 1);
1450 gtk_grid_attach(grid, sep2, 3,
row, 1, 1);
1451 gtk_grid_attach(grid, file, 4,
row, 1, 1);
1454 gtk_box_pack_start(GTK_BOX(rbox), GTK_WIDGET(grid),
FALSE,
FALSE, 0);
1456 gtk_widget_show_all(
d->dialog);
1459 gtk_widget_set_visible(GTK_WIDGET(grid),
dt_conf_get_bool(
"ui_last/import_copy"));
1468 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(
d->file_chooser));
1473 gtk_file_chooser_select_all(GTK_FILE_CHOOSER(
d->file_chooser));
1482 GtkFileChooser *chooser = GTK_FILE_CHOOSER(
d->file_chooser);
1483 gchar *
folder = gtk_file_chooser_get_current_folder(chooser);
1486 GFile *folder_file = g_file_new_for_path(
folder);
1487 GFileEnumerator *files = NULL;
1491 files = g_file_enumerate_children(
1492 folder_file, G_FILE_ATTRIBUTE_STANDARD_NAME
"," G_FILE_ATTRIBUTE_STANDARD_TYPE,
1493 G_FILE_QUERY_INFO_NONE, NULL, NULL);
1494 g_object_unref(folder_file);
1499 GtkFileFilter *filter = gtk_file_chooser_get_filter(chooser);
1504 const GtkFileFilterFlags filter_needed = gtk_file_filter_get_needed(filter);
1507 while(g_file_enumerator_iterate(files, NULL, &file, NULL, NULL))
1513 gchar *parse_name = g_file_get_parse_name(file);
1514 gchar *uri = g_file_get_uri(file);
1515 gchar *basename = g_file_get_basename(file);
1516 gchar *filepath = g_file_get_path(file);
1517 GtkFileFilterInfo filter_info = { filter_needed,
1522 const gboolean is_regular = !
IS_NULL_PTR(filepath) && g_file_test(filepath, G_FILE_TEST_IS_REGULAR);
1525 const gboolean is_in_lib = (is_path_in_lib > -1) || (is_metadata_in_lib > -1);
1529 if(gtk_file_filter_filter(filter, &filter_info)
1530 && !(is_regular && !is_in_lib))
1532 gtk_file_chooser_unselect_file(chooser, file);
1553 if(
d->selection_scan_timeout_id > 0)
1555 g_source_remove(
d->selection_scan_timeout_id);
1556 d->selection_scan_timeout_id = 0;
1562 g_signal_handlers_disconnect_by_func(G_OBJECT(
d->file_chooser), G_CALLBACK(
_selection_changed),
d);
1563 g_signal_handlers_disconnect_by_func(G_OBJECT(
d->file_chooser), G_CALLBACK(
update_preview_cb),
d);
1564 g_signal_handlers_disconnect_by_func(G_OBJECT(
d->file_chooser), G_CALLBACK(
_file_activated), GTK_DIALOG(
d->dialog));
1565 g_signal_handlers_disconnect_by_func(G_OBJECT(
d->file_chooser), G_CALLBACK(
_update_directory), NULL);
1572 gtk_widget_destroy(
d->dialog);
1574 d->file_chooser = NULL;
1579 d->help_string = NULL;
1580 d->test_path = NULL;
1581 d->selected_files = NULL;
1582 d->filter_all = NULL;
1583 d->filter_raw = NULL;
1584 d->filter_raster = NULL;
1593 d->selection_scan_timeout_id = 0;
1595 d->path_file = NULL;
1598 d->scan_state->generation = 0;
1599 d->scan_state->refcount = 1;
1600 d->scan_state->closing =
FALSE;
1614 gboolean release =
FALSE;
1616 d->scan_state->closing =
TRUE;
1617 d->scan_state->generation++;
1618 if(
d->scan_state->refcount > 0)
d->scan_state->refcount--;
1619 release = (
d->scan_state->refcount == 0);
1626 d->scan_state = NULL;
1642 dt_import_t *
import = g_malloc(sizeof(dt_import_t));
1644 import->files = NULL;
1645 import->elements = 0;
1646 import->scan_errors = 0;
1648 import->scan_state =
d->scan_state;
1650 import->scan_state->refcount++;
1656 import->selection = gtk_file_chooser_get_uris(GTK_FILE_CHOOSER(
d->file_chooser));
1660 GtkFileFilter *active_filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(
d->file_chooser));
1661 if(!
IS_NULL_PTR(active_filter) && active_filter ==
d->filter_raw)
1663 else if(!
IS_NULL_PTR(active_filter) && active_filter ==
d->filter_raster)
1670 d->last_filter_type =
import->filter_type;
1683 import->files = NULL;
1685 import->selection = NULL;
1688 gboolean release =
FALSE;
1690 if(import->scan_state->refcount > 0)
import->scan_state->refcount--;
1691 release = (
import->scan_state->refcount == 0);
1698 import->scan_state = NULL;
1712 GtkWidget *dialog = gtk_dialog_new_with_buttons(
"Message",
1714 GTK_DIALOG_DESTROY_WITH_PARENT,
1718 gtk_window_set_title(GTK_WINDOW(dialog), _(
"Some files have not been copied"));
1722 GtkWidget *label = gtk_label_new(_(
"The following source files have not been copied "
1723 "because similarly-named files already exist on the destination. "
1724 "This may be because the files have already been imported "
1725 "or the naming pattern leads to non-unique file names."));
1726 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
1729 GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1730 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC,
1731 GTK_POLICY_AUTOMATIC);
1732 gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrolled_window),
TRUE);
1735 GtkListStore *
store = gtk_list_store_new(1, G_TYPE_STRING);
1737 for(GList *file = g_list_first(data->
discarded); file; file = g_list_next(file))
1741 gtk_list_store_append(
store, &iter);
1742 gtk_list_store_set(
store, &iter, 0, (
char *)file->data, -1);
1748 GtkTreeViewColumn *col = gtk_tree_view_column_new();
1749 gtk_tree_view_column_set_title(col, _(
"Origin path"));
1750 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1751 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
1752 gtk_tree_view_column_set_attributes(col, renderer,
"text", 0, NULL);
1753 gtk_tree_view_append_column(GTK_TREE_VIEW(
view), col);
1754 g_object_unref(
store);
1758 gtk_box_pack_start(GTK_BOX(box), label,
TRUE,
TRUE, 0);
1759 gtk_box_pack_start(GTK_BOX(box), scrolled_window,
TRUE,
TRUE, 0);
1761 gtk_container_add(GTK_CONTAINER(scrolled_window),
view);
1764 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1765 gtk_container_add(GTK_CONTAINER(content_area), box);
1766 gtk_widget_show_all(dialog);
1768#ifdef GDK_WINDOWING_QUARTZ
1772 gtk_dialog_run(GTK_DIALOG(dialog));
1773 gtk_widget_destroy(dialog);
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
Handle default and user-set shortcuts (accelerators)
GtkWidget * dt_gui_main_window(void)
void dt_gui_refocus_center()
static void error(char *msg)
const char * extension(dt_imageio_module_data_t *data)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static dt_aligned_pixel_t rgb
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)
Read the stored string for name as a private copy.
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
dt_image_flags_t dt_image_flags_from_extension(const char *extension)
int32_t dt_image_get_id(int32_t film_id, const gchar *filename)
gboolean dt_image_is_hdr(const dt_image_t *img)
void dt_image_init(dt_image_t *img)
void dt_image_film_roll_directory(const dt_image_t *img, char *pathname, size_t pathname_len)
gboolean dt_image_get_usercrop(const dt_image_t *img, dt_boundingbox_t box)
void dt_control_log(const char *msg,...)
struct dt_control_t * dt_control_get_global(void)
void dt_control_image_enumerator_cleanup(void *p)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
GDateTime * dt_string_to_datetime(const char *string)
gboolean dt_datetime_img_to_local(char *local, const size_t local_size, const dt_image_t *img, const gboolean msec)
gboolean dt_datetime_unix_to_exif(char *exif, const size_t exif_size, const time_t *unix)
gboolean dt_datetime_entry_to_exif(char *exif, const size_t exif_size, const char *entry)
#define DT_DATETIME_LENGTH
#define DT_DATETIME_EXIF_LENGTH
GtkTreeStore * store
its model, owned by the view
GtkWidget * folder
destination folder chooser
GtkWidget * view
the tree view
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
int dt_exif_read(dt_image_t *img, const char *path)
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
gchar * dt_loc_get_home_dir(const gchar *user)
int32_t dt_film_get_id(const char *folder)
void dt_gtkentry_setup_completion(GtkEntry *entry, const dt_gtkentry_completion_spec *compl_list, const char *trigger_char)
const dt_gtkentry_completion_spec * dt_gtkentry_get_default_path_compl_list()
float dt_boundingbox_t[4]
@ ORIENTATION_ROTATE_CCW_90_DEG
@ ORIENTATION_ROTATE_CW_90_DEG
@ ORIENTATION_ROTATE_180_DEG
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
const char *const * dt_image_ext_ldr_list(void)
gboolean dt_image_ext_is_gui_raw(const char *ext)
gboolean dt_image_ext_is_gui_raster(const char *ext)
const char *const * dt_image_ext_raw_list(void)
const char *const * dt_image_ext_hdr_list(void)
gboolean dt_supported_image(const gchar *filename)
void dt_imageio_close_standalone(dt_mipmap_buffer_t *buf)
Release a buffer from dt_imageio_open_standalone(). NULL-safe, and safe to call on a buffer whose ope...
dt_imageio_retval_t dt_imageio_open_standalone(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Decode a file into a buffer the CALLER owns, with no cache involvement.
gboolean dt_imageio_crop_thumbnail(const dt_boundingbox_t box, uint8_t *const buffer, int32_t *width, int32_t *height)
Crop an 8-bit RGBA preview buffer in place to a normalized bounding box.
int dt_imageio_large_thumbnail(const char *filename, uint8_t **buffer, int32_t *th_width, int32_t *th_height, dt_colorspaces_color_profile_type_t *color_space, const int width, const int height)
Load the thumbnail embedded into a RAW file having at least the size MAX(width, height) x MAX(width,...
static void _resize_dialog(GtkWidget *widget)
static void dt_import_cleanup(void *import)
static void _datetime_changed_callback(GtkEntry *entry, dt_lib_import_t *d)
static void _do_select_all_clicked(GtkWidget *widget, dt_lib_import_t *d)
static int32_t _get_selected_files_job(dt_job_t *job)
static int _import_discarded_files_popup(dt_control_image_enumerator_t *params)
static void _import_discarded_files_schedule(dt_control_image_enumerator_t *params)
static void _update_date(GtkCalendar *calendar, GtkWidget *entry)
static void _process_file_list(gpointer instance, GList *files, int elements, gboolean finished, guint scan_errors, gpointer user_data)
Import a list of file by copying them or not, and adding them to database.
void dt_control_get_selected_files(dt_lib_import_t *d, gboolean destroy_window)
static void _filename_changed(GtkWidget *widget, dt_lib_import_t *d)
static void _selection_changed(GtkWidget *filechooser, dt_lib_import_t *d)
static int _is_in_library_by_path(const gchar *folder, const char *filename)
static void gui_cleanup(dt_lib_import_t *d)
void dt_gui_import_init_handlers(void)
Register the GUI-side import handlers (the discarded-files recap dialog).
static dt_import_t * dt_import_init(dt_lib_import_t *d, const uint32_t generation)
static void _set_selected_files_label(dt_lib_import_t *d, const guint elements, const guint scan_errors)
static void _gtk_label_set_and_free(GtkWidget *widget, gchar *label)
static void _jobcode_changed(GtkFileChooserButton *widget, dt_lib_import_t *d)
static void _copy_toggled_callback(GtkWidget *combobox, dt_lib_import_t *d)
static gboolean _scan_still_valid(dt_import_t *const import)
static void _file_activated(GtkFileChooser *chooser, GtkDialog *dialog)
static void _set_test_path(dt_lib_import_t *d, dt_image_t *img)
static void _do_select_none_clicked(GtkWidget *widget, dt_lib_import_t *d)
static void _file_filters(dt_lib_import_t *d)
static void _filelist_changed_callback(gpointer instance, GList *files, guint elements, guint finished, guint scan_errors, gpointer user_data)
static void _do_select_new_clicked(GtkWidget *widget, dt_lib_import_t *d)
static GdkPixbuf * _import_get_thumbnail(const gchar *filename, const int width, const int height, const gboolean valid_exif, dt_image_t *img)
static void _do_select_new(dt_lib_import_t *d)
static void _base_dir_changed(GtkFileChooserButton *self, dt_lib_import_t *d)
static void _cleanup(dt_lib_import_t *d)
static dt_lib_import_t * _init()
static GtkWidget * _attach_aligned_grid_item(GtkWidget *grid, const int row, const int column, const char *label, const GtkAlign align, const gboolean fixed_width, const gboolean full_width)
static int _is_in_library_by_metadata(GFile *file)
static void gui_init(dt_lib_import_t *d)
static void _project_dir_changed(GtkWidget *widget, dt_lib_import_t *d)
static void _build_filter(GtkFileFilter *filter, const gchar *extension)
static int32_t dt_get_selected_files(dt_import_t *import)
gboolean dt_import_passes_filter(const dt_import_filter_type_t filter_type, const gchar *pathname)
static void _do_select_all(dt_lib_import_t *d)
static void _filter_document(GVfs *vfs, GFile *document, dt_import_t *import)
static void _report_scan_error(dt_import_t *const import, GFile *folder, GError *error)
void _file_chooser_response(GtkDialog *dialog, gint response_id, dt_lib_import_t *d)
static void _update_directory(GtkWidget *file_chooser, dt_lib_import_t *d)
static gboolean _selection_changed_scan_trigger(gpointer user_data)
Trigger recursive import candidate detection after selection settle time.
static void update_preview_cb(GtkFileChooser *file_chooser, gpointer userdata)
static void _exif_text_set_and_free(dt_lib_import_t *d, exif_fields_t field, gchar *label)
static void _recurse_selection(GSList *selection, dt_import_t *const import)
static void _do_select_none(dt_lib_import_t *d)
static void _recurse_folder(GVfs *vfs, GFile *folder, dt_import_t *const import)
static GtkWidget * _attach_grid_separator(GtkWidget *grid, const int row, const int length)
static void _set_help_string(dt_lib_import_t *d, gboolean copy)
@ DT_IMPORT_FILTER_RASTER
gchar * dt_build_filename_from_pattern(const char *const filename, const int index, dt_image_t *img, dt_control_import_t *data)
Build a full path for a given image file, given a pattern.
int dt_control_import(dt_control_import_t data)
Process a list of images to import with or without copying the files on an arbitrary hard-drive.
void dt_control_import_set_discarded_files_handler(dt_control_import_discarded_handler_t handler)
void dt_control_import_data_free(dt_control_import_t *data)
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_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
void dt_control_job_dispose(_dt_job_t *job)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define CLAMPF(a, mn, mx)
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_colorspaces_color_profile_type_t color_space
#define __OMP_PARALLEL_FOR__(...)
void dt_osx_disallow_fullscreen(GtkWidget *widget)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
dt_colorspaces_color_profile_type_t
void copy(TYPE *dest, TYPE *source, size_t num_el)
Copy a flat buffer used to initialize test matrices.
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_FILELIST_CHANGED
Raised when the recursive file crawler returns. no params, return :
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
char * dt_variables_expand(dt_variables_params_t *params, gchar *source, gboolean iterate)
void dt_variables_params_destroy(dt_variables_params_t *params)
gboolean dt_get_user_pictures_dir(const gchar *homedir, gchar *picdir, size_t picdir_size)
Gets the path to the current OS pictures directory.
void dt_variables_params_init(dt_variables_params_t **params)
const float uint32_t state[4]
static const char *const day[7]
char * target_file_pattern
char * target_subfolder_pattern
dt_image_orientation_t orientation
dt_import_filter_type_t filter_type
dt_import_scan_state_t * scan_state
GtkWidget * selected_files
GtkFileFilter * filter_all
dt_import_scan_state_t * scan_state
GtkFileFilter * filter_raster
guint selection_scan_timeout_id
dt_import_filter_type_t last_filter_type
GtkWidget * exif_info[EXIF_LAST_FIELD]
GtkFileFilter * filter_raw
gchar * dt_util_path_get_dirname(const gchar *filename)
char * dt_util_format_exposure(const float exposuretime)