1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8; coding: utf-8 -*- */
4 * Copyright (C) 2000 JP Rosevear
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program 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 GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
21 * Authors: JP Rosevear
22 * Gustavo Giráldez <gustavo.giraldez@gmx.net>
31 #include <glib/gi18n.h>
37 #include "tree-data.h"
38 #include "project-model.h"
39 #include "project-view.h"
40 #include "project-marshal.h"
41 #include "project-util.h"
53 static guint signals
[LAST_SIGNAL
] = { 0 };
55 /* Project model filter with drag and drop support
56 *---------------------------------------------------------------------------*/
59 GtkTreeModelFilter parent
;
60 } PmProjectModelFilter
;
63 GtkTreeModelFilterClass parent_class
;
64 } PmProjectModelFilterClass
;
66 #define PM_TYPE_PROJECT_MODEL_FILTER (pm_project_model_filter_get_type ())
67 #define PM_PROJECT_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PM_TYPE_PROJECT_MODEL_FILTER, PmProjectModelFilter))
71 pm_project_model_filter_class_init (PmProjectModelFilterClass
*class)
76 pm_project_model_filter_init (PmProjectModelFilter
*model
)
81 idrag_source_row_draggable (GtkTreeDragSource
*drag_source
, GtkTreePath
*path
)
85 gboolean retval
= FALSE
;
87 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source
), &iter
, path
))
90 gtk_tree_model_get (GTK_TREE_MODEL (drag_source
), &iter
,
91 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
94 if (data
->is_shortcut
) {
95 /* shortcuts can be moved */
98 } else if (data
->type
== GBF_TREE_NODE_TARGET
) {
99 /* don't allow duplicate shortcuts */
100 if (data
->shortcut
== NULL
)
108 idrag_source_drag_data_delete (GtkTreeDragSource
*drag_source
, GtkTreePath
*path
)
114 idrag_dest_drag_data_received (GtkTreeDragDest
*drag_dest
,
116 GtkSelectionData
*selection_data
)
118 GtkTreeModel
*src_model
= NULL
;
119 GtkTreePath
*src_path
= NULL
;
120 GtkTreeModel
*project_model
;
121 gboolean retval
= FALSE
;
123 if (GTK_IS_TREE_MODEL_FILTER (drag_dest
))
125 project_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (drag_dest
));
129 project_model
= GTK_TREE_MODEL (drag_dest
);
131 g_return_val_if_fail (GBF_IS_PROJECT_MODEL (project_model
), FALSE
);
133 if (gtk_tree_get_row_drag_data (selection_data
,
136 src_model
== GTK_TREE_MODEL (project_model
)) {
139 GbfTreeData
*data
= NULL
;
141 if (gtk_tree_model_get_iter (src_model
, &iter
, src_path
)) {
142 gtk_tree_model_get (src_model
, &iter
,
143 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
147 GtkTreePath
*child_path
;
149 child_path
= gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (drag_dest
), dest
);
150 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
152 gbf_project_model_move_target_shortcut (GBF_PROJECT_MODEL (project_model
),
153 &iter
, data
, child_path
);
157 gbf_project_model_add_target_shortcut (GBF_PROJECT_MODEL (project_model
),
158 NULL
, data
, child_path
, NULL
);
160 gtk_tree_path_free (child_path
);
167 gtk_tree_path_free (src_path
);
173 idrag_dest_row_drop_possible (GtkTreeDragDest
*drag_dest
,
174 GtkTreePath
*dest_path
,
175 GtkSelectionData
*selection_data
)
177 GtkTreeModel
*src_model
;
178 GtkTreeModel
*project_model
;
179 GtkTreePath
*src_path
;
181 gboolean retval
= FALSE
;
183 //g_return_val_if_fail (GBF_IS_PROJECT_MODEL (drag_dest), FALSE);
185 if (GTK_IS_TREE_MODEL_FILTER (drag_dest
))
187 project_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (drag_dest
));
191 project_model
= GTK_TREE_MODEL (drag_dest
);
194 if (!gtk_tree_get_row_drag_data (selection_data
,
202 if (gtk_tree_model_get_iter (src_model
, &iter
, src_path
))
204 GbfTreeData
*data
= NULL
;
206 gtk_tree_model_get (src_model
, &iter
,
207 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
211 /* can only drag to ourselves and only new toplevel nodes will
213 if (src_model
== project_model
&&
214 gtk_tree_path_get_depth (dest_path
) == 1)
216 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
222 GtkTreePath
*root_path
;
223 GtkTreePath
*child_path
;
225 root_path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model
));
226 child_path
= gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (drag_dest
), dest_path
);
227 retval
= gtk_tree_path_compare (child_path
, root_path
) <= 0;
228 gtk_tree_path_free (child_path
);
229 gtk_tree_path_free (root_path
);
234 gtk_tree_path_free (src_path
);
240 pm_project_model_filter_drag_source_iface_init (GtkTreeDragSourceIface
*iface
)
242 iface
->row_draggable
= idrag_source_row_draggable
;
243 iface
->drag_data_delete
= idrag_source_drag_data_delete
;
247 pm_project_model_filter_drag_dest_iface_init (GtkTreeDragDestIface
*iface
)
249 iface
->drag_data_received
= idrag_dest_drag_data_received
;
250 iface
->row_drop_possible
= idrag_dest_row_drop_possible
;
253 static GType
pm_project_model_filter_get_type (void);
255 G_DEFINE_TYPE_WITH_CODE (PmProjectModelFilter
,
256 pm_project_model_filter
,
257 GTK_TYPE_TREE_MODEL_FILTER
,
258 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE
,
259 pm_project_model_filter_drag_source_iface_init
)
260 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST
,
261 pm_project_model_filter_drag_dest_iface_init
));
264 static GtkTreeModel
*
265 pm_project_model_filter_new (GtkTreeModel
*child_model
,
268 PmProjectModelFilter
*model
;
270 model
= g_object_new (PM_TYPE_PROJECT_MODEL_FILTER
,
271 "child-model", child_model
,
272 "virtual-root", root
,
275 return GTK_TREE_MODEL (model
);
282 static void gbf_project_view_class_init (GbfProjectViewClass
*klass
);
283 static void gbf_project_view_init (GbfProjectView
*tree
);
284 static void destroy (GtkWidget
*object
);
286 static void set_pixbuf (GtkTreeViewColumn
*tree_column
,
287 GtkCellRenderer
*cell
,
291 static void set_text (GtkTreeViewColumn
*tree_column
,
292 GtkCellRenderer
*cell
,
298 G_DEFINE_TYPE(GbfProjectView
, gbf_project_view
, GTK_TYPE_TREE_VIEW
);
301 row_activated (GtkTreeView
*tree_view
,
303 GtkTreeViewColumn
*column
)
310 model
= gtk_tree_view_get_model (tree_view
);
312 gtk_tree_model_get_iter (GTK_TREE_MODEL (model
), &iter
, path
);
314 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
315 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
318 uri
= gbf_tree_data_get_uri (data
);
320 g_signal_emit (G_OBJECT (tree_view
),
321 signals
[URI_ACTIVATED
], 0,
325 if (data
->type
== GBF_TREE_NODE_TARGET
) {
326 g_signal_emit (G_OBJECT (tree_view
),
327 signals
[TARGET_SELECTED
], 0,
331 if (data
->type
== GBF_TREE_NODE_GROUP
) {
332 g_signal_emit (G_OBJECT (tree_view
),
333 signals
[GROUP_SELECTED
], 0,
339 static void on_node_loaded (AnjutaPmProject
*sender
, AnjutaProjectNode
*node
, gboolean complete
, GError
*error
, GbfProjectView
*view
);
342 dispose (GObject
*object
)
344 GbfProjectView
*view
;
346 view
= GBF_PROJECT_VIEW (object
);
350 g_object_unref (G_OBJECT (view
->filter
));
355 AnjutaPmProject
*old_project
;
357 old_project
= gbf_project_model_get_project (view
->model
);
358 if (old_project
!= NULL
)
360 g_signal_handlers_disconnect_by_func (old_project
, G_CALLBACK (on_node_loaded
), view
);
362 g_object_unref (G_OBJECT (view
->model
));
366 G_OBJECT_CLASS (gbf_project_view_parent_class
)->dispose (object
);
370 destroy (GtkWidget
*object
)
372 GbfProjectView
*tree
;
374 tree
= GBF_PROJECT_VIEW (object
);
376 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
)
377 (* GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
) (object
);
381 get_icon (GFile
*file
)
383 const gchar
** icon_names
;
384 GtkIconInfo
* icon_info
;
386 GdkPixbuf
* pixbuf
= NULL
;
387 GFileInfo
* file_info
;
388 GError
*error
= NULL
;
390 file_info
= g_file_query_info (file
,
391 G_FILE_ATTRIBUTE_STANDARD_ICON
,
392 G_FILE_QUERY_INFO_NONE
,
396 if (file_info
== NULL
)
398 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
399 GTK_STOCK_MISSING_IMAGE
,
401 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
406 icon
= g_file_info_get_icon(file_info
);
407 g_object_get (icon
, "names", &icon_names
, NULL
);
408 icon_info
= gtk_icon_theme_choose_icon (gtk_icon_theme_get_default(),
411 GTK_ICON_LOOKUP_GENERIC_FALLBACK
);
412 pixbuf
= gtk_icon_info_load_icon (icon_info
, NULL
);
413 gtk_icon_info_free(icon_info
);
414 g_object_unref (file_info
);
421 set_pixbuf (GtkTreeViewColumn
*tree_column
,
422 GtkCellRenderer
*cell
,
427 GbfTreeData
*data
= NULL
;
428 GdkPixbuf
*pixbuf
= NULL
;
430 gtk_tree_model_get (model
, iter
,
431 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
432 g_return_if_fail (data
!= NULL
);
433 /* FIXME: segmentation fault with shortcut when corresponding
434 * data is removed before the shortcut, so data = NULL.
435 * Perhaps we can add a GtkTreeReference to the shortcut
436 * node to remove the shortcut when the node is destroyed */
438 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
440 data
= data
->shortcut
;
442 switch (data
->type
) {
443 case GBF_TREE_NODE_SOURCE
:
445 pixbuf
= get_icon (data
->source
);
448 case GBF_TREE_NODE_ROOT
:
449 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
452 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
455 case GBF_TREE_NODE_GROUP
:
456 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
459 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
462 case GBF_TREE_NODE_TARGET
:
464 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
467 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
471 case GBF_TREE_NODE_MODULE
:
473 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
474 GTK_STOCK_DND_MULTIPLE
,
476 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
480 case GBF_TREE_NODE_PACKAGE
:
482 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
485 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
490 /* Can reach this if type = GBF_TREE_NODE_SHORTCUT. It
491 * means a shortcut with the original data removed */
495 g_object_set (GTK_CELL_RENDERER (cell
), "pixbuf", pixbuf
, NULL
);
497 g_object_unref (pixbuf
);
501 set_text (GtkTreeViewColumn
*tree_column
,
502 GtkCellRenderer
*cell
,
509 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
510 /* data can be NULL just after gtk_tree_store_insert before
511 calling gtk_tree_store_set */
512 g_object_set (GTK_CELL_RENDERER (cell
), "text",
513 data
== NULL
? "" : data
->name
, NULL
);
517 search_equal_func (GtkTreeModel
*model
, gint column
,
518 const gchar
*key
, GtkTreeIter
*iter
,
524 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
525 if (strncmp (data
->name
, key
, strlen (key
)) == 0)
531 draw (GtkWidget
*widget
, cairo_t
*cr
)
533 GtkTreeModel
*view_model
;
535 GtkTreeView
*tree_view
;
536 gint event_handled
= FALSE
;
538 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw
!= NULL
)
539 GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw (widget
, cr
);
541 tree_view
= GTK_TREE_VIEW (widget
);
542 view_model
= gtk_tree_view_get_model (tree_view
);
543 if (GTK_IS_TREE_MODEL_FILTER (view_model
))
545 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
547 if (gtk_cairo_should_draw_window (cr
, gtk_tree_view_get_bin_window (tree_view
)) &&
548 model
&& GBF_IS_PROJECT_MODEL (model
)) {
552 /* paint an horizontal ruler to separate the project
553 * tree from the target shortcuts */
555 root
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
557 if (view_model
!= model
)
560 GtkTreePath
*child_path
;
562 child_path
= gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (view_model
), root
);
563 gtk_tree_path_free (root
);
566 gtk_tree_view_get_background_area (
567 tree_view
, root
, gtk_tree_view_get_column (tree_view
, 0), &rect
);
568 gtk_paint_hline (gtk_widget_get_style (widget
),
570 gtk_widget_get_state (widget
),
573 rect
.x
, rect
.x
+ rect
.width
,
575 gtk_tree_path_free (root
);
579 return event_handled
;
583 gbf_project_view_class_init (GbfProjectViewClass
*klass
)
585 GObjectClass
*g_object_class
;
586 GtkWidgetClass
*widget_class
;
587 GtkTreeViewClass
*tree_view_class
;
589 g_object_class
= G_OBJECT_CLASS (klass
);
590 widget_class
= GTK_WIDGET_CLASS (klass
);
591 tree_view_class
= GTK_TREE_VIEW_CLASS (klass
);
593 g_object_class
->dispose
= dispose
;
594 widget_class
->destroy
= destroy
;
595 widget_class
->draw
= draw
;
596 tree_view_class
->row_activated
= row_activated
;
598 signals
[URI_ACTIVATED
] =
599 g_signal_new ("uri_activated",
600 GBF_TYPE_PROJECT_VIEW
,
602 G_STRUCT_OFFSET (GbfProjectViewClass
,
605 g_cclosure_marshal_VOID__STRING
,
606 G_TYPE_NONE
, 1, G_TYPE_STRING
);
608 signals
[TARGET_SELECTED
] =
609 g_signal_new ("target_selected",
610 GBF_TYPE_PROJECT_VIEW
,
612 G_STRUCT_OFFSET (GbfProjectViewClass
,
615 g_cclosure_marshal_VOID__POINTER
,
616 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
617 signals
[GROUP_SELECTED
] =
618 g_signal_new ("group_selected",
619 GBF_TYPE_PROJECT_VIEW
,
621 G_STRUCT_OFFSET (GbfProjectViewClass
,
624 g_cclosure_marshal_VOID__POINTER
,
625 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
626 signals
[NODE_LOADED
] =
627 g_signal_new ("node-loaded",
628 GBF_TYPE_PROJECT_VIEW
,
630 G_STRUCT_OFFSET (GbfProjectViewClass
,
633 pm_cclosure_marshal_VOID__POINTER_BOOLEAN_BOXED
,
642 is_project_node_visible (GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
646 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
647 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
650 return (data
!= NULL
) && (gbf_tree_data_get_node (data
) != NULL
);
654 gbf_project_view_init (GbfProjectView
*tree
)
656 GtkCellRenderer
*renderer
;
657 GtkTreeViewColumn
*column
;
658 static GtkTargetEntry row_targets
[] = {
659 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET
, 0 }
662 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree
), FALSE
);
663 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (tree
), TRUE
);
664 gtk_tree_view_set_search_column (GTK_TREE_VIEW (tree
), 0);
665 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (tree
),
669 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree
),
672 G_N_ELEMENTS (row_targets
),
674 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tree
),
676 G_N_ELEMENTS (row_targets
),
679 /* set renderer for files column. */
680 column
= gtk_tree_view_column_new ();
681 renderer
= gtk_cell_renderer_pixbuf_new ();
682 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
683 gtk_tree_view_column_set_cell_data_func (column
, renderer
, set_pixbuf
, tree
, NULL
);
685 renderer
= gtk_cell_renderer_text_new ();
686 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
687 gtk_tree_view_column_set_cell_data_func (column
, renderer
, set_text
, tree
, NULL
);
689 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
692 tree
->model
= gbf_project_model_new (NULL
);
693 tree
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (tree
->model
), NULL
));
694 gtk_tree_model_filter_set_visible_func (tree
->filter
, is_project_node_visible
, tree
, NULL
);
696 gtk_tree_view_set_model (GTK_TREE_VIEW (tree
), GTK_TREE_MODEL (tree
->filter
));
700 gbf_project_view_new (void)
702 return GTK_WIDGET (g_object_new (GBF_TYPE_PROJECT_VIEW
, NULL
));
706 gbf_project_view_find_selected (GbfProjectView
*view
, AnjutaProjectNodeType type
)
708 AnjutaProjectNode
*node
= NULL
;
711 g_return_val_if_fail (view
!= NULL
, NULL
);
712 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
714 data
= gbf_project_view_get_first_selected (view
, NULL
);
718 node
= gbf_tree_data_get_node (data
);
720 /* walk up the hierarchy searching for a node of the given type */
721 while ((node
!= NULL
) && (type
!= ANJUTA_PROJECT_UNKNOWN
) && (anjuta_project_node_get_node_type (node
) != type
))
723 node
= anjuta_project_node_parent (node
);
731 gbf_project_view_get_first_selected (GbfProjectView
*view
, GtkTreeIter
* selected
)
733 GtkTreeSelection
*selection
;
734 GbfTreeData
*data
= NULL
;
738 g_return_val_if_fail (view
!= NULL
, NULL
);
739 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
741 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
742 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
747 if (gtk_tree_model_get_iter (model
, &iter
, list
->data
))
751 if (GTK_IS_TREE_MODEL_FILTER (model
))
753 GtkTreeIter child_iter
;
755 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model
), &child_iter
, &iter
);
756 *selected
= child_iter
;
764 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
765 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
768 g_list_foreach (list
, (GFunc
)gtk_tree_path_free
, NULL
);
776 gbf_project_view_set_cursor_to_iter (GbfProjectView
*view
,
777 GtkTreeIter
*selected
)
779 GtkTreePath
*path
= NULL
;
780 GtkTreeIter view_iter
;
782 /* select node if we find it in the view*/
783 if ((selected
!= NULL
) && gtk_tree_model_filter_convert_child_iter_to_iter (
784 GTK_TREE_MODEL_FILTER (view
->filter
), &view_iter
, selected
))
786 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->filter
), &view_iter
);
790 /* Check if it is a shortcut */
795 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), selected
,
796 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
799 if ((data
!= NULL
) && (data
->shortcut
!= NULL
))
801 /* Select the corresponding node */
804 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
->shortcut
))
806 if (gtk_tree_model_filter_convert_child_iter_to_iter (
807 GTK_TREE_MODEL_FILTER (view
->filter
), &view_iter
, &iter
))
809 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->filter
), &view_iter
);
815 /* Try to select root node */
818 GtkTreePath
*root_path
;
820 root_path
= gbf_project_model_get_project_root (view
->model
);
823 path
= gtk_tree_model_filter_convert_child_path_to_path (
824 GTK_TREE_MODEL_FILTER (view
->filter
), root_path
);
825 gtk_tree_path_free (root_path
);
829 /* Take the first node */
832 path
= gtk_tree_path_new_first ();
838 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), path
);
840 gtk_tree_view_set_cursor (GTK_TREE_VIEW (view
), path
, NULL
, FALSE
);
841 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view
), path
, NULL
,
843 gtk_tree_path_free (path
);
849 on_each_get_data (GtkTreeModel
*model
,
854 GList
**selected
= (GList
**)user_data
;
857 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
858 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
861 *selected
= g_list_prepend (*selected
, data
);
865 gbf_project_view_get_all_selected (GbfProjectView
*view
)
867 GtkTreeSelection
*selection
;
868 GList
*selected
= NULL
;
870 g_return_val_if_fail (view
!= NULL
, FALSE
);
871 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
873 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
874 gtk_tree_selection_selected_foreach (selection
, on_each_get_data
, &selected
);
876 return g_list_reverse (selected
);
880 on_each_get_iter (GtkTreeModel
*model
,
885 GList
**selected
= (GList
**)user_data
;
887 *selected
= g_list_prepend (*selected
, gtk_tree_iter_copy (iter
));
891 gbf_project_view_get_all_selected_iter (GbfProjectView
*view
)
893 GtkTreeSelection
*selection
;
894 GList
*selected
= NULL
;
896 g_return_val_if_fail (view
!= NULL
, FALSE
);
897 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
899 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
900 gtk_tree_selection_selected_foreach (selection
, on_each_get_iter
, &selected
);
902 return g_list_reverse (selected
);
906 gbf_project_view_update_shortcut (GbfProjectView
*view
, AnjutaProjectNode
*parent
)
911 /* Get all root node */
912 valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, NULL
);
917 AnjutaProjectNode
* old_node
= NULL
;
919 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
920 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
923 /* Shortcuts are always at the beginning */
924 if (data
->type
!= GBF_TREE_NODE_SHORTCUT
) break;
926 old_node
= gbf_tree_data_get_node (data
);
927 if (old_node
== parent
)
930 gbf_project_view_update_tree (view
, parent
, &child
);
932 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
937 compare_node_name (gconstpointer a
, gconstpointer b
)
939 const AnjutaProjectNode
*node
= (const AnjutaProjectNode
*)a
;
940 const gchar
*name
= (const gchar
*)b
;
942 return g_strcmp0 (anjuta_project_node_get_name (node
), name
);
946 list_visible_children (AnjutaProjectNode
*parent
)
948 AnjutaProjectNode
*node
;
951 for (node
= anjuta_project_node_first_child (parent
); node
!= NULL
; node
= anjuta_project_node_next_sibling (node
))
953 if (anjuta_project_node_get_node_type (node
) != ANJUTA_PROJECT_OBJECT
)
955 list
= g_list_prepend (list
, node
);
959 /* object node are hidden, get their children instead */
960 GList
*children
= list_visible_children (node
);
962 children
= g_list_reverse (children
);
963 list
= g_list_concat (children
, list
);
966 list
= g_list_reverse (list
);
972 gbf_project_view_update_tree (GbfProjectView
*view
, AnjutaProjectNode
*parent
, GtkTreeIter
*iter
)
977 GbfTreeData
*data
= NULL
;
979 /* Get all new nodes */
980 nodes
= list_visible_children (parent
);
982 /* walk the tree nodes */
983 if (gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, iter
))
985 gboolean valid
= TRUE
;
989 AnjutaProjectNode
* data_node
= NULL
;
991 /* Look for current node */
992 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
993 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
996 data_node
= gbf_tree_data_get_node (data
);
999 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
1001 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1005 if (data
->type
== GBF_TREE_NODE_UNKNOWN
)
1007 node
= g_list_find_custom (nodes
, data
->name
, compare_node_name
);
1011 GtkTreePath
*child_path
;
1012 GtkTreeModelFilter
*filter
;
1016 expanded
= data
->expanded
;
1017 shortcut
= data
->has_shortcut
;
1018 data_node
= (AnjutaProjectNode
*)node
->data
;
1019 gbf_tree_data_free (data
);
1020 data
= gbf_tree_data_new_node (data_node
);
1021 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &child
,
1022 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1025 /* Node already exist, remove it from the list */
1026 nodes
= g_list_delete_link (nodes
, node
);
1028 /* Update shortcut */
1029 gbf_project_view_update_shortcut (view
, data_node
);
1031 /* update recursively */
1032 gbf_project_view_update_tree (view
, data_node
, &child
);
1039 gbf_project_model_add_target_shortcut (view
->model
, &iter
, data
, NULL
, &expanded
);
1042 /* Expand shortcut */
1043 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1044 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
1045 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1046 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1047 gtk_tree_path_free (child_path
);
1048 gtk_tree_path_free (path
);
1051 data
->expanded
= expanded
;
1054 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1055 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &child
);
1056 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1057 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1058 expanded
= gtk_tree_view_row_expanded (GTK_TREE_VIEW (view
), child_path
);
1059 gtk_tree_path_free (child_path
);
1060 gtk_tree_path_free (path
);
1063 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1067 node
= g_list_find (nodes
, data_node
);
1070 /* Node already exist, remove it from the list */
1071 nodes
= g_list_delete_link (nodes
, node
);
1073 /* Update shortcut */
1074 gbf_project_view_update_shortcut (view
, data_node
);
1076 /* update recursively */
1077 gbf_project_view_update_tree (view
, data_node
, &child
);
1079 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1083 /* Node has been deleted */
1084 valid
= gbf_project_model_remove (view
->model
, &child
);
1090 /* add the remaining sources, targets and groups */
1091 for (node
= nodes
; node
; node
= node
->next
)
1093 gbf_project_model_add_node (view
->model
, node
->data
, iter
, 0);
1096 /* Expand parent, needed if the parent hasn't any children when it was created */
1099 /* Check parent data */
1100 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), iter
,
1101 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1106 GtkTreePath
*child_path
;
1107 GtkTreeModelFilter
*filter
;
1109 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1110 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), iter
);
1111 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1112 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1113 gtk_tree_path_free (child_path
);
1114 gtk_tree_path_free (path
);
1115 data
->expanded
= FALSE
;
1120 /* Shorcuts functions
1121 *---------------------------------------------------------------------------*/
1124 gbf_project_view_sort_shortcuts (GbfProjectView
*view
)
1126 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1127 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1128 GTK_SORT_ASCENDING
);
1129 gbf_project_model_sort_shortcuts (view
->model
);
1130 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1131 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1132 GTK_SORT_ASCENDING
);
1137 gbf_project_view_get_shortcut_list (GbfProjectView
*view
)
1140 GtkTreeModel
* model
;
1144 model
= GTK_TREE_MODEL (view
->model
);
1147 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1149 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (model
), &iter
))
1152 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1153 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1156 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
1160 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
->shortcut
))
1165 str
= g_string_new (NULL
);
1171 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1172 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1175 if (data
->node
!= NULL
)
1177 if (str
->len
!= 0) g_string_prepend (str
, "//");
1178 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1181 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1182 list
= g_list_prepend (list
, str
->str
);
1183 g_string_free (str
, FALSE
);
1187 list
= g_list_reverse (list
);
1194 save_expanded_node (GtkTreeView
*view
, GtkTreePath
*path
, gpointer user_data
)
1196 GList
**list
= (GList
**)user_data
;
1197 GtkTreeModel
*model
;
1200 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1202 if (gtk_tree_model_get_iter (model
, &iter
, path
))
1207 str
= g_string_new (NULL
);
1213 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1214 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1217 if (data
->node
!= NULL
)
1219 if (str
->len
!= 0) g_string_prepend (str
, "//");
1220 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1223 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1225 *list
= g_list_prepend (*list
, str
->str
);
1226 g_string_free (str
, FALSE
);
1231 gbf_project_view_get_expanded_list (GbfProjectView
*view
)
1235 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (view
), save_expanded_node
, &list
);
1236 list
= g_list_reverse (list
);
1242 gbf_project_view_remove_all_shortcut (GbfProjectView
* view
)
1244 GtkTreeModel
* model
;
1248 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1250 /* Remove all current shortcuts */
1251 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1256 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1257 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1260 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
1262 valid
= gbf_project_model_remove (GBF_PROJECT_MODEL (model
), &iter
);
1266 /* No more shortcut */
1273 gbf_project_view_set_shortcut_list (GbfProjectView
*view
, GList
*shortcuts
)
1277 gbf_project_model_set_default_shortcut (view
->model
, shortcuts
== NULL
);
1279 for (item
= g_list_first (shortcuts
); item
!= NULL
; item
= g_list_next (item
))
1281 gchar
*name
= (gchar
*)item
->data
;
1284 GtkTreeIter
*parent
= NULL
;
1288 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1289 if (end
!= NULL
) *end
= '\0';
1292 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1296 /* Create proxy node */
1297 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1298 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1299 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1300 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1304 data
->has_shortcut
= TRUE
;
1306 /* Create another proxy at root level to keep shortcut order */
1307 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1308 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, NULL
);
1309 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1310 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1318 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1319 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1321 if (end
== NULL
) data
->has_shortcut
= TRUE
;
1331 while (end
!= NULL
);
1338 gbf_project_view_set_expanded_list (GbfProjectView
*view
, GList
*expand
)
1342 for (item
= g_list_first (expand
); item
!= NULL
; item
= g_list_next (item
))
1344 gchar
*name
= (gchar
*)item
->data
;
1347 GtkTreeIter
*parent
= NULL
;
1351 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1352 if (end
!= NULL
) *end
= '\0';
1355 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1359 /* Create proxy node */
1360 data
= gbf_tree_data_new_proxy (name
, TRUE
);
1361 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1362 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1363 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1370 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1371 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1373 data
->expanded
= TRUE
;
1383 while (end
!= NULL
);
1390 gbf_project_view_get_node_from_iter (GbfProjectView
*view
, GtkTreeIter
*iter
)
1392 return gbf_project_model_get_node (view
->model
, iter
);
1396 gbf_project_view_get_node_from_file (GbfProjectView
*view
, AnjutaProjectNodeType type
, GFile
*file
)
1399 AnjutaProjectNode
*node
= NULL
;
1401 if (gbf_project_model_find_file (view
->model
, &iter
, NULL
, type
, file
))
1404 node
= gbf_project_model_get_node (view
->model
, &iter
);
1411 gbf_project_view_remove_data (GbfProjectView
*view
, GbfTreeData
*data
, GError
**error
)
1415 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
))
1417 gbf_project_model_remove (view
->model
, &iter
);
1428 on_node_loaded (AnjutaPmProject
*sender
, AnjutaProjectNode
*node
, gboolean complete
, GError
*error
, GbfProjectView
*view
)
1432 g_warning ("unable to load node");
1433 g_signal_emit (G_OBJECT (view
), NODE_LOADED
, 0, NULL
, complete
, error
);
1440 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1441 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1442 GTK_SORT_ASCENDING
);
1444 found
= gbf_project_model_find_node (view
->model
, &iter
, NULL
, node
);
1447 if (anjuta_project_node_get_node_type (node
) != ANJUTA_PROJECT_ROOT
)
1449 g_critical ("Unable to find node %s", anjuta_project_node_get_name (node
));
1454 GtkTreePath
*child_path
;
1455 GtkTreeModelFilter
*filter
;
1457 if (!gbf_project_model_find_child_name (view
->model
, &iter
, NULL
, anjuta_project_node_get_name (node
)))
1459 gbf_project_model_add_node (view
->model
, node
, NULL
, 0);
1460 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view
->model
), &iter
);
1466 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1467 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1469 if (data
->type
== GBF_TREE_NODE_UNKNOWN
)
1471 /* Replace with real node */
1472 GbfTreeData
*new_data
;
1474 new_data
= gbf_tree_data_new_node (node
);
1475 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1476 GBF_PROJECT_MODEL_COLUMN_DATA
, new_data
,
1478 gbf_tree_data_free (data
);
1480 gbf_project_view_update_tree (view
, node
, &iter
);
1483 /* Expand root node */
1484 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
1485 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1486 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1487 if (child_path
!= NULL
) gtk_tree_view_expand_row (GTK_TREE_VIEW (view
), child_path
, FALSE
);
1488 gtk_tree_path_free (child_path
);
1489 gtk_tree_path_free (path
);
1494 gbf_project_view_update_tree (view
, node
, &iter
);
1496 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1497 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1498 GTK_SORT_ASCENDING
);
1500 g_signal_emit (G_OBJECT (view
), signals
[NODE_LOADED
], 0, found
? &iter
: NULL
, complete
, NULL
);
1505 // Add shortcut for all new primary targets
1506 gbf_project_model_set_default_shortcut (view
->model
, TRUE
);
1512 gbf_project_view_set_project (GbfProjectView
*view
, AnjutaPmProject
*project
)
1514 AnjutaPmProject
*old_project
;
1516 old_project
= gbf_project_model_get_project (view
->model
);
1517 if (old_project
!= NULL
)
1519 g_signal_handlers_disconnect_by_func (old_project
, G_CALLBACK (on_node_loaded
), view
);
1522 g_signal_connect (project
, "loaded", G_CALLBACK (on_node_loaded
), view
);
1524 gbf_project_model_set_project (view
->model
, project
);
1528 gbf_project_view_set_parent_view (GbfProjectView
*view
,
1529 GbfProjectView
*parent
,
1533 if (view
->model
!= NULL
) g_object_unref (view
->model
);
1534 if (view
->filter
!= NULL
) g_object_unref (view
->model
);
1536 view
->model
= g_object_ref (parent
->model
);
1537 view
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (view
->model
), root
));
1538 gtk_tree_view_set_model (GTK_TREE_VIEW (view
), GTK_TREE_MODEL (view
->filter
));
1542 gbf_project_view_set_visible_func (GbfProjectView
*view
,
1543 GtkTreeModelFilterVisibleFunc func
,
1545 GDestroyNotify destroy
)
1549 gtk_tree_model_filter_set_visible_func (view
->filter
, is_project_node_visible
, view
, NULL
);
1553 gtk_tree_model_filter_set_visible_func (view
->filter
, func
, data
, destroy
);
1555 gtk_tree_model_filter_refilter (view
->filter
);
1559 gbf_project_view_find_file (GbfProjectView
*view
, GtkTreeIter
* iter
, GFile
*file
, GbfTreeNodeType type
)
1561 return gbf_project_model_find_file (view
->model
, iter
, NULL
, type
, file
);
1565 gbf_project_view_get_model (GbfProjectView
*view
)
1571 gbf_project_view_get_project_root (GbfProjectView
*view
, GtkTreeIter
*iter
)
1573 GtkTreeModel
*model
;
1574 GtkTreeModel
*view_model
;
1576 gboolean ok
= FALSE
;
1578 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1580 if (GTK_IS_TREE_MODEL_FILTER (model
))
1582 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
1585 path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
1588 ok
= gtk_tree_model_get_iter (model
, iter
, path
);
1589 gtk_tree_path_free (path
);