68#ifdef GDK_WINDOWING_QUARTZ
71#include <glib/gstdio.h>
104 return _(
"File on disk");
108 const size_t old_params_size,
const int old_version,
const int new_version,
111 if(old_version == 1 && new_version == 3)
113 typedef struct dt_imageio_disk_v1_t
118 } dt_imageio_disk_v1_t;
121 dt_imageio_disk_v1_t *o = (dt_imageio_disk_v1_t *)old_params;
123 g_strlcpy(
n->filename, o->filename,
sizeof(
n->filename));
126 *new_size = self->params_size(self);
129 if(old_version == 2 && new_version == 3)
131 typedef struct dt_imageio_disk_v2_t
136 } dt_imageio_disk_v2_t;
139 dt_imageio_disk_v2_t *o = (dt_imageio_disk_v2_t *)old_params;
141 g_strlcpy(
n->filename, o->filename,
sizeof(
n->filename));
144 *new_size = self->params_size(self);
159 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
160 _(
"select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
161 _(
"_select as output destination"), _(
"_cancel"));
163 gchar *old = g_strdup(gtk_entry_get_text(
d->entry));
164 char *c = g_strstr_len(old, -1,
"$");
166 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), old);
168 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
170 gchar *dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
171 char *composed = g_build_filename(dir,
"$(FILE_NAME)", NULL);
174 gtk_entry_set_text(GTK_ENTRY(
d->entry), cleaned);
175 gtk_editable_set_position(GTK_EDITABLE(
d->entry), strlen(cleaned));
180 g_object_unref(filechooser);
188 const gchar *pattern = gtk_entry_get_text(
d->entry);
192 gtk_label_set_text(GTK_LABEL(
d->preview), _(
"select an image to preview the export path"));
197 gboolean from_cache =
FALSE;
213 gchar *full = g_strdup_printf(
"%s.%s", expanded, fdata ? mformat->extension(fdata) :
"");
214 if(fdata) mformat->free_params(mformat, fdata);
217 gtk_label_set_text(GTK_LABEL(
d->preview), full);
227 dt_conf_set_string(
"plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(entry));
249 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(hbox),
TRUE,
FALSE, 0);
251 widget = gtk_entry_new();
253 gtk_box_pack_start(GTK_BOX(hbox), widget,
TRUE,
TRUE, 0);
257 gtk_entry_set_text(GTK_ENTRY(widget), dir);
258 gtk_editable_set_position(GTK_EDITABLE(widget), strlen(dir));
263 d->entry = GTK_ENTRY(widget);
264 gtk_entry_set_width_chars(GTK_ENTRY(widget), 0);
265 gtk_widget_set_tooltip_text(widget,
266 _(
"enter the path where to put exported images\nvariables support bash like string manipulation\n"
267 "type '$(' to activate the completion and see the list of variables"));
271 gtk_widget_set_tooltip_text(widget, _(
"select directory"));
272 gtk_box_pack_start(GTK_BOX(hbox), widget,
FALSE,
FALSE, 0);
273 g_signal_connect(G_OBJECT(widget),
"clicked", G_CALLBACK(
button_clicked), self);
277 gtk_widget_set_tooltip_text(
d->onsave_action, _(
"Expected behaviour if the current naming pattern\n"
278 "produces a filename that already exists."));
282 gtk_box_pack_start(GTK_BOX(self->
widget),
d->onsave_action,
TRUE,
TRUE, 0);
286 d->preview = gtk_label_new(
"");
287 gtk_widget_set_halign(
d->preview, GTK_ALIGN_START);
288 gtk_label_set_line_wrap(GTK_LABEL(
d->preview),
TRUE);
289 gtk_label_set_max_width_chars(GTK_LABEL(
d->preview), 60);
310 dt_conf_set_string(
"plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(
d->entry));
328 const gboolean high_quality,
const gboolean export_masks,
337 g_strlcpy(pattern,
d->filename,
sizeof(pattern));
338 gboolean from_cache =
FALSE;
353 gboolean fail =
FALSE;
368 if(total > 1 && !g_strrstr(pattern,
"$"))
370 snprintf(pattern + strlen(pattern),
sizeof(pattern) - strlen(pattern),
"_$(SEQUENCE)");
374 g_strlcpy(pattern, fixed_path,
sizeof(pattern));
383 g_strlcpy(filename, result_filename,
sizeof(filename));
388 char last_char = *(filename + strlen(filename) - 1);
389 if(last_char ==
'/' || last_char ==
'\\')
393 if (snprintf(pattern,
sizeof(pattern),
"%s" G_DIR_SEPARATOR_S
"$(FILE_NAME)",
d->filename) <
sizeof(pattern))
397 char *output_dir = g_path_get_dirname(filename);
399 if(g_mkdir_with_parents(output_dir, 0755))
401 fprintf(stderr,
"[imageio_storage_disk] could not create directory: `%s'!\n", output_dir);
402 dt_control_log(_(
"could not create directory `%s'!"), output_dir);
406 if(g_access(output_dir, W_OK | X_OK) != 0)
408 fprintf(stderr,
"[imageio_storage_disk] could not write to directory: `%s'!\n", output_dir);
409 dt_control_log(_(
"could not write to directory `%s'!"), output_dir);
414 const char *ext = format->extension(fdata);
415 char *c = filename + strlen(filename);
416 size_t filename_free_space =
sizeof(filename) - (c - filename);
417 snprintf(c, filename_free_space,
".%s", ext);
426 while(g_file_test(filename, G_FILE_TEST_EXISTS))
428 snprintf(c, filename_free_space,
"_%.2d.%s", seq, ext);
435 if(g_file_test(filename, G_FILE_TEST_EXISTS))
439 fprintf(stderr,
"[export_job] skipping `%s'\n", filename);
440 dt_control_log(ngettext(
"%d/%d skipping `%s'",
"%d/%d skipping `%s'", num),
441 num, total, filename);
452 icc_filename, icc_intent, self, sdata, num, total, metadata) != 0)
454 fprintf(stderr,
"[imageio_storage_disk] could not export to file: `%s'!\n", filename);
459 fprintf(stderr,
"[export_job] exported to `%s'\n", filename);
460 dt_control_log(ngettext(
"%d/%d exported to `%s'",
"%d/%d exported to `%s'", num),
461 num, total, filename);
479 g_strlcpy(
d->filename, text,
sizeof(
d->filename));
481 d->onsave_action =
dt_conf_get_int(
"plugins/imageio/storage/disk/overwrite");
502 if(
size != self->params_size(self))
return 1;
504 gtk_entry_set_text(GTK_ENTRY(
g->entry),
d->filename);
505 gtk_editable_set_position(GTK_EDITABLE(
g->entry), strlen(
d->filename));
515 return g_strdup(_(
"you are going to export on overwrite mode, this will overwrite any existing images\n\n"
516 "do you really want to continue?"));
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....
GtkWidget * dt_gui_main_window(void)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
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.
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
One declared attribute of name from the generated XML, as text.
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
void dt_control_log(const char *msg,...)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
void * get_params(dt_imageio_module_storage_t *self)
static void _filename_lock_init(void)
char * ask_user_confirmation(dt_imageio_module_storage_t *self)
void gui_cleanup(dt_imageio_module_storage_t *self)
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
static void onsave_action_toggle_callback(GtkWidget *widget, gpointer user_data)
size_t params_size(dt_imageio_module_storage_t *self)
void gui_init(dt_imageio_module_storage_t *self)
static void _update_preview(disk_t *d)
void init(dt_imageio_module_storage_t *self)
void gui_reset(dt_imageio_module_storage_t *self)
dt_disk_onconflict_actions_t
@ DT_EXPORT_ONCONFLICT_SKIP
@ DT_EXPORT_ONCONFLICT_UNIQUEFILENAME
@ DT_EXPORT_ONCONFLICT_OVERWRITE
void * legacy_params(dt_imageio_module_storage_t *self, const void *const old_params, const size_t old_params_size, const int old_version, const int new_version, size_t *new_size)
static dt_pthread_mutex_t _filename_lock
static pthread_once_t _filename_lock_once
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
static void button_clicked(GtkWidget *widget, dt_imageio_module_storage_t *self)
static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
static void _selection_changed_callback(gpointer instance, dt_imageio_module_storage_t *self)
GtkTreeStore * store
its model, owned by the 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_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
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()
int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
dt_imageio_module_format_t * dt_imageio_get_format()
#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 dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
#define DT_MAX_PATH_FOR_PARAMS
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
dt_colorspaces_color_profile_type_t
int32_t dt_selection_get_first_id(struct dt_selection_t *selection)
struct dt_selection_t * dt_selection_get_global(void)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
struct dt_control_signal_t * dt_control_signal_get_global(void)
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
#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)
void dt_variables_set_max_width_height(dt_variables_params_t *params, int max_width, int max_height)
void dt_variables_params_init(dt_variables_params_t **params)
GtkWidget * onsave_action
dt_variables_params_t * vp
dt_disk_onconflict_actions_t onsave_action
char filename[DT_MAX_PATH_FOR_PARAMS]
GModule *GtkWidget * widget
Telling the user something happened.
gchar * dt_cleanup_separators(gchar *string)
gchar * dt_util_fix_path(const gchar *path)