Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / file-manager / file-view.c
blob89ba9ae73e540b6c9254b4912e817433ef3e45e5
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 #include <gio/gio.h>
39 #include <string.h>
41 #define HAVE_TOOLTIP_API (GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 12))
42 #include <glib/gi18n.h>
44 #include <gtk/gtktooltip.h>
46 #include <libanjuta/anjuta-debug.h>
48 typedef struct _AnjutaFileViewPrivate AnjutaFileViewPrivate;
50 struct _AnjutaFileViewPrivate
52 FileModel* model;
54 GList* saved_paths;
55 GtkTreeRowReference* current_selection;
58 #define ANJUTA_FILE_VIEW_GET_PRIVATE(o) \
59 (G_TYPE_INSTANCE_GET_PRIVATE((o), ANJUTA_TYPE_FILE_VIEW, AnjutaFileViewPrivate))
61 G_DEFINE_TYPE (AnjutaFileView, file_view, GTK_TYPE_TREE_VIEW);
63 enum
65 PROP_BASE_URI = 1,
66 PROP_END
69 void
70 file_view_refresh (AnjutaFileView* view)
72 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
73 GtkTreePath* tree_path;
75 file_model_refresh (priv->model);
77 tree_path = gtk_tree_path_new_first ();
78 gtk_tree_view_expand_row (GTK_TREE_VIEW (view), tree_path, FALSE);
79 gtk_tree_path_free (tree_path);
82 void file_view_rename (AnjutaFileView* view)
84 /* TODO */
87 gboolean file_view_can_rename (AnjutaFileView* view)
89 /* TODO */
90 return FALSE;
93 GFile*
94 file_view_get_selected (AnjutaFileView* view)
96 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
97 GtkTreeSelection* selection =
98 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
99 GtkTreeIter selected;
100 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
102 GFile* file = file_model_get_file (priv->model, &selected);
103 return file;
105 else
106 return NULL;
109 static gboolean
110 file_view_button_press_event (GtkWidget* widget, GdkEventButton* event)
112 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
113 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
114 GtkTreeIter selected;
115 gboolean is_dir;
116 GtkTreePath* path = NULL;
117 GFile* file;
119 GtkTreeSelection* selection =
120 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
122 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
124 GtkTreeIter select_iter;
125 GtkTreeModel* sort_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
126 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(sort_model),
127 &select_iter, &selected);
128 gtk_tree_model_get (GTK_TREE_MODEL(priv->model), &select_iter,
129 COLUMN_IS_DIR, &is_dir,
130 -1);
131 file = file_model_get_file (priv->model, &select_iter);
133 path = gtk_tree_model_get_path(sort_model, &selected);
135 else
137 file = NULL;
138 is_dir = FALSE;
141 switch (event->button)
143 case 1: /* Left mouse button */
145 if (event->type == GDK_2BUTTON_PRESS)
147 if (is_dir)
149 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (view),
150 path))
152 gtk_tree_view_expand_row (GTK_TREE_VIEW (view),
153 path,
154 FALSE);
156 else
158 gtk_tree_view_collapse_row (GTK_TREE_VIEW (view),
159 path);
162 else
164 g_signal_emit_by_name (G_OBJECT (view),
165 "file-open",
166 file);
169 break;
171 case 3: /* Right mouse button */
173 g_signal_emit_by_name (G_OBJECT (view),
174 "show-popup-menu",
175 file,
176 is_dir,
177 event->button,
178 event->time);
181 if (file)
182 g_object_unref (file);
183 if (path)
184 gtk_tree_path_free(path);
185 return
186 GTK_WIDGET_CLASS (file_view_parent_class)->button_press_event (widget,
187 event);
190 static void
191 file_view_show_extended_data (AnjutaFileView* view, GtkTreeIter* iter)
193 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
194 GtkTreeModel* file_model = GTK_TREE_MODEL (priv->model);
195 GFile* file;
196 GFileInfo* file_info;
197 gboolean is_dir;
199 gtk_tree_model_get (file_model, iter, COLUMN_IS_DIR, &is_dir, -1);
200 if (!is_dir)
202 gchar* display;
203 gchar time_str[128];
204 gtk_tree_model_get (file_model, iter, COLUMN_FILE, &file, -1);
205 time_t time;
207 file_info = g_file_query_info (file,
208 "standard::*,time::changed",
209 G_FILE_QUERY_INFO_NONE,
210 NULL, NULL);
211 time = g_file_info_get_attribute_uint64(file_info, "time::changed");
212 strftime(time_str, 127, "%x %X", localtime(&time));
213 display = g_markup_printf_escaped("%s\n"
214 "<small><tt>%s</tt></small>",
215 g_file_info_get_display_name(file_info),
216 time_str);
218 gtk_tree_store_set (GTK_TREE_STORE(file_model), iter,
219 COLUMN_DISPLAY, display,
220 -1);
222 g_object_unref (file_info);
223 g_free(display);
227 static void
228 file_view_selection_changed (GtkTreeSelection* selection, AnjutaFileView* view)
230 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
231 GtkTreeModel* file_model = GTK_TREE_MODEL(priv->model);
232 GtkTreeIter selected;
233 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
235 if (priv->current_selection)
237 GtkTreeIter iter;
238 GtkTreePath* path = gtk_tree_row_reference_get_path (priv->current_selection);
239 if (path && gtk_tree_model_get_iter (file_model, &iter, path))
241 gchar* filename;
242 gtk_tree_model_get (file_model, &iter, COLUMN_FILENAME, &filename, -1);
243 gtk_tree_store_set (GTK_TREE_STORE (file_model), &iter,
244 COLUMN_DISPLAY, filename, -1);
245 g_free(filename);
246 gtk_tree_path_free(path);
248 gtk_tree_row_reference_free(priv->current_selection);
249 priv->current_selection = NULL;
252 if (gtk_tree_selection_get_selected (selection, &model, &selected))
254 GtkTreeIter real_selection;
255 GtkTreePath* path;
256 GFile* file;
257 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(model),
258 &real_selection, &selected);
260 path = gtk_tree_model_get_path(file_model, &real_selection);
261 priv->current_selection = gtk_tree_row_reference_new (file_model, path);
262 gtk_tree_path_free(path);
264 file_view_show_extended_data (view, &real_selection);
266 file = file_model_get_file(FILE_MODEL(file_model), &real_selection);
267 g_signal_emit_by_name (G_OBJECT (view), "current-file-changed",
268 file, NULL);
269 g_object_unref (file);
271 else
273 g_signal_emit_by_name (G_OBJECT (view), "current-file-changed",
274 NULL, NULL);
276 DEBUG_PRINT ("selection_changed");
279 static gboolean
280 file_view_query_tooltip (GtkWidget* widget, gint x, gint y, gboolean keyboard,
281 GtkTooltip* tooltip)
283 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
284 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
285 GtkTreeModel* model_sort;
286 GtkTreeModel* file_model = GTK_TREE_MODEL (priv->model);
287 GtkTreePath* path;
288 GtkTreeIter iter;
289 GtkTreeIter real_iter;
290 gchar* filename;
292 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (view),
293 &x, &y, keyboard,
294 &model_sort,
295 &path,
296 &iter))
297 return FALSE;
299 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model_sort),
300 &real_iter, &iter);
302 filename = file_model_get_filename (FILE_MODEL (file_model), &real_iter);
303 gtk_tooltip_set_text (tooltip, filename);
304 gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (view),
305 tooltip,
306 path);
308 g_free (filename);
309 gtk_tree_path_free (path);
311 return TRUE;
314 static int
315 file_view_sort_model(GtkTreeModel* model,
316 GtkTreeIter* iter1,
317 GtkTreeIter* iter2,
318 gpointer null)
320 gint sort1, sort2;
321 gchar *filename1 = NULL, *filename2 = NULL;
322 gboolean is_dir1, is_dir2;
323 gint retval = 0;
325 gtk_tree_model_get (model, iter1,
326 COLUMN_FILENAME, &filename1,
327 COLUMN_SORT, &sort1,
328 COLUMN_IS_DIR, &is_dir1, -1);
329 gtk_tree_model_get (model, iter2,
330 COLUMN_FILENAME, &filename2,
331 COLUMN_SORT, &sort2,
332 COLUMN_IS_DIR, &is_dir2, -1);
334 if (sort1 != sort2)
336 retval = sort2 - sort1;
338 else if (is_dir1 != is_dir2)
340 retval = is_dir1 ? -1 : 1;
342 else if (filename1 && filename2)
344 retval = strcmp(filename1, filename2);
346 g_free(filename1);
347 g_free(filename2);
349 return retval;
352 static void
353 file_view_init (AnjutaFileView *object)
355 GtkCellRenderer* renderer_pixbuf;
356 GtkCellRenderer* renderer_display;
357 GtkTreeViewColumn* column;
358 GtkTreeSelection* selection;
359 GtkTreeModel* sort_model;
361 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
363 priv->current_selection = NULL;
365 priv->model = file_model_new (GTK_TREE_VIEW(object), NULL);
366 sort_model = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(priv->model));
368 gtk_tree_view_set_model (GTK_TREE_VIEW(object), sort_model);
369 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(sort_model),
370 file_view_sort_model,
371 NULL,
372 NULL);
374 renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
375 renderer_display = gtk_cell_renderer_text_new ();
377 column = gtk_tree_view_column_new ();
378 gtk_tree_view_column_set_title (column, _("Filename"));
379 gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
380 gtk_tree_view_column_pack_start (column, renderer_display, FALSE);
381 gtk_tree_view_column_set_attributes (column, renderer_pixbuf,
382 "pixbuf", COLUMN_PIXBUF, NULL);
383 gtk_tree_view_column_set_attributes (column, renderer_display,
384 "markup", COLUMN_DISPLAY, NULL);
385 gtk_tree_view_append_column (GTK_TREE_VIEW (object), column);
387 selection =
388 gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
389 g_signal_connect (selection, "changed",
390 G_CALLBACK (file_view_selection_changed), object);
392 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (object), FALSE);
394 g_object_set (object, "has-tooltip", TRUE, NULL);
397 static void
398 file_view_get_property (GObject *object, guint prop_id, GValue *value,
399 GParamSpec *pspec)
401 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
402 gchar* uri;
404 switch (prop_id)
406 case PROP_BASE_URI:
407 g_object_get (G_OBJECT(priv->model), "base_uri", &uri, NULL);
408 g_value_set_string (value, uri);
409 break;
410 default:
411 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 break;
416 static void
417 file_view_set_property (GObject *object, guint prop_id, const GValue *value,
418 GParamSpec *pspec)
420 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
422 switch (prop_id)
424 case PROP_BASE_URI:
425 g_object_set (G_OBJECT (priv->model), "base_uri", g_value_get_string (value),
426 NULL);
427 break;
428 default:
429 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
430 break;
434 static void
435 file_view_finalize (GObject *object)
437 G_OBJECT_CLASS (file_view_parent_class)->finalize (object);
440 static void
441 file_view_class_init (AnjutaFileViewClass *klass)
443 GObjectClass* object_class = G_OBJECT_CLASS (klass);
444 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
446 g_type_class_add_private (klass, sizeof (AnjutaFileViewPrivate));
448 object_class->finalize = file_view_finalize;
449 object_class->set_property = file_view_set_property;
450 object_class->get_property = file_view_get_property;
452 g_object_class_install_property (object_class,
453 PROP_BASE_URI,
454 g_param_spec_string ("base_uri",
455 _("Base uri"),
456 _("Uri of the top-most path displayed"),
457 NULL,
458 G_PARAM_READABLE |
459 G_PARAM_WRITABLE |
460 G_PARAM_CONSTRUCT));
461 g_signal_new ("file-open",
462 ANJUTA_TYPE_FILE_VIEW,
463 G_SIGNAL_RUN_LAST,
464 G_STRUCT_OFFSET (AnjutaFileViewClass, file_open),
465 NULL, NULL,
466 g_cclosure_marshal_VOID__OBJECT,
467 G_TYPE_NONE,
469 G_TYPE_OBJECT,
470 NULL);
472 g_signal_new ("current-file-changed",
473 ANJUTA_TYPE_FILE_VIEW,
474 G_SIGNAL_RUN_LAST,
475 G_STRUCT_OFFSET (AnjutaFileViewClass, current_uri_changed),
476 NULL, NULL,
477 g_cclosure_marshal_VOID__OBJECT,
478 G_TYPE_NONE,
480 G_TYPE_OBJECT,
481 NULL);
483 g_signal_new ("show-popup-menu",
484 ANJUTA_TYPE_FILE_VIEW,
485 G_SIGNAL_RUN_LAST,
486 G_STRUCT_OFFSET (AnjutaFileViewClass, show_popup_menu),
487 NULL, NULL,
488 file_view_cclosure_marshal_VOID__OBJECT_BOOLEAN_INT_INT,
489 G_TYPE_NONE,
491 G_TYPE_OBJECT,
492 G_TYPE_BOOLEAN,
493 G_TYPE_INT,
494 G_TYPE_INT,
495 NULL);
497 widget_class->button_press_event = file_view_button_press_event;
499 /* Tooltips */
500 widget_class->query_tooltip = file_view_query_tooltip;
503 GtkWidget*
504 file_view_new (void)
506 return g_object_new (ANJUTA_TYPE_FILE_VIEW, NULL);