Updated Makefile.am files after make -f git.mk
[anjuta.git] / plugins / file-manager / file-view.c
blob88e276c77dace410aa0af0eeeb8765b2471d33bd
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 <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
32 #include <gio/gio.h>
34 #include <string.h>
36 #define HAVE_TOOLTIP_API (GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 12))
37 #include <glib/gi18n.h>
38 #include <glib/gprintf.h>
39 #include <glib/gstdio.h>
41 #include <libanjuta/anjuta-utils.h>
42 #include <libanjuta/anjuta-debug.h>
43 #include <libanjuta/anjuta-vcs-status.h>
45 typedef struct _AnjutaFileViewPrivate AnjutaFileViewPrivate;
47 struct _AnjutaFileViewPrivate
49 FileModel* model;
51 GList* saved_paths;
52 GtkTreeRowReference* current_selection;
54 GFile* pending_selected_file;
57 GtkTargetEntry uri_targets[] =
60 "text/uri-list",
61 0, /* no flags */
67 #define ANJUTA_FILE_VIEW_GET_PRIVATE(o) \
68 (G_TYPE_INSTANCE_GET_PRIVATE((o), ANJUTA_TYPE_FILE_VIEW, AnjutaFileViewPrivate))
70 G_DEFINE_TYPE (AnjutaFileView, file_view, GTK_TYPE_TREE_VIEW);
72 static const gchar*
73 get_status_string(AnjutaVcsStatus status)
75 switch (status)
77 case ANJUTA_VCS_STATUS_NONE:
78 return NULL;
79 case ANJUTA_VCS_STATUS_MODIFIED:
80 return _("Modified");
81 case ANJUTA_VCS_STATUS_DELETED:
82 return _("Deleted");
83 case ANJUTA_VCS_STATUS_ADDED:
84 return _("Added");
85 case ANJUTA_VCS_STATUS_CONFLICTED:
86 return _("Conflicted");
87 case ANJUTA_VCS_STATUS_UPTODATE:
88 return _("Up-to-date");
89 case ANJUTA_VCS_STATUS_LOCKED:
90 return _("Locked");
91 case ANJUTA_VCS_STATUS_MISSING:
92 return _("Missing");
93 case ANJUTA_VCS_STATUS_UNVERSIONED:
94 return _("Unversioned");
95 case ANJUTA_VCS_STATUS_IGNORED:
96 return _("Ignored");
97 default:
98 break;
101 return NULL;
104 enum
106 PROP_BASE_PATH = 1,
107 PROP_END
110 void
111 file_view_refresh (AnjutaFileView* view)
113 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
114 GtkTreePath* tree_path;
116 file_model_refresh (priv->model);
118 tree_path = gtk_tree_path_new_first ();
119 gtk_tree_view_expand_row (GTK_TREE_VIEW (view), tree_path, FALSE);
120 gtk_tree_path_free (tree_path);
124 static void
125 file_view_rename_edit_finish (GtkCellRendererText *renderer,
126 gchar *path,
127 gchar *new_text,
128 gpointer user_data) {
129 AnjutaFileView* view = (AnjutaFileView*) user_data ;
130 GFile* file = file_view_get_selected (view);
133 gchar * newFilename ;
134 gchar * oldFilename ;
135 gchar * oldPath ;
136 gchar * fileBasename ;
137 GFile * parent = NULL ;
138 if(!g_file_has_parent(file, NULL)) {/* You try to rename "/" */
139 anjuta_util_dialog_error(NULL, _("You can't rename \"/\"!"), NULL);
140 return ;
143 fileBasename = g_file_get_basename(file) ;
144 parent = g_file_get_parent(file) ;
145 oldPath = g_file_get_path (parent) ;
147 /* Creating the new filename */
148 newFilename = g_strconcat(oldPath, G_DIR_SEPARATOR_S, new_text, NULL);
149 oldFilename = g_strconcat(oldPath, G_DIR_SEPARATOR_S, fileBasename, NULL);
151 if(g_rename(oldFilename, newFilename))
152 anjuta_util_dialog_error(NULL,
153 _("An error has occurred!\n\
154 Maybe your permissions are insufficient or the filename is wrong")
155 , NULL);
157 g_object_unref(parent) ;
158 g_free(newFilename) ;
159 g_free(oldFilename) ;
160 g_free(oldPath) ;
161 g_free(fileBasename) ;
164 static void
165 file_view_rename_edit_start (GtkCellRenderer *cell,
166 GtkCellEditable *editable,
167 const gchar *path,
168 gpointer data)
170 if (GTK_IS_ENTRY (editable)) {
171 GtkEntry *entry = GTK_ENTRY (editable);
173 AnjutaFileView* view = (AnjutaFileView*) data ;
174 GFile* file = file_view_get_selected (view);
176 gchar * fileBasename ;
177 fileBasename = g_file_get_basename(file) ;
178 gtk_entry_set_text(entry, fileBasename);
179 g_free(fileBasename) ;
183 void file_view_rename (AnjutaFileView* view)
186 GtkTreeSelection * selection = gtk_tree_view_get_selection(
187 GTK_TREE_VIEW(view));
188 GtkTreeIter iter ;
189 GtkTreeModel * model = NULL ;
190 gtk_tree_selection_get_selected(selection, &model, &iter);
192 GtkTreePath * path = gtk_tree_model_get_path(model, &iter);
193 GtkTreeViewColumn * column = gtk_tree_view_get_column(GTK_TREE_VIEW(view),
196 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(view)
197 , path, column,
198 NULL, TRUE);
199 gtk_tree_path_free(path) ;
202 gboolean file_view_can_rename (AnjutaFileView* view)
204 /* TODO
205 * Maybe it can be use for windows (look if file is already open)
207 return FALSE;
210 GFile*
211 file_view_get_selected (AnjutaFileView* view)
213 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
214 GtkTreeSelection* selection =
215 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
216 GtkTreeIter selected;
217 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
219 GFile* file;
220 GtkTreeIter real_iter;
221 GtkTreeModel* sort_model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
223 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(sort_model),
224 &real_iter, &selected);
226 file = file_model_get_file (priv->model, &real_iter);
227 return file;
229 else
230 return NULL;
233 static void
234 file_view_select_iter (AnjutaFileView* view, GtkTreeIter iter)
236 GtkTreeModelSort* model_sort;
237 GtkTreeIter sort_iter;
238 GtkTreeSelection* selection;
239 GtkTreePath* path;
241 model_sort = GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
243 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
244 gtk_tree_model_sort_convert_child_iter_to_iter (model_sort, &sort_iter, &iter);
245 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model_sort), &sort_iter);
247 gtk_tree_selection_select_iter (selection, &sort_iter);
248 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), path, NULL, TRUE, 0.5, 0.0);
251 static void
252 file_view_select_from_iter (AnjutaFileView* view, GtkTreeIter iter)
254 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
256 GtkTreeModelSort* model_sort;
257 gboolean valid;
258 GtkTreeIter sort_iter;
259 GFile* file;
261 model_sort = GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
265 gboolean is_dummy, is_dir;
267 gtk_tree_model_get (GTK_TREE_MODEL (priv->model), &iter,
268 COLUMN_FILE, &file, COLUMN_DUMMY, &is_dummy,
269 COLUMN_IS_DIR, &is_dir, -1);
271 if (is_dummy)
272 break;
274 if (g_file_equal (priv->pending_selected_file, file))
276 file_view_select_iter (view, iter);
277 break;
280 else if (g_file_has_prefix (priv->pending_selected_file, file))
282 if (is_dir)
284 GtkTreePath *path = NULL;
286 gtk_tree_model_sort_convert_child_iter_to_iter (model_sort, &sort_iter, &iter);
287 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model_sort), &sort_iter);
289 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), path))
291 GtkTreeIter parent = iter;
292 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->model), &iter, &parent);
293 gtk_tree_path_free (path);
295 else
297 gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, FALSE);
298 gtk_tree_path_free (path);
299 break;
302 else
304 file_view_select_iter (view, iter);
305 break;
308 else
309 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->model), &iter);
311 g_clear_object (&file);
313 } while (valid);
315 if (file)
316 g_object_unref (file);
319 static void
320 file_view_directory_expanded (FileModel* model, GtkTreeIter* iter, GtkTreePath* path,
321 gpointer user_data)
323 AnjutaFileView* view = user_data;
324 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
326 if (priv->pending_selected_file)
328 GFile *dir;
330 gtk_tree_model_get (GTK_TREE_MODEL (priv->model), iter,
331 COLUMN_FILE, &dir, -1);
333 if (g_file_has_prefix (priv->pending_selected_file, dir))
334 file_view_select_from_iter (view, *iter);
336 g_object_unref (dir);
340 void
341 file_view_set_selected (AnjutaFileView* view, GFile *selected)
343 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
345 GtkTreeIter iter;
346 gboolean valid;
348 g_clear_object (&priv->pending_selected_file);
349 priv->pending_selected_file = g_object_ref (selected);
351 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->model), &iter);
352 if (valid)
353 file_view_select_from_iter (view, iter);
356 static void
357 file_view_drag_data_get (GtkWidget* widget,
358 GdkDragContext *drag_context,
359 GtkSelectionData *data,
360 guint info,
361 guint time)
363 AnjutaFileView* view = ANJUTA_FILE_VIEW(widget);
364 GFile* selected = file_view_get_selected (view);
366 if (selected)
368 gchar* uris[2];
369 uris[0] = g_file_get_uri (selected);
370 uris[1] = NULL;
371 gtk_selection_data_set_uris (data, uris);
372 g_free(uris[0]);
376 static void
377 file_view_row_activated (GtkTreeView* widget, GtkTreePath* sort_path,
378 GtkTreeViewColumn* column)
380 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
381 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
382 GtkTreeIter selected;
383 GtkTreePath* path = NULL;
384 gboolean is_dir;
385 GFile* file;
387 GtkTreeIter select_iter;
388 GtkTreeModel* sort_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
389 gtk_tree_model_get_iter (sort_model, &selected, sort_path);
390 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(sort_model),
391 &select_iter, &selected);
392 gtk_tree_model_get (GTK_TREE_MODEL(priv->model), &select_iter,
393 COLUMN_IS_DIR, &is_dir,
394 -1);
395 file = file_model_get_file (priv->model, &select_iter);
397 path = gtk_tree_model_get_path(sort_model, &selected);
399 if (is_dir)
401 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (view),
402 path))
404 gtk_tree_view_expand_row (GTK_TREE_VIEW (view),
405 path,
406 FALSE);
408 else
410 gtk_tree_view_collapse_row (GTK_TREE_VIEW (view),
411 path);
414 else
416 g_signal_emit_by_name (G_OBJECT (view),
417 "file-open",
418 file);
420 if (file)
421 g_object_unref (file);
422 if (path)
423 gtk_tree_path_free(path);
426 static gboolean
427 file_view_key_press_event (GtkWidget* widget, GdkEventKey* event)
429 if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter)
431 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
432 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
433 GtkTreeIter selected;
435 GtkTreeSelection* selection =
436 gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
438 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
440 GFile* file;
441 GtkTreeIter select_iter;
442 GtkTreeModel* sort_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
443 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(sort_model),
444 &select_iter, &selected);
445 file = file_model_get_file (priv->model, &select_iter);
446 if (file != NULL)
448 g_signal_emit_by_name (G_OBJECT (view),
449 "file-open",
450 file);
451 g_object_unref (file);
455 return
456 GTK_WIDGET_CLASS (file_view_parent_class)->key_press_event (widget,
457 event);
460 static void
461 file_view_do_popup_menu (GtkWidget* widget, GdkEventButton* event)
463 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
464 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
465 GtkTreeSelection* selection =
466 gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
467 GFile* file = NULL;
468 gboolean is_dir = FALSE;
469 GtkTreeIter selected;
470 gint button, event_time;
472 if (gtk_tree_selection_get_selected (selection, NULL, &selected))
474 GtkTreeIter select_iter;
475 GtkTreeModel* sort_model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
476 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(sort_model),
477 &select_iter, &selected);
478 gtk_tree_model_get (GTK_TREE_MODEL(priv->model), &select_iter,
479 COLUMN_IS_DIR, &is_dir,
480 -1);
481 file = file_model_get_file (priv->model, &select_iter);
484 if (event)
486 button = event->button;
487 event_time = event->time;
489 else
491 button = 0;
492 event_time = gtk_get_current_event_time ();
495 g_signal_emit_by_name (G_OBJECT(widget), "show-popup-menu",
496 file, is_dir, button, event_time);
497 if (file)
498 g_object_unref (file);
501 static gboolean
502 file_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
504 gint retval =
505 GTK_WIDGET_CLASS (file_view_parent_class)->button_press_event (widget,
506 event);
507 /* Ignore double-clicks and triple-clicks */
508 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
510 GtkTreePath *path;
512 /* Select file under cursor if not selected */
513 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
514 event->x,event->y, &path, NULL, NULL, NULL))
516 GtkTreeSelection *selection;
518 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (widget));
519 if (!gtk_tree_selection_path_is_selected(selection, path))
521 gtk_tree_selection_unselect_all(selection);
522 gtk_tree_selection_select_path(selection, path);
523 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget),
524 path, NULL, FALSE);
526 gtk_tree_path_free (path);
528 file_view_do_popup_menu (widget, event);
530 return TRUE;
534 return retval;
538 static gboolean
539 file_view_popup_menu (GtkWidget* widget)
541 file_view_do_popup_menu(widget, NULL);
542 return TRUE;
545 static void
546 file_view_show_extended_data (AnjutaFileView* view, GtkTreeIter* iter)
548 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
550 GtkTreeModel* file_model = GTK_TREE_MODEL (priv->model);
551 gboolean is_dummy, is_dir;
552 GFile* file;
553 GFileInfo* file_info;
554 time_t time;
555 gchar* display;
556 gchar time_str[128];
557 AnjutaVcsStatus status;
559 gtk_tree_model_get (file_model, iter, COLUMN_DUMMY, &is_dummy,
560 COLUMN_IS_DIR, &is_dir, -1);
561 if (is_dummy || is_dir)
562 return;
565 gtk_tree_model_get (file_model, iter, COLUMN_FILE, &file,
566 COLUMN_STATUS, &status, -1);
568 file_info = g_file_query_info (file,
569 "standard::*,time::changed",
570 G_FILE_QUERY_INFO_NONE,
571 NULL, NULL);
572 g_object_unref (file);
573 if (!file_info)
574 return;
576 time = g_file_info_get_attribute_uint64(file_info, "time::changed");
577 strftime(time_str, 127, "%x %X", localtime(&time));
578 if (get_status_string(status))
580 display = g_markup_printf_escaped("%s\n"
581 "<small><tt>%s</tt></small>\n"
582 "<small>%s</small>",
583 g_file_info_get_display_name(file_info),
584 time_str,
585 get_status_string(status));
587 else
589 display = g_markup_printf_escaped("%s\n"
590 "<small><tt>%s</tt></small>",
591 g_file_info_get_display_name(file_info),
592 time_str);
594 gtk_tree_store_set (GTK_TREE_STORE(file_model), iter,
595 COLUMN_DISPLAY, display,
596 -1);
598 g_object_unref (file_info);
599 g_free(display);
602 static void
603 file_view_selection_changed (GtkTreeSelection* selection, AnjutaFileView* view)
605 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
606 GtkTreeModel* file_model = GTK_TREE_MODEL(priv->model);
607 GtkTreeIter selected;
608 GtkTreeModel* model = gtk_tree_view_get_model (GTK_TREE_VIEW(view));
610 if (priv->current_selection)
612 GtkTreeIter iter;
613 GtkTreePath* path = gtk_tree_row_reference_get_path (priv->current_selection);
614 if (path && gtk_tree_model_get_iter (file_model, &iter, path))
616 gchar* filename;
617 gtk_tree_model_get (file_model, &iter, COLUMN_FILENAME, &filename, -1);
618 gtk_tree_store_set (GTK_TREE_STORE (file_model), &iter,
619 COLUMN_DISPLAY, filename, -1);
620 g_free(filename);
621 gtk_tree_path_free(path);
623 gtk_tree_row_reference_free(priv->current_selection);
624 priv->current_selection = NULL;
627 if (gtk_tree_selection_get_selected (selection, &model, &selected))
629 GtkTreeIter real_selection;
630 GtkTreePath* path;
631 GFile* file;
632 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(model),
633 &real_selection, &selected);
635 path = gtk_tree_model_get_path(file_model, &real_selection);
636 priv->current_selection = gtk_tree_row_reference_new (file_model, path);
637 gtk_tree_path_free(path);
639 file_view_show_extended_data (view, &real_selection);
641 file = file_model_get_file(FILE_MODEL(file_model), &real_selection);
642 g_signal_emit_by_name (G_OBJECT (view), "current-file-changed",
643 file, NULL);
644 g_object_unref (file);
646 else
648 g_signal_emit_by_name (G_OBJECT (view), "current-file-changed",
649 NULL, NULL);
652 /* The pending selection is now either done or if the user changed the
653 * selection before it was finished we cancel it. */
654 g_clear_object (&priv->pending_selected_file);
656 DEBUG_PRINT ("%s", "selection_changed");
659 static gboolean
660 file_view_query_tooltip (GtkWidget* widget, gint x, gint y, gboolean keyboard,
661 GtkTooltip* tooltip)
663 AnjutaFileView* view = ANJUTA_FILE_VIEW (widget);
664 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
665 GtkTreeModel* model_sort;
666 GtkTreeModel* file_model = GTK_TREE_MODEL (priv->model);
667 GtkTreePath* path;
668 GtkTreeIter iter;
669 GtkTreeIter real_iter;
670 gchar* filename;
671 gboolean result = TRUE;
672 GdkRectangle visible_rect, column_rect;
673 GdkScreen *screen = gdk_screen_get_default ();
674 PangoContext *context;
675 PangoLayout *layout;
676 gint width, height;
678 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (view),
679 &x, &y, keyboard,
680 &model_sort,
681 &path,
682 &iter))
683 return FALSE;
685 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model_sort),
686 &real_iter, &iter);
688 filename = file_model_get_filename (FILE_MODEL (file_model), &real_iter);
690 context = gdk_pango_context_get_for_screen (screen);
691 layout = pango_layout_new (context);
693 pango_layout_set_text (layout, filename, -1);
694 pango_layout_get_pixel_size (layout, &width, &height);
696 gtk_tree_view_get_visible_rect (GTK_TREE_VIEW (view), &visible_rect);
697 gtk_tree_view_get_cell_area (GTK_TREE_VIEW (view), path,
698 gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0), &column_rect);
700 if (column_rect.x + width > visible_rect.x + visible_rect.width ||
701 column_rect.x < visible_rect.x)
703 gtk_tooltip_set_text (tooltip, filename);
704 gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (view),
705 tooltip,
706 path);
707 } else
709 result = FALSE;
712 g_free (filename);
713 gtk_tree_path_free (path);
714 g_object_unref (layout);
715 g_object_unref (context);
717 return result;
720 static int
721 file_view_sort_model(GtkTreeModel* model,
722 GtkTreeIter* iter1,
723 GtkTreeIter* iter2,
724 gpointer null)
726 gint sort1, sort2;
727 gchar *filename1 = NULL, *filename2 = NULL;
728 gboolean is_dir1, is_dir2;
729 gint retval = 0;
731 gtk_tree_model_get (model, iter1,
732 COLUMN_FILENAME, &filename1,
733 COLUMN_SORT, &sort1,
734 COLUMN_IS_DIR, &is_dir1, -1);
735 gtk_tree_model_get (model, iter2,
736 COLUMN_FILENAME, &filename2,
737 COLUMN_SORT, &sort2,
738 COLUMN_IS_DIR, &is_dir2, -1);
740 if (sort1 != sort2)
742 retval = sort2 - sort1;
744 else if (is_dir1 != is_dir2)
746 retval = is_dir1 ? -1 : 1;
748 else if (filename1 && filename2)
750 retval = strcasecmp(filename1, filename2);
752 g_free(filename1);
753 g_free(filename2);
755 return retval;
758 #define EMBLEM_ADDED "vcs-added.png"
759 #define EMBLEM_CONFLICT "vcs-conflict.png"
760 #define EMBLEM_DELETED "vcs-deleted.png"
761 #define EMBLEM_IGNORED "vcs-ignored.png"
762 #define EMBLEM_LOCKED "vcs-locked.png"
763 #define EMBLEM_UNVERSIONED "vcs-unversioned.png"
764 #define EMBLEM_UPTODATE "vcs-updated.png"
765 #define EMBLEM_MODIFIED "vcs-modified.png"
767 #define COMPOSITE_ALPHA 225
769 static GdkPixbuf*
770 get_vcs_emblem (AnjutaVcsStatus status)
772 GdkPixbuf* emblem ;
773 switch (status)
775 case ANJUTA_VCS_STATUS_ADDED:
776 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_ADDED, NULL);
777 break;
778 case ANJUTA_VCS_STATUS_MODIFIED:
779 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_MODIFIED, NULL);
780 break;
781 case ANJUTA_VCS_STATUS_DELETED:
782 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_DELETED, NULL);
783 break;
784 case ANJUTA_VCS_STATUS_CONFLICTED:
785 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_CONFLICT, NULL);
786 break;
787 case ANJUTA_VCS_STATUS_LOCKED:
788 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_LOCKED, NULL);
789 break;
790 case ANJUTA_VCS_STATUS_UNVERSIONED:
791 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_UNVERSIONED, NULL);
792 break;
793 case ANJUTA_VCS_STATUS_UPTODATE:
794 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_UPTODATE, NULL);
795 break;
796 case ANJUTA_VCS_STATUS_IGNORED:
797 emblem = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"EMBLEM_IGNORED, NULL);
798 break;
799 default:
800 emblem = NULL;
802 return emblem;
805 static void
806 file_view_render_pixbuf_with_emblem (GtkTreeViewColumn* tree_column,
807 GtkCellRenderer* cell,
808 GtkTreeModel* tree_model,
809 GtkTreeIter* iter,
810 gpointer data)
812 GdkPixbuf* file_icon = NULL;
813 GdkPixbuf* emblem = NULL;
815 AnjutaVcsStatus status;
817 gtk_tree_model_get (tree_model, iter,
818 COLUMN_STATUS, &status,
819 COLUMN_PIXBUF, &file_icon, -1);
821 if (file_icon)
823 emblem = get_vcs_emblem (status);
824 if (emblem)
826 GdkPixbuf *new_icon;
828 new_icon = gdk_pixbuf_copy (file_icon);
829 gdk_pixbuf_composite (emblem,
830 new_icon,
831 0, 0,
832 gdk_pixbuf_get_width (file_icon),
833 gdk_pixbuf_get_height (file_icon),
834 0, 0,
835 1, 1,
836 GDK_INTERP_BILINEAR,
837 COMPOSITE_ALPHA);
839 g_object_set (cell, "pixbuf", new_icon, NULL);
841 g_object_unref (new_icon);
842 g_object_unref (emblem);
844 else
846 g_object_set (cell, "pixbuf", file_icon, NULL);
848 g_object_unref (file_icon);
852 static void
853 file_view_init (AnjutaFileView *object)
855 GtkCellRenderer* renderer_pixbuf;
856 GtkCellRenderer* renderer_display;
857 GtkTreeViewColumn* column;
858 GtkTreeSelection* selection;
859 GtkTreeModel* sort_model;
861 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
863 priv->current_selection = NULL;
865 priv->model = file_model_new (GTK_TREE_VIEW(object), NULL);
866 g_signal_connect_object (priv->model, "directory-expanded",
867 G_CALLBACK (file_view_directory_expanded), object, 0);
869 sort_model = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(priv->model));
871 gtk_tree_view_set_model (GTK_TREE_VIEW(object), sort_model);
872 /* set_model takes a reference so we can release the reference we got when
873 * the sort_model was created. */
874 g_object_unref (sort_model);
875 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE(sort_model),
876 file_view_sort_model,
877 NULL,
878 NULL);
880 renderer_pixbuf = gtk_cell_renderer_pixbuf_new ();
881 renderer_display = gtk_cell_renderer_text_new ();
883 g_object_set(renderer_display,
884 "mode", GTK_CELL_RENDERER_MODE_EDITABLE,
885 "editable", TRUE, NULL);
886 g_object_connect(renderer_display, "signal::edited",
887 file_view_rename_edit_finish, object, NULL);
888 g_object_connect(renderer_display, "signal::editing-started",
889 file_view_rename_edit_start, object, NULL);
891 column = gtk_tree_view_column_new ();
892 gtk_tree_view_column_set_title (column, _("Filename"));
893 gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE);
894 gtk_tree_view_column_pack_start (column, renderer_display, FALSE);
895 gtk_tree_view_column_set_cell_data_func(column,
896 renderer_pixbuf,
897 file_view_render_pixbuf_with_emblem,
898 object, NULL);
899 gtk_tree_view_column_set_attributes (column, renderer_display,
900 "markup", COLUMN_DISPLAY,
901 NULL);
902 gtk_tree_view_append_column (GTK_TREE_VIEW (object), column);
904 selection =
905 gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
906 g_signal_connect (selection, "changed",
907 G_CALLBACK (file_view_selection_changed), object);
909 /* DND */
910 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW(object),
911 GDK_BUTTON1_MASK,
912 uri_targets,
914 GDK_ACTION_MOVE);
916 /* Typeahead search */
917 gtk_tree_view_set_search_column (GTK_TREE_VIEW (object), COLUMN_FILENAME);
920 static void
921 file_view_get_property (GObject *object, guint prop_id, GValue *value,
922 GParamSpec *pspec)
924 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
926 switch (prop_id)
928 case PROP_BASE_PATH:
929 g_object_get_property (G_OBJECT(priv->model), "base-path", value);
930 break;
931 default:
932 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
933 break;
937 static void
938 file_view_set_property (GObject *object, guint prop_id, const GValue *value,
939 GParamSpec *pspec)
941 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
943 switch (prop_id)
945 case PROP_BASE_PATH:
946 g_object_set_property (G_OBJECT (priv->model), "base-path", value);
947 break;
948 default:
949 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
950 break;
954 static void
955 file_view_finalize (GObject *object)
957 AnjutaFileViewPrivate *priv = ANJUTA_FILE_VIEW_GET_PRIVATE (object);
959 g_object_unref (priv->model);
961 G_OBJECT_CLASS (file_view_parent_class)->finalize (object);
964 static void
965 file_view_class_init (AnjutaFileViewClass *klass)
967 GObjectClass* object_class = G_OBJECT_CLASS (klass);
968 GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
969 GtkTreeViewClass* tree_class = GTK_TREE_VIEW_CLASS(klass);
971 g_type_class_add_private (klass, sizeof (AnjutaFileViewPrivate));
973 object_class->finalize = file_view_finalize;
974 object_class->set_property = file_view_set_property;
975 object_class->get_property = file_view_get_property;
977 g_object_class_install_property (object_class,
978 PROP_BASE_PATH,
979 g_param_spec_object ("base-path",
980 _("Base Path"),
981 _("GFile representing the top-most path displayed"),
982 G_TYPE_FILE,
983 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
984 g_signal_new ("file-open",
985 ANJUTA_TYPE_FILE_VIEW,
986 G_SIGNAL_RUN_LAST,
987 G_STRUCT_OFFSET (AnjutaFileViewClass, file_open),
988 NULL, NULL,
989 g_cclosure_marshal_VOID__OBJECT,
990 G_TYPE_NONE,
992 G_TYPE_OBJECT,
993 NULL);
995 g_signal_new ("current-file-changed",
996 ANJUTA_TYPE_FILE_VIEW,
997 G_SIGNAL_RUN_LAST,
998 G_STRUCT_OFFSET (AnjutaFileViewClass, current_uri_changed),
999 NULL, NULL,
1000 g_cclosure_marshal_VOID__OBJECT,
1001 G_TYPE_NONE,
1003 G_TYPE_OBJECT,
1004 NULL);
1006 g_signal_new ("show-popup-menu",
1007 ANJUTA_TYPE_FILE_VIEW,
1008 G_SIGNAL_RUN_LAST,
1009 G_STRUCT_OFFSET (AnjutaFileViewClass, show_popup_menu),
1010 NULL, NULL,
1011 file_view_cclosure_marshal_VOID__OBJECT_BOOLEAN_INT_INT,
1012 G_TYPE_NONE,
1014 G_TYPE_OBJECT,
1015 G_TYPE_BOOLEAN,
1016 G_TYPE_INT,
1017 G_TYPE_INT,
1018 NULL);
1020 tree_class->row_activated = file_view_row_activated;
1021 widget_class->key_press_event = file_view_key_press_event;
1022 widget_class->popup_menu = file_view_popup_menu;
1023 widget_class->button_press_event = file_view_button_press_event;
1025 /* Tooltips */
1026 widget_class->query_tooltip = file_view_query_tooltip;
1028 /* Dnd */
1029 widget_class->drag_data_get = file_view_drag_data_get;
1032 void
1033 file_view_refresh_vcs (AnjutaFileView* view)
1035 AnjutaFileViewPrivate* priv = ANJUTA_FILE_VIEW_GET_PRIVATE (view);
1036 file_model_update_vcs_status(priv->model);
1040 GtkWidget*
1041 file_view_new (void)
1043 return g_object_new (ANJUTA_TYPE_FILE_VIEW,
1044 "headers-visible", FALSE,
1045 "has-tooltip", TRUE,
1046 "enable-search", TRUE,
1047 NULL);