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 #include <gdk/gdkkeysyms.h>
22 #include <gtk/gtk.h>
23 #include <string.h>
24 
25 #include "gui/conversion.h"
26 #include "core/siril.h"
27 #include "core/proto.h"
28 #include "core/processing.h"
29 #include "core/OS_utils.h"
30 #include "io/conversion.h"
31 #include "io/sequence.h"
32 #include "gui/utils.h"
33 #include "gui/callbacks.h"
34 #include "gui/message_dialog.h"
35 #include "gui/progress_and_log.h"
36 #include "algos/sorting.h"
37 
38 static gchar *destroot = NULL;
39 static GtkListStore *liststore_convert = NULL;
40 static GtkTreeView *tree_view = NULL;
41 static GtkTreeModel *model = NULL;
42 static gboolean warning_is_displayed = FALSE;
43 
44 static void check_for_conversion_form_completeness();
45 static void on_input_files_change();
46 static sequence_type get_activated_output_type();
47 
init_widgets()48 static void init_widgets() {
49 	if (!tree_view) {
50 		tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview_convert"));
51 		model = gtk_tree_view_get_model(tree_view);
52 		liststore_convert = GTK_LIST_STORE(
53 				gtk_builder_get_object(builder, "liststore_convert"));
54 	}
55 	g_assert(tree_view);
56 	g_assert(model);
57 	g_assert(liststore_convert);
58 }
59 
count_converted_files()60 int count_converted_files() {
61 	init_widgets();
62 	GtkTreeIter iter;
63 	gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
64 
65 	int count = 0;
66 	while (valid) {
67 		gtk_tree_model_get(model, &iter, -1);
68 		valid = gtk_tree_model_iter_next (model, &iter);
69 		count++;
70 	}
71 	return count;
72 }
73 
count_selected_files()74 int count_selected_files() {
75 	init_widgets();
76 	GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
77 	return gtk_tree_selection_count_selected_rows(selection);
78 }
79 
initialize_convert()80 static void initialize_convert() {
81 	gchar *file_data;
82 	GtkTreeIter iter;
83 	GList *list = NULL;
84 
85 	init_widgets();
86 
87 	if (get_thread_run()) {
88 		PRINT_ANOTHER_THREAD_RUNNING;
89 		return;
90 	}
91 
92 	if (file_name_has_invalid_chars(destroot)) {
93 		siril_message_dialog(GTK_MESSAGE_ERROR, _("Invalid char"), _("Please remove invalid characters in the sequence name "
94 				"before trying to convert images into a new sequence again."));
95 		return;
96 	}
97 
98 	if (g_file_test(destroot, G_FILE_TEST_EXISTS)) {
99 		char *title = siril_log_message(_("A file named %s already exists. "
100 				"Do you want to replace it?\n"), destroot);
101 		gboolean replace = siril_confirm_dialog(title, _("The file already exists. "
102 				"Replacing it will overwrite its contents."), _("Replace File"));
103 		if (!replace) return;
104 	}
105 
106 	gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
107 	if (!valid) return;	//The tree is empty
108 
109 	gboolean no_sequence_to_convert = TRUE;
110 	gboolean there_is_an_image = FALSE;
111 	gboolean there_is_an_xtrans = FALSE;
112 	gboolean there_is_a_film = FALSE;
113 	int count = 0;
114 	while (valid) {
115 		gtk_tree_model_get(model, &iter, COLUMN_FILENAME_FULL, &file_data, -1);
116 
117 		list = g_list_prepend(list, file_data);
118 
119 		const char *src_ext = get_filename_ext(file_data);
120 
121 		image_type type = get_type_for_extension(src_ext);
122 		if (type == TYPEAVI || type == TYPESER) {
123 			no_sequence_to_convert = FALSE;
124 			if (type == TYPEAVI)
125 				there_is_a_film = TRUE;
126 		}
127 		else if (type == TYPEUNDEF) {
128 			char *title = siril_log_message(_("Filetype is not supported, cannot convert: %s\n"), src_ext);
129 			gchar *msg = g_strdup_printf(_("File extension '%s' is not supported.\n"
130 				"Verify that you typed the extension correctly.\n"
131 				"If so, you may need to install third-party software to enable "
132 				"this file type conversion, look at the README file.\n"
133 				"If the file type you are trying to load is listed in supported "
134 				"formats, you may notify the developers that the extension you are "
135 				"trying to use should be recognized for this type."), src_ext);
136 			siril_message_dialog(GTK_MESSAGE_ERROR, title, msg);
137 			return;
138 
139 		}
140 		else if (type == TYPERAW && !g_ascii_strcasecmp(src_ext, "raf")) {
141 			there_is_an_xtrans = TRUE;
142 			there_is_an_image = TRUE;
143 		}
144 		// because of fitseq, we can't use this check for FITS
145 		else if (type != TYPEFITS)
146 			there_is_an_image = TRUE;
147 		valid = gtk_tree_model_iter_next(model, &iter);
148 		count++;
149 	}
150 
151 	sequence_type output_type = get_activated_output_type();
152 	int nb_allowed;
153 	if (!allow_to_open_files(count, &nb_allowed) && output_type == SEQ_REGULAR) {
154 		gboolean confirm = siril_confirm_dialog(_("Too many files are being converted."),
155 				_("You are about to convert a large amount of files into standard FITS files."
156 						"However, your OS limits the number of files that will be processed in the same time."
157 						"You may want to convert your input files into a FITS sequence."), _("Convert to FITS Sequence"));
158 		if (!confirm) return;
159 	}
160 
161 	GtkToggleButton *toggle = GTK_TOGGLE_BUTTON(lookup_widget("multiple_seq"));
162 	gboolean multiple = gtk_toggle_button_get_active(toggle);
163 	toggle = GTK_TOGGLE_BUTTON(lookup_widget("demosaicingButton"));
164 	gboolean debayer = gtk_toggle_button_get_active(toggle);
165 	toggle = GTK_TOGGLE_BUTTON(lookup_widget("convert_symlink"));
166 	gboolean symbolic_link = gtk_toggle_button_get_active(toggle);
167 
168 	if (output_type == SEQ_REGULAR && debayer && symbolic_link) {
169 		siril_log_message(_("Symbolic links cannot be used when demosaicing the images, new images will be created\n"));
170 		symbolic_link = FALSE;
171 	}
172 	if (multiple && there_is_an_image) {
173 		siril_message_dialog(GTK_MESSAGE_WARNING, _("A conflict has been detected."),
174 				_("Creating multiple sequences can only be done with only sequences as input."));
175 		g_list_free_full(list, g_free);
176 		return;
177 	}
178 	if (output_type == SEQ_SER && there_is_an_xtrans && !debayer) {
179 		siril_message_dialog(GTK_MESSAGE_WARNING, _("A conflict has been detected."),
180 				_("FujiFilm XTRANS sensors are not supported by SER v2 (CFA-style) standard. You may use FITS sequences instead."));
181 		g_list_free_full(list, g_free);
182 		return;
183 	}
184 
185 	siril_log_color_message(_("Conversion: processing %d files...\n"), "green", count);
186 
187 	set_cursor_waiting(TRUE);
188 	control_window_switch_to_tab(OUTPUT_LOGS);
189 
190 	/* g_list_append() has to traverse the entire list to find the end,
191 	 * which is inefficient when adding multiple elements. A common idiom
192 	 * to avoid the inefficiency is to use g_list_prepend() and reverse the
193 	 * list with g_list_reverse() when all elements have been added. */
194 	list = g_list_reverse(list);
195 	/* convert the list to an array for parallel processing */
196 	char **files_to_convert = glist_to_array(list, &count);
197 
198 	struct _convert_data *args = malloc(sizeof(struct _convert_data));
199 	if (!args) {
200 		PRINT_ALLOC_ERR;
201 		return;
202 	}
203 	if (output_type == SEQ_REGULAR) {
204 		GtkEntry *startEntry = GTK_ENTRY(lookup_widget("startIndiceEntry"));
205 		const gchar *index = gtk_entry_get_text(startEntry);
206 		args->start = (g_ascii_strtoll(index, NULL, 10) <= 0
207 						|| g_ascii_strtoll(index, NULL, 10) >= INDEX_MAX) ?	1 : g_ascii_strtoll(index, NULL, 10);
208 	}
209 	else args->start = 0;
210 	args->list = files_to_convert;
211 	args->total = count;
212 	args->nb_converted_files = 0;
213 	args->input_has_a_seq = !no_sequence_to_convert;
214 	args->input_has_a_film = there_is_a_film;
215 	args->destroot = g_strdup(destroot);
216 	args->debayer = debayer;
217 	args->make_link = symbolic_link;
218 	args->output_type = output_type;
219 	args->multiple_output = multiple;
220 	gettimeofday(&(args->t_start), NULL);
221 	start_in_new_thread(convert_thread_worker, args);
222 	return;
223 }
224 
on_convroot_entry_activate(GtkEntry * entry,gpointer user_data)225 void on_convroot_entry_activate(GtkEntry *entry, gpointer user_data) {
226 	initialize_convert();
227 }
228 
on_convert_button_clicked(GtkButton * button,gpointer user_data)229 void on_convert_button_clicked(GtkButton *button, gpointer user_data) {
230 	initialize_convert();
231 }
232 
add_file_to_list(GFile * file)233 static void add_file_to_list(GFile *file) {
234 	GtkTreeIter iter;
235 
236 	GFileInfo *info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED ","
237 			G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, NULL, NULL);
238 	guint64 mtime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
239 	GDateTime *dt = g_date_time_new_from_unix_local(mtime);
240 	gchar *date = g_date_time_format(dt, "%c");
241 	const gchar *filename = g_file_peek_path(file);
242 	gchar *bname = g_file_get_basename(file);
243 	gchar *size = g_format_size(g_file_info_get_size(info));
244 
245 	gtk_list_store_append(liststore_convert, &iter);
246 	gtk_list_store_set(liststore_convert, &iter,
247 			COLUMN_FILENAME, bname,
248 			COLUMN_FILENAME_FULL, filename,
249 			COLUMN_SIZE, size,
250 			COLUMN_SIZE_INT64, g_file_info_get_size(info),
251 			COLUMN_DATE, date,
252 			COLUMN_DATE_UNIX, mtime,
253 			-1);
254 
255 	g_free(bname);
256 	g_object_unref(info);
257 	g_date_time_unref(dt);
258 	g_free(date);
259 	g_free(size);
260 }
261 
get_row_references_of_selected_rows(GtkTreeSelection * selection,GtkTreeModel * model)262 static GList *get_row_references_of_selected_rows(GtkTreeSelection *selection,
263 		GtkTreeModel *model) {
264 	GList *ref = NULL;
265 	GList *sel, *s;
266 
267 	sel = gtk_tree_selection_get_selected_rows(selection, &model);
268 
269 	for (s = sel; s; s = s->next) {
270 		GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model,	(GtkTreePath *) s->data);
271 		ref = g_list_prepend(ref, rowref);
272 	}
273 	g_list_free_full(sel, (GDestroyNotify) gtk_tree_path_free);
274 	return ref;
275 }
276 
remove_selected_files_from_list()277 static void remove_selected_files_from_list() {
278 	GtkTreeSelection *selection;
279 	GList *references, *list;
280 
281 	init_widgets();
282 	selection = gtk_tree_view_get_selection(tree_view);
283 	references = get_row_references_of_selected_rows(selection, model);
284 	for (list = references; list; list = list->next) {
285 		GtkTreeIter iter;
286 		GtkTreePath *path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)list->data);
287 		if (path) {
288 			if (gtk_tree_model_get_iter(model, &iter, path)) {
289 				gtk_list_store_remove(liststore_convert, &iter);
290 			}
291 			gtk_tree_path_free(path);
292 		}
293 	}
294 	g_list_free(references);
295 	gtk_tree_selection_unselect_all(selection);
296 }
297 
name_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)298 static gint name_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
299 		gpointer user_data) {
300 	gchar *name_a, *name_b;
301 	gchar *collate_key1, *collate_key2;
302 	gint ret;
303 
304 	gtk_tree_model_get(model, a, COLUMN_FILENAME, &name_a, -1);
305 	gtk_tree_model_get(model, b, COLUMN_FILENAME, &name_b, -1);
306 
307 	collate_key1  = g_utf8_collate_key_for_filename(name_a, strlen(name_a));
308 	collate_key2  = g_utf8_collate_key_for_filename(name_b, strlen(name_b));
309 
310 	ret = g_strcmp0(collate_key1, collate_key2);
311 
312 	g_free(collate_key1);
313 	g_free(collate_key2);
314 	g_free(name_a);
315 	g_free(name_b);
316 
317 	return ret;
318 }
319 
size_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)320 static gint size_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
321 		gpointer user_data) {
322 	gint64 *size_a, *size_b;
323 
324 	gtk_tree_model_get(model, a, COLUMN_SIZE_INT64, &size_a, -1);
325 	gtk_tree_model_get(model, b, COLUMN_SIZE_INT64, &size_b, -1);
326 
327 	return size_a < size_b ? -1 : (size_a == size_b ? 0 : 1);
328 }
329 
date_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)330 static gint date_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
331 		gpointer user_data) {
332 	guint64 *date_a, *date_b;
333 
334 	gtk_tree_model_get(model, a, COLUMN_DATE_UNIX, &date_a, -1);
335 	gtk_tree_model_get(model, b, COLUMN_DATE_UNIX, &date_b, -1);
336 
337 	return date_a < date_b ? -1 : (date_a == date_b ? 0 : 1);
338 }
339 
fill_convert_list(GSList * list)340 void fill_convert_list(GSList *list) {
341 	GSList *l;
342 	init_widgets();
343 
344 	for (l = list; l; l = l->next) {
345 		char *filename;
346 
347 		filename = (char *) l->data;
348 		GFile *file = g_file_new_for_path(filename);
349 
350 		add_file_to_list(file);
351 		g_free(filename);
352 		g_object_unref(file);
353 	}
354 	check_for_conversion_form_completeness();
355 	on_input_files_change();
356 }
357 
on_clear_convert_button_clicked(GtkToolButton * button,gpointer user_data)358 void on_clear_convert_button_clicked(GtkToolButton *button, gpointer user_data) {
359 	init_widgets();
360 	gtk_list_store_clear(liststore_convert);
361 	check_for_conversion_form_completeness();
362 	on_input_files_change();
363 }
364 
on_remove_convert_button_clicked(GtkToolButton * button,gpointer user_data)365 void on_remove_convert_button_clicked(GtkToolButton *button, gpointer user_data) {
366 	init_widgets();
367 	remove_selected_files_from_list();
368 	check_for_conversion_form_completeness();
369 	on_input_files_change();
370 }
371 
on_treeview_convert_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,gpointer user_data)372 void on_treeview_convert_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time,
373 		gpointer user_data) {
374 	gtk_drag_unhighlight(widget);
375 }
376 
on_treeview_convert_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)377 gboolean on_treeview_convert_drag_motion(GtkWidget *widget, GdkDragContext *context,
378 		gint x, gint y, guint time) {
379 	gtk_drag_highlight(widget);
380 
381 	return TRUE;
382 }
383 
on_treeview_convert_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)384 void on_treeview_convert_drag_data_received(GtkWidget *widget,
385 		GdkDragContext *context, gint x, gint y,
386 		GtkSelectionData *selection_data, guint info, guint time,
387 		gpointer user_data) {
388 
389 	gchar **uris, **str;
390 	const guchar *data;
391 	GSList *list = NULL;
392 	gint bad_files = 0;
393 
394 	if (info != 0)
395 		return;
396 
397 	data = gtk_selection_data_get_data(selection_data);
398 	uris = g_uri_list_extract_uris((gchar *) data);
399 
400 	for (str = uris; *str; str++) {
401 		GError *error = NULL;
402 		gchar *path = g_filename_from_uri(*str, NULL, &error);
403 		if (path) {
404 			const char *src_ext = get_filename_ext(path);
405 			if (src_ext) {
406 				if (get_type_for_extension(src_ext) == TYPEUNDEF) {
407 					bad_files++;
408 				} else {
409 					list = g_slist_prepend(list, path);
410 				}
411 			} else bad_files++;
412 		} else {
413 			fprintf(stderr, "Could not convert uri to local path: %s",
414 					error->message);
415 			bad_files++;
416 			g_clear_error(&error);
417 		}
418 	}
419 	list = g_slist_sort(list, (GCompareFunc) strcompare);
420 	fill_convert_list(list);
421 	if (bad_files) {
422 		gchar *loc_str = ngettext("%d file was ignored while drag and drop\n",
423 				"%d files were ignored while drag and drop\n", bad_files);
424 		loc_str = g_strdup_printf(loc_str, bad_files);
425 		char *msg = siril_log_message(loc_str);
426 		siril_message_dialog(GTK_MESSAGE_INFO, msg,
427 				_("Files with unknown extension cannot be dropped in this area. "
428 						"Therefore they are ignored."));
429 		g_free(loc_str);
430 	}
431 	g_strfreev(uris);
432 	g_slist_free(list);
433 	on_input_files_change();
434 }
435 
on_treeview_convert_key_release_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)436 gboolean on_treeview_convert_key_release_event(GtkWidget *widget, GdkEventKey *event,
437 		gpointer user_data) {
438 	if (event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete
439 			|| event->keyval == GDK_KEY_BackSpace) {
440 		remove_selected_files_from_list();
441 		check_for_conversion_form_completeness();
442 		on_input_files_change();
443 		return TRUE;
444 	}
445 	return FALSE;
446 }
447 
check_for_conversion_form_completeness()448 static void check_for_conversion_form_completeness() {
449 	GtkTreeIter iter;
450 	static GtkWidget *go_button = NULL;
451 	if (!go_button)
452 		go_button = lookup_widget("convert_button");
453 
454 	init_widgets();
455 	gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
456 	gtk_widget_set_sensitive(go_button, destroot && destroot[0] != '\0' && valid);
457 }
458 
on_input_files_change()459 static void on_input_files_change() {
460 	/* we override the sort function in order to provide natural sort order */
461 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_FILENAME, (GtkTreeIterCompareFunc) name_sort_func, NULL, NULL);
462 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_SIZE, (GtkTreeIterCompareFunc) size_sort_func, NULL, NULL);
463 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), COLUMN_DATE_UNIX, (GtkTreeIterCompareFunc) date_sort_func, NULL, NULL);
464 
465 	update_statusbar_convert();
466 }
467 
468 /******************************* Callback functions ***********************************/
469 
470 // TODO: put a red lining around the entry instead of removing bad chars
insert_text_handler(GtkEntry * entry,const gchar * text,gint length,gint * position,gpointer data)471 void insert_text_handler(GtkEntry *entry, const gchar *text, gint length,
472 		gint *position, gpointer data) {
473 	GtkEditable *editable = GTK_EDITABLE(entry);
474 	int i, count = 0;
475 
476 	gchar *result = g_strndup(text, length);
477 
478 	for (i = 0; i < length; i++) {
479 		if (is_forbiden_in_filename(text[i]))
480 			continue;
481 		result[count++] = text[i];
482 	}
483 
484 	if (count > 0) {
485 		g_signal_handlers_block_by_func(G_OBJECT (editable),
486 				G_CALLBACK (insert_text_handler), data);
487 		gtk_editable_insert_text(editable, result, count, position);
488 		g_signal_handlers_unblock_by_func(G_OBJECT (editable),
489 				G_CALLBACK (insert_text_handler), data);
490 	}
491 	g_signal_stop_emission_by_name(G_OBJECT(editable), "insert_text");
492 
493 	g_free(result);
494 }
495 
update_statusbar_convert()496 void update_statusbar_convert() {
497 	static GtkLabel *status_label = NULL;
498 	if (!status_label)
499 		status_label = GTK_LABEL(lookup_widget("statuslabel_convert"));
500 
501 	int nb_files = count_converted_files();
502 	if (nb_files == 0)
503 		gtk_label_set_text(status_label, " ");
504 	else {
505 		int selected = count_selected_files();
506 		gchar *str1, *total;
507 
508 		str1 = ngettext("%d file loaded", "%d files loaded", nb_files);
509 		str1 = g_strdup_printf(str1, nb_files);
510 		if (selected == 0) {
511 			total = g_strdup(str1);
512 		} else {
513 			gchar *str2 = ngettext("%d file selected", "%d files selected", selected);
514 			str2 = g_strdup_printf(str2, selected);
515 			total = g_strdup_printf("%s, %s", str1, str2);
516 			g_free(str2);
517 		}
518 		gtk_label_set_text(status_label, total);
519 		g_free(str1);
520 		g_free(total);
521 	}
522 }
523 
on_treeview_selection5_changed(GtkTreeSelection * treeselection,gpointer user_data)524 void on_treeview_selection5_changed(GtkTreeSelection *treeselection,
525 		gpointer user_data) {
526 	update_statusbar_convert();
527 }
528 
process_destroot(sequence_type output_type)529 void process_destroot(sequence_type output_type) {
530 	static GtkEntry *convroot_entry = NULL;
531 	if (!convroot_entry)
532 		convroot_entry = GTK_ENTRY(lookup_widget("convroot_entry"));
533 
534 	const gchar *name = gtk_entry_get_text(convroot_entry);
535 	if (*name == '\0') {
536 		g_free(destroot);
537 		destroot = NULL;
538 		return;
539 	}
540 	destroot = g_str_to_ascii(name, NULL); // we want to avoid special char
541 	gboolean seq_exists = FALSE;
542 	if (output_type == SEQ_SER) {
543 		if (!g_str_has_suffix(destroot, ".ser"))
544 			str_append(&destroot, ".ser");
545 		seq_exists = check_if_seq_exist(destroot, FALSE);
546 	}
547 	else if (output_type == SEQ_FITSEQ) {
548 		if (!g_str_has_suffix(destroot, com.pref.ext))
549 			str_append(&destroot, com.pref.ext);
550 		seq_exists = check_if_seq_exist(destroot, FALSE);
551 	}
552 	else {
553 		destroot = format_basename(destroot, TRUE);
554 		seq_exists = check_if_seq_exist(destroot, TRUE);
555 	}
556 
557 	if (seq_exists && !warning_is_displayed) {
558 		set_icon_entry(convroot_entry, "gtk-dialog-warning");
559 		warning_is_displayed = TRUE;
560 	}
561 	else if (!seq_exists && warning_is_displayed) {
562 		set_icon_entry(convroot_entry, NULL);
563 		warning_is_displayed = FALSE;
564 	}
565 }
566 
567 /* 0: FITS images
568  * 1: SER sequence
569  * 2: FITS sequence
570  */
get_activated_output_type()571 static sequence_type get_activated_output_type() {
572 	static GtkComboBox *combo = NULL;
573 	if (!combo)
574 		combo = GTK_COMBO_BOX(gtk_builder_get_object(builder, "prepro_output_type_combo1"));
575 	return (sequence_type)gtk_combo_box_get_active(combo);
576 }
577 
578 // truncates destroot if it's more than 120 characters, append a '_' if it
579 // doesn't end with one or a '-'
on_convtoroot_changed(GtkEditable * editable,gpointer user_data)580 void on_convtoroot_changed(GtkEditable *editable, gpointer user_data){
581 	process_destroot(get_activated_output_type());
582 	check_for_conversion_form_completeness();
583 }
584 
585 // used for global file opening
on_demosaicing_toggled(GtkToggleButton * togglebutton,gpointer user_data)586 void on_demosaicing_toggled(GtkToggleButton *togglebutton, gpointer user_data) {
587 	com.pref.debayer.open_debayer = gtk_toggle_button_get_active(togglebutton);
588 }
589 
on_prepro_output_type_combo1_changed(GtkComboBox * combo,gpointer user_data)590 void on_prepro_output_type_combo1_changed(GtkComboBox *combo, gpointer user_data) {
591 	static GtkWidget *multiple_seq = NULL, *convert_symlink = NULL, *start = NULL;
592 	if (!multiple_seq) {
593 		multiple_seq = lookup_widget("multiple_seq");
594 		convert_symlink = lookup_widget("convert_symlink");
595 		start = lookup_widget("startIndiceEntry");
596 	}
597 
598 	sequence_type output = gtk_combo_box_get_active(combo);
599 	gboolean seqfile_output = output == SEQ_SER || output == SEQ_FITSEQ;
600 	gtk_widget_set_visible(multiple_seq, seqfile_output);
601 	gtk_widget_set_visible(start, !seqfile_output);
602 	if (!seqfile_output)
603 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(multiple_seq), FALSE);
604 	gtk_widget_set_visible(convert_symlink, !seqfile_output);
605 	process_destroot(output);
606 	check_for_conversion_form_completeness();
607 }
608