2008-02-11 Johannes Schmid <jhs@gnome.org>
[anjuta-git-plugin.git] / plugins / file-manager / file-view.c
blob9f10423884110e6464ba0c815dcb1e0ee91f988b
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * file-manager
4 * Copyright (C) Johannes Schmid 2007 <jhs@gnome.org>
5 *
6 * file-manager is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
13 * file-manager is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 * See the GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with file-manager. If not, write to:
20 * The Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301, USA.
25 #include "file-view.h"
26 #include "file-model.h"
27 #include "file-view-marshal.h"
29 #include <gtk/gtkcellrenderertext.h>
30 #include <gtk/gtkcellrendererpixbuf.h>
31 #include <gtk/gtkcellrendererprogress.h>
32 #include <gtk/gtktreestore.h>
33 #include <gtk/gtktreeselection.h>
34 #include <gtk/gtktreemodelsort.h>
35 #include <gtk/gtkversion.h>
37 #define HAVE_TOOLTIP_API (GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 12))
38 #include <glib/gi18n.h>
40 #if HAVE_TOOLTIP_API
41 # include <gtk/gtktooltip.h>
42 #endif
44 #include <libanjuta/anjuta-debug.h>
46 typedef struct _AnjutaFileViewPrivate AnjutaFileViewPrivate;
48 struct _AnjutaFileViewPrivate
50 FileModel* model;
52 GList* saved_paths;
53 guint refresh_idle_id;
56 #define ANJUTA_FILE_VIEW_GET_PRIVATE(o) \
57 (G_TYPE_INSTANCE_GET_PRIVATE((o), ANJUTA_TYPE_FILE_VIEW, AnjutaFileViewPrivate))
59 G_DEFINE_TYPE (AnjutaFileView, file_view, GTK_TYPE_TREE_VIEW);
61 enum
63 PROP_BASE_URI = 1,
64 PROP_END
67 static void
68 file_view_cancel_refresh(AnjutaFileView* view)
70 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE(view);
71 if (priv->refresh_idle_id)
73 GSource* source = g_main_context_find_source_by_id (g_main_context_default(),
74 priv->refresh_idle_id);
75 g_source_destroy (source);
76 priv->refresh_idle_id = 0;
80 static void
81 file_view_on_file_clicked (GtkTreeViewColumn* column, AnjutaFileView* view)
86 static void
87 file_view_save_expanded_row (GtkTreeView* tree_view, GtkTreePath* path,
88 gpointer user_data)
90 AnjutaFileView* view = ANJUTA_FILE_VIEW (tree_view);
91 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
92 priv->saved_paths = g_list_append (priv->saved_paths,
93 gtk_tree_path_to_string (path));
96 static void
97 file_view_get_expanded_rows (AnjutaFileView* view)
99 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
101 priv->saved_paths = NULL;
102 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (view),
103 file_view_save_expanded_row,
104 priv->saved_paths);
107 static gboolean
108 file_view_expand_row_idle (gpointer user_data)
110 AnjutaFileView* view = ANJUTA_FILE_VIEW (user_data);
111 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
113 if (priv->saved_paths)
115 gchar* path_string = (gchar*) priv->saved_paths->data;
116 GtkTreePath* path = gtk_tree_path_new_from_string (path_string);
118 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), path);
119 gtk_tree_path_free (path);
120 g_free (path_string);
121 priv->saved_paths = g_list_next (priv->saved_paths);
122 return TRUE;
124 else
126 g_list_free (priv->saved_paths);
127 priv->saved_paths = NULL;
128 priv->refresh_idle_id = 0;
129 return FALSE;
133 void
134 file_view_refresh (AnjutaFileView* view, gboolean remember_open)
136 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
137 GtkTreePath* tree_path;
139 file_view_cancel_refresh(view);
141 if (remember_open)
143 file_view_get_expanded_rows (view);
146 file_model_refresh (priv->model);
148 tree_path = gtk_tree_path_new_first ();
149 gtk_tree_view_expand_row (GTK_TREE_VIEW (view), tree_path, FALSE);
150 if (remember_open)
152 priv->refresh_idle_id = g_idle_add (file_view_expand_row_idle, view);
156 gchar*
157 file_view_get_selected (AnjutaFileView* view)
159 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
160 GtkTreeSelection* selection =
161 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
162 GtkTreeIter selected;
163 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
165 gchar* uri = file_model_get_uri (priv->model, &selected);
166 return uri;
168 else
169 return NULL;
172 static gboolean
173 file_view_button_press_event (GtkWidget* widget, GdkEventButton* event)
175 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
176 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
177 GtkTreeIter selected;
178 gchar* uri;
179 gboolean is_dir;
180 GtkTreePath* path = NULL;
182 GtkTreeSelection* selection =
183 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
185 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
187 path = gtk_tree_model_get_path (GTK_TREE_MODEL(priv->model), &selected);
188 gtk_tree_model_get (GTK_TREE_MODEL(priv->model), &selected,
189 COLUMN_URI, &uri,
190 COLUMN_IS_DIR, &is_dir,
191 -1);
193 else
195 uri = NULL;
196 is_dir = FALSE;
199 switch (event->button)
201 case 1: /* Left mouse button */
203 if (event->type == GDK_2BUTTON_PRESS)
205 if (is_dir)
207 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (view),
208 path))
210 gtk_tree_view_expand_row (GTK_TREE_VIEW (view),
211 path,
212 FALSE);
214 else
216 gtk_tree_view_collapse_row (GTK_TREE_VIEW (view),
217 path);
220 else
222 g_signal_emit_by_name (G_OBJECT (view),
223 "file-open",
224 uri);
227 break;
229 case 3: /* Right mouse button */
231 g_signal_emit_by_name (G_OBJECT (view),
232 "show-popup-menu",
233 uri,
234 is_dir,
235 event->button,
236 event->time);
239 if (path != NULL)
240 gtk_tree_path_free (path);
241 g_free (uri);
242 return
243 GTK_WIDGET_CLASS (file_view_parent_class)->button_press_event (widget,
244 event);
247 static void
248 file_view_selection_changed (GtkTreeSelection* selection, AnjutaFileView* view)
250 GtkTreeIter selected;
251 GtkTreeModel* model;
252 if (gtk_tree_selection_get_selected (selection, &model, &selected))
254 gchar* uri = file_model_get_uri (FILE_MODEL(model), &selected);
255 g_signal_emit_by_name (G_OBJECT (view), "current-uri-changed",
256 uri, NULL);
257 g_free(uri);
259 else
261 g_signal_emit_by_name (G_OBJECT (view), "current-uri-changed",
262 NULL, NULL);
266 #if HAVE_TOOLTIP_API
267 static gboolean
268 file_view_query_tooltip (GtkWidget* widget, gint x, gint y, gboolean keyboard,
269 GtkTooltip* tooltip)
271 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
272 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
273 GtkTreeModel* model = GTK_TREE_MODEL (priv->model);
274 GtkTreePath* path;
275 GtkTreeIter iter;
277 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW(view),
278 x, y, &path, NULL, NULL, NULL);
279 if (path)
281 if (gtk_tree_model_get_iter (model, &iter, path))
283 gchar* filename = file_model_get_filename (priv->model, &iter);
284 gtk_tooltip_set_markup (tooltip, filename);
285 g_free(filename);
286 gtk_tree_path_free (path);
287 return TRUE;
289 gtk_tree_path_free (path);
291 return FALSE;
293 #endif
295 static void
296 file_view_init (AnjutaFileView *object)
298 GtkCellRenderer* renderer_text;
299 GtkCellRenderer* renderer_pixbuf;
300 GtkTreeViewColumn* column;
301 GtkTreeSelection* selection;
303 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
305 priv->model = file_model_new (GTK_TREE_VIEW(object), NULL);
307 gtk_tree_view_set_model (GTK_TREE_VIEW (object), GTK_TREE_MODEL(priv->model));
309 renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
310 renderer_text = gtk_cell_renderer_text_new ();
312 column = gtk_tree_view_column_new ();
313 gtk_tree_view_column_set_title (column, _("Filename"));
314 gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
315 gtk_tree_view_column_pack_start (column, renderer_text, FALSE);
316 gtk_tree_view_column_set_attributes (column, renderer_pixbuf,
317 "pixbuf", COLUMN_PIXBUF, NULL);
318 gtk_tree_view_column_set_attributes (column, renderer_text,
319 "text", COLUMN_FILENAME, NULL);
320 gtk_tree_view_append_column (GTK_TREE_VIEW (object), column);
322 g_signal_connect (G_OBJECT (column), "clicked",
323 G_CALLBACK (file_view_on_file_clicked), object);
325 selection =
326 gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
327 g_signal_connect (selection, "changed",
328 G_CALLBACK (file_view_selection_changed), object);
330 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (object), FALSE);
332 #if HAVE_TOOLTIP_API
333 g_object_set (object, "has-tooltip", TRUE, NULL);
334 #endif
337 static void
338 file_view_get_property (GObject *object, guint prop_id, GValue *value,
339 GParamSpec *pspec)
341 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
342 gchar* uri;
344 switch (prop_id)
346 case PROP_BASE_URI:
347 g_object_get (G_OBJECT(priv->model), "base_uri", &uri, NULL);
348 g_value_set_string (value, uri);
349 break;
350 default:
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
352 break;
356 static void
357 file_view_set_property (GObject *object, guint prop_id, const GValue *value,
358 GParamSpec *pspec)
360 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
362 switch (prop_id)
364 case PROP_BASE_URI:
365 g_object_set (G_OBJECT (priv->model), "base_uri", g_value_get_string (value),
366 NULL);
367 break;
368 default:
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 break;
374 static void
375 file_view_finalize (GObject *object)
377 AnjutaFileView* view = ANJUTA_FILE_VIEW (object);
378 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
380 G_OBJECT_CLASS (file_view_parent_class)->finalize (object);
383 static void
384 file_view_class_init (AnjutaFileViewClass *klass)
386 GObjectClass* object_class = G_OBJECT_CLASS (klass);
387 GtkTreeViewClass* parent_class = GTK_TREE_VIEW_CLASS (klass);
388 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
390 g_type_class_add_private (klass, sizeof (AnjutaFileViewPrivate));
392 object_class->finalize = file_view_finalize;
393 object_class->set_property = file_view_set_property;
394 object_class->get_property = file_view_get_property;
396 g_object_class_install_property (object_class,
397 PROP_BASE_URI,
398 g_param_spec_string ("base_uri",
399 _("Base uri"),
400 _("Uri of the top-most path displayed"),
401 NULL,
402 G_PARAM_READABLE |
403 G_PARAM_WRITABLE |
404 G_PARAM_CONSTRUCT));
405 g_signal_new ("file-open",
406 ANJUTA_TYPE_FILE_VIEW,
407 G_SIGNAL_RUN_LAST,
408 G_STRUCT_OFFSET (AnjutaFileViewClass, file_open),
409 NULL, NULL,
410 g_cclosure_marshal_VOID__STRING,
411 G_TYPE_NONE,
413 G_TYPE_STRING,
414 NULL);
416 g_signal_new ("current-uri-changed",
417 ANJUTA_TYPE_FILE_VIEW,
418 G_SIGNAL_RUN_LAST,
419 G_STRUCT_OFFSET (AnjutaFileViewClass, current_uri_changed),
420 NULL, NULL,
421 g_cclosure_marshal_VOID__STRING,
422 G_TYPE_NONE,
424 G_TYPE_STRING,
425 NULL);
427 g_signal_new ("show-popup-menu",
428 ANJUTA_TYPE_FILE_VIEW,
429 G_SIGNAL_RUN_LAST,
430 G_STRUCT_OFFSET (AnjutaFileViewClass, show_popup_menu),
431 NULL, NULL,
432 file_view_cclosure_marshal_VOID__STRING_BOOLEAN_INT_INT,
433 G_TYPE_NONE,
435 G_TYPE_STRING,
436 G_TYPE_BOOLEAN,
437 G_TYPE_INT,
438 G_TYPE_INT,
439 NULL);
441 widget_class->button_press_event = file_view_button_press_event;
443 /* Tooltips */
444 #if HAVE_TOOLTIP_API
445 widget_class->query_tooltip = file_view_query_tooltip;
446 #endif
450 GtkWidget*
451 file_view_new (void)
453 return g_object_new (ANJUTA_TYPE_FILE_VIEW, NULL);