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