1 /*
2  *      treebrowser.c - v0.20
3  *
4  *      Copyright 2010 Adrian Dimitrov <dimitrov.adrian@gmail.com>
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 # include "config.h"
9 #endif
10 
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <glib.h>
16 #include <glib/gstdio.h>
17 #include <gdk/gdkkeysyms.h>
18 
19 #include "geany.h"
20 #include <geanyplugin.h>
21 #include <gp_gtkcompat.h>
22 
23 #include <gio/gio.h>
24 
25 #ifdef G_OS_WIN32
26 # include <windows.h>
27 #endif
28 
29 /* These items are set by Geany before plugin_init() is called. */
30 GeanyPlugin 				*geany_plugin;
31 GeanyData 					*geany_data;
32 
33 static gint 				page_number 				= 0;
34 static GtkTreeStore 		*treestore;
35 static GtkWidget 			*treeview;
36 static GtkWidget 			*sidebar_vbox;
37 static GtkWidget 			*sidebar_vbox_bars;
38 static GtkWidget 			*filter;
39 static GtkWidget 			*addressbar;
40 static gchar 				*addressbar_last_address 	= NULL;
41 
42 static GtkTreeIter 			bookmarks_iter;
43 static gboolean 			bookmarks_expanded = FALSE;
44 
45 static GtkTreeViewColumn 	*treeview_column_text;
46 static GtkCellRenderer 		*render_icon, *render_text;
47 
48 /* ------------------
49  * FLAGS
50  * ------------------ */
51 
52 static gboolean 			flag_on_expand_refresh 		= FALSE;
53 
54 /* ------------------
55  *  CONFIG VARS
56  * ------------------ */
57 
58 #ifndef G_OS_WIN32
59 # define CONFIG_OPEN_EXTERNAL_CMD_DEFAULT "xdg-open '%d'"
60 # define CONFIG_OPEN_TERMINAL_DEFAULT "xterm"
61 #else
62 # define CONFIG_OPEN_EXTERNAL_CMD_DEFAULT "explorer '%d'"
63 # define CONFIG_OPEN_TERMINAL_DEFAULT "cmd"
64 #endif
65 
66 static gchar 				*CONFIG_FILE 				= NULL;
67 static gchar 				*CONFIG_OPEN_EXTERNAL_CMD 	= NULL;
68 static gchar 				*CONFIG_OPEN_TERMINAL 	= NULL;
69 static gboolean 			CONFIG_REVERSE_FILTER 		= FALSE;
70 static gboolean 			CONFIG_ONE_CLICK_CHDOC 		= FALSE;
71 static gboolean 			CONFIG_SHOW_HIDDEN_FILES 	= FALSE;
72 static gboolean 			CONFIG_HIDE_OBJECT_FILES 	= FALSE;
73 static gint 				CONFIG_SHOW_BARS			= 1;
74 static gboolean 			CONFIG_CHROOT_ON_DCLICK		= FALSE;
75 static gboolean 			CONFIG_FOLLOW_CURRENT_DOC 	= TRUE;
76 static gboolean 			CONFIG_ON_DELETE_CLOSE_FILE = TRUE;
77 static gboolean 			CONFIG_ON_OPEN_FOCUS_EDITOR = FALSE;
78 static gboolean 			CONFIG_SHOW_TREE_LINES 		= TRUE;
79 static gboolean 			CONFIG_SHOW_BOOKMARKS 		= FALSE;
80 static gint 				CONFIG_SHOW_ICONS 			= 2;
81 static gboolean				CONFIG_OPEN_NEW_FILES 		= TRUE;
82 
83 /* ------------------
84  * TREEVIEW STRUCT
85  * ------------------ */
86 
87 enum
88 {
89 	TREEBROWSER_COLUMNC 								= 4,
90 
91 	TREEBROWSER_COLUMN_ICON 							= 0,
92 	TREEBROWSER_COLUMN_NAME 							= 1,
93 	TREEBROWSER_COLUMN_URI 								= 2,
94 	TREEBROWSER_COLUMN_FLAG 							= 3,
95 
96 	TREEBROWSER_RENDER_ICON 							= 0,
97 	TREEBROWSER_RENDER_TEXT 							= 1,
98 
99 	TREEBROWSER_FLAGS_SEPARATOR 						= -1
100 };
101 
102 
103 /* Keybinding(s) */
104 enum
105 {
106 	KB_FOCUS_FILE_LIST,
107 	KB_FOCUS_PATH_ENTRY,
108 	KB_RENAME_OBJECT,
109 	KB_CREATE_FILE,
110 	KB_CREATE_DIR,
111 	KB_REFRESH,
112 	KB_TRACK_CURRENT,
113 	KB_COUNT
114 };
115 
116 
117 /* ------------------
118  * PLUGIN INFO
119  * ------------------ */
120 
121 PLUGIN_VERSION_CHECK(224)
122 
123 PLUGIN_SET_TRANSLATABLE_INFO(
124 	LOCALEDIR,
125 	GETTEXT_PACKAGE,
126 	_("TreeBrowser"),
127 	_("This plugin adds a tree browser to Geany, allowing the user to "
128 	  "browse files using a tree view of the directory being browsed."),
129 	"1.32" ,
130 	"Adrian Dimitrov (dimitrov.adrian@gmail.com)")
131 
132 
133 /* ------------------
134  * PREDEFINES
135  * ------------------ */
136 
137 #define foreach_slist_free(node, list) for (node = list, list = NULL; g_slist_free_1(list), node != NULL; list = node, node = node->next)
138 
139 
140 /* ------------------
141  * PROTOTYPES
142  * ------------------ */
143 
144 static void 	project_open_cb(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *config, G_GNUC_UNUSED gpointer data);
145 static void 	treebrowser_browse(gchar *directory, gpointer parent);
146 static void 	treebrowser_bookmarks_set_state(void);
147 static void 	treebrowser_load_bookmarks(void);
148 static void 	treebrowser_tree_store_iter_clear_nodes(gpointer iter, gboolean delete_root);
149 static void 	treebrowser_rename_current(void);
150 static void 	on_menu_create_new_object(GtkMenuItem *menuitem, const gchar *type);
151 static void 	load_settings(void);
152 static gboolean save_settings(void);
153 
154 
155 /* ------------------
156  * PLUGIN CALLBACKS
157  * ------------------ */
158 
159 PluginCallback plugin_callbacks[] =
160 {
161 	{ "project-open", (GCallback) &project_open_cb, TRUE, NULL },
162 	{ NULL, NULL, FALSE, NULL }
163 };
164 
165 
166 /* ------------------
167  * TREEBROWSER CORE FUNCTIONS
168  * ------------------ */
169 
170 static gboolean
tree_view_row_expanded_iter(GtkTreeView * tree_view,GtkTreeIter * iter)171 tree_view_row_expanded_iter(GtkTreeView *tree_view, GtkTreeIter *iter)
172 {
173 	GtkTreePath *tree_path;
174 	gboolean expanded;
175 
176 	tree_path = gtk_tree_model_get_path(gtk_tree_view_get_model(tree_view), iter);
177 	expanded = gtk_tree_view_row_expanded(tree_view, tree_path);
178 	gtk_tree_path_free(tree_path);
179 
180 	return expanded;
181 }
182 
183 #if GTK_CHECK_VERSION(3, 10, 0)
184 static GdkPixbuf *
utils_pixbuf_from_name(const gchar * icon_name)185 utils_pixbuf_from_name(const gchar *icon_name)
186 {
187 	GError *error = NULL;
188 	GtkIconTheme *icon_theme;
189 	GdkPixbuf *pixbuf;
190 
191 	icon_theme = gtk_icon_theme_get_default ();
192 	pixbuf = gtk_icon_theme_load_icon(icon_theme, icon_name, 16, 0, &error);
193 
194 	if (!pixbuf)
195 	{
196 		g_warning("Couldn't load icon: %s", error->message);
197 		g_error_free(error);
198 		return NULL;
199 	}
200 
201 	return pixbuf;
202 }
203 #else
204 static GdkPixbuf *
utils_pixbuf_from_stock(const gchar * stock_id)205 utils_pixbuf_from_stock(const gchar *stock_id)
206 {
207 	GtkIconSet *icon_set;
208 
209 	icon_set = gtk_icon_factory_lookup_default(stock_id);
210 
211 	if (icon_set)
212 		return gtk_icon_set_render_icon(icon_set, gtk_widget_get_default_style(),
213 										gtk_widget_get_default_direction(),
214 										GTK_STATE_NORMAL, GTK_ICON_SIZE_MENU, NULL, NULL);
215 	return NULL;
216 }
217 #endif
218 
219 static GdkPixbuf *
utils_pixbuf_from_path(gchar * path)220 utils_pixbuf_from_path(gchar *path)
221 {
222 	GIcon 		*icon;
223 	GdkPixbuf 	*ret = NULL;
224 	GtkIconInfo *info;
225 	gchar 		*ctype;
226 	gint 		width;
227 
228 	ctype = g_content_type_guess(path, NULL, 0, NULL);
229 	icon = g_content_type_get_icon(ctype);
230 	g_free(ctype);
231 
232 	if (icon != NULL)
233 	{
234 		gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, NULL);
235 		info = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), icon, width, GTK_ICON_LOOKUP_USE_BUILTIN);
236 		g_object_unref(icon);
237 		if (!info)
238 		{
239 			icon = g_themed_icon_new("text-x-generic");
240 			if (icon != NULL)
241 			{
242 				info = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), icon, width, GTK_ICON_LOOKUP_USE_BUILTIN);
243 				g_object_unref(icon);
244 			}
245 		}
246 		if (!info)
247 			return NULL;
248 		ret = gtk_icon_info_load_icon (info, NULL);
249 		gtk_icon_info_free(info);
250 	}
251 	return ret;
252 }
253 
254 
255 /* result must be freed */
256 static gchar*
path_is_in_dir(gchar * src,gchar * find)257 path_is_in_dir(gchar* src, gchar* find)
258 {
259 	guint i = 0;
260 
261 	gchar *diffed_path = NULL, *tmp = NULL;
262 	gchar **src_segments = NULL, **find_segments = NULL;
263 	guint src_segments_n = 0, find_segments_n = 0, n = 0;
264 
265 	src_segments = g_strsplit(src, G_DIR_SEPARATOR_S, 0);
266 	find_segments = g_strsplit(find, G_DIR_SEPARATOR_S, 0);
267 
268 	src_segments_n = g_strv_length(src_segments);
269 	find_segments_n = g_strv_length(find_segments);
270 
271 	n = src_segments_n;
272 	if (find_segments_n < n)
273 		n = find_segments_n;
274 
275 	for(i = 1; i<n; i++)
276 		if (utils_str_equal(find_segments[i], src_segments[i]) != TRUE)
277 			break;
278 		else
279 		{
280 			tmp = g_strconcat(diffed_path == NULL ? "" : diffed_path,
281 								G_DIR_SEPARATOR_S, find_segments[i], NULL);
282 			g_free(diffed_path);
283 			diffed_path = tmp;
284 		}
285 
286 	g_strfreev(src_segments);
287 	g_strfreev(find_segments);
288 
289 	return diffed_path;
290 }
291 
292 /* Return: FALSE - if file is filtered and not shown, and TRUE - if file isn`t filtered, and have to be shown */
293 static gboolean
check_filtered(const gchar * base_name)294 check_filtered(const gchar *base_name)
295 {
296 	gchar		**filters;
297 	guint 		i;
298 	gboolean 	temporary_reverse 	= FALSE;
299 	const gchar *exts[] 			= {".o", ".obj", ".so", ".dll", ".a", ".lib", ".la", ".lo", ".pyc"};
300 	guint exts_len;
301 	const gchar *ext;
302 	gboolean	filtered;
303 
304 	if (CONFIG_HIDE_OBJECT_FILES)
305 	{
306 		exts_len = G_N_ELEMENTS(exts);
307 		for (i = 0; i < exts_len; i++)
308 		{
309 			ext = exts[i];
310 			if (g_str_has_suffix(base_name, ext))
311 				return FALSE;
312 		}
313 	}
314 
315 	if (EMPTY(gtk_entry_get_text(GTK_ENTRY(filter))))
316 		return TRUE;
317 
318 	filters = g_strsplit(gtk_entry_get_text(GTK_ENTRY(filter)), ";", 0);
319 
320 	if (utils_str_equal(filters[0], "!") == TRUE)
321 	{
322 		temporary_reverse = TRUE;
323 		i = 1;
324 	}
325 	else
326 		i = 0;
327 
328 	filtered = CONFIG_REVERSE_FILTER || temporary_reverse ? TRUE : FALSE;
329 	for (; filters[i]; i++)
330 	{
331 		if (utils_str_equal(base_name, "*") || g_pattern_match_simple(filters[i], base_name))
332 		{
333 			filtered = CONFIG_REVERSE_FILTER || temporary_reverse ? FALSE : TRUE;
334 			break;
335 		}
336 	}
337 	g_strfreev(filters);
338 
339 	return filtered;
340 }
341 
342 #ifdef G_OS_WIN32
343 static gboolean
win32_check_hidden(const gchar * filename)344 win32_check_hidden(const gchar *filename)
345 {
346 	DWORD attrs;
347 	static wchar_t w_filename[MAX_PATH];
348 	MultiByteToWideChar(CP_UTF8, 0, filename, -1, w_filename, sizeof(w_filename));
349 	attrs = GetFileAttributesW(w_filename);
350 	if (attrs != INVALID_FILE_ATTRIBUTES && attrs & FILE_ATTRIBUTE_HIDDEN)
351 		return TRUE;
352 	return FALSE;
353 }
354 #endif
355 
356 /* Returns: whether name should be hidden. */
357 static gboolean
check_hidden(const gchar * filename)358 check_hidden(const gchar *filename)
359 {
360 	gsize len;
361 	const gchar *base_name = NULL;
362 	base_name = g_path_get_basename(filename);
363 
364 	if (EMPTY(base_name))
365 		return FALSE;
366 
367 	if (CONFIG_SHOW_HIDDEN_FILES)
368 		return FALSE;
369 
370 #ifdef G_OS_WIN32
371 	if (win32_check_hidden(filename))
372 		return TRUE;
373 #else
374 	if (base_name[0] == '.')
375 		return TRUE;
376 #endif
377 
378 	len = strlen(base_name);
379 	if (base_name[len - 1] == '~')
380 		return TRUE;
381 
382 	return FALSE;
383 }
384 
385 static gchar*
get_default_dir(void)386 get_default_dir(void)
387 {
388 	gchar 			*dir;
389 	GeanyProject 	*project 	= geany->app->project;
390 	GeanyDocument	*doc 		= document_get_current();
391 
392 	if (doc != NULL && doc->file_name != NULL && g_path_is_absolute(doc->file_name))
393 	{
394 		gchar *dir_name;
395 		gchar *ret;
396 
397 		dir_name = g_path_get_dirname(doc->file_name);
398 		ret = utils_get_locale_from_utf8(dir_name);
399 		g_free (dir_name);
400 
401 		return ret;
402 	}
403 
404 	if (project)
405 		dir = project->base_path;
406 	else
407 		dir = geany->prefs->default_open_path;
408 
409 	if (! EMPTY(dir))
410 		return utils_get_locale_from_utf8(dir);
411 
412 	return g_get_current_dir();
413 }
414 
415 static gchar *
get_terminal(void)416 get_terminal(void)
417 {
418 	gchar 		*terminal;
419 #ifdef G_OS_WIN32
420 	terminal = g_strdup("cmd");
421 #else
422 	terminal = g_strdup(CONFIG_OPEN_TERMINAL);
423 #endif
424 	return terminal;
425 }
426 
427 static gboolean
treebrowser_checkdir(gchar * directory)428 treebrowser_checkdir(gchar *directory)
429 {
430 	gboolean is_dir;
431 	static gboolean old_value = TRUE;
432 #if !GTK_CHECK_VERSION(3, 0, 0)
433 	static const GdkColor red 	= {0, 0xffff, 0x6666, 0x6666};
434 	static const GdkColor white = {0, 0xffff, 0xffff, 0xffff};
435 #endif
436 
437 	is_dir = g_file_test(directory, G_FILE_TEST_IS_DIR);
438 
439 	if (old_value != is_dir)
440 	{
441 #if GTK_CHECK_VERSION(3, 0, 0)
442 		GtkStyleContext *context;
443 		context = gtk_widget_get_style_context(GTK_WIDGET(addressbar));
444 		if (is_dir)
445 		{
446 			gtk_style_context_remove_class(context, "invalid");
447 		}
448 		else
449 		{
450 			gtk_style_context_add_class(context, "invalid");
451 		}
452 #else
453 		gtk_widget_modify_base(GTK_WIDGET(addressbar), GTK_STATE_NORMAL, is_dir ? NULL : &red);
454 		gtk_widget_modify_text(GTK_WIDGET(addressbar), GTK_STATE_NORMAL, is_dir ? NULL : &white);
455 #endif
456 		old_value = is_dir;
457 	}
458 
459 	if (!is_dir)
460 	{
461 		if (CONFIG_SHOW_BARS == 0)
462 			dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("%s: no such directory."), directory);
463 
464 		return FALSE;
465 	}
466 
467 	return is_dir;
468 }
469 
470 static void
treebrowser_chroot(const gchar * dir)471 treebrowser_chroot(const gchar *dir)
472 {
473 	gchar *directory;
474 
475 	if (g_str_has_suffix(dir, G_DIR_SEPARATOR_S))
476 		directory = g_strndup(dir, strlen(dir)-1);
477 	else
478 		directory = g_strdup(dir);
479 
480 	gtk_entry_set_text(GTK_ENTRY(addressbar), directory);
481 
482 	if (!directory || strlen(directory) == 0)
483 		setptr(directory, g_strdup(G_DIR_SEPARATOR_S));
484 
485 	if (! treebrowser_checkdir(directory))
486 	{
487 		g_free(directory);
488 		return;
489 	}
490 
491 	treebrowser_bookmarks_set_state();
492 
493 	setptr(addressbar_last_address, directory);
494 
495 	treebrowser_browse(addressbar_last_address, NULL);
496 	treebrowser_load_bookmarks();
497 }
498 
499 static void
treebrowser_browse(gchar * directory,gpointer parent)500 treebrowser_browse(gchar *directory, gpointer parent)
501 {
502 	GtkTreeIter 	iter, iter_empty, *last_dir_iter = NULL;
503 	gboolean 		is_dir;
504 	gboolean 		expanded = FALSE, has_parent;
505 	gchar 			*utf8_name;
506 	GSList 			*list, *node;
507 
508 	gchar 			*fname;
509 	gchar 			*uri;
510 
511 	directory 		= g_strconcat(directory, G_DIR_SEPARATOR_S, NULL);
512 
513 	has_parent = parent ? gtk_tree_store_iter_is_valid(treestore, parent) : FALSE;
514 	if (has_parent)
515 	{
516 		if (parent == &bookmarks_iter)
517 			treebrowser_load_bookmarks();
518 	}
519 	else
520 		parent = NULL;
521 
522 	if (has_parent && tree_view_row_expanded_iter(GTK_TREE_VIEW(treeview), parent))
523 	{
524 		expanded = TRUE;
525 		treebrowser_bookmarks_set_state();
526 	}
527 
528 	if (parent)
529 		treebrowser_tree_store_iter_clear_nodes(parent, FALSE);
530 	else
531 		gtk_tree_store_clear(treestore);
532 
533 	list = utils_get_file_list(directory, NULL, NULL);
534 	if (list != NULL)
535 	{
536 		foreach_slist_free(node, list)
537 		{
538 			fname 		= node->data;
539 			uri 		= g_strconcat(directory, fname, NULL);
540 			is_dir 		= g_file_test (uri, G_FILE_TEST_IS_DIR);
541 			utf8_name 	= utils_get_utf8_from_locale(fname);
542 
543 			if (!check_hidden(uri))
544 			{
545 				GdkPixbuf *icon = NULL;
546 
547 				if (is_dir)
548 				{
549 					if (last_dir_iter == NULL)
550 						gtk_tree_store_prepend(treestore, &iter, parent);
551 					else
552 					{
553 						gtk_tree_store_insert_after(treestore, &iter, parent, last_dir_iter);
554 						gtk_tree_iter_free(last_dir_iter);
555 					}
556 					last_dir_iter = gtk_tree_iter_copy(&iter);
557 #if GTK_CHECK_VERSION(3, 10, 0)
558 					icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_name("folder") : NULL;
559 #else
560 					icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_stock(GTK_STOCK_DIRECTORY) : NULL;
561 #endif
562 					gtk_tree_store_set(treestore, &iter,
563 										TREEBROWSER_COLUMN_ICON, 	icon,
564 										TREEBROWSER_COLUMN_NAME, 	fname,
565 										TREEBROWSER_COLUMN_URI, 	uri,
566 										-1);
567 					gtk_tree_store_prepend(treestore, &iter_empty, &iter);
568 					gtk_tree_store_set(treestore, &iter_empty,
569 									TREEBROWSER_COLUMN_ICON, 	NULL,
570 									TREEBROWSER_COLUMN_NAME, 	_("(Empty)"),
571 									TREEBROWSER_COLUMN_URI, 	NULL,
572 									-1);
573 				}
574 				else
575 				{
576 					if (check_filtered(utf8_name))
577 					{
578 						icon = CONFIG_SHOW_ICONS == 2
579 									? utils_pixbuf_from_path(uri)
580 									: CONFIG_SHOW_ICONS
581 #if GTK_CHECK_VERSION(3, 10, 0)
582 										? utils_pixbuf_from_name("text-x-generic")
583 #else
584 										? utils_pixbuf_from_stock(GTK_STOCK_FILE)
585 #endif
586 										: NULL;
587 						gtk_tree_store_append(treestore, &iter, parent);
588 						gtk_tree_store_set(treestore, &iter,
589 										TREEBROWSER_COLUMN_ICON, 	icon,
590 										TREEBROWSER_COLUMN_NAME, 	fname,
591 										TREEBROWSER_COLUMN_URI, 	uri,
592 										-1);
593 					}
594 				}
595 
596 				if (icon)
597 					g_object_unref(icon);
598 			}
599 			g_free(utf8_name);
600 			g_free(uri);
601 			g_free(fname);
602 		}
603 	}
604 	else
605 	{
606 		gtk_tree_store_prepend(treestore, &iter_empty, parent);
607 		gtk_tree_store_set(treestore, &iter_empty,
608 						TREEBROWSER_COLUMN_ICON, 	NULL,
609 						TREEBROWSER_COLUMN_NAME, 	_("(Empty)"),
610 						TREEBROWSER_COLUMN_URI, 	NULL,
611 						-1);
612 	}
613 
614 	if (has_parent)
615 	{
616 		if (expanded)
617 			gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview), gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), parent), FALSE);
618 	}
619 	else
620 		treebrowser_load_bookmarks();
621 
622 	g_free(directory);
623 
624 }
625 
626 static void
treebrowser_bookmarks_set_state(void)627 treebrowser_bookmarks_set_state(void)
628 {
629 	if (gtk_tree_store_iter_is_valid(treestore, &bookmarks_iter))
630 		bookmarks_expanded = tree_view_row_expanded_iter(GTK_TREE_VIEW(treeview), &bookmarks_iter);
631 	else
632 		bookmarks_expanded = FALSE;
633 }
634 
635 static void
treebrowser_load_bookmarks(void)636 treebrowser_load_bookmarks(void)
637 {
638 	gchar 		*bookmarks;
639 	gchar 		*contents, *path_full;
640 	gchar 		**lines, **line;
641 	GtkTreeIter iter;
642 	gchar 		*pos;
643 	GdkPixbuf 	*icon = NULL;
644 
645 	if (! CONFIG_SHOW_BOOKMARKS)
646 		return;
647 
648 	bookmarks = g_build_filename(g_get_home_dir(), ".gtk-bookmarks", NULL);
649 	if (g_file_get_contents(bookmarks, &contents, NULL, NULL))
650 	{
651 		if (gtk_tree_store_iter_is_valid(treestore, &bookmarks_iter))
652 		{
653 			bookmarks_expanded = tree_view_row_expanded_iter(GTK_TREE_VIEW(treeview), &bookmarks_iter);
654 			treebrowser_tree_store_iter_clear_nodes(&bookmarks_iter, FALSE);
655 		}
656 		else
657 		{
658 			gtk_tree_store_prepend(treestore, &bookmarks_iter, NULL);
659 #if GTK_CHECK_VERSION(3, 10, 0)
660 			icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_name("go-home") : NULL;
661 #else
662 			icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_stock(GTK_STOCK_HOME) : NULL;
663 #endif
664 			gtk_tree_store_set(treestore, &bookmarks_iter,
665 											TREEBROWSER_COLUMN_ICON, 	icon,
666 											TREEBROWSER_COLUMN_NAME, 	_("Bookmarks"),
667 											TREEBROWSER_COLUMN_URI, 	NULL,
668 											-1);
669 			if (icon)
670 				g_object_unref(icon);
671 
672 			gtk_tree_store_insert_after(treestore, &iter, NULL, &bookmarks_iter);
673 			gtk_tree_store_set(treestore, &iter,
674 											TREEBROWSER_COLUMN_ICON, 	NULL,
675 											TREEBROWSER_COLUMN_NAME, 	NULL,
676 											TREEBROWSER_COLUMN_URI, 	NULL,
677 											TREEBROWSER_COLUMN_FLAG, 	TREEBROWSER_FLAGS_SEPARATOR,
678 											-1);
679 		}
680 		lines = g_strsplit (contents, "\n", 0);
681 		for (line = lines; *line; ++line)
682 		{
683 			if (**line)
684 			{
685 				pos = g_utf8_strchr (*line, -1, ' ');
686 				if (pos != NULL)
687 				{
688 					*pos = '\0';
689 				}
690 			}
691 			path_full = g_filename_from_uri(*line, NULL, NULL);
692 			if (path_full != NULL)
693 			{
694 				if (g_file_test(path_full, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
695 				{
696 					gchar *file_name = g_path_get_basename(path_full);
697 
698 					gtk_tree_store_append(treestore, &iter, &bookmarks_iter);
699 #if GTK_CHECK_VERSION(3, 10, 0)
700 					icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_name("folder") : NULL;
701 #else
702 					icon = CONFIG_SHOW_ICONS ? utils_pixbuf_from_stock(GTK_STOCK_DIRECTORY) : NULL;
703 #endif
704 					gtk_tree_store_set(treestore, &iter,
705 												TREEBROWSER_COLUMN_ICON, 	icon,
706 												TREEBROWSER_COLUMN_NAME, 	file_name,
707 												TREEBROWSER_COLUMN_URI, 	path_full,
708 												-1);
709 					g_free(file_name);
710 					if (icon)
711 						g_object_unref(icon);
712 					gtk_tree_store_append(treestore, &iter, &iter);
713 					gtk_tree_store_set(treestore, &iter,
714 											TREEBROWSER_COLUMN_ICON, 	NULL,
715 											TREEBROWSER_COLUMN_NAME, 	_("(Empty)"),
716 											TREEBROWSER_COLUMN_URI, 	NULL,
717 												-1);
718 				}
719 				g_free(path_full);
720 			}
721 		}
722 		g_strfreev(lines);
723 		g_free(contents);
724 		if (bookmarks_expanded)
725 		{
726 			GtkTreePath *tree_path;
727 
728 			tree_path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), &bookmarks_iter);
729 			gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview), tree_path, FALSE);
730 			gtk_tree_path_free(tree_path);
731 		}
732 	}
733 	g_free(bookmarks);
734 }
735 
736 static gboolean
treebrowser_search(gchar * uri,gpointer parent)737 treebrowser_search(gchar *uri, gpointer parent)
738 {
739 	GtkTreeIter 	iter;
740 	GtkTreePath 	*path;
741 	gchar 			*uri_current;
742 
743 	if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), &iter, parent))
744 	{
745 		do
746 		{
747 			if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(treestore), &iter))
748 				if (treebrowser_search(uri, &iter))
749 					return TRUE;
750 
751 			gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, TREEBROWSER_COLUMN_URI, &uri_current, -1);
752 
753 			if (utils_str_equal(uri, uri_current) == TRUE)
754 			{
755 				path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), &iter);
756 				gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path);
757 				gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeview), path, NULL, FALSE, 0, 0);
758 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(treeview), path, treeview_column_text, FALSE);
759 				gtk_tree_path_free(path);
760 				g_free(uri_current);
761 				return TRUE;
762 			}
763 			else
764 				g_free(uri_current);
765 
766 		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(treestore), &iter));
767 	}
768 
769 	return FALSE;
770 }
771 
772 static void
fs_remove(gchar * root,gboolean delete_root)773 fs_remove(gchar *root, gboolean delete_root)
774 {
775 	gchar *path;
776 	const gchar *name;
777 
778 	if (! g_file_test(root, G_FILE_TEST_EXISTS))
779 		return;
780 
781 	if (g_file_test(root, G_FILE_TEST_IS_DIR))
782 	{
783 		GDir *dir;
784 		dir = g_dir_open (root, 0, NULL);
785 
786 		if (!dir)
787 		{
788 			if (delete_root)
789 			{
790 				g_remove(root);
791 			}
792 			else return;
793 		}
794 
795 		name = g_dir_read_name (dir);
796 		while (name != NULL)
797 		{
798 			path = g_build_filename(root, name, NULL);
799 			if (g_file_test(path, G_FILE_TEST_IS_DIR))
800 				fs_remove(path, delete_root);
801 			g_remove(path);
802 			g_free(path);
803 			name = g_dir_read_name(dir);
804 		}
805 		g_dir_close(dir);
806 	}
807 	else
808 		delete_root = TRUE;
809 
810 	if (delete_root)
811 		g_remove(root);
812 
813 	return;
814 }
815 
816 static void
showbars(gboolean state)817 showbars(gboolean state)
818 {
819 	if (state)
820 	{
821 		gtk_widget_show(sidebar_vbox_bars);
822 		if (!CONFIG_SHOW_BARS)
823 			CONFIG_SHOW_BARS = 1;
824 	}
825 	else
826 	{
827 		gtk_widget_hide(sidebar_vbox_bars);
828 		CONFIG_SHOW_BARS = 0;
829 	}
830 
831 	save_settings();
832 }
833 
834 static void
treebrowser_tree_store_iter_clear_nodes(gpointer iter,gboolean delete_root)835 treebrowser_tree_store_iter_clear_nodes(gpointer iter, gboolean delete_root)
836 {
837 	GtkTreeIter i;
838 
839 	if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), &i, iter))
840 	{
841 		while (gtk_tree_store_remove(GTK_TREE_STORE(treestore), &i))
842 			/* do nothing */;
843 	}
844 	if (delete_root)
845 		gtk_tree_store_remove(GTK_TREE_STORE(treestore), iter);
846 }
847 
848 static gboolean
treebrowser_expand_to_path(gchar * root,gchar * find)849 treebrowser_expand_to_path(gchar* root, gchar* find)
850 {
851 	guint i = 0;
852 	gboolean founded = FALSE, global_founded = FALSE;
853 	gchar *new = NULL;
854 	gchar **root_segments = NULL, **find_segments = NULL;
855 	guint find_segments_n = 0;
856 
857 	root_segments = g_strsplit(root, G_DIR_SEPARATOR_S, 0);
858 	find_segments = g_strsplit(find, G_DIR_SEPARATOR_S, 0);
859 
860 	find_segments_n = g_strv_length(find_segments)-1;
861 
862 
863 	for (i = 1; i<=find_segments_n; i++)
864 	{
865 		new = g_strconcat(new ? new : "", G_DIR_SEPARATOR_S, find_segments[i], NULL);
866 
867 		if (founded)
868 		{
869 			if (treebrowser_search(new, NULL))
870 				global_founded = TRUE;
871 		}
872 		else
873 			if (utils_str_equal(root, new) == TRUE)
874 				founded = TRUE;
875 	}
876 
877 	g_free(new);
878 	g_strfreev(root_segments);
879 	g_strfreev(find_segments);
880 
881 	return global_founded;
882 }
883 
884 static gboolean
treebrowser_track_current(void)885 treebrowser_track_current(void)
886 {
887 
888 	GeanyDocument	*doc 		= document_get_current();
889 	gchar 			*path_current;
890 	gchar			**path_segments = NULL;
891 	gchar 			*froot = NULL;
892 
893 	if (doc != NULL && doc->file_name != NULL && g_path_is_absolute(doc->file_name))
894 	{
895 		path_current = utils_get_locale_from_utf8(doc->file_name);
896 
897 		/*
898 		 * Checking if the document is in the expanded or collapsed files
899 		 */
900 		if (! treebrowser_search(path_current, NULL))
901 		{
902 			/*
903 			 * Else we have to chroting to the document`s nearles path
904 			 */
905 
906 			froot = path_is_in_dir(addressbar_last_address, g_path_get_dirname(path_current));
907 
908 			if (froot == NULL)
909 				froot = g_strdup(G_DIR_SEPARATOR_S);
910 
911 			if (utils_str_equal(froot, addressbar_last_address) != TRUE)
912 				treebrowser_chroot(froot);
913 
914 			treebrowser_expand_to_path(froot, path_current);
915 		}
916 
917 		g_strfreev(path_segments);
918 		g_free(froot);
919 		g_free(path_current);
920 
921 		return FALSE;
922 	}
923 	return FALSE;
924 }
925 
926 static gboolean
treebrowser_iter_rename(gpointer iter)927 treebrowser_iter_rename(gpointer iter)
928 {
929 	GtkTreeViewColumn 	*column;
930 	GtkCellRenderer 	*renderer;
931 	GtkTreePath 		*path;
932 	GList 				*renderers;
933 
934 	if (gtk_tree_store_iter_is_valid(treestore, iter))
935 	{
936 		path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), iter);
937 		if (G_LIKELY(path != NULL))
938 		{
939 			column 		= gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0);
940 			renderers 	= gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
941 			renderer 	= g_list_nth_data(renderers, TREEBROWSER_RENDER_TEXT);
942 
943 			g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
944 			gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(treeview), path, column, renderer, TRUE);
945 
946 			gtk_tree_path_free(path);
947 			g_list_free(renderers);
948 			return TRUE;
949 		}
950 	}
951 	return FALSE;
952 }
953 
954 static void
treebrowser_rename_current(void)955 treebrowser_rename_current(void)
956 {
957 	GtkTreeSelection 	*selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
958 	GtkTreeIter 		iter;
959 	GtkTreeModel 		*model;
960 
961 	if (gtk_tree_selection_get_selected(selection, &model, &iter))
962 	{
963 		treebrowser_iter_rename(&iter);
964 	}
965 }
966 
967 static void
treebrowser_create_new_current(const gchar * type)968 treebrowser_create_new_current(const gchar *type)
969 {
970 	on_menu_create_new_object(NULL, type);
971 }
972 
973 
974 /* ------------------
975  * RIGHTCLICK MENU EVENTS
976  * ------------------*/
977 
978 static void
on_menu_go_up(GtkMenuItem * menuitem,gpointer * user_data)979 on_menu_go_up(GtkMenuItem *menuitem, gpointer *user_data)
980 {
981 	gchar *uri;
982 
983 	uri = g_path_get_dirname(addressbar_last_address);
984 	treebrowser_chroot(uri);
985 	g_free(uri);
986 }
987 
988 static void
on_menu_current_path(GtkMenuItem * menuitem,gpointer * user_data)989 on_menu_current_path(GtkMenuItem *menuitem, gpointer *user_data)
990 {
991 	gchar *uri;
992 
993 	uri = get_default_dir();
994 	treebrowser_chroot(uri);
995 	g_free(uri);
996 }
997 
998 static void
on_menu_open_externally(GtkMenuItem * menuitem,gchar * uri)999 on_menu_open_externally(GtkMenuItem *menuitem, gchar *uri)
1000 {
1001 	gchar 				*cmd, *locale_cmd, *dir, *c;
1002 	GString 			*cmd_str 	= g_string_new(CONFIG_OPEN_EXTERNAL_CMD);
1003 	GError 				*error 		= NULL;
1004 
1005 	dir = g_file_test(uri, G_FILE_TEST_IS_DIR) ? g_strdup(uri) : g_path_get_dirname(uri);
1006 
1007 	utils_string_replace_all(cmd_str, "%f", uri);
1008 	utils_string_replace_all(cmd_str, "%d", dir);
1009 
1010 	cmd = g_string_free(cmd_str, FALSE);
1011 	locale_cmd = utils_get_locale_from_utf8(cmd);
1012 	if (! g_spawn_command_line_async(locale_cmd, &error))
1013 	{
1014 		c = strchr(cmd, ' ');
1015 		if (c != NULL)
1016 			*c = '\0';
1017 		ui_set_statusbar(TRUE,
1018 			_("Could not execute configured external command '%s' (%s)."),
1019 			cmd, error->message);
1020 		g_error_free(error);
1021 	}
1022 	g_free(locale_cmd);
1023 	g_free(cmd);
1024 	g_free(dir);
1025 }
1026 
1027 static void
on_menu_open_terminal(GtkMenuItem * menuitem,gchar * uri)1028 on_menu_open_terminal(GtkMenuItem *menuitem, gchar *uri)
1029 {
1030 	gchar *argv[2] = {NULL, NULL};
1031 	argv[0] = get_terminal();
1032 
1033 	if (g_file_test(uri, G_FILE_TEST_EXISTS))
1034 		uri = g_file_test(uri, G_FILE_TEST_IS_DIR) ? g_strdup(uri) : g_path_get_dirname(uri);
1035 	else
1036 		uri = g_strdup(addressbar_last_address);
1037 
1038 	g_spawn_async(uri, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
1039 	g_free(uri);
1040 	g_free(argv[0]);
1041 }
1042 
1043 static void
on_menu_set_as_root(GtkMenuItem * menuitem,gchar * uri)1044 on_menu_set_as_root(GtkMenuItem *menuitem, gchar *uri)
1045 {
1046 	if (g_file_test(uri, G_FILE_TEST_IS_DIR))
1047 		treebrowser_chroot(uri);
1048 }
1049 
1050 static void
on_menu_find_in_files(GtkMenuItem * menuitem,gchar * uri)1051 on_menu_find_in_files(GtkMenuItem *menuitem, gchar *uri)
1052 {
1053 	search_show_find_in_files_dialog(uri);
1054 }
1055 
1056 static void
on_menu_create_new_object(GtkMenuItem * menuitem,const gchar * type)1057 on_menu_create_new_object(GtkMenuItem *menuitem, const gchar *type)
1058 {
1059 	GtkTreeSelection 	*selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1060 	GtkTreeIter 		iter, iter_parent;
1061 	GtkTreeModel 		*model;
1062 	gchar 				*uri, *uri_new = NULL;
1063 	gboolean 			refresh_root = FALSE;
1064 
1065 	if (gtk_tree_selection_get_selected(selection, &model, &iter))
1066 	{
1067 		gtk_tree_model_get(model, &iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1068 		/* If not a directory, find parent directory */
1069 		if (! g_file_test(uri, G_FILE_TEST_IS_DIR))
1070 		{
1071 			if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treestore), &iter_parent, &iter))
1072 			{
1073 				iter = iter_parent;
1074 				/* Set URI from parent iter */
1075 				g_free(uri);
1076 				gtk_tree_model_get(model, &iter_parent, TREEBROWSER_COLUMN_URI, &uri, -1);
1077 			}
1078 			else
1079 				refresh_root = TRUE;
1080 		}
1081 	}
1082 	else
1083 	{
1084 		refresh_root 	= TRUE;
1085 		uri 			= g_strdup(addressbar_last_address);
1086 	}
1087 
1088 	if (utils_str_equal(type, "directory"))
1089 		uri_new = g_strconcat(uri, G_DIR_SEPARATOR_S, _("NewDirectory"), NULL);
1090 	else if (utils_str_equal(type, "file"))
1091 		uri_new = g_strconcat(uri, G_DIR_SEPARATOR_S, _("NewFile"), NULL);
1092 
1093 	if (uri_new)
1094 	{
1095 		if (!(g_file_test(uri_new, G_FILE_TEST_EXISTS) &&
1096 			!dialogs_show_question(_("Target file '%s' exists.\nDo you really want to replace it with an empty file?"), uri_new)))
1097 		{
1098 			gboolean creation_success = FALSE;
1099 
1100 			while(g_file_test(uri_new, G_FILE_TEST_EXISTS))
1101 				setptr(uri_new, g_strconcat(uri_new, "_", NULL));
1102 
1103 			if (utils_str_equal(type, "directory"))
1104 				creation_success = (g_mkdir(uri_new, 0755) == 0);
1105 			else
1106 				creation_success = (g_creat(uri_new, 0644) != -1);
1107 
1108 			if (creation_success)
1109 			{
1110 				treebrowser_browse(uri, refresh_root ? NULL : &iter);
1111 				if (treebrowser_search(uri_new, NULL))
1112 					treebrowser_rename_current();
1113 				if (utils_str_equal(type, "file") && CONFIG_OPEN_NEW_FILES == TRUE)
1114 					document_open_file(uri_new,FALSE, NULL,NULL);
1115 			}
1116 		}
1117 		g_free(uri_new);
1118 	}
1119 	g_free(uri);
1120 }
1121 
1122 static void
on_menu_rename(GtkMenuItem * menuitem,gpointer * user_data)1123 on_menu_rename(GtkMenuItem *menuitem, gpointer *user_data)
1124 {
1125 	treebrowser_rename_current();
1126 }
1127 
1128 static void
on_menu_delete(GtkMenuItem * menuitem,gpointer * user_data)1129 on_menu_delete(GtkMenuItem *menuitem, gpointer *user_data)
1130 {
1131 
1132 	GtkTreeSelection 	*selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1133 	GtkTreeIter 		iter, iter_parent;
1134 	GtkTreeModel 		*model;
1135 	gchar 				*uri, *uri_parent;
1136 
1137 	if (! gtk_tree_selection_get_selected(selection, &model, &iter))
1138 		return;
1139 
1140 	gtk_tree_model_get(model, &iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1141 
1142 	if (dialogs_show_question(_("Do you really want to delete '%s' ?"), uri))
1143 	{
1144 		if (CONFIG_ON_DELETE_CLOSE_FILE && !g_file_test(uri, G_FILE_TEST_IS_DIR))
1145 			document_close(document_find_by_filename(uri));
1146 
1147 		uri_parent = g_path_get_dirname(uri);
1148 		fs_remove(uri, TRUE);
1149 		if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treestore), &iter_parent, &iter))
1150 			treebrowser_browse(uri_parent, &iter_parent);
1151 		else
1152 			treebrowser_browse(uri_parent, NULL);
1153 		g_free(uri_parent);
1154 	}
1155 	g_free(uri);
1156 }
1157 
1158 static void
on_menu_refresh(GtkMenuItem * menuitem,gpointer * user_data)1159 on_menu_refresh(GtkMenuItem *menuitem, gpointer *user_data)
1160 {
1161 	GtkTreeSelection 	*selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1162 	GtkTreeIter 		iter;
1163 	GtkTreeModel 		*model;
1164 	gchar 				*uri;
1165 
1166 	if (gtk_tree_selection_get_selected(selection, &model, &iter))
1167 	{
1168 		gtk_tree_model_get(model, &iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1169 		if (g_file_test(uri, G_FILE_TEST_IS_DIR))
1170 			treebrowser_browse(uri, &iter);
1171 		g_free(uri);
1172 	}
1173 	else
1174 		treebrowser_browse(addressbar_last_address, NULL);
1175 }
1176 
1177 static void
on_menu_expand_all(GtkMenuItem * menuitem,gpointer * user_data)1178 on_menu_expand_all(GtkMenuItem *menuitem, gpointer *user_data)
1179 {
1180 	gtk_tree_view_expand_all(GTK_TREE_VIEW(treeview));
1181 }
1182 
1183 static void
on_menu_collapse_all(GtkMenuItem * menuitem,gpointer * user_data)1184 on_menu_collapse_all(GtkMenuItem *menuitem, gpointer *user_data)
1185 {
1186 	gtk_tree_view_collapse_all(GTK_TREE_VIEW(treeview));
1187 }
1188 
1189 static void
on_menu_close(GtkMenuItem * menuitem,gchar * uri)1190 on_menu_close(GtkMenuItem *menuitem, gchar *uri)
1191 {
1192 	if (g_file_test(uri, G_FILE_TEST_EXISTS))
1193 		document_close(document_find_by_filename(uri));
1194 }
1195 
1196 static void
on_menu_close_children(GtkMenuItem * menuitem,gchar * uri)1197 on_menu_close_children(GtkMenuItem *menuitem, gchar *uri)
1198 {
1199 	guint i;
1200 	size_t uri_len = strlen(uri);
1201 	for (i=0; i < GEANY(documents_array)->len; i++)
1202 	{
1203 		if (documents[i]->is_valid)
1204 		{
1205 			/* the document filename should always be longer than the uri when closing children
1206 			 * Compare the beginning of the filename string to see if it matchs the uri*/
1207 			if (strlen(documents[i]->file_name) > uri_len)
1208 			{
1209 				if (strncmp(uri, documents[i]->file_name, uri_len)==0)
1210 					document_close(documents[i]);
1211 			}
1212 		}
1213 	}
1214 }
1215 
1216 static void
on_menu_copy_uri(GtkMenuItem * menuitem,gchar * uri)1217 on_menu_copy_uri(GtkMenuItem *menuitem, gchar *uri)
1218 {
1219 	GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
1220 	gtk_clipboard_set_text(cb, uri, -1);
1221 }
1222 
1223 static void
on_menu_show_bookmarks(GtkMenuItem * menuitem,gpointer * user_data)1224 on_menu_show_bookmarks(GtkMenuItem *menuitem, gpointer *user_data)
1225 {
1226 	CONFIG_SHOW_BOOKMARKS = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
1227 	save_settings();
1228 	treebrowser_chroot(addressbar_last_address);
1229 }
1230 
1231 static void
on_menu_show_hidden_files(GtkMenuItem * menuitem,gpointer * user_data)1232 on_menu_show_hidden_files(GtkMenuItem *menuitem, gpointer *user_data)
1233 {
1234 	CONFIG_SHOW_HIDDEN_FILES = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem));
1235 	save_settings();
1236 	treebrowser_browse(addressbar_last_address, NULL);
1237 }
1238 
1239 static void
on_menu_show_bars(GtkMenuItem * menuitem,gpointer * user_data)1240 on_menu_show_bars(GtkMenuItem *menuitem, gpointer *user_data)
1241 {
1242 	showbars(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)));
1243 }
1244 
1245 static GtkWidget*
create_popup_menu(const gchar * name,const gchar * uri)1246 create_popup_menu(const gchar *name, const gchar *uri)
1247 {
1248 	GtkWidget *item, *menu = gtk_menu_new();
1249 
1250 	gboolean is_exists 		= g_file_test(uri, G_FILE_TEST_EXISTS);
1251 	gboolean is_dir 		= is_exists ? g_file_test(uri, G_FILE_TEST_IS_DIR) : FALSE;
1252 	gboolean is_document 	= document_find_by_filename(uri) != NULL ? TRUE : FALSE;
1253 
1254 #if GTK_CHECK_VERSION(3, 10, 0)
1255 	item = ui_image_menu_item_new("go-up", _("Go _Up"));
1256 #else
1257 	item = ui_image_menu_item_new(GTK_STOCK_GO_UP, _("Go _Up"));
1258 #endif
1259 	gtk_container_add(GTK_CONTAINER(menu), item);
1260 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_go_up), NULL);
1261 
1262 #if GTK_CHECK_VERSION(3, 10, 0)
1263 	item = ui_image_menu_item_new("go-up", _("Set _Path From Document"));
1264 #else
1265 	item = ui_image_menu_item_new(GTK_STOCK_GO_UP, _("Set _Path From Document"));
1266 #endif
1267 	gtk_container_add(GTK_CONTAINER(menu), item);
1268 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_current_path), NULL);
1269 
1270 #if GTK_CHECK_VERSION(3, 10, 0)
1271 	item = ui_image_menu_item_new("document-open", _("_Open Externally"));
1272 #else
1273 	item = ui_image_menu_item_new(GTK_STOCK_OPEN, _("_Open Externally"));
1274 #endif
1275 	gtk_container_add(GTK_CONTAINER(menu), item);
1276 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_open_externally), g_strdup(uri), (GClosureNotify)g_free, 0);
1277 	gtk_widget_set_sensitive(item, is_exists);
1278 
1279 	item = ui_image_menu_item_new("utilities-terminal", _("Open _Terminal"));
1280 	gtk_container_add(GTK_CONTAINER(menu), item);
1281 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_open_terminal), g_strdup(uri), (GClosureNotify)g_free, 0);
1282 
1283 #if GTK_CHECK_VERSION(3, 10, 0)
1284 	item = ui_image_menu_item_new("go-top", _("Set as _Root"));
1285 #else
1286 	item = ui_image_menu_item_new(GTK_STOCK_GOTO_TOP, _("Set as _Root"));
1287 #endif
1288 	gtk_container_add(GTK_CONTAINER(menu), item);
1289 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_set_as_root), g_strdup(uri), (GClosureNotify)g_free, 0);
1290 	gtk_widget_set_sensitive(item, is_dir);
1291 
1292 #if GTK_CHECK_VERSION(3, 10, 0)
1293 	item = ui_image_menu_item_new("view-refresh", _("Refres_h"));
1294 #else
1295 	item = ui_image_menu_item_new(GTK_STOCK_REFRESH, _("Refres_h"));
1296 #endif
1297 	gtk_container_add(GTK_CONTAINER(menu), item);
1298 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_refresh), NULL);
1299 
1300 #if GTK_CHECK_VERSION(3, 10, 0)
1301 	item = ui_image_menu_item_new("edit-find", _("_Find in Files"));
1302 #else
1303 	item = ui_image_menu_item_new(GTK_STOCK_FIND, _("_Find in Files"));
1304 #endif
1305 	gtk_container_add(GTK_CONTAINER(menu), item);
1306 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_find_in_files), g_strdup(uri), (GClosureNotify)g_free, 0);
1307 	gtk_widget_set_sensitive(item, is_dir);
1308 
1309 	item = gtk_separator_menu_item_new();
1310 	gtk_container_add(GTK_CONTAINER(menu), item);
1311 
1312 #if GTK_CHECK_VERSION(3, 10, 0)
1313 	item = ui_image_menu_item_new("list-add", _("N_ew Folder"));
1314 #else
1315 	item = ui_image_menu_item_new(GTK_STOCK_ADD, _("N_ew Folder"));
1316 #endif
1317 	gtk_container_add(GTK_CONTAINER(menu), item);
1318 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_create_new_object), (gpointer)"directory");
1319 
1320 #if GTK_CHECK_VERSION(3, 10, 0)
1321 	item = ui_image_menu_item_new("document-new", _("_New File"));
1322 #else
1323 	item = ui_image_menu_item_new(GTK_STOCK_NEW, _("_New File"));
1324 #endif
1325 	gtk_container_add(GTK_CONTAINER(menu), item);
1326 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_create_new_object), (gpointer)"file");
1327 
1328 #if GTK_CHECK_VERSION(3, 10, 0)
1329 	item = ui_image_menu_item_new("document-save-as", _("Rena_me"));
1330 #else
1331 	item = ui_image_menu_item_new(GTK_STOCK_SAVE_AS, _("Rena_me"));
1332 #endif
1333 	gtk_container_add(GTK_CONTAINER(menu), item);
1334 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_rename), NULL);
1335 	gtk_widget_set_sensitive(item, is_exists);
1336 
1337 #if GTK_CHECK_VERSION(3, 10, 0)
1338 	item = ui_image_menu_item_new("edit-delete", _("_Delete"));
1339 #else
1340 	item = ui_image_menu_item_new(GTK_STOCK_DELETE, _("_Delete"));
1341 #endif
1342 	gtk_container_add(GTK_CONTAINER(menu), item);
1343 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_delete), NULL);
1344 	gtk_widget_set_sensitive(item, is_exists);
1345 
1346 	item = gtk_separator_menu_item_new();
1347 	gtk_container_add(GTK_CONTAINER(menu), item);
1348 
1349 #if GTK_CHECK_VERSION(3, 10, 0)
1350 	item = ui_image_menu_item_new("window-close", g_strdup_printf(_("Close: %s"), name));
1351 #else
1352 	item = ui_image_menu_item_new(GTK_STOCK_CLOSE, g_strdup_printf(_("Close: %s"), name));
1353 #endif
1354 	gtk_container_add(GTK_CONTAINER(menu), item);
1355 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_close), g_strdup(uri), (GClosureNotify)g_free, 0);
1356 	gtk_widget_set_sensitive(item, is_document);
1357 
1358 #if GTK_CHECK_VERSION(3, 10, 0)
1359 	item = ui_image_menu_item_new("window-close", g_strdup_printf(_("Clo_se Child Documents ")));
1360 #else
1361 	item = ui_image_menu_item_new(GTK_STOCK_CLOSE, g_strdup_printf(_("Clo_se Child Documents ")));
1362 #endif
1363 	gtk_container_add(GTK_CONTAINER(menu), item);
1364 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_close_children), g_strdup(uri), (GClosureNotify)g_free, 0);
1365 	gtk_widget_set_sensitive(item, is_dir);
1366 
1367 #if GTK_CHECK_VERSION(3, 10, 0)
1368 	item = ui_image_menu_item_new("edit-copy", _("_Copy Full Path to Clipboard"));
1369 #else
1370 	item = ui_image_menu_item_new(GTK_STOCK_COPY, _("_Copy Full Path to Clipboard"));
1371 #endif
1372 	gtk_container_add(GTK_CONTAINER(menu), item);
1373 	g_signal_connect_data(item, "activate", G_CALLBACK(on_menu_copy_uri), g_strdup(uri), (GClosureNotify)g_free, 0);
1374 	gtk_widget_set_sensitive(item, is_exists);
1375 
1376 	item = gtk_separator_menu_item_new();
1377 	gtk_container_add(GTK_CONTAINER(menu), item);
1378 	gtk_widget_show(item);
1379 
1380 #if GTK_CHECK_VERSION(3, 10, 0)
1381 	item = ui_image_menu_item_new("go-next", _("E_xpand All"));
1382 #else
1383 	item = ui_image_menu_item_new(GTK_STOCK_GO_FORWARD, _("E_xpand All"));
1384 #endif
1385 	gtk_container_add(GTK_CONTAINER(menu), item);
1386 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_expand_all), NULL);
1387 
1388 #if GTK_CHECK_VERSION(3, 10, 0)
1389 	item = ui_image_menu_item_new("go-previous", _("Coll_apse All"));
1390 #else
1391 	item = ui_image_menu_item_new(GTK_STOCK_GO_BACK, _("Coll_apse All"));
1392 #endif
1393 	gtk_container_add(GTK_CONTAINER(menu), item);
1394 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_collapse_all), NULL);
1395 
1396 	item = gtk_separator_menu_item_new();
1397 	gtk_container_add(GTK_CONTAINER(menu), item);
1398 
1399 	item = gtk_check_menu_item_new_with_mnemonic(_("Show Boo_kmarks"));
1400 	gtk_container_add(GTK_CONTAINER(menu), item);
1401 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), CONFIG_SHOW_BOOKMARKS);
1402 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_show_bookmarks), NULL);
1403 
1404 	item = gtk_check_menu_item_new_with_mnemonic(_("Sho_w Hidden Files"));
1405 	gtk_container_add(GTK_CONTAINER(menu), item);
1406 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), CONFIG_SHOW_HIDDEN_FILES);
1407 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_show_hidden_files), NULL);
1408 
1409 	item = gtk_check_menu_item_new_with_mnemonic(_("Show Tool_bars"));
1410 	gtk_container_add(GTK_CONTAINER(menu), item);
1411 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), CONFIG_SHOW_BARS ? TRUE : FALSE);
1412 	g_signal_connect(item, "activate", G_CALLBACK(on_menu_show_bars), NULL);
1413 
1414 	gtk_widget_show_all(menu);
1415 
1416 	return menu;
1417 }
1418 
1419 
1420 /* ------------------
1421  * TOOLBAR`S EVENTS
1422  * ------------------ */
1423 
1424 static void
on_button_go_up(void)1425 on_button_go_up(void)
1426 {
1427 	gchar *uri;
1428 
1429 	uri = g_path_get_dirname(addressbar_last_address);
1430 	treebrowser_chroot(uri);
1431 	g_free(uri);
1432 }
1433 
1434 static void
on_button_refresh(void)1435 on_button_refresh(void)
1436 {
1437 	treebrowser_chroot(addressbar_last_address);
1438 }
1439 
1440 static void
on_button_go_home(void)1441 on_button_go_home(void)
1442 {
1443 	gchar *uri;
1444 
1445 	uri = g_strdup(g_get_home_dir());
1446 	treebrowser_chroot(uri);
1447 	g_free(uri);
1448 }
1449 
1450 static void
on_button_current_path(void)1451 on_button_current_path(void)
1452 {
1453 	gchar *uri;
1454 
1455 	uri = get_default_dir();
1456 	treebrowser_chroot(uri);
1457 	g_free(uri);
1458 }
1459 
1460 static void
on_button_hide_bars(void)1461 on_button_hide_bars(void)
1462 {
1463 	showbars(FALSE);
1464 }
1465 
1466 static void
on_addressbar_activate(GtkEntry * entry,gpointer user_data)1467 on_addressbar_activate(GtkEntry *entry, gpointer user_data)
1468 {
1469 	gchar *directory = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
1470 	treebrowser_chroot(directory);
1471 }
1472 
1473 static void
on_filter_activate(GtkEntry * entry,gpointer user_data)1474 on_filter_activate(GtkEntry *entry, gpointer user_data)
1475 {
1476 	treebrowser_chroot(addressbar_last_address);
1477 }
1478 
1479 static void
on_filter_clear(GtkEntry * entry,gint icon_pos,GdkEvent * event,gpointer data)1480 on_filter_clear(GtkEntry *entry, gint icon_pos, GdkEvent *event, gpointer data)
1481 {
1482 	gtk_entry_set_text(entry, "");
1483 	treebrowser_chroot(addressbar_last_address);
1484 }
1485 
1486 
1487 /* ------------------
1488  * TREEVIEW EVENTS
1489  * ------------------ */
1490 
1491 static gboolean
on_treeview_mouseclick(GtkWidget * widget,GdkEventButton * event,GtkTreeSelection * selection)1492 on_treeview_mouseclick(GtkWidget *widget, GdkEventButton *event, GtkTreeSelection *selection)
1493 {
1494 	if (event->button == 3)
1495 	{
1496 		GtkTreeIter 	iter;
1497 		GtkTreeModel 	*model;
1498 		GtkTreePath *path;
1499 		GtkWidget *menu;
1500 		gchar *name = NULL, *uri = NULL;
1501 
1502 		/* Get tree path for row that was clicked */
1503 		if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
1504 																		 (gint) event->x,
1505 																		 (gint) event->y,
1506 																		 &path, NULL, NULL, NULL))
1507 		{
1508 			/* Unselect current selection; select clicked row from path */
1509 			gtk_tree_selection_unselect_all(selection);
1510 			gtk_tree_selection_select_path(selection, path);
1511 			gtk_tree_path_free(path);
1512 		}
1513 
1514 		if (gtk_tree_selection_get_selected(selection, &model, &iter))
1515 			gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter,
1516 								TREEBROWSER_COLUMN_NAME, &name,
1517 								TREEBROWSER_COLUMN_URI, &uri,
1518 								-1);
1519 
1520 		menu = create_popup_menu(name != NULL ? name : "", uri != NULL ? uri : "");
1521 
1522 #if GTK_CHECK_VERSION(3, 22, 0)
1523 		gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
1524 #else
1525 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
1526 #endif
1527 
1528 		g_free(name);
1529 		g_free(uri);
1530 		return TRUE;
1531 	}
1532 
1533 	return FALSE;
1534 }
1535 
1536 static gboolean
on_treeview_keypress(GtkWidget * widget,GdkEventKey * event)1537 on_treeview_keypress(GtkWidget *widget, GdkEventKey *event)
1538 {
1539 	GtkTreeIter		iter;
1540 	GtkTreeModel	*model;
1541 	GtkTreePath		*path;
1542 	GdkModifierType	modifiers = gtk_accelerator_get_default_mod_mask();
1543 
1544 	if (event->keyval == GDK_space)
1545 	{
1546 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model, &iter))
1547 		{
1548 			path = gtk_tree_model_get_path(model, &iter);
1549 			if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1550 				gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1551 			else
1552 				gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
1553 			return TRUE;
1554 		}
1555 	}
1556 	if (event->keyval == GDK_BackSpace)
1557 	{
1558 		on_button_go_up();
1559 		return TRUE;
1560 	}
1561 	if ((event->keyval == GDK_Menu) ||
1562 	    (event->keyval == GDK_F10 && (event->state & modifiers) == GDK_SHIFT_MASK))
1563 	{
1564 		gchar *name = NULL, *uri = NULL;
1565 		GtkWidget *menu;
1566 
1567 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model, &iter))
1568 			gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter,
1569 								TREEBROWSER_COLUMN_NAME, &name,
1570 								TREEBROWSER_COLUMN_URI, &uri,
1571 								-1);
1572 
1573 		menu = create_popup_menu(name != NULL ? name : "", uri != NULL ? uri : "");
1574 #if GTK_CHECK_VERSION(3, 22, 0)
1575 		gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
1576 #else
1577 		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, event->time);
1578 #endif
1579 
1580 		g_free(name);
1581 		g_free(uri);
1582 
1583 		return TRUE;
1584 	}
1585 	if (event->keyval == GDK_Left)
1586 	{
1587 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model, &iter))
1588 		{
1589 			path = gtk_tree_model_get_path(model, &iter);
1590 			if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1591 				gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1592 			else if (gtk_tree_path_get_depth(path) > 1) {
1593 				gtk_tree_path_up(path);
1594 				gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, NULL, FALSE);
1595 				gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), path);
1596 			}
1597 		}
1598 		return TRUE;
1599 	}
1600 	if (event->keyval == GDK_Right)
1601 	{
1602 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)), &model, &iter))
1603 		{
1604 			path = gtk_tree_model_get_path(model, &iter);
1605 			if (!gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1606 				gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
1607 		}
1608 		return TRUE;
1609 	}
1610 
1611 	return FALSE;
1612 }
1613 
1614 static void
on_treeview_changed(GtkWidget * widget,gpointer user_data)1615 on_treeview_changed(GtkWidget *widget, gpointer user_data)
1616 {
1617 	GtkTreeIter 	iter;
1618 	GtkTreeModel 	*model;
1619 	gchar 			*uri;
1620 
1621 	if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(widget), &model, &iter))
1622 	{
1623 		gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter,
1624 							TREEBROWSER_COLUMN_URI, &uri,
1625 							-1);
1626 		if (uri == NULL)
1627 			return;
1628 
1629 		if (g_file_test(uri, G_FILE_TEST_EXISTS)) {
1630 			if (!g_file_test(uri, G_FILE_TEST_IS_DIR) && CONFIG_ONE_CLICK_CHDOC)
1631 				document_open_file(uri, FALSE, NULL, NULL);
1632 		}
1633 
1634 		g_free(uri);
1635 	}
1636 }
1637 
1638 static void
on_treeview_row_activated(GtkWidget * widget,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)1639 on_treeview_row_activated(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
1640 {
1641 	GtkTreeIter 	iter;
1642 	gchar 			*uri;
1643 
1644 	gtk_tree_model_get_iter(GTK_TREE_MODEL(treestore), &iter, path);
1645 	gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1646 
1647 	if (uri == NULL)
1648 		return;
1649 
1650 	if (g_file_test (uri, G_FILE_TEST_IS_DIR))
1651 		if (CONFIG_CHROOT_ON_DCLICK)
1652 			treebrowser_chroot(uri);
1653 		else
1654 			if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1655 				gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1656 			else {
1657 				treebrowser_browse(uri, &iter);
1658 				gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, FALSE);
1659 			}
1660 	else {
1661 		document_open_file(uri, FALSE, NULL, NULL);
1662 		if (CONFIG_ON_OPEN_FOCUS_EDITOR)
1663 			keybindings_send_command(GEANY_KEY_GROUP_FOCUS, GEANY_KEYS_FOCUS_EDITOR);
1664 	}
1665 
1666 	g_free(uri);
1667 }
1668 
1669 static void
on_treeview_row_expanded(GtkWidget * widget,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)1670 on_treeview_row_expanded(GtkWidget *widget, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
1671 {
1672 	gchar *uri;
1673 
1674 	gtk_tree_model_get(GTK_TREE_MODEL(treestore), iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1675 	if (uri == NULL)
1676 		return;
1677 
1678 	if (flag_on_expand_refresh == FALSE)
1679 	{
1680 		flag_on_expand_refresh = TRUE;
1681 		treebrowser_browse(uri, iter);
1682 		gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview), path, FALSE);
1683 		flag_on_expand_refresh = FALSE;
1684 	}
1685 	if (CONFIG_SHOW_ICONS)
1686 	{
1687 #if GTK_CHECK_VERSION(3, 10, 0)
1688 		GdkPixbuf *icon = utils_pixbuf_from_name("document-open");
1689 #else
1690 		GdkPixbuf *icon = utils_pixbuf_from_stock(GTK_STOCK_OPEN);
1691 #endif
1692 
1693 		gtk_tree_store_set(treestore, iter, TREEBROWSER_COLUMN_ICON, icon, -1);
1694 		g_object_unref(icon);
1695 	}
1696 
1697 	g_free(uri);
1698 }
1699 
1700 static void
on_treeview_row_collapsed(GtkWidget * widget,GtkTreeIter * iter,GtkTreePath * path,gpointer user_data)1701 on_treeview_row_collapsed(GtkWidget *widget, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
1702 {
1703 	gchar *uri;
1704 	gtk_tree_model_get(GTK_TREE_MODEL(treestore), iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1705 	if (uri == NULL)
1706 		return;
1707 	if (CONFIG_SHOW_ICONS)
1708 	{
1709 #if GTK_CHECK_VERSION(3, 10, 0)
1710 		GdkPixbuf *icon = utils_pixbuf_from_name("folder");
1711 #else
1712 		GdkPixbuf *icon = utils_pixbuf_from_stock(GTK_STOCK_DIRECTORY);
1713 #endif
1714 
1715 		gtk_tree_store_set(treestore, iter, TREEBROWSER_COLUMN_ICON, icon, -1);
1716 		g_object_unref(icon);
1717 	}
1718 	g_free(uri);
1719 }
1720 
1721 static void
on_treeview_renamed(GtkCellRenderer * renderer,const gchar * path_string,const gchar * name_new,gpointer user_data)1722 on_treeview_renamed(GtkCellRenderer *renderer, const gchar *path_string, const gchar *name_new, gpointer user_data)
1723 {
1724 
1725 	GtkTreeViewColumn 	*column;
1726 	GList 				*renderers;
1727 	GtkTreeIter 		iter, iter_parent;
1728 	gchar 				*uri, *uri_new, *dirname;
1729 
1730 	column 		= gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0);
1731 	renderers 	= gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1732 	renderer 	= g_list_nth_data(renderers, TREEBROWSER_RENDER_TEXT);
1733 	g_list_free(renderers);
1734 
1735 	g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL);
1736 
1737 	if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(treestore), &iter, path_string))
1738 	{
1739 		gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, TREEBROWSER_COLUMN_URI, &uri, -1);
1740 		if (uri)
1741 		{
1742 			dirname = g_path_get_dirname(uri);
1743 			uri_new = g_strconcat(dirname, G_DIR_SEPARATOR_S, name_new, NULL);
1744 			g_free(dirname);
1745 			if (!(g_file_test(uri_new, G_FILE_TEST_EXISTS) &&
1746 				strcmp(uri, uri_new) != 0 &&
1747 				!dialogs_show_question(_("Target file '%s' exists, do you really want to replace it?"), uri_new)))
1748 			{
1749 				if (g_rename(uri, uri_new) == 0)
1750 				{
1751 					dirname = g_path_get_dirname(uri_new);
1752 					gtk_tree_store_set(treestore, &iter,
1753 									TREEBROWSER_COLUMN_NAME, name_new,
1754 									TREEBROWSER_COLUMN_URI, uri_new,
1755 									-1);
1756 					if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(treestore), &iter_parent, &iter))
1757 						treebrowser_browse(dirname, &iter_parent);
1758 					else
1759 						treebrowser_browse(dirname, NULL);
1760 					g_free(dirname);
1761 
1762 					if (!g_file_test(uri, G_FILE_TEST_IS_DIR))
1763 					{
1764 						GeanyDocument *doc = document_find_by_filename(uri);
1765 						if (doc && document_close(doc))
1766 							document_open_file(uri_new, FALSE, NULL, NULL);
1767 					}
1768 				}
1769 			}
1770 			g_free(uri_new);
1771 			g_free(uri);
1772 		}
1773 	}
1774 }
1775 
1776 static void
treebrowser_track_current_cb(void)1777 treebrowser_track_current_cb(void)
1778 {
1779 	if (CONFIG_FOLLOW_CURRENT_DOC)
1780 		treebrowser_track_current();
1781 }
1782 
1783 
1784 /* ------------------
1785  * TREEBROWSER INITIAL FUNCTIONS
1786  * ------------------ */
1787 
1788 static gboolean
treeview_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1789 treeview_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
1790 {
1791 	gint flag;
1792 	gtk_tree_model_get(model, iter, TREEBROWSER_COLUMN_FLAG, &flag, -1);
1793 	return (flag == TREEBROWSER_FLAGS_SEPARATOR);
1794 }
1795 
1796 static GtkWidget*
create_view_and_model(void)1797 create_view_and_model(void)
1798 {
1799 
1800 	GtkWidget 			*view;
1801 
1802 	view 					= gtk_tree_view_new();
1803 	treeview_column_text	= gtk_tree_view_column_new();
1804 	render_icon 			= gtk_cell_renderer_pixbuf_new();
1805 	render_text 			= gtk_cell_renderer_text_new();
1806 
1807 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
1808 	gtk_tree_view_append_column(GTK_TREE_VIEW(view), treeview_column_text);
1809 
1810 	gtk_tree_view_column_pack_start(treeview_column_text, render_icon, FALSE);
1811 	gtk_tree_view_column_set_attributes(treeview_column_text, render_icon, "pixbuf", TREEBROWSER_RENDER_ICON, NULL);
1812 
1813 	gtk_tree_view_column_pack_start(treeview_column_text, render_text, TRUE);
1814 	gtk_tree_view_column_add_attribute(treeview_column_text, render_text, "text", TREEBROWSER_RENDER_TEXT);
1815 
1816 	gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), TRUE);
1817 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(view), TREEBROWSER_COLUMN_NAME);
1818 
1819 	gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(view), treeview_separator_func, NULL, NULL);
1820 
1821 	ui_widget_modify_font_from_string(view, geany->interface_prefs->tagbar_font);
1822 
1823 	g_object_set(view, "has-tooltip", TRUE, "tooltip-column", TREEBROWSER_COLUMN_URI, NULL);
1824 
1825 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), GTK_SELECTION_SINGLE);
1826 
1827 	gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(view), CONFIG_SHOW_TREE_LINES);
1828 
1829 	treestore = gtk_tree_store_new(TREEBROWSER_COLUMNC, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
1830 
1831 	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(treestore));
1832 	g_signal_connect(G_OBJECT(render_text), "edited", G_CALLBACK(on_treeview_renamed), view);
1833 
1834 	return view;
1835 }
1836 
1837 static void
create_sidebar(void)1838 create_sidebar(void)
1839 {
1840 	GtkWidget 			*scrollwin;
1841 	GtkWidget 			*toolbar;
1842 	GtkWidget 			*wid;
1843 	GtkTreeSelection 	*selection;
1844 
1845 #if GTK_CHECK_VERSION(3, 0, 0)
1846 	GtkCssProvider *provider;
1847 	GdkDisplay *display;
1848 	GdkScreen *screen;
1849 
1850 	provider = gtk_css_provider_new ();
1851 	display = gdk_display_get_default ();
1852 	screen = gdk_display_get_default_screen (display);
1853 	gtk_style_context_add_provider_for_screen (screen,
1854 		GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1855 	gtk_css_provider_load_from_data (GTK_CSS_PROVIDER(provider),
1856 		"#addressbar.invalid {color: #ffffff; background: #ff6666;}",
1857 		-1, NULL);
1858 #endif
1859 
1860 	treeview 				= create_view_and_model();
1861 	sidebar_vbox 			= gtk_vbox_new(FALSE, 0);
1862 	sidebar_vbox_bars 		= gtk_vbox_new(FALSE, 0);
1863 	selection 				= gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1864 	addressbar 				= gtk_entry_new();
1865 #if GTK_CHECK_VERSION(3, 10, 0)
1866 	gtk_widget_set_name(addressbar, "addressbar");
1867 #endif
1868 	filter 					= gtk_entry_new();
1869 	scrollwin 				= gtk_scrolled_window_new(NULL, NULL);
1870 
1871 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1872 
1873 	toolbar = gtk_toolbar_new();
1874 	gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_MENU);
1875 	gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
1876 
1877 #if GTK_CHECK_VERSION(3, 10, 0)
1878 	wid = gtk_image_new_from_icon_name("go-up", GTK_ICON_SIZE_SMALL_TOOLBAR);
1879 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1880 #else
1881 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_GO_UP));
1882 #endif
1883 	gtk_widget_set_tooltip_text(wid, _("Go up"));
1884 	g_signal_connect(wid, "clicked", G_CALLBACK(on_button_go_up), NULL);
1885 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1886 
1887 #if GTK_CHECK_VERSION(3, 10, 0)
1888 	wid = gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_SMALL_TOOLBAR);
1889 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1890 #else
1891 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH));
1892 #endif
1893 	gtk_widget_set_tooltip_text(wid, _("Refresh"));
1894 	g_signal_connect(wid, "clicked", G_CALLBACK(on_button_refresh), NULL);
1895 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1896 
1897 #if GTK_CHECK_VERSION(3, 10, 0)
1898 	wid = gtk_image_new_from_icon_name("go-home", GTK_ICON_SIZE_SMALL_TOOLBAR);
1899 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1900 #else
1901 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_HOME));
1902 #endif
1903 	gtk_widget_set_tooltip_text(wid, _("Home"));
1904 	g_signal_connect(wid, "clicked", G_CALLBACK(on_button_go_home), NULL);
1905 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1906 
1907 #if GTK_CHECK_VERSION(3, 10, 0)
1908 	wid = gtk_image_new_from_icon_name("go-jump", GTK_ICON_SIZE_SMALL_TOOLBAR);
1909 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1910 #else
1911 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_JUMP_TO));
1912 #endif
1913 	gtk_widget_set_tooltip_text(wid, _("Set path from document"));
1914 	g_signal_connect(wid, "clicked", G_CALLBACK(on_button_current_path), NULL);
1915 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1916 
1917 #if GTK_CHECK_VERSION(3, 10, 0)
1918 	wid = gtk_image_new_from_icon_name("folder", GTK_ICON_SIZE_SMALL_TOOLBAR);
1919 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1920 #else
1921 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_DIRECTORY));
1922 #endif
1923 	gtk_widget_set_tooltip_text(wid, _("Track path"));
1924 	g_signal_connect(wid, "clicked", G_CALLBACK(treebrowser_track_current), NULL);
1925 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1926 
1927 #if GTK_CHECK_VERSION(3, 10, 0)
1928 	wid = gtk_image_new_from_icon_name("window-close", GTK_ICON_SIZE_SMALL_TOOLBAR);
1929 	wid = GTK_WIDGET(gtk_tool_button_new(wid, NULL));
1930 #else
1931 	wid = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_CLOSE));
1932 #endif
1933 	gtk_widget_set_tooltip_text(wid, _("Hide bars"));
1934 	g_signal_connect(wid, "clicked", G_CALLBACK(on_button_hide_bars), NULL);
1935 	gtk_container_add(GTK_CONTAINER(toolbar), wid);
1936 
1937 	gtk_container_add(GTK_CONTAINER(scrollwin), 			treeview);
1938 	gtk_box_pack_start(GTK_BOX(sidebar_vbox_bars), 			filter, 			FALSE, TRUE,  1);
1939 	gtk_box_pack_start(GTK_BOX(sidebar_vbox_bars), 			addressbar, 		FALSE, TRUE,  1);
1940 	gtk_box_pack_start(GTK_BOX(sidebar_vbox_bars), 			toolbar, 			FALSE, TRUE,  1);
1941 
1942 	gtk_widget_set_tooltip_text(filter,
1943 		_("Filter (*.c;*.h;*.cpp), and if you want temporary filter using the '!' reverse try for example this '!;*.c;*.h;*.cpp'"));
1944 	ui_entry_add_clear_icon(GTK_ENTRY(filter));
1945 	g_signal_connect(filter, "icon-release", G_CALLBACK(on_filter_clear), NULL);
1946 
1947 	gtk_widget_set_tooltip_text(addressbar,
1948 		_("Addressbar for example '/projects/my-project'"));
1949 
1950 	if (CONFIG_SHOW_BARS == 2)
1951 	{
1952 		gtk_box_pack_start(GTK_BOX(sidebar_vbox), 				scrollwin, 			TRUE,  TRUE,  1);
1953 		gtk_box_pack_start(GTK_BOX(sidebar_vbox), 				sidebar_vbox_bars, 	FALSE, TRUE,  1);
1954 	}
1955 	else
1956 	{
1957 		gtk_box_pack_start(GTK_BOX(sidebar_vbox), 				sidebar_vbox_bars, 	FALSE, TRUE,  1);
1958 		gtk_box_pack_start(GTK_BOX(sidebar_vbox), 				scrollwin, 			TRUE,  TRUE,  1);
1959 	}
1960 
1961 	g_signal_connect(selection, 		"changed", 				G_CALLBACK(on_treeview_changed), 				NULL);
1962 	g_signal_connect(treeview, 			"button-press-event", 	G_CALLBACK(on_treeview_mouseclick), 			selection);
1963 	g_signal_connect(treeview, 			"row-activated", 		G_CALLBACK(on_treeview_row_activated), 			NULL);
1964 	g_signal_connect(treeview, 			"row-collapsed", 		G_CALLBACK(on_treeview_row_collapsed), 			NULL);
1965 	g_signal_connect(treeview, 			"row-expanded", 		G_CALLBACK(on_treeview_row_expanded), 			NULL);
1966 	g_signal_connect(treeview, 			"key-press-event", 		G_CALLBACK(on_treeview_keypress), 			NULL);
1967 	g_signal_connect(addressbar, 		"activate", 			G_CALLBACK(on_addressbar_activate), 			NULL);
1968 	g_signal_connect(filter, 			"activate", 			G_CALLBACK(on_filter_activate), 				NULL);
1969 
1970 	gtk_widget_show_all(sidebar_vbox);
1971 
1972 	page_number = gtk_notebook_append_page(GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook),
1973 							sidebar_vbox, gtk_label_new(_("Tree Browser")));
1974 
1975 	showbars(CONFIG_SHOW_BARS);
1976 }
1977 
1978 
1979 /* ------------------
1980  * CONFIG DIALOG
1981  * ------------------ */
1982 
1983 static struct
1984 {
1985 	GtkWidget *OPEN_EXTERNAL_CMD;
1986 	GtkWidget *OPEN_TERMINAL;
1987 	GtkWidget *REVERSE_FILTER;
1988 	GtkWidget *ONE_CLICK_CHDOC;
1989 	GtkWidget *SHOW_HIDDEN_FILES;
1990 	GtkWidget *HIDE_OBJECT_FILES;
1991 	GtkWidget *SHOW_BARS;
1992 	GtkWidget *CHROOT_ON_DCLICK;
1993 	GtkWidget *FOLLOW_CURRENT_DOC;
1994 	GtkWidget *ON_DELETE_CLOSE_FILE;
1995 	GtkWidget *ON_OPEN_FOCUS_EDITOR;
1996 	GtkWidget *SHOW_TREE_LINES;
1997 	GtkWidget *SHOW_BOOKMARKS;
1998 	GtkWidget *SHOW_ICONS;
1999 	GtkWidget *OPEN_NEW_FILES;
2000 } configure_widgets;
2001 
2002 static void
load_settings(void)2003 load_settings(void)
2004 {
2005 	GKeyFile *config 	= g_key_file_new();
2006 
2007 	g_key_file_load_from_file(config, CONFIG_FILE, G_KEY_FILE_NONE, NULL);
2008 
2009 	CONFIG_OPEN_EXTERNAL_CMD 		=  utils_get_setting_string(config, "treebrowser", "open_external_cmd", 	CONFIG_OPEN_EXTERNAL_CMD_DEFAULT);
2010 	CONFIG_OPEN_TERMINAL 				= utils_get_setting_string(config, "treebrowser", "open_terminal", CONFIG_OPEN_TERMINAL_DEFAULT);
2011 	CONFIG_REVERSE_FILTER 			= utils_get_setting_boolean(config, "treebrowser", "reverse_filter", 		CONFIG_REVERSE_FILTER);
2012 	CONFIG_ONE_CLICK_CHDOC 			= utils_get_setting_boolean(config, "treebrowser", "one_click_chdoc", 		CONFIG_ONE_CLICK_CHDOC);
2013 	CONFIG_SHOW_HIDDEN_FILES 		= utils_get_setting_boolean(config, "treebrowser", "show_hidden_files", 	CONFIG_SHOW_HIDDEN_FILES);
2014 	CONFIG_HIDE_OBJECT_FILES 		= utils_get_setting_boolean(config, "treebrowser", "hide_object_files", 	CONFIG_HIDE_OBJECT_FILES);
2015 	CONFIG_SHOW_BARS 				= utils_get_setting_integer(config, "treebrowser", "show_bars", 			CONFIG_SHOW_BARS);
2016 	CONFIG_CHROOT_ON_DCLICK 		= utils_get_setting_boolean(config, "treebrowser", "chroot_on_dclick", 		CONFIG_CHROOT_ON_DCLICK);
2017 	CONFIG_FOLLOW_CURRENT_DOC 		= utils_get_setting_boolean(config, "treebrowser", "follow_current_doc", 	CONFIG_FOLLOW_CURRENT_DOC);
2018 	CONFIG_ON_DELETE_CLOSE_FILE 	= utils_get_setting_boolean(config, "treebrowser", "on_delete_close_file", 	CONFIG_ON_DELETE_CLOSE_FILE);
2019 	CONFIG_ON_OPEN_FOCUS_EDITOR		= utils_get_setting_boolean(config, "treebrowser", "on_open_focus_editor", 	CONFIG_ON_OPEN_FOCUS_EDITOR);
2020 	CONFIG_SHOW_TREE_LINES 			= utils_get_setting_boolean(config, "treebrowser", "show_tree_lines", 		CONFIG_SHOW_TREE_LINES);
2021 	CONFIG_SHOW_BOOKMARKS 			= utils_get_setting_boolean(config, "treebrowser", "show_bookmarks", 		CONFIG_SHOW_BOOKMARKS);
2022 	CONFIG_SHOW_ICONS 				= utils_get_setting_integer(config, "treebrowser", "show_icons", 			CONFIG_SHOW_ICONS);
2023 	CONFIG_OPEN_NEW_FILES			= utils_get_setting_boolean(config, "treebrowser", "open_new_files",		CONFIG_OPEN_NEW_FILES);
2024 
2025 	g_key_file_free(config);
2026 }
2027 
2028 static gboolean
save_settings(void)2029 save_settings(void)
2030 {
2031 	GKeyFile 	*config 		= g_key_file_new();
2032 	gchar 		*config_dir 	= g_path_get_dirname(CONFIG_FILE);
2033 	gchar 		*data;
2034 
2035 	g_key_file_load_from_file(config, CONFIG_FILE, G_KEY_FILE_NONE, NULL);
2036 	if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0)
2037 	{
2038 		g_free(config_dir);
2039 		g_key_file_free(config);
2040 		return FALSE;
2041 	}
2042 
2043 	g_key_file_set_string(config, 	"treebrowser", "open_external_cmd", 	CONFIG_OPEN_EXTERNAL_CMD);
2044 	g_key_file_set_string(config, 	"treebrowser", "open_terminal", 	CONFIG_OPEN_TERMINAL);
2045 	g_key_file_set_boolean(config, 	"treebrowser", "reverse_filter", 		CONFIG_REVERSE_FILTER);
2046 	g_key_file_set_boolean(config, 	"treebrowser", "one_click_chdoc", 		CONFIG_ONE_CLICK_CHDOC);
2047 	g_key_file_set_boolean(config, 	"treebrowser", "show_hidden_files", 	CONFIG_SHOW_HIDDEN_FILES);
2048 	g_key_file_set_boolean(config, 	"treebrowser", "hide_object_files", 	CONFIG_HIDE_OBJECT_FILES);
2049 	g_key_file_set_integer(config, 	"treebrowser", "show_bars", 			CONFIG_SHOW_BARS);
2050 	g_key_file_set_boolean(config, 	"treebrowser", "chroot_on_dclick", 		CONFIG_CHROOT_ON_DCLICK);
2051 	g_key_file_set_boolean(config, 	"treebrowser", "follow_current_doc", 	CONFIG_FOLLOW_CURRENT_DOC);
2052 	g_key_file_set_boolean(config, 	"treebrowser", "on_delete_close_file", 	CONFIG_ON_DELETE_CLOSE_FILE);
2053 	g_key_file_set_boolean(config, 	"treebrowser", "on_open_focus_editor", 	CONFIG_ON_OPEN_FOCUS_EDITOR);
2054 	g_key_file_set_boolean(config, 	"treebrowser", "show_tree_lines", 		CONFIG_SHOW_TREE_LINES);
2055 	g_key_file_set_boolean(config, 	"treebrowser", "show_bookmarks", 		CONFIG_SHOW_BOOKMARKS);
2056 	g_key_file_set_integer(config, 	"treebrowser", "show_icons", 			CONFIG_SHOW_ICONS);
2057 	g_key_file_set_boolean(config,	"treebrowser", "open_new_files",		CONFIG_OPEN_NEW_FILES);
2058 
2059 	data = g_key_file_to_data(config, NULL, NULL);
2060 	utils_write_file(CONFIG_FILE, data);
2061 	g_free(data);
2062 
2063 	g_free(config_dir);
2064 	g_key_file_free(config);
2065 
2066 	return TRUE;
2067 }
2068 
2069 static void
on_configure_response(GtkDialog * dialog,gint response,gpointer user_data)2070 on_configure_response(GtkDialog *dialog, gint response, gpointer user_data)
2071 {
2072 
2073 	if (! (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY))
2074 		return;
2075 
2076 	CONFIG_OPEN_EXTERNAL_CMD 	= gtk_editable_get_chars(GTK_EDITABLE(configure_widgets.OPEN_EXTERNAL_CMD), 0, -1);
2077 	CONFIG_OPEN_TERMINAL     	= gtk_editable_get_chars(GTK_EDITABLE(configure_widgets.OPEN_TERMINAL), 0, -1);
2078 	CONFIG_REVERSE_FILTER 		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.REVERSE_FILTER));
2079 	CONFIG_ONE_CLICK_CHDOC 		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.ONE_CLICK_CHDOC));
2080 	CONFIG_SHOW_HIDDEN_FILES 	= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_HIDDEN_FILES));
2081 	CONFIG_HIDE_OBJECT_FILES 	= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.HIDE_OBJECT_FILES));
2082 	CONFIG_SHOW_BARS 			= gtk_combo_box_get_active(GTK_COMBO_BOX(configure_widgets.SHOW_BARS));
2083 	CONFIG_CHROOT_ON_DCLICK 	= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.CHROOT_ON_DCLICK));
2084 	CONFIG_FOLLOW_CURRENT_DOC 	= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.FOLLOW_CURRENT_DOC));
2085 	CONFIG_ON_DELETE_CLOSE_FILE = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.ON_DELETE_CLOSE_FILE));
2086 	CONFIG_ON_OPEN_FOCUS_EDITOR	= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.ON_OPEN_FOCUS_EDITOR));
2087 	CONFIG_SHOW_TREE_LINES 		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_TREE_LINES));
2088 	CONFIG_SHOW_BOOKMARKS 		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_BOOKMARKS));
2089 	CONFIG_SHOW_ICONS 			= gtk_combo_box_get_active(GTK_COMBO_BOX(configure_widgets.SHOW_ICONS));
2090 	CONFIG_OPEN_NEW_FILES		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_widgets.OPEN_NEW_FILES));
2091 
2092 	if (save_settings() == TRUE)
2093 	{
2094 		gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(treeview), CONFIG_SHOW_TREE_LINES);
2095 		treebrowser_chroot(addressbar_last_address);
2096 		if (CONFIG_SHOW_BOOKMARKS)
2097 			treebrowser_load_bookmarks();
2098 		showbars(CONFIG_SHOW_BARS);
2099 	}
2100 	else
2101 		dialogs_show_msgbox(GTK_MESSAGE_ERROR,
2102 			_("Plugin configuration directory could not be created."));
2103 }
2104 
2105 GtkWidget*
plugin_configure(GtkDialog * dialog)2106 plugin_configure(GtkDialog *dialog)
2107 {
2108 	GtkWidget 		*label;
2109 	GtkWidget 		*vbox, *hbox;
2110 
2111 	vbox 	= gtk_vbox_new(FALSE, 0);
2112 	hbox 	= gtk_hbox_new(FALSE, 0);
2113 
2114 	label 	= gtk_label_new(_("External open command"));
2115 	configure_widgets.OPEN_EXTERNAL_CMD = gtk_entry_new();
2116 	gtk_entry_set_text(GTK_ENTRY(configure_widgets.OPEN_EXTERNAL_CMD), CONFIG_OPEN_EXTERNAL_CMD);
2117 #if GTK_CHECK_VERSION(3, 14, 0)
2118 	gtk_widget_set_halign(label, 0);
2119 	gtk_widget_set_valign(label, 0.5);
2120 #else
2121 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
2122 #endif
2123 	gtk_widget_set_tooltip_text(configure_widgets.OPEN_EXTERNAL_CMD,
2124 		_("The command to execute when using \"Open with\". You can use %f and %d wildcards.\n"
2125 		  "%f will be replaced with the filename including full path\n"
2126 		  "%d will be replaced with the path name of the selected file without the filename"));
2127 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
2128 	gtk_box_pack_start(GTK_BOX(hbox), configure_widgets.OPEN_EXTERNAL_CMD, FALSE, FALSE, 0);
2129 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 6);
2130 
2131 	hbox = gtk_hbox_new(FALSE, 0);
2132 	label = gtk_label_new(_("Terminal"));
2133 	configure_widgets.OPEN_TERMINAL = gtk_entry_new();
2134 	gtk_entry_set_text(GTK_ENTRY(configure_widgets.OPEN_TERMINAL), CONFIG_OPEN_TERMINAL);
2135 
2136 #if GTK_CHECK_VERSION(3, 14, 0)
2137 	gtk_widget_set_halign(label, 0);
2138 	gtk_widget_set_valign(label, 0.5);
2139 #else
2140 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
2141 #endif
2142 	gtk_widget_set_tooltip_text(configure_widgets.OPEN_TERMINAL,
2143 		_("The terminal to use with the command \"Open Terminal\""));
2144 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
2145 	gtk_box_pack_start(GTK_BOX(hbox), configure_widgets.OPEN_TERMINAL, FALSE, FALSE, 0);
2146 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 6);
2147 
2148 	hbox = gtk_hbox_new(FALSE, 0);
2149 	label = gtk_label_new(_("Toolbar"));
2150 	configure_widgets.SHOW_BARS = gtk_combo_box_text_new();
2151 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_BARS), _("Hidden"));
2152 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_BARS), _("Top"));
2153 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_BARS), _("Bottom"));
2154 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
2155 	gtk_box_pack_start(GTK_BOX(hbox), configure_widgets.SHOW_BARS, FALSE, FALSE, 0);
2156 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 6);
2157 	gtk_widget_set_tooltip_text(configure_widgets.SHOW_BARS,
2158 		_("If position is changed, the option require plugin restart."));
2159 	gtk_combo_box_set_active(GTK_COMBO_BOX(configure_widgets.SHOW_BARS), CONFIG_SHOW_BARS);
2160 
2161 	hbox = gtk_hbox_new(FALSE, 0);
2162 	label = gtk_label_new(_("Show icons"));
2163 	configure_widgets.SHOW_ICONS = gtk_combo_box_text_new();
2164 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_ICONS), _("None"));
2165 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_ICONS), _("Base"));
2166 	gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(configure_widgets.SHOW_ICONS), _("Content-type"));
2167 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 6);
2168 	gtk_box_pack_start(GTK_BOX(hbox), configure_widgets.SHOW_ICONS, FALSE, FALSE, 0);
2169 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 6);
2170 	gtk_combo_box_set_active(GTK_COMBO_BOX(configure_widgets.SHOW_ICONS), CONFIG_SHOW_ICONS);
2171 
2172 	configure_widgets.SHOW_HIDDEN_FILES = gtk_check_button_new_with_label(_("Show hidden files"));
2173 #if GTK_CHECK_VERSION(3, 20, 0)
2174 	gtk_widget_set_focus_on_click(configure_widgets.SHOW_HIDDEN_FILES, FALSE);
2175 #else
2176 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.SHOW_HIDDEN_FILES), FALSE);
2177 #endif
2178 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_HIDDEN_FILES), CONFIG_SHOW_HIDDEN_FILES);
2179 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.SHOW_HIDDEN_FILES, FALSE, FALSE, 0);
2180 	gtk_widget_set_tooltip_text(configure_widgets.SHOW_HIDDEN_FILES,
2181 		_("On Windows, this just hide files that are prefixed with '.' (dot)"));
2182 
2183 	configure_widgets.HIDE_OBJECT_FILES = gtk_check_button_new_with_label(_("Hide object files"));
2184 #if GTK_CHECK_VERSION(3, 20, 0)
2185 	gtk_widget_set_focus_on_click(configure_widgets.HIDE_OBJECT_FILES, FALSE);
2186 #else
2187 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.HIDE_OBJECT_FILES), FALSE);
2188 #endif
2189 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.HIDE_OBJECT_FILES), CONFIG_HIDE_OBJECT_FILES);
2190 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.HIDE_OBJECT_FILES, FALSE, FALSE, 0);
2191 	gtk_widget_set_tooltip_text(configure_widgets.HIDE_OBJECT_FILES,
2192 		_("Don't show generated object files in the file browser, this includes *.o, *.obj. *.so, *.dll, *.a, *.lib"));
2193 
2194 	configure_widgets.REVERSE_FILTER = gtk_check_button_new_with_label(_("Reverse filter"));
2195 #if GTK_CHECK_VERSION(3, 20, 0)
2196 	gtk_widget_set_focus_on_click(configure_widgets.REVERSE_FILTER, FALSE);
2197 #else
2198 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.REVERSE_FILTER), FALSE);
2199 #endif
2200 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.REVERSE_FILTER), CONFIG_REVERSE_FILTER);
2201 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.REVERSE_FILTER, FALSE, FALSE, 0);
2202 
2203 	configure_widgets.FOLLOW_CURRENT_DOC = gtk_check_button_new_with_label(_("Follow current document"));
2204 #if GTK_CHECK_VERSION(3, 20, 0)
2205 	gtk_widget_set_focus_on_click(configure_widgets.FOLLOW_CURRENT_DOC, FALSE);
2206 #else
2207 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.FOLLOW_CURRENT_DOC), FALSE);
2208 #endif
2209 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.FOLLOW_CURRENT_DOC), CONFIG_FOLLOW_CURRENT_DOC);
2210 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.FOLLOW_CURRENT_DOC, FALSE, FALSE, 0);
2211 
2212 	configure_widgets.ONE_CLICK_CHDOC = gtk_check_button_new_with_label(_("Single click, open document and focus it"));
2213 #if GTK_CHECK_VERSION(3, 20, 0)
2214 	gtk_widget_set_focus_on_click(configure_widgets.ONE_CLICK_CHDOC, FALSE);
2215 #else
2216 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.ONE_CLICK_CHDOC), FALSE);
2217 #endif
2218 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.ONE_CLICK_CHDOC), CONFIG_ONE_CLICK_CHDOC);
2219 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.ONE_CLICK_CHDOC, FALSE, FALSE, 0);
2220 
2221 	configure_widgets.CHROOT_ON_DCLICK = gtk_check_button_new_with_label(_("Double click open directory"));
2222 #if GTK_CHECK_VERSION(3, 20, 0)
2223 	gtk_widget_set_focus_on_click(configure_widgets.ONE_CLICK_CHDOC, FALSE);
2224 #else
2225 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.CHROOT_ON_DCLICK), FALSE);
2226 #endif
2227 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.CHROOT_ON_DCLICK), CONFIG_CHROOT_ON_DCLICK);
2228 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.CHROOT_ON_DCLICK, FALSE, FALSE, 0);
2229 
2230 	configure_widgets.ON_DELETE_CLOSE_FILE = gtk_check_button_new_with_label(_("On delete file, close it if is opened"));
2231 #if GTK_CHECK_VERSION(3, 20, 0)
2232 	gtk_widget_set_focus_on_click(configure_widgets.ON_DELETE_CLOSE_FILE, FALSE);
2233 #else
2234 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.ON_DELETE_CLOSE_FILE), FALSE);
2235 #endif
2236 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.ON_DELETE_CLOSE_FILE), CONFIG_ON_DELETE_CLOSE_FILE);
2237 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.ON_DELETE_CLOSE_FILE, FALSE, FALSE, 0);
2238 
2239 	configure_widgets.ON_OPEN_FOCUS_EDITOR = gtk_check_button_new_with_label(_("Focus editor on file open"));
2240 #if GTK_CHECK_VERSION(3, 20, 0)
2241 	gtk_widget_set_focus_on_click(configure_widgets.ON_OPEN_FOCUS_EDITOR, FALSE);
2242 #else
2243 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.ON_OPEN_FOCUS_EDITOR), FALSE);
2244 #endif
2245 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.ON_OPEN_FOCUS_EDITOR), CONFIG_ON_OPEN_FOCUS_EDITOR);
2246 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.ON_OPEN_FOCUS_EDITOR, FALSE, FALSE, 0);
2247 
2248 	configure_widgets.SHOW_TREE_LINES = gtk_check_button_new_with_label(_("Show tree lines"));
2249 #if GTK_CHECK_VERSION(3, 20, 0)
2250 	gtk_widget_set_focus_on_click(configure_widgets.SHOW_TREE_LINES, FALSE);
2251 #else
2252 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.SHOW_TREE_LINES), FALSE);
2253 #endif
2254 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_TREE_LINES), CONFIG_SHOW_TREE_LINES);
2255 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.SHOW_TREE_LINES, FALSE, FALSE, 0);
2256 
2257 	configure_widgets.SHOW_BOOKMARKS = gtk_check_button_new_with_label(_("Show bookmarks"));
2258 #if GTK_CHECK_VERSION(3, 20, 0)
2259 	gtk_widget_set_focus_on_click(configure_widgets.SHOW_BOOKMARKS, FALSE);
2260 #else
2261 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.SHOW_BOOKMARKS), FALSE);
2262 #endif
2263 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.SHOW_BOOKMARKS), CONFIG_SHOW_BOOKMARKS);
2264 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.SHOW_BOOKMARKS, FALSE, FALSE, 0);
2265 
2266 	configure_widgets.OPEN_NEW_FILES = gtk_check_button_new_with_label(_("Open new files"));
2267 #if GTK_CHECK_VERSION(3, 20, 0)
2268 	gtk_widget_set_focus_on_click(configure_widgets.OPEN_NEW_FILES, FALSE);
2269 #else
2270 	gtk_button_set_focus_on_click(GTK_BUTTON(configure_widgets.OPEN_NEW_FILES ), FALSE);
2271 #endif
2272 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(configure_widgets.OPEN_NEW_FILES ), CONFIG_OPEN_NEW_FILES);
2273 	gtk_box_pack_start(GTK_BOX(vbox), configure_widgets.OPEN_NEW_FILES , FALSE, FALSE, 0);
2274 
2275 	gtk_widget_show_all(vbox);
2276 
2277 	g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
2278 
2279 	return vbox;
2280 }
2281 
2282 
2283 /* ------------------
2284  * GEANY HOOKS
2285  * ------------------ */
2286 
2287 static void
project_open_cb(G_GNUC_UNUSED GObject * obj,G_GNUC_UNUSED GKeyFile * config,G_GNUC_UNUSED gpointer data)2288 project_open_cb(G_GNUC_UNUSED GObject *obj, G_GNUC_UNUSED GKeyFile *config, G_GNUC_UNUSED gpointer data)
2289 {
2290 	gchar *uri;
2291 
2292 	uri = get_default_dir();
2293 	treebrowser_chroot(uri);
2294 	g_free(uri);
2295 }
2296 
kb_activate(guint key_id)2297 static void kb_activate(guint key_id)
2298 {
2299 	gtk_notebook_set_current_page(GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook), page_number);
2300 	switch (key_id)
2301 	{
2302 		case KB_FOCUS_FILE_LIST:
2303 			gtk_widget_grab_focus(treeview);
2304 			break;
2305 
2306 		case KB_FOCUS_PATH_ENTRY:
2307 			gtk_widget_grab_focus(addressbar);
2308 			break;
2309 
2310 		case KB_RENAME_OBJECT:
2311 			treebrowser_rename_current();
2312 			break;
2313 
2314 		case KB_CREATE_FILE:
2315 			treebrowser_create_new_current("file");
2316 			break;
2317 
2318 		case KB_CREATE_DIR:
2319 			treebrowser_create_new_current("directory");
2320 			break;
2321 
2322 		case KB_REFRESH:
2323 			on_menu_refresh(NULL, NULL);
2324 			break;
2325 
2326 		case KB_TRACK_CURRENT:
2327 			treebrowser_track_current();
2328 			break;
2329 	}
2330 }
2331 
2332 void
plugin_init(GeanyData * data)2333 plugin_init(GeanyData *data)
2334 {
2335 	GeanyKeyGroup *key_group;
2336 
2337 	CONFIG_FILE = g_strconcat(geany->app->configdir, G_DIR_SEPARATOR_S, "plugins", G_DIR_SEPARATOR_S,
2338 		"treebrowser", G_DIR_SEPARATOR_S, "treebrowser.conf", NULL);
2339 
2340 	flag_on_expand_refresh = FALSE;
2341 
2342 	load_settings();
2343 	create_sidebar();
2344 	treebrowser_chroot(get_default_dir());
2345 
2346 	/* setup keybindings */
2347 	key_group = plugin_set_key_group(geany_plugin, "file_browser", KB_COUNT, NULL);
2348 
2349 	keybindings_set_item(key_group, KB_FOCUS_FILE_LIST, kb_activate,
2350 		0, 0, "focus_file_list", _("Focus File List"), NULL);
2351 	keybindings_set_item(key_group, KB_FOCUS_PATH_ENTRY, kb_activate,
2352 		0, 0, "focus_path_entry", _("Focus Path Entry"), NULL);
2353 	keybindings_set_item(key_group, KB_RENAME_OBJECT, kb_activate,
2354 		0, 0, "rename_object", _("Rename Object"), NULL);
2355 	keybindings_set_item(key_group, KB_CREATE_FILE, kb_activate,
2356 		0, 0, "create_file", _("New File"), NULL);
2357 	keybindings_set_item(key_group, KB_CREATE_DIR, kb_activate,
2358 		0, 0, "create_dir", _("New Folder"), NULL);
2359 	keybindings_set_item(key_group, KB_REFRESH, kb_activate,
2360 		0, 0, "rename_refresh", _("Refresh"), NULL);
2361 	keybindings_set_item(key_group, KB_TRACK_CURRENT, kb_activate,
2362 		0, 0, "track_current", _("Track Current"), NULL);
2363 
2364 	plugin_signal_connect(geany_plugin, NULL, "document-activate", TRUE,
2365 		(GCallback)&treebrowser_track_current_cb, NULL);
2366 }
2367 
2368 void
plugin_cleanup(void)2369 plugin_cleanup(void)
2370 {
2371 	g_free(addressbar_last_address);
2372 	g_free(CONFIG_FILE);
2373 	g_free(CONFIG_OPEN_EXTERNAL_CMD);
2374 	g_free(CONFIG_OPEN_TERMINAL);
2375 	gtk_widget_destroy(sidebar_vbox);
2376 }
2377