1 /*
2 * This file is part of Siril, an astronomy image processor.
3 * Copyright (C) 2005-2011 Francois Meyer (dulle at free.fr)
4 * Copyright (C) 2012-2021 team free-astro (see more in AUTHORS file)
5 * Reference site is https://free-astro.org/index.php/Siril
6 *
7 * Siril is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Siril is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Siril. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 * GTK File Chooser static functions
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "core/siril.h"
29 #include "core/proto.h"
30 #include "core/OS_utils.h"
31 #include "core/initfile.h"
32 #include "algos/sorting.h"
33 #include "io/conversion.h"
34 #include "io/films.h"
35 #include "io/sequence.h"
36 #include "io/single_image.h"
37 #include "io/fits_sequence.h"
38 #include "gui/utils.h"
39 #include "gui/callbacks.h"
40 #include "gui/progress_and_log.h"
41 #include "gui/message_dialog.h"
42 #include "gui/dialog_preview.h"
43 #include "gui/conversion.h"
44
45 #include "open_dialog.h"
46
gtk_filter_add(GtkFileChooser * file_chooser,const gchar * title,const gchar * pattern,gboolean set_default)47 static void gtk_filter_add(GtkFileChooser *file_chooser, const gchar *title,
48 const gchar *pattern, gboolean set_default) {
49 gchar **patterns;
50 gint i;
51
52 GtkFileFilter *f = gtk_file_filter_new();
53 gtk_file_filter_set_name(f, title);
54 /* get the patterns */
55 patterns = g_strsplit(pattern, ";", -1);
56 for (i = 0; patterns[i] != NULL; i++)
57 gtk_file_filter_add_pattern(f, patterns[i]);
58 /* free the patterns */
59 g_strfreev(patterns);
60 gtk_file_chooser_add_filter(file_chooser, f);
61 if (set_default)
62 gtk_file_chooser_set_filter(file_chooser, f);
63 }
64
set_filters_dialog(GtkFileChooser * chooser,int whichdial)65 static void set_filters_dialog(GtkFileChooser *chooser, int whichdial) {
66 GString *all_filter = NULL;
67 gchar *fits_filter = "*.fit;*.FIT;*.fits;*.FITS;*.fts;*.FTS;*.fits.fz";
68 gchar *netpbm_filter = "*.ppm;*.PPM;*.pnm;*.PNM;*.pgm;*.PGM";
69 gchar *pic_filter = "*.pic;*.PIC";
70 gchar *ser_filter = "*.ser;*.SER";
71 if (whichdial != OD_CONVERT && whichdial != OD_OPEN) {
72 gtk_filter_add(chooser, _("FITS Files (*.fit, *.fits, *.fts, *.fits.fz)"),
73 fits_filter, com.filter == TYPEFITS);
74 } else {
75 all_filter = g_string_new(fits_filter);
76 }
77 if (whichdial == OD_OPEN || whichdial == OD_CONVERT) {
78 #ifdef HAVE_LIBRAW
79 /* RAW FILES */
80 int nb_raw;
81 char *raw;
82 int i;
83
84 nb_raw = get_nb_raw_supported();
85 raw = calloc(sizeof(char), nb_raw * 12 + 1);// we assume the extension size of 3 char "*.xxx;*.XXX;" = 12
86 for (i = 0; i < nb_raw; i++) {
87 char *ext;
88 gchar *upcase;
89
90 upcase = g_ascii_strup(supported_raw[i].extension, strlen(supported_raw[i].extension));
91 ext = g_strdup_printf("*.%s;*.%s;", supported_raw[i].extension,
92 upcase);
93 strcat(raw, ext);
94
95 g_free(ext);
96 g_free(upcase);
97 }
98 raw[strlen(raw) - 1] = '\0';
99 if (whichdial != OD_CONVERT && whichdial != OD_OPEN) {
100 gtk_filter_add(chooser, _("RAW DSLR Camera Files"), raw,
101 com.filter == TYPERAW);
102 } else {
103 all_filter = g_string_append(all_filter, ";");
104 all_filter = g_string_append(all_filter, raw);
105 }
106
107 free(raw);
108
109 #endif
110 /* GRAPHICS FILES */
111 GString *s_supported_graph, *s_pattern;
112 gchar *graphics_supported, *graphics_filter;
113
114 s_supported_graph = g_string_new(_("Graphics Files (*.bmp"));
115 s_pattern = g_string_new("*.bmp;*.BMP;");
116 #ifdef HAVE_LIBJPEG
117 s_supported_graph = g_string_append(s_supported_graph, ", *.jpg, *.jpeg");
118 s_pattern = g_string_append(s_pattern, "*.jpg;*.JPG;*.jpeg;*.JPEG;");
119 #endif
120
121 #ifdef HAVE_LIBHEIF
122 s_supported_graph = g_string_append(s_supported_graph, ", *.heic, *.heif");
123 s_pattern = g_string_append(s_pattern, "*.heic;*.HEIC;*.heif;*.HEIF;");
124 #endif
125
126 #ifdef HAVE_LIBPNG
127 s_supported_graph = g_string_append(s_supported_graph, ", *.png");
128 s_pattern = g_string_append(s_pattern, "*.png;*.PNG;");
129 #endif
130
131 #ifdef HAVE_LIBTIFF
132 s_supported_graph = g_string_append(s_supported_graph, ", *.tif, *.tiff");
133 s_pattern = g_string_append(s_pattern, "*.tif;*.TIF;*.tiff;*.TIFF");
134 #endif
135 s_supported_graph = g_string_append(s_supported_graph, ")");
136
137 graphics_supported = g_string_free(s_supported_graph, FALSE);
138 graphics_filter = g_string_free(s_pattern, FALSE);
139 if (whichdial != OD_CONVERT && whichdial != OD_OPEN) {
140 gtk_filter_add(chooser, graphics_supported, graphics_filter,
141 com.filter == TYPEBMP || com.filter == TYPEJPG
142 || com.filter == TYPEPNG || com.filter == TYPETIFF);
143
144 /* NETPBM FILES */
145 gtk_filter_add(chooser, _("Netpbm Files (*.ppm, *.pnm, *.pgm)"),
146 netpbm_filter, com.filter == TYPEPNM);
147 /* IRIS FILES */
148 gtk_filter_add(chooser, _("IRIS PIC Files (*.pic)"), pic_filter,
149 com.filter == TYPEPIC);
150 /* SER FILES */
151 gtk_filter_add(chooser, _("SER files (*.ser)"), ser_filter,
152 com.filter == TYPESER);
153 } else {
154 all_filter = g_string_append(all_filter, ";");
155 all_filter = g_string_append(all_filter, graphics_filter);
156 all_filter = g_string_append(all_filter, ";");
157 all_filter = g_string_append(all_filter, netpbm_filter);
158 all_filter = g_string_append(all_filter, ";");
159 all_filter = g_string_append(all_filter, pic_filter);
160 all_filter = g_string_append(all_filter, ";");
161 all_filter = g_string_append(all_filter, ser_filter);
162 }
163
164 #ifdef HAVE_FFMS2
165 /* FILM FILES */
166 int nb_film;
167 char *film_filter;
168 int j;
169
170 nb_film = get_nb_film_ext_supported();
171 film_filter = calloc(sizeof(char), nb_film * 14 + 1);// we assume the extension size of 4 char "*.xxxx;*.XXXX;" = 14
172 for (j = 0; j < nb_film; j++) {
173 char *ext;
174 gchar *upcase;
175
176 upcase = g_ascii_strup(supported_film[j].extension,
177 strlen(supported_film[j].extension));
178 ext = g_strdup_printf("*.%s;*.%s;", supported_film[j].extension,
179 upcase);
180 strcat(film_filter, ext);
181
182 g_free(ext);
183 g_free(upcase);
184 }
185 film_filter[strlen(film_filter) - 1] = '\0';
186
187 if (whichdial != OD_CONVERT && whichdial != OD_OPEN) {
188 gtk_filter_add(chooser, _("Film Files (*.avi, *.mpg, ...)"), film_filter,
189 com.filter == TYPEAVI);
190 } else {
191 all_filter = g_string_append(all_filter, ";");
192 all_filter = g_string_append(all_filter, film_filter);
193 }
194 free(film_filter);
195 #endif
196 g_free(graphics_supported);
197 g_free(graphics_filter);
198
199 if (whichdial == OD_CONVERT || whichdial == OD_OPEN) {
200 gchar *filter = g_string_free(all_filter, FALSE);
201
202 gtk_filter_add(chooser, _("All supported files"), filter, TRUE);
203 g_free(filter);
204 }
205 }
206 }
207
on_debayer_toggled(GtkToggleButton * togglebutton,gpointer user_data)208 static void on_debayer_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
209 gtk_toggle_button_set_active((GtkToggleButton *)user_data, gtk_toggle_button_get_active(togglebutton));
210 }
211
siril_add_debayer_toggle_button(GtkFileChooser * dialog)212 static void siril_add_debayer_toggle_button(GtkFileChooser *dialog) {
213 GtkToggleButton *main_debayer_button = GTK_TOGGLE_BUTTON(lookup_widget("demosaicingButton"));
214 GtkWidget *toggle_debayer = gtk_check_button_new_with_label(_("Debayer"));
215
216 gtk_widget_show(toggle_debayer);
217 gtk_file_chooser_set_extra_widget(dialog, toggle_debayer);
218 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_debayer), gtk_toggle_button_get_active(main_debayer_button));
219 g_signal_connect(GTK_TOGGLE_BUTTON(toggle_debayer), "toggled", G_CALLBACK(on_debayer_toggled), (gpointer) main_debayer_button);
220 }
221
opendial(int whichdial)222 static void opendial(int whichdial) {
223 SirilWidget *widgetdialog;
224 GtkFileChooser *dialog = NULL;
225 fileChooserPreview *preview = NULL;
226 GtkWindow *control_window = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
227 gint res;
228 int retval;
229
230 if (!com.wd)
231 return;
232
233 switch (whichdial) {
234 case OD_NULL:
235 fprintf(stderr, "whichdial undefined, should not happen\n");
236 return;
237 case OD_FLAT:
238 case OD_DARK:
239 case OD_OFFSET:
240 widgetdialog = siril_file_chooser_open(control_window, GTK_FILE_CHOOSER_ACTION_OPEN);
241 dialog = GTK_FILE_CHOOSER(widgetdialog);
242 gtk_file_chooser_set_current_folder(dialog, com.wd);
243 gtk_file_chooser_set_select_multiple(dialog, FALSE);
244 set_filters_dialog(dialog, whichdial);
245 siril_file_chooser_add_preview(dialog, preview);
246 break;
247 case OD_CWD:
248 widgetdialog = siril_file_chooser_open(control_window, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
249 dialog = GTK_FILE_CHOOSER(widgetdialog);
250 gtk_file_chooser_set_current_folder(dialog, com.wd);
251 gtk_file_chooser_set_select_multiple(dialog, FALSE);
252 break;
253 case OD_OPEN:
254 widgetdialog = siril_file_chooser_open(control_window, GTK_FILE_CHOOSER_ACTION_OPEN);
255 dialog = GTK_FILE_CHOOSER(widgetdialog);
256 gtk_file_chooser_set_current_folder(dialog, com.wd);
257 gtk_file_chooser_set_select_multiple(dialog, FALSE);
258 set_filters_dialog(dialog, whichdial);
259 siril_file_chooser_add_preview(dialog, preview);
260 siril_add_debayer_toggle_button(dialog);
261 break;
262 case OD_CONVERT:
263 widgetdialog = siril_file_chooser_add(control_window, GTK_FILE_CHOOSER_ACTION_OPEN);
264 dialog = GTK_FILE_CHOOSER(widgetdialog);
265 gtk_file_chooser_set_current_folder(dialog, com.wd);
266 gtk_file_chooser_set_select_multiple(dialog, TRUE);
267 set_filters_dialog(dialog, whichdial);
268 }
269
270 if (!dialog)
271 return;
272
273 wait:
274 res = siril_dialog_run(widgetdialog);
275
276 if (res == GTK_RESPONSE_ACCEPT) {
277 GSList *list = NULL;
278 gchar *filename, *err;
279 gboolean anything_loaded;
280 GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
281 GtkEntry *flat_entry, *dark_entry, *bias_entry;
282 GtkToggleButton *flat_button, *dark_button, *bias_button;
283 GtkWidget *pbutton;
284
285 filename = gtk_file_chooser_get_filename(chooser);
286 if (!filename)
287 goto wait;
288
289 if (fitseq_is_fitseq(filename, NULL)
290 && ((whichdial == OD_FLAT) || (whichdial == OD_DARK) || (whichdial == OD_OFFSET))) {
291 siril_message_dialog(GTK_MESSAGE_ERROR, _("Format not supported."),
292 _("FITS sequences are not supported for master files. Please select a single FITS file."));
293 goto wait;
294 }
295
296 pbutton = lookup_widget("prepro_button");
297 flat_entry = GTK_ENTRY(lookup_widget("flatname_entry"));
298 dark_entry = GTK_ENTRY(lookup_widget("darkname_entry"));
299 bias_entry = GTK_ENTRY(lookup_widget("offsetname_entry"));
300
301 flat_button = GTK_TOGGLE_BUTTON(lookup_widget("useflat_button"));
302 dark_button = GTK_TOGGLE_BUTTON(lookup_widget("usedark_button"));
303 bias_button = GTK_TOGGLE_BUTTON(lookup_widget("useoffset_button"));
304
305 anything_loaded = sequence_is_loaded() || single_image_is_loaded();
306
307 switch (whichdial) {
308 case OD_FLAT:
309 gtk_entry_set_text(flat_entry, filename);
310 gtk_toggle_button_set_active(flat_button, TRUE);
311 gtk_widget_set_sensitive(pbutton, anything_loaded);
312 break;
313
314 case OD_DARK:
315 gtk_entry_set_text(dark_entry, filename);
316 gtk_toggle_button_set_active(dark_button, TRUE);
317 gtk_widget_set_sensitive(pbutton, anything_loaded);
318 break;
319
320 case OD_OFFSET:
321 gtk_entry_set_text(bias_entry, filename);
322 gtk_toggle_button_set_active(bias_button, TRUE);
323 gtk_widget_set_sensitive(pbutton, anything_loaded);
324 break;
325
326 case OD_CWD:
327 if (!siril_change_dir(filename, &err)) {
328 writeinitfile();
329 set_GUI_CWD();
330 } else {
331 siril_message_dialog(GTK_MESSAGE_ERROR, _("Error"), err);
332 }
333 break;
334
335 case OD_OPEN:
336 set_cursor_waiting(TRUE);
337 retval = open_single_image(filename);
338 set_cursor_waiting(FALSE);
339 if (retval == OPEN_IMAGE_CANCEL) goto wait;
340 break;
341
342 case OD_CONVERT:
343 list = gtk_file_chooser_get_filenames(chooser);
344 list = g_slist_sort(list, (GCompareFunc) strcompare);
345 fill_convert_list(list);
346 g_slist_free(list);
347 break;
348 }
349 g_free(filename);
350 }
351 siril_preview_free(preview);
352 siril_widget_destroy(widgetdialog);
353 }
354
on_darkfile_button_clicked(GtkButton * button,gpointer user_data)355 void on_darkfile_button_clicked(GtkButton *button, gpointer user_data) {
356 opendial(OD_DARK);
357 }
358
cwd_btton_clicked()359 void cwd_btton_clicked() {
360 opendial(OD_CWD);
361 }
362
on_offsetfile_button_clicked(GtkButton * button,gpointer user_data)363 void on_offsetfile_button_clicked(GtkButton *button, gpointer user_data) {
364 opendial(OD_OFFSET);
365 }
366
on_flatfile_button_clicked(GtkButton * button,gpointer user_data)367 void on_flatfile_button_clicked(GtkButton *button, gpointer user_data) {
368 opendial(OD_FLAT);
369 }
370
header_open_button_clicked()371 void header_open_button_clicked() {
372 opendial(OD_OPEN);
373 }
374
on_select_convert_button_clicked(GtkToolButton * button,gpointer user_data)375 void on_select_convert_button_clicked(GtkToolButton *button, gpointer user_data) {
376 opendial(OD_CONVERT);
377 }
378
379 /** callback function for recent document opened
380 *
381 * @param chooser
382 * @param user_data
383 */
on_open_recent_action_item_activated(GtkRecentChooser * chooser,gpointer user_data)384 void on_open_recent_action_item_activated(GtkRecentChooser *chooser,
385 gpointer user_data) {
386 gchar *uri, *path;
387 GError *error = NULL;
388
389 uri = gtk_recent_chooser_get_current_uri(chooser);
390
391 path = g_filename_from_uri(uri, NULL, &error);
392 if (error) {
393 g_warning("Could not convert uri \"%s\" to a local path: %s", uri,
394 error->message);
395 g_clear_error(&error);
396 return;
397 }
398
399 open_single_image(path);
400
401 g_free(uri);
402 g_free(path);
403 }
404