2
* This file is part of LaTeXila.
4
* Copyright Ā© 2009, 2010 SĆ©bastien Wilmet
6
* LaTeXila is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* LaTeXila is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with LaTeXila. If not, see <http://www.gnu.org/licenses/>.
20
#include <string.h> // for strcmp
26
#include "file_browser.h"
27
#include "callbacks.h"
28
#include "external_commands.h"
30
static void fill_list_store_with_dir (const gchar *directory);
31
static void cb_go_to_home_dir (GtkButton *button, gpointer user_data);
32
static void cb_go_to_parent_dir (GtkButton *button, gpointer user_data);
33
static void cb_jump_dir_current_doc (GtkButton *button, gpointer user_data);
34
static void cb_file_browser_row_activated (GtkTreeView *tree_view,
35
GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data);
36
static gint sort_list_alphabetical_order (gconstpointer a, gconstpointer b);
37
static void cb_combo_parent_dir_changed (GtkComboBox *combo_box,
40
// list of files and directories of the current directory
41
static GtkListStore *list_store;
42
// for the list of directories showed in a combobox
43
static GtkListStore *parent_dir_store;
44
static GtkComboBox *combo;
47
init_file_browser (GtkWidget *vbox)
50
GtkWidget *hbox = gtk_hbox_new (TRUE, 0);
51
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
53
// go to the home user directory
55
GtkWidget *home_button = gtk_button_new ();
56
gtk_button_set_relief (GTK_BUTTON (home_button), GTK_RELIEF_NONE);
57
GtkWidget *home_icon = gtk_image_new_from_stock (GTK_STOCK_HOME,
58
GTK_ICON_SIZE_BUTTON);
59
gtk_container_add (GTK_CONTAINER (home_button), home_icon);
60
gtk_widget_set_tooltip_text (home_button, _("Go to the home directory"));
61
g_signal_connect (G_OBJECT (home_button), "clicked",
62
G_CALLBACK (cb_go_to_home_dir), NULL);
63
gtk_box_pack_start (GTK_BOX (hbox), home_button, TRUE, TRUE, 0);
66
// go to the parent directory
68
GtkWidget *parent_dir_button = gtk_button_new ();
69
gtk_button_set_relief (GTK_BUTTON (parent_dir_button), GTK_RELIEF_NONE);
70
GtkWidget *parent_dir_icon = gtk_image_new_from_stock (GTK_STOCK_GO_UP,
71
GTK_ICON_SIZE_BUTTON);
72
gtk_container_add (GTK_CONTAINER (parent_dir_button), parent_dir_icon);
73
gtk_widget_set_tooltip_text (parent_dir_button, _("Go to the parent directory"));
74
g_signal_connect (G_OBJECT (parent_dir_button), "clicked",
75
G_CALLBACK (cb_go_to_parent_dir), NULL);
76
gtk_box_pack_start (GTK_BOX (hbox), parent_dir_button, TRUE, TRUE, 0);
79
// jump to the directory of the current document
81
GtkWidget *jump_button = gtk_button_new ();
82
gtk_button_set_relief (GTK_BUTTON (jump_button), GTK_RELIEF_NONE);
83
GtkWidget *jump_icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO,
84
GTK_ICON_SIZE_BUTTON);
85
gtk_container_add (GTK_CONTAINER (jump_button), jump_icon);
86
gtk_widget_set_tooltip_text (jump_button,
87
_("Go to the directory of the current document"));
88
g_signal_connect (G_OBJECT (jump_button), "clicked",
89
G_CALLBACK (cb_jump_dir_current_doc), NULL);
90
gtk_box_pack_start (GTK_BOX (hbox), jump_button, TRUE, TRUE, 0);
95
GtkWidget *refresh_button = gtk_button_new ();
96
gtk_button_set_relief (GTK_BUTTON (refresh_button), GTK_RELIEF_NONE);
97
GtkWidget *refresh_icon = gtk_image_new_from_stock (GTK_STOCK_REFRESH,
98
GTK_ICON_SIZE_BUTTON);
99
gtk_container_add (GTK_CONTAINER (refresh_button), refresh_icon);
100
gtk_widget_set_tooltip_text (refresh_button, _("Refresh"));
101
g_signal_connect (G_OBJECT (refresh_button), "clicked",
102
G_CALLBACK (cb_file_browser_refresh), NULL);
103
gtk_box_pack_start (GTK_BOX (hbox), refresh_button, TRUE, TRUE, 0);
106
/* list of parent directories */
108
parent_dir_store = gtk_list_store_new (N_COLS_PARENT_DIR,
109
G_TYPE_STRING, // indentation (spaces)
110
G_TYPE_STRING, // stock-id of a pixbuf
111
G_TYPE_STRING, // directory name
112
G_TYPE_STRING // full path
115
GtkWidget *combo_box =
116
gtk_combo_box_new_with_model (GTK_TREE_MODEL (parent_dir_store));
117
g_object_unref (parent_dir_store);
118
combo = GTK_COMBO_BOX (combo_box);
120
g_signal_connect (G_OBJECT (combo_box), "changed",
121
G_CALLBACK (cb_combo_parent_dir_changed), NULL);
124
GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
125
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
126
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
127
"text", COL_PARENT_DIR_INDENT, NULL);
130
renderer = gtk_cell_renderer_pixbuf_new ();
131
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
132
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
133
"stock-id", COL_PARENT_DIR_PIXBUF, NULL);
136
renderer = gtk_cell_renderer_text_new ();
137
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
138
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
139
"text", COL_PARENT_DIR_DIRECTORY, NULL);
140
// omit characters at the end of the text if not enough place
141
g_object_set (renderer, "ellipsize-set", TRUE,
142
"ellipsize", PANGO_ELLIPSIZE_END, NULL);
144
gtk_box_pack_start (GTK_BOX (vbox), combo_box, FALSE, FALSE, 0);
147
/* list of files and directories */
149
list_store = gtk_list_store_new (N_COLS_FILE_BROWSER,
150
G_TYPE_STRING, // stock-id of a pixbuf
151
G_TYPE_STRING // file
154
fill_list_store_with_dir (NULL);
156
GtkWidget *tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
157
g_object_unref (list_store);
158
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
160
// dubble-click on a row will open the file
161
g_signal_connect (G_OBJECT (tree_view), "row-activated",
162
G_CALLBACK (cb_file_browser_row_activated), NULL);
164
GtkTreeViewColumn *column = gtk_tree_view_column_new ();
165
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
168
GtkCellRenderer *renderer1 = gtk_cell_renderer_pixbuf_new ();
169
gtk_tree_view_column_pack_start (column, renderer1, FALSE);
170
gtk_tree_view_column_set_attributes (column, renderer1,
171
"stock-id", COL_FILE_BROWSER_PIXBUF,
174
// show the file name
175
GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new ();
176
gtk_tree_view_column_pack_start (column, renderer2, FALSE);
177
gtk_tree_view_column_set_attributes (column, renderer2,
178
"text", COL_FILE_BROWSER_FILE,
182
GtkWidget *scrollbar = gtk_scrolled_window_new (NULL, NULL);
183
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollbar),
184
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
185
gtk_container_add (GTK_CONTAINER (scrollbar), tree_view);
187
gtk_box_pack_start (GTK_BOX (vbox), scrollbar, TRUE, TRUE, 0);
192
cb_file_browser_refresh (GtkButton *button, gpointer user_data)
194
fill_list_store_with_dir (NULL);
199
fill_list_store_with_dir (const gchar *directory)
201
// if directory is NULL, open the current directory
202
GError *error = NULL;
204
if (directory == NULL)
205
dir = g_dir_open (latexila.prefs.file_browser_dir, 0, &error);
207
dir = g_dir_open (directory, 0, &error);
211
print_warning ("File browser: %s", error->message);
214
GtkWidget *dialog = gtk_message_dialog_new (latexila.main_window,
215
GTK_DIALOG_DESTROY_WITH_PARENT,
219
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
220
"%s", error->message);
221
gtk_dialog_run (GTK_DIALOG (dialog));
222
gtk_widget_destroy (dialog);
224
g_error_free (error);
228
gtk_list_store_clear (list_store);
229
gtk_list_store_clear (parent_dir_store);
231
if (directory != NULL)
233
g_free (latexila.prefs.file_browser_dir);
234
latexila.prefs.file_browser_dir = g_strdup (directory);
237
/* append all the files contained in the directory */
238
const gchar *read_name = NULL;
239
GList *directory_list = NULL;
240
GList *file_list = NULL;
241
while ((read_name = g_dir_read_name (dir)) != NULL)
243
// not show hidden files
244
if (read_name[0] == '.' && (! latexila.prefs.file_browser_show_all_files
245
|| ! latexila.prefs.file_browser_show_hidden_files))
248
gchar *full_path = g_build_filename (latexila.prefs.file_browser_dir,
251
// make a copy of read_name, else there are memory errors if the
252
// directory is very big (/usr/bin for example)
253
gchar *tmp = g_strdup (read_name);
255
if (g_file_test (full_path, G_FILE_TEST_IS_DIR))
256
directory_list = g_list_prepend (directory_list, (gpointer) tmp);
258
// show all files or only *.tex, *.pdf, *.dvi, *.ps and *.bib
259
else if (latexila.prefs.file_browser_show_all_files
260
|| g_str_has_suffix (full_path, ".tex")
261
|| g_str_has_suffix (full_path, ".pdf")
262
|| g_str_has_suffix (full_path, ".dvi")
263
|| g_str_has_suffix (full_path, ".ps")
264
|| g_str_has_suffix (full_path, ".bib"))
266
file_list = g_list_prepend (file_list, (gpointer) tmp);
274
// sort the lists in alphabetical order
275
directory_list = g_list_sort (directory_list, sort_list_alphabetical_order);
276
file_list = g_list_sort (file_list, sort_list_alphabetical_order);
280
// traverse the directory list
281
GList *current = directory_list;
282
while (current != NULL)
284
gchar *directory = current->data;
286
// append the directory to the list store
287
gtk_list_store_append (list_store, &iter);
288
gtk_list_store_set (list_store, &iter,
289
COL_FILE_BROWSER_PIXBUF, GTK_STOCK_DIRECTORY,
290
COL_FILE_BROWSER_FILE, directory,
294
current = g_list_next (current);
297
// traverse the file list
299
while (current != NULL)
301
gchar *file = current->data;
304
if (g_str_has_suffix (file, ".tex"))
305
stock_id = GTK_STOCK_EDIT;
306
else if (g_str_has_suffix (file, ".pdf"))
307
stock_id = "view_pdf";
308
else if (g_str_has_suffix (file, ".dvi"))
309
stock_id = "view_dvi";
310
else if (g_str_has_suffix (file, ".ps"))
311
stock_id = "view_ps";
313
stock_id = GTK_STOCK_FILE;
316
// append the file to the list store
317
gtk_list_store_append (list_store, &iter);
318
gtk_list_store_set (list_store, &iter,
319
COL_FILE_BROWSER_PIXBUF, stock_id,
320
COL_FILE_BROWSER_FILE, file,
324
current = g_list_next (current);
327
g_list_free (directory_list);
328
g_list_free (file_list);
330
/* fill the parent directory list */
331
if (! g_path_is_absolute (latexila.prefs.file_browser_dir))
334
GList *parent_dirs = NULL;
335
parent_dirs = g_list_append (parent_dirs,
336
g_strdup (latexila.prefs.file_browser_dir));
337
gchar *path = latexila.prefs.file_browser_dir;
341
gchar *parent = g_path_get_dirname (path);
342
parent_dirs = g_list_prepend (parent_dirs, parent);
344
if (strcmp (parent, "/") == 0)
348
current = parent_dirs;
350
while (current != NULL)
352
gchar *current_dir = current->data;
357
basename = g_strdup (_("File System"));
359
basename = g_path_get_basename (current_dir);
362
gchar *indent = g_strnfill (i * 2, ' ');
367
stock_id = GTK_STOCK_HARDDISK;
368
else if (strcmp (current_dir, g_get_home_dir ()) == 0)
369
stock_id = GTK_STOCK_HOME;
371
stock_id = GTK_STOCK_DIRECTORY;
373
gtk_list_store_append (parent_dir_store, &iter);
374
gtk_list_store_set (parent_dir_store, &iter,
375
COL_PARENT_DIR_INDENT, indent,
376
COL_PARENT_DIR_PIXBUF, stock_id,
377
COL_PARENT_DIR_DIRECTORY, basename,
378
COL_PARENT_DIR_PATH, current_dir,
381
g_free (current_dir);
384
current = g_list_next (current);
388
// select the last parent directory
389
gtk_combo_box_set_active_iter (combo, &iter);
393
cb_go_to_home_dir (GtkButton *button, gpointer user_data)
395
fill_list_store_with_dir (g_get_home_dir ());
399
cb_go_to_parent_dir (GtkButton *button, gpointer user_data)
401
gchar *path = g_path_get_dirname (latexila.prefs.file_browser_dir);
402
fill_list_store_with_dir (path);
407
cb_jump_dir_current_doc (GtkButton *button, gpointer user_data)
409
if (latexila.active_doc == NULL || latexila.active_doc->path == NULL)
412
gchar *path = g_path_get_dirname (latexila.active_doc->path);
413
fill_list_store_with_dir (path);
418
cb_file_browser_row_activated (GtkTreeView *tree_view, GtkTreePath *path,
419
GtkTreeViewColumn *column, gpointer user_data)
422
GtkTreeModel *model = GTK_TREE_MODEL (list_store);
423
gtk_tree_model_get_iter (model, &iter, path);
426
gtk_tree_model_get (model, &iter,
427
COL_FILE_BROWSER_FILE, &file,
430
gchar *full_path = g_build_filename (latexila.prefs.file_browser_dir,
433
// open the directory
434
if (g_file_test (full_path, G_FILE_TEST_IS_DIR))
435
fill_list_store_with_dir (full_path);
438
else if (g_str_has_suffix (full_path, ".pdf"))
439
view_document (_("View PDF"), full_path);
440
else if (g_str_has_suffix (full_path, ".dvi"))
441
view_document (_("View DVI"), full_path);
442
else if (g_str_has_suffix (full_path, ".ps"))
443
view_document (_("View PS"), full_path);
447
open_new_document_without_uri (full_path);
453
sort_list_alphabetical_order (gconstpointer a, gconstpointer b)
455
return g_utf8_collate ((char *) a, (char *) b);
459
cb_combo_parent_dir_changed (GtkComboBox *combo_box, gpointer user_data)
462
if (gtk_combo_box_get_active_iter (combo_box, &iter))
465
GtkTreeModel *model = gtk_combo_box_get_model (combo_box);
466
gtk_tree_model_get (model, &iter,
467
COL_PARENT_DIR_PATH, &path,
470
// avoid infinite loop (this function is called in
471
// fill_list_store_with_dir())
472
if (strcmp (path, latexila.prefs.file_browser_dir) != 0)
473
fill_list_store_with_dir (path);