1 /*
2  * Copyright 2017 LarsGit223
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 /*
20  * This file contains all the code for the dialogs.
21  */
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25 
26 #include "wb_globals.h"
27 #include "dialogs.h"
28 #include "utils.h"
29 
30 extern GeanyPlugin *geany_plugin;
31 
32 
33 /** Shows the dialog "Create new file".
34  *
35  * The dialog lets the user create a new file (filter *).
36  *
37  * @param path The current folder
38  * @return The filename
39  *
40  **/
dialogs_create_new_file(const gchar * path)41 gchar *dialogs_create_new_file(const gchar *path)
42 {
43 	gchar *filename = NULL;
44 	GtkWidget *dialog;
45 
46 	dialog = gtk_file_chooser_dialog_new(_("Create new file"),
47 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SAVE,
48 		_("_Cancel"), GTK_RESPONSE_CANCEL,
49 		_("C_reate"), GTK_RESPONSE_ACCEPT, NULL);
50 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
51 
52 	if (path != NULL)
53 	{
54 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
55 	}
56 
57 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
58 	{
59 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
60 	}
61 
62 	gtk_widget_destroy(dialog);
63 
64 	return filename;
65 }
66 
67 
68 /** Shows the dialog "Create new directory".
69  *
70  * The dialog lets the user create a new directory.
71  *
72  * @param path The current folder
73  * @return The filename
74  *
75  **/
dialogs_create_new_directory(const gchar * path)76 gchar *dialogs_create_new_directory(const gchar *path)
77 {
78 	gchar *filename = NULL;
79 	GtkWidget *dialog;
80 
81 	dialog = gtk_file_chooser_dialog_new(_("Create new directory"),
82 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
83 		_("_Cancel"), GTK_RESPONSE_CANCEL,
84 		_("C_reate"), GTK_RESPONSE_ACCEPT, NULL);
85 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
86 
87 	if (path != NULL)
88 	{
89 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
90 	}
91 
92 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
93 	{
94 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
95 	}
96 
97 	gtk_widget_destroy(dialog);
98 
99 	return filename;
100 }
101 
102 
103 /** Shows the dialog "Create new workbench".
104  *
105  * The dialog lets the user create a new workbench file (filter *.geanywb).
106  *
107  * @return The filename
108  *
109  **/
dialogs_create_new_workbench(void)110 gchar *dialogs_create_new_workbench(void)
111 {
112 	gchar *filename = NULL;
113 	GtkWidget *dialog;
114 
115 	dialog = gtk_file_chooser_dialog_new(_("Create new workbench"),
116 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SAVE,
117 		_("_Cancel"), GTK_RESPONSE_CANCEL,
118 		_("C_reate"), GTK_RESPONSE_ACCEPT, NULL);
119 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "new.geanywb");
120 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
121 
122 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
123 	{
124 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
125 	}
126 
127 	gtk_widget_destroy(dialog);
128 
129 	return filename;
130 }
131 
132 
133 /** Shows the dialog "Open workbench".
134  *
135  * The dialog lets the user choose an existing workbench file (filter *.geanywb).
136  *
137  * @return The filename
138  *
139  **/
dialogs_open_workbench(void)140 gchar *dialogs_open_workbench(void)
141 {
142 	gchar *filename = NULL;
143 	GtkWidget *dialog;
144 	GtkFileFilter *filter;
145 
146 	dialog = gtk_file_chooser_dialog_new(_("Open workbench"),
147 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_OPEN,
148 		_("_Cancel"), GTK_RESPONSE_CANCEL,
149 		_("_Open"), GTK_RESPONSE_ACCEPT, NULL);
150 
151 	filter = gtk_file_filter_new();
152 	gtk_file_filter_set_name(filter, _("Workbench files (.geanywb)"));
153 	gtk_file_filter_add_pattern(filter, "*.geanywb");
154 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
155 	filter = gtk_file_filter_new();
156 	gtk_file_filter_set_name(filter, _("All Files"));
157 	gtk_file_filter_add_pattern(filter, "*");
158 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
159 
160 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
161 	{
162 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
163 	}
164 
165 	gtk_widget_destroy(dialog);
166 
167 	return filename;
168 }
169 
170 
171 /** Shows the dialog "Add project".
172  *
173  * The dialog lets the user choose an existing project file
174  * (filter *.geany or *).
175  *
176  * @return The filename
177  *
178  **/
dialogs_add_project(void)179 gchar *dialogs_add_project(void)
180 {
181 	gchar *filename = NULL;
182 	GtkWidget *dialog;
183 	GtkFileFilter *filter;
184 
185 	dialog = gtk_file_chooser_dialog_new(_("Add project"),
186 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_OPEN,
187 		_("_Cancel"), GTK_RESPONSE_CANCEL,
188 		_("_Add"), GTK_RESPONSE_ACCEPT, NULL);
189 
190 	filter = gtk_file_filter_new();
191 	gtk_file_filter_set_name(filter, _("Project files (.geany)"));
192 	gtk_file_filter_add_pattern(filter, "*.geany");
193 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
194 	filter = gtk_file_filter_new();
195 	gtk_file_filter_set_name(filter, _("All Files"));
196 	gtk_file_filter_add_pattern(filter, "*");
197 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
198 
199 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
200 	{
201 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
202 	}
203 
204 	gtk_widget_destroy(dialog);
205 
206 	return filename;
207 }
208 
209 
210 /** Shows the dialog "Add directory".
211  *
212  * The dialog lets the user choose an existing folder.
213  *
214  * @return The filename
215  *
216  **/
dialogs_add_directory(WB_PROJECT * project)217 gchar *dialogs_add_directory(WB_PROJECT *project)
218 {
219 	gchar *filename = NULL;
220 	GtkWidget *dialog;
221 
222 	dialog = gtk_file_chooser_dialog_new(_("Add directory"),
223 		GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
224 		_("_Cancel"), GTK_RESPONSE_CANCEL,
225 		_("_Add"), GTK_RESPONSE_ACCEPT, NULL);
226 	if (project != NULL)
227 	{
228 		const gchar *path;
229 
230 		/* Set the current folder to the location of the project file */
231 		path = wb_project_get_filename(project);
232 		if (path != NULL)
233 		{
234 			gchar *dirname = g_path_get_dirname(path);
235 			gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dirname);
236 			g_free(dirname);
237 		}
238 	}
239 
240 	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
241 	{
242 		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
243 	}
244 
245 	gtk_widget_destroy(dialog);
246 
247 	return filename;
248 }
249 
250 
251 /* Split patterns in str into gchar** */
split_patterns(const gchar * str)252 static gchar **split_patterns(const gchar *str)
253 {
254 	GString *tmp;
255 	gchar **ret;
256 	gchar *input;
257 
258 	input = g_strdup(str);
259 
260 	g_strstrip(input);
261 	tmp = g_string_new(input);
262 	g_free(input);
263 	do {} while (utils_string_replace_all(tmp, "  ", " "));
264 	ret = g_strsplit(tmp->str, " ", -1);
265 	g_string_free(tmp, TRUE);
266 	return ret;
267 }
268 
269 typedef struct S_DIALOG_DIR_SETTINGS_DATA
270 {
271 	GtkWidget *dialog;
272 	GtkWidget *w_label_file_patterns;
273 	GtkWidget *w_file_patterns;
274 	GtkWidget *w_label_ignored_dirs_patterns;
275 	GtkWidget *w_ignored_dirs_patterns;
276 	GtkWidget *w_label_ignored_file_patterns;
277 	GtkWidget *w_ignored_file_patterns;
278 	GtkWidget *w_scan_mode_wb;
279 	GtkWidget *w_scan_mode_git;
280 }DIALOG_DIR_SETTINGS_DATA;
281 
button_filter_workbench_toggled(GtkToggleButton * togglebutton,gpointer user_data)282 static void button_filter_workbench_toggled(GtkToggleButton *togglebutton,
283 											gpointer user_data)
284 {
285 	DIALOG_DIR_SETTINGS_DATA *data;
286 
287 	data = user_data;
288 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->w_scan_mode_wb)))
289 	{
290 		gtk_widget_set_sensitive (data->w_label_file_patterns, TRUE);
291 		gtk_widget_set_sensitive (data->w_file_patterns, TRUE);
292 		gtk_widget_set_sensitive (data->w_label_ignored_dirs_patterns, TRUE);
293 		gtk_widget_set_sensitive (data->w_ignored_dirs_patterns, TRUE);
294 		gtk_widget_set_sensitive (data->w_label_ignored_file_patterns, TRUE);
295 		gtk_widget_set_sensitive (data->w_ignored_file_patterns, TRUE);
296 	}
297 	else
298 	{
299 		gtk_widget_set_sensitive (data->w_label_file_patterns, FALSE);
300 		gtk_widget_set_sensitive (data->w_file_patterns, FALSE);
301 		gtk_widget_set_sensitive (data->w_label_ignored_dirs_patterns, FALSE);
302 		gtk_widget_set_sensitive (data->w_ignored_dirs_patterns, FALSE);
303 		gtk_widget_set_sensitive (data->w_label_ignored_file_patterns, FALSE);
304 		gtk_widget_set_sensitive (data->w_ignored_file_patterns, FALSE);
305 	}
306 }
307 
button_filter_git_toggled(GtkToggleButton * togglebutton,gpointer user_data)308 static void button_filter_git_toggled(GtkToggleButton *togglebutton,
309 									gpointer user_data)
310 {
311 	/* Nothing to do for now... */
312 }
313 
314 /** Shows the directory settings dialog.
315  *
316  * The dialog lets the user edit the settings for file patterns, irnored file patterns and
317  * ignored directories patterns. On accept the result is directly stored in @a directory.
318  *
319  * @param  project   The project to which directory belongs to
320  * @param  directory Location of WB_PROJECT_DIR to store the settings into
321  * @return TRUE if the settings have changed, FALSE otherwise
322  *
323  **/
dialogs_directory_settings(WB_PROJECT * project,WB_PROJECT_DIR * directory)324 gboolean dialogs_directory_settings(WB_PROJECT *project, WB_PROJECT_DIR *directory)
325 {
326 	DIALOG_DIR_SETTINGS_DATA *data;
327 	GtkWidget *label, *content_area;
328 	GtkWidget *vbox, *hbox, *hbox1;
329 #if GTK_CHECK_VERSION(3, 4, 0)
330 	GtkWidget *grid;
331 #else
332 	GtkWidget *table;
333 #endif
334 	GtkDialogFlags flags;
335 	gchar *file_patterns_old, *ignored_file_patterns_old, *ignored_dirs_patterns_old;
336 	WB_PROJECT_SCAN_MODE scan_mode_old, scan_mode;
337 	gchar *abs_path;
338 	gboolean changed;
339 	guint row = 0;
340 
341 	data = g_new0(DIALOG_DIR_SETTINGS_DATA, 1);
342 
343 	/* Create the widgets */
344 	flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
345 	data->dialog = gtk_dialog_new_with_buttons(_("Directory settings"),
346 											   GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window),
347 											   flags,
348 											   _("_Cancel"), GTK_RESPONSE_CANCEL,
349 											   _("_OK"), GTK_RESPONSE_ACCEPT,
350 											   NULL);
351 	content_area = gtk_dialog_get_content_area(GTK_DIALOG (data->dialog));
352 
353 	vbox = gtk_vbox_new(FALSE, 0);
354 
355 #if GTK_CHECK_VERSION(3, 4, 0)
356 	grid = gtk_grid_new ();
357 	gtk_grid_set_row_spacing (GTK_GRID(grid), 5);
358 	gtk_grid_set_column_spacing (GTK_GRID(grid), 10);
359 #else
360 	table = gtk_table_new(5, 2, FALSE);
361 	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
362 	gtk_table_set_col_spacings(GTK_TABLE(table), 10);
363 #endif
364 
365 	data->w_scan_mode_wb = gtk_radio_button_new_with_label (NULL, _("filter files using the workbench plugin"));
366 	g_signal_connect(data->w_scan_mode_wb, "toggled",
367 			G_CALLBACK(button_filter_workbench_toggled), data);
368 	gtk_box_pack_start(GTK_BOX(vbox), data->w_scan_mode_wb, FALSE, FALSE, 6);
369 
370 	data->w_label_file_patterns = gtk_label_new(_("File patterns:"));
371 #if GTK_CHECK_VERSION(3, 16, 0)
372 	gtk_label_set_xalign (GTK_LABEL(data->w_label_file_patterns), 0);
373 	gtk_label_set_yalign (GTK_LABEL(data->w_label_file_patterns), 0);
374 #else
375 	gtk_misc_set_alignment(GTK_MISC(data->w_label_file_patterns), 0, 0);
376 #endif
377 	data->w_file_patterns = gtk_entry_new();
378 #if GTK_CHECK_VERSION(3, 4, 0)
379 	gtk_grid_attach (GTK_GRID(grid), data->w_label_file_patterns, 0, row, 1, 1);
380 	gtk_grid_attach (GTK_GRID(grid), data->w_file_patterns, 1, row, 1, 1);
381 	gtk_widget_set_valign (data->w_label_file_patterns, GTK_ALIGN_BASELINE);
382 	gtk_widget_set_hexpand (data->w_label_file_patterns, FALSE);
383 	gtk_widget_set_valign (data->w_file_patterns, GTK_ALIGN_BASELINE);
384 	gtk_widget_set_hexpand (data->w_file_patterns, TRUE);
385 #else
386 	ui_table_add_row(GTK_TABLE(table), row + 1, data->w_label_file_patterns, data->w_file_patterns, NULL);
387 #endif
388 	row++;
389 	ui_entry_add_clear_icon(GTK_ENTRY(data->w_file_patterns));
390 	gtk_widget_set_tooltip_text(data->w_file_patterns,
391 		_("Space separated list of patterns that are used to identify files "
392 		  "that shall be displayed in the directory tree."));
393 	file_patterns_old = g_strjoinv(" ", wb_project_dir_get_file_patterns(directory));
394 	gtk_entry_set_text(GTK_ENTRY(data->w_file_patterns), file_patterns_old);
395 
396 	data->w_label_ignored_file_patterns = gtk_label_new(_("Ignored file patterns:"));
397 #if GTK_CHECK_VERSION(3, 16, 0)
398 	gtk_label_set_xalign (GTK_LABEL(data->w_label_ignored_file_patterns), 0);
399 	gtk_label_set_yalign (GTK_LABEL(data->w_label_ignored_file_patterns), 0);
400 #else
401 	gtk_misc_set_alignment(GTK_MISC(data->w_label_ignored_file_patterns), 0, 0);
402 #endif
403 	data->w_ignored_file_patterns = gtk_entry_new();
404 	ui_entry_add_clear_icon(GTK_ENTRY(data->w_ignored_file_patterns));
405 #if GTK_CHECK_VERSION(3, 4, 0)
406 	gtk_grid_attach (GTK_GRID(grid), data->w_label_ignored_file_patterns, 0, row, 1, 1);
407 	gtk_grid_attach (GTK_GRID(grid), data->w_ignored_file_patterns, 1, row, 1, 1);
408 	gtk_widget_set_valign (data->w_label_ignored_file_patterns, GTK_ALIGN_BASELINE);
409 	gtk_widget_set_hexpand (data->w_label_ignored_file_patterns, FALSE);
410 	gtk_widget_set_valign (data->w_ignored_file_patterns, GTK_ALIGN_BASELINE);
411 	gtk_widget_set_hexpand (data->w_ignored_file_patterns, TRUE);
412 #else
413 	ui_table_add_row(GTK_TABLE(table), row + 1, data->w_label_ignored_file_patterns, data->w_ignored_file_patterns, NULL);
414 #endif
415 	row++;
416 	gtk_widget_set_tooltip_text(data->w_ignored_file_patterns,
417 		_("Space separated list of patterns that are used to identify files "
418 		  "that shall not be displayed in the directory tree."));
419 	ignored_file_patterns_old = g_strjoinv(" ", wb_project_dir_get_ignored_file_patterns(directory));
420 	gtk_entry_set_text(GTK_ENTRY(data->w_ignored_file_patterns), ignored_file_patterns_old);
421 
422 	data->w_label_ignored_dirs_patterns = gtk_label_new(_("Ignored directory patterns:"));
423 #if GTK_CHECK_VERSION(3, 16, 0)
424 	gtk_label_set_xalign (GTK_LABEL(data->w_label_ignored_dirs_patterns), 0);
425 	gtk_label_set_yalign (GTK_LABEL(data->w_label_ignored_dirs_patterns), 0);
426 #else
427 	gtk_misc_set_alignment(GTK_MISC(data->w_label_ignored_dirs_patterns), 0, 0);
428 #endif
429 	data->w_ignored_dirs_patterns = gtk_entry_new();
430 	ui_entry_add_clear_icon(GTK_ENTRY(data->w_ignored_dirs_patterns));
431 #if GTK_CHECK_VERSION(3, 4, 0)
432 	gtk_grid_attach (GTK_GRID(grid), data->w_label_ignored_dirs_patterns, 0, row, 1, 1);
433 	gtk_grid_attach (GTK_GRID(grid), data->w_ignored_dirs_patterns, 1, row, 1, 1);
434 	gtk_widget_set_valign (data->w_label_ignored_dirs_patterns, GTK_ALIGN_BASELINE);
435 	gtk_widget_set_hexpand (data->w_label_ignored_dirs_patterns, FALSE);
436 	gtk_widget_set_valign (data->w_ignored_dirs_patterns, GTK_ALIGN_BASELINE);
437 	gtk_widget_set_hexpand (data->w_ignored_dirs_patterns, TRUE);
438 #else
439 	ui_table_add_row(GTK_TABLE(table), row + 1, data->w_label_ignored_dirs_patterns, data->w_ignored_dirs_patterns, NULL);
440 #endif
441 	row++;
442 	gtk_widget_set_tooltip_text(data->w_ignored_dirs_patterns,
443 		_("Space separated list of patterns that are used to identify directories "
444 		  "that shall not be scanned for source files."));
445 	ignored_dirs_patterns_old = g_strjoinv(" ", wb_project_dir_get_ignored_dirs_patterns(directory));
446 	gtk_entry_set_text(GTK_ENTRY(data->w_ignored_dirs_patterns), ignored_dirs_patterns_old);
447 
448 #if GTK_CHECK_VERSION(3, 12, 0)
449 	gtk_widget_set_margin_start (grid, 32);
450 #endif
451 #if GTK_CHECK_VERSION(3, 4, 0)
452 	gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 6);
453 #else
454 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 6);
455 #endif
456 
457 	data->w_scan_mode_git = gtk_radio_button_new_with_label (
458 		gtk_radio_button_get_group(GTK_RADIO_BUTTON (data->w_scan_mode_wb)),
459 		_("filter files using git (.gitignore)"));
460 	g_signal_connect(data->w_scan_mode_git, "toggled",
461 			G_CALLBACK(button_filter_git_toggled), data);
462 	gtk_box_pack_start(GTK_BOX(vbox), data->w_scan_mode_git, FALSE, FALSE, 6);
463 
464 	hbox1 = gtk_hbox_new(FALSE, 0);
465 	label = gtk_label_new(_("Note: the patterns above affect only the workbench directory and are not used in the Find in Files\n"
466 	"dialog."));
467 	gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 0);
468 	gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 6);
469 
470 	hbox = gtk_hbox_new(FALSE, 0);
471 	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6);
472 
473 	/* Add the label, and show everything we’ve added */
474 	gtk_container_add(GTK_CONTAINER (content_area), label);
475 	gtk_container_add(GTK_CONTAINER (content_area), hbox);
476 
477 
478 	scan_mode_old = wb_project_dir_get_scan_mode(directory);
479 	abs_path = get_combined_path(wb_project_get_filename(project),
480 		wb_project_dir_get_base_dir(directory));
481 	if (!is_git_repository(abs_path))
482 	{
483 		/* Disable git filter option if the directory is not a git repository. */
484 		gtk_widget_set_sensitive (data->w_scan_mode_git, FALSE);
485 	}
486 	else
487 	{
488 		/* Both options are possible, set the active option from
489 		   the current settings. */
490 		if (scan_mode_old == WB_PROJECT_SCAN_MODE_WORKBENCH)
491 		{
492 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->w_scan_mode_wb), TRUE);
493 		}
494 		else
495 		{
496 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->w_scan_mode_git), TRUE);
497 		}
498 	}
499 	g_free(abs_path);
500 
501 
502 	gtk_widget_show_all(data->dialog);
503 	gint result = gtk_dialog_run(GTK_DIALOG(data->dialog));
504 	changed = FALSE;
505 	if (result == GTK_RESPONSE_ACCEPT)
506 	{
507 		const gchar *str;
508 		gchar **file_patterns, **ignored_dirs_patterns, **ignored_file_patterns;
509 
510 		scan_mode = WB_PROJECT_SCAN_MODE_WORKBENCH;
511 		if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->w_scan_mode_git)))
512 		{
513 			scan_mode = WB_PROJECT_SCAN_MODE_GIT;
514 		}
515 		if (scan_mode_old != scan_mode)
516 		{
517 			changed = TRUE;
518 		}
519 
520 		str = gtk_entry_get_text(GTK_ENTRY(data->w_file_patterns));
521 		if (g_strcmp0(str, file_patterns_old) != 0)
522 		{
523 			changed = TRUE;
524 		}
525 		file_patterns = split_patterns(str);
526 
527 		str = gtk_entry_get_text(GTK_ENTRY(data->w_ignored_dirs_patterns));
528 		if (g_strcmp0(str, ignored_dirs_patterns_old) != 0)
529 		{
530 			changed = TRUE;
531 		}
532 		ignored_dirs_patterns = split_patterns(str);
533 
534 		str = gtk_entry_get_text(GTK_ENTRY(data->w_ignored_file_patterns));
535 		if (g_strcmp0(str, ignored_file_patterns_old) != 0)
536 		{
537 			changed = TRUE;
538 		}
539 		ignored_file_patterns = split_patterns(str);
540 
541 		wb_project_dir_set_scan_mode(project, directory, scan_mode);
542 		wb_project_dir_set_file_patterns(directory, file_patterns);
543 		wb_project_dir_set_ignored_dirs_patterns(directory, ignored_dirs_patterns);
544 		wb_project_dir_set_ignored_file_patterns(directory, ignored_file_patterns);
545 
546 		g_strfreev(file_patterns);
547 		g_strfreev(ignored_dirs_patterns);
548 		g_strfreev(ignored_file_patterns);
549 	}
550 
551 	g_free(file_patterns_old);
552 	g_free(ignored_file_patterns_old);
553 	g_free(ignored_dirs_patterns_old);
554 	gtk_widget_destroy(data->dialog);
555 
556 	return changed;
557 }
558 
559 
560 /** Shows the workbench settings dialog.
561  *
562  * The dialog lets the user edit the settings for option "Rescan all projects on open".
563  * On accept the result is directly stored in @a workbench.
564  *
565  * @param  workbench Location of WORKBENCH to store the settings into
566  * @return TRUE if the settings have changed, FALSE otherwise
567  *
568  **/
dialogs_workbench_settings(WORKBENCH * workbench)569 gboolean dialogs_workbench_settings(WORKBENCH *workbench)
570 {
571 	gint result;
572 	GtkWidget *w_rescan_projects_on_open, *w_enable_live_update, *w_expand_on_hover;
573 	GtkWidget *dialog, *content_area, *w_enable_tree_lines;
574 	GtkWidget *vbox, *hbox;
575 #if GTK_CHECK_VERSION(3, 4, 0)
576 	GtkWidget *grid;
577 #else
578 	GtkWidget *table;
579 #endif
580 	GtkDialogFlags flags;
581 	gboolean changed, rescan_projects_on_open, rescan_projects_on_open_old;
582 	gboolean enable_live_update, enable_live_update_old;
583 	gboolean expand_on_hover, expand_on_hover_old;
584 	gboolean enable_tree_lines, enable_tree_lines_old;
585 
586 	/* Create the widgets */
587 	flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
588 	dialog = gtk_dialog_new_with_buttons(_("Workbench settings"),
589 										 GTK_WINDOW(wb_globals.geany_plugin->geany_data->main_widgets->window),
590 										 flags,
591 										 _("_Cancel"), GTK_RESPONSE_CANCEL,
592 										 _("_OK"), GTK_RESPONSE_ACCEPT,
593 										 NULL);
594 	content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
595 
596 	vbox = gtk_vbox_new(FALSE, 0);
597 
598 #if GTK_CHECK_VERSION(3, 4, 0)
599 	grid = gtk_grid_new ();
600 	gtk_grid_set_row_spacing (GTK_GRID(grid), 5);
601 	gtk_grid_set_column_spacing (GTK_GRID(grid), 10);
602 #else
603 	table = gtk_table_new(5, 2, FALSE);
604 	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
605 	gtk_table_set_col_spacings(GTK_TABLE(table), 10);
606 #endif
607 
608 	w_rescan_projects_on_open = gtk_check_button_new_with_mnemonic(_("_Rescan all projects on open"));
609 #if GTK_CHECK_VERSION(3, 4, 0)
610 	gtk_grid_attach (GTK_GRID(grid), w_rescan_projects_on_open, 0, 0, 1, 1);
611 	gtk_widget_set_halign (w_rescan_projects_on_open, GTK_ALIGN_CENTER);
612 	gtk_widget_set_hexpand (w_rescan_projects_on_open, TRUE);
613 	gtk_widget_set_valign (w_rescan_projects_on_open, GTK_ALIGN_CENTER);
614 	gtk_widget_set_vexpand (w_rescan_projects_on_open, TRUE);
615 #else
616 	ui_table_add_row(GTK_TABLE(table), 0, w_rescan_projects_on_open, NULL);
617 #endif
618 	gtk_widget_set_tooltip_text(w_rescan_projects_on_open,
619 		_("If the option is activated (default), then all projects will be re-scanned "
620 		  "on opening of the workbench."));
621 	rescan_projects_on_open_old = workbench_get_rescan_projects_on_open(workbench);
622 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_rescan_projects_on_open), rescan_projects_on_open_old);
623 
624 	w_enable_live_update = gtk_check_button_new_with_mnemonic(_("_Enable live update"));
625 #if GTK_CHECK_VERSION(3, 4, 0)
626 	gtk_grid_attach (GTK_GRID(grid), w_enable_live_update, 0, 1, 1, 1);
627 	gtk_widget_set_halign (w_enable_live_update, GTK_ALIGN_CENTER);
628 	gtk_widget_set_hexpand (w_enable_live_update, TRUE);
629 	gtk_widget_set_valign (w_enable_live_update, GTK_ALIGN_CENTER);
630 	gtk_widget_set_vexpand (w_enable_live_update, TRUE);
631 #else
632 	ui_table_add_row(GTK_TABLE(table), 1, w_enable_live_update, NULL);
633 #endif
634 	gtk_widget_set_tooltip_text(w_enable_live_update,
635 		_("If the option is activated (default), then the list of files and the sidebar "
636 		  "will be updated automatically if a file or directory is created, removed or renamed. "
637 		  "A manual re-scan is not required if the option is enabled."));
638 	enable_live_update_old = workbench_get_enable_live_update(workbench);
639 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_enable_live_update), enable_live_update_old);
640 
641 	w_expand_on_hover = gtk_check_button_new_with_mnemonic(_("_Expand on hover"));
642 #if GTK_CHECK_VERSION(3, 4, 0)
643 	gtk_grid_attach (GTK_GRID(grid), w_expand_on_hover, 0, 2, 1, 1);
644 	gtk_widget_set_halign (w_expand_on_hover, GTK_ALIGN_CENTER);
645 	gtk_widget_set_hexpand (w_expand_on_hover, TRUE);
646 	gtk_widget_set_valign (w_expand_on_hover, GTK_ALIGN_CENTER);
647 	gtk_widget_set_vexpand (w_expand_on_hover, TRUE);
648 #else
649 	ui_table_add_row(GTK_TABLE(table), 2, w_expand_on_hover, NULL);
650 #endif
651 	gtk_widget_set_tooltip_text(w_expand_on_hover,
652 		_("If the option is activated, then a tree node in the sidebar "
653 		  "will be expanded or collapsed by hovering over it with the mouse cursor."));
654 	expand_on_hover_old = workbench_get_expand_on_hover(workbench);
655 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_expand_on_hover), expand_on_hover_old);
656 
657 	w_enable_tree_lines = gtk_check_button_new_with_mnemonic(_("_Enable tree lines"));
658 #if GTK_CHECK_VERSION(3, 4, 0)
659 	gtk_grid_attach (GTK_GRID(grid), w_enable_tree_lines, 0, 3, 1, 1);
660 	gtk_widget_set_halign (w_enable_tree_lines, GTK_ALIGN_CENTER);
661 	gtk_widget_set_hexpand (w_enable_tree_lines, TRUE);
662 	gtk_widget_set_valign (w_enable_tree_lines, GTK_ALIGN_CENTER);
663 	gtk_widget_set_vexpand (w_enable_tree_lines, TRUE);
664 #else
665 	ui_table_add_row(GTK_TABLE(table), 3, w_enable_tree_lines, NULL);
666 #endif
667 	gtk_widget_set_tooltip_text(w_enable_tree_lines,
668 		_("If the option is activated, lines will be drawn between "
669 		  "the nodes in the sidebar tree."));
670 	enable_tree_lines_old = workbench_get_enable_tree_lines(workbench);
671 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_enable_tree_lines), enable_tree_lines_old);
672 
673 #if GTK_CHECK_VERSION(3, 4, 0)
674 	gtk_box_pack_start(GTK_BOX(vbox), grid, FALSE, FALSE, 6);
675 #else
676 	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 6);
677 #endif
678 
679 	hbox = gtk_hbox_new(FALSE, 0);
680 	gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6);
681 
682 	/* Show everything we’ve added, run dialog */
683 	gtk_container_add(GTK_CONTAINER (content_area), hbox);
684 	gtk_widget_show_all(dialog);
685 	result = gtk_dialog_run(GTK_DIALOG(dialog));
686 
687 	changed = FALSE;
688 	if (result == GTK_RESPONSE_ACCEPT)
689 	{
690 		rescan_projects_on_open = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_rescan_projects_on_open));
691 		if (rescan_projects_on_open != rescan_projects_on_open_old)
692 		{
693 			changed = TRUE;
694 			workbench_set_rescan_projects_on_open(workbench, rescan_projects_on_open);
695 		}
696 		enable_live_update = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_enable_live_update));
697 		if (enable_live_update != enable_live_update_old)
698 		{
699 			changed = TRUE;
700 			workbench_set_enable_live_update(workbench, enable_live_update);
701 		}
702 		expand_on_hover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_expand_on_hover));
703 		if (expand_on_hover != expand_on_hover_old)
704 		{
705 			changed = TRUE;
706 			workbench_set_expand_on_hover(workbench, expand_on_hover);
707 		}
708 		enable_tree_lines = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w_enable_tree_lines));
709 		if (enable_tree_lines != enable_tree_lines_old)
710 		{
711 			changed = TRUE;
712 			workbench_set_enable_tree_lines(workbench, enable_tree_lines);
713 		}
714 	}
715 
716 	gtk_widget_destroy(dialog);
717 
718 	return changed;
719 }
720