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-2017 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 <string.h>
22 
23 #include "core/siril.h"
24 #include "core/proto.h"
25 #include "core/initfile.h"
26 #include "gui/utils.h"
27 #include "gui/callbacks.h"
28 
29 #include "message_dialog.h"
30 
show_modal_dialog(gpointer p)31 static gboolean show_modal_dialog(gpointer p) {
32 	struct siril_dialog_data *args = (struct siril_dialog_data *) p;
33 	GtkTextIter itBeg, itEnd;
34 	GtkWidget *dialog;
35 
36 	dialog = gtk_message_dialog_new(args->parent,
37 			GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
38 			GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", args->primary_text);
39 
40 	if (args->secondary_text)
41 		gtk_message_dialog_format_secondary_markup(GTK_MESSAGE_DIALOG(dialog),
42 				"%s", args->secondary_text);
43 
44 	if (args->data) {
45 		GtkTextBuffer *buffer;
46 		GtkWidget *swindow;
47 		GtkWidget *tview;
48 
49 		tview = gtk_text_view_new();
50 		buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tview));
51 		gtk_text_buffer_get_bounds(buffer, &itBeg, &itEnd);
52 		gtk_text_buffer_delete(buffer, &itBeg, &itEnd);
53 		gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tview), FALSE);
54 		gtk_text_view_set_editable(GTK_TEXT_VIEW(tview), FALSE);
55 		gtk_text_buffer_set_text(buffer, args->data, strlen(args->data));
56 		gtk_widget_set_halign(tview, GTK_ALIGN_FILL);
57 		gtk_widget_set_valign(tview, GTK_ALIGN_FILL);
58 		gtk_widget_set_margin_start(tview, 6);
59 		gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tview), GTK_WRAP_WORD);
60 
61 		swindow = gtk_scrolled_window_new(NULL, NULL);
62 		gtk_container_add(GTK_CONTAINER(swindow), tview);
63 		gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
64 				swindow, FALSE, FALSE, 0);
65 		gtk_widget_set_size_request(swindow, -1, 200);
66 
67 		gtk_widget_show(swindow);
68 		gtk_widget_show(tview);
69 	}
70 
71 	gtk_dialog_run(GTK_DIALOG(dialog));
72 
73 	gtk_widget_destroy(dialog);
74 	g_free(args);
75 	return FALSE;
76 }
77 
strip_last_ret_char(gchar * str)78 static gchar *strip_last_ret_char(gchar *str) {
79 	char *pch;
80 	int len;
81 
82 	pch = strrchr(str, '\0');
83 	len = pch - str;
84 
85 	if (str[len - 1] == '\n') {
86 		str[len - 1] = '\0';
87 	}
88 	return str;
89 }
90 
91 /******* Public functions *****************/
92 
siril_message_dialog(GtkMessageType type,char * title,char * text)93 void siril_message_dialog(GtkMessageType type, char *title, char *text) {
94 	/* headless has no GUI, so no dialog; script has a GUI but calls it from another thread
95 	 * so it's not safe to use dialogs in the calling thread, we just ignore it for now. */
96 	if (com.headless || com.script)
97 		return;	// show_dialog usually follows a siril_log_message() call
98 	struct siril_dialog_data *args = g_try_malloc(sizeof(struct siril_dialog_data));
99 
100 	args->parent = siril_get_active_window();
101 	if (!GTK_IS_WINDOW(args->parent)) {
102 		args->parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
103 	}
104 	/* first we want to remove the '\n' at the end of the title and text
105 	 * if message come from siril_log_message
106 	 */
107 	strip_last_ret_char(title);
108 	strip_last_ret_char(text);
109 
110 	args->primary_text = title;
111 	args->secondary_text = text;
112 	args->data = NULL;
113 	args->type = type;
114 	show_modal_dialog(args);
115 }
116 
117 struct message_data {
118 	GtkMessageType type;
119 	char *title;
120 	char *text;
121 };
122 
siril_message_dialog_idle(gpointer p)123 static gboolean siril_message_dialog_idle(gpointer p) {
124 	struct message_data *data = (struct message_data *) p;
125 	siril_message_dialog(data->type, data->title, data->text);
126 	free(data->title);
127 	free(data->text);
128 	free(data);
129 	return FALSE;
130 }
131 
queue_message_dialog(GtkMessageType type,char * title,char * text)132 void queue_message_dialog(GtkMessageType type, char *title, char *text) {
133 	if (com.headless || com.script)
134 		return;	// show_dialog usually follows a siril_log_message() call
135 	struct message_data *data = malloc(sizeof(struct message_data));
136 	data->type = type;
137 	data->title = strdup(title);
138 	data->text = strdup(text);
139 	gdk_threads_add_idle(siril_message_dialog_idle, data);
140 }
141 
siril_data_dialog(GtkMessageType type,char * title,char * text,gchar * data)142 void siril_data_dialog(GtkMessageType type, char *title, char *text, gchar *data) {
143 	if (com.headless || com.script)
144 		return;	// show_dialog usually follows a siril_log_message() call
145 	struct siril_dialog_data *args = malloc(sizeof(struct siril_dialog_data));
146 
147 	args->parent = siril_get_active_window();
148 	if (!GTK_IS_WINDOW(args->parent)) {
149 		args->parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
150 	}
151 	/* first we want to remove the '\n' at the end of the title and text
152 	 * if message come from siril_log_message
153 	 */
154 	strip_last_ret_char(title);
155 	strip_last_ret_char(text);
156 
157 	args->primary_text = title;
158 	args->secondary_text = text;
159 	args->data = data;
160 	args->type = type;
161 	show_modal_dialog(args);
162 }
163 
siril_confirm_dialog_internal(gchar * title,gchar * msg,gchar * button_accept,gboolean checkbutton,gboolean * user_data)164 static gboolean siril_confirm_dialog_internal(gchar *title, gchar *msg, gchar *button_accept, gboolean checkbutton, gboolean *user_data) {
165 	GtkWindow *parent;
166 	GtkWidget *dialog, *check = NULL;
167 	gint res;
168 	gboolean ok = FALSE;
169 	gboolean var_to_return = FALSE;
170 
171 	parent = siril_get_active_window();
172 	if (!GTK_IS_WINDOW(parent)) {
173 		/* could happen if the GtkWindow has been destroyed right after the call
174 		 * This is the case for chooser dialog */
175 		parent = GTK_WINDOW(GTK_APPLICATION_WINDOW(lookup_widget("control_window")));
176 	}
177 
178 	/* first we want to remove the '\n' at the end of the title and text
179 	 * if message come from siril_log_message
180 	 */
181 	strip_last_ret_char(title);
182 	strip_last_ret_char(msg);
183 
184 	dialog = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL,
185 			GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, "%s", title);
186 	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", msg);
187 
188 	gtk_dialog_add_button(GTK_DIALOG(dialog), button_accept, GTK_RESPONSE_ACCEPT);
189 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
190 
191 	if (checkbutton) {
192 		check = gtk_check_button_new_with_mnemonic(_("_Do not show this dialog again"));
193 		gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG (dialog))),
194 				check, FALSE, FALSE, 0);
195 		gtk_widget_set_halign(check, GTK_ALIGN_START);
196 		gtk_widget_set_margin_start(check, 6);
197 		gtk_widget_show(check);
198 	}
199 	res = gtk_dialog_run(GTK_DIALOG(dialog));
200 	if (res == GTK_RESPONSE_ACCEPT) {
201 		ok = TRUE;
202 		if (check) {
203 			var_to_return = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
204 		}
205 	}
206 	if (user_data) {
207 		*user_data = var_to_return;
208 	}
209 
210 	gtk_widget_destroy(dialog);
211 
212 	return ok;
213 }
214 
siril_confirm_dialog(gchar * title,gchar * msg,gchar * button_accept)215 gboolean siril_confirm_dialog(gchar *title, gchar *msg, gchar *button_accept) {
216 	return siril_confirm_dialog_internal(title, msg, button_accept, FALSE, NULL);
217 }
218 
siril_confirm_dialog_and_remember(gchar * title,gchar * msg,gchar * button_accept,gboolean * user_data)219 gboolean siril_confirm_dialog_and_remember(gchar *title, gchar *msg, gchar *button_accept, gboolean *user_data) {
220 	return siril_confirm_dialog_internal(title, msg, button_accept, TRUE, user_data);
221 }
222