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,
340 dispose (GObject
*object
)
342 GbfProjectView
*view
;
344 view
= GBF_PROJECT_VIEW (object
);
348 g_object_unref (G_OBJECT (view
->filter
));
353 g_object_unref (G_OBJECT (view
->model
));
357 G_OBJECT_CLASS (gbf_project_view_parent_class
)->dispose (object
);
361 destroy (GtkWidget
*object
)
363 GbfProjectView
*tree
;
365 tree
= GBF_PROJECT_VIEW (object
);
367 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
)
368 (* GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
) (object
);
372 get_icon (GFile
*file
)
374 const gchar
** icon_names
;
375 GtkIconInfo
* icon_info
;
377 GdkPixbuf
* pixbuf
= NULL
;
378 GFileInfo
* file_info
;
379 GError
*error
= NULL
;
381 file_info
= g_file_query_info (file
,
382 G_FILE_ATTRIBUTE_STANDARD_ICON
,
383 G_FILE_QUERY_INFO_NONE
,
387 if (file_info
== NULL
)
389 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
390 GTK_STOCK_MISSING_IMAGE
,
392 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
397 icon
= g_file_info_get_icon(file_info
);
398 g_object_get (icon
, "names", &icon_names
, NULL
);
399 icon_info
= gtk_icon_theme_choose_icon (gtk_icon_theme_get_default(),
402 GTK_ICON_LOOKUP_GENERIC_FALLBACK
);
403 pixbuf
= gtk_icon_info_load_icon (icon_info
, NULL
);
404 gtk_icon_info_free(icon_info
);
405 g_object_unref (file_info
);
412 set_pixbuf (GtkTreeViewColumn
*tree_column
,
413 GtkCellRenderer
*cell
,
418 GbfTreeData
*data
= NULL
;
419 GdkPixbuf
*pixbuf
= NULL
;
421 gtk_tree_model_get (model
, iter
,
422 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
423 g_return_if_fail (data
!= NULL
);
424 /* FIXME: segmentation fault with shortcut when corresponding
425 * data is removed before the shortcut, so data = NULL.
426 * Perhaps we can add a GtkTreeReference to the shortcut
427 * node to remove the shortcut when the node is destroyed */
429 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
431 data
= data
->shortcut
;
433 switch (data
->type
) {
434 case GBF_TREE_NODE_SOURCE
:
436 pixbuf
= get_icon (data
->source
);
439 case GBF_TREE_NODE_ROOT
:
440 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
443 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
446 case GBF_TREE_NODE_GROUP
:
447 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
450 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
453 case GBF_TREE_NODE_TARGET
:
455 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
458 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
462 case GBF_TREE_NODE_MODULE
:
464 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
465 GTK_STOCK_DND_MULTIPLE
,
467 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
471 case GBF_TREE_NODE_PACKAGE
:
473 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
476 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
481 /* Can reach this if type = GBF_TREE_NODE_SHORTCUT. It
482 * means a shortcut with the original data removed */
486 g_object_set (GTK_CELL_RENDERER (cell
), "pixbuf", pixbuf
, NULL
);
488 g_object_unref (pixbuf
);
492 set_text (GtkTreeViewColumn
*tree_column
,
493 GtkCellRenderer
*cell
,
500 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
501 /* data can be NULL just after gtk_tree_store_insert before
502 calling gtk_tree_store_set */
503 g_object_set (GTK_CELL_RENDERER (cell
), "text",
504 data
== NULL
? "" : data
->name
, NULL
);
508 search_equal_func (GtkTreeModel
*model
, gint column
,
509 const gchar
*key
, GtkTreeIter
*iter
,
515 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
516 if (strncmp (data
->name
, key
, strlen (key
)) == 0)
522 draw (GtkWidget
*widget
, cairo_t
*cr
)
524 GtkTreeModel
*view_model
;
526 GtkTreeView
*tree_view
;
527 gint event_handled
= FALSE
;
529 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw
!= NULL
)
530 GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw (widget
, cr
);
532 tree_view
= GTK_TREE_VIEW (widget
);
533 view_model
= gtk_tree_view_get_model (tree_view
);
534 if (GTK_IS_TREE_MODEL_FILTER (view_model
))
536 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
538 if (gtk_cairo_should_draw_window (cr
, gtk_tree_view_get_bin_window (tree_view
)) &&
539 model
&& GBF_IS_PROJECT_MODEL (model
)) {
543 /* paint an horizontal ruler to separate the project
544 * tree from the target shortcuts */
546 root
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
548 if (view_model
!= model
)
551 GtkTreePath
*child_path
;
553 child_path
= gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (view_model
), root
);
554 gtk_tree_path_free (root
);
557 gtk_tree_view_get_background_area (
558 tree_view
, root
, gtk_tree_view_get_column (tree_view
, 0), &rect
);
559 gtk_paint_hline (gtk_widget_get_style (widget
),
561 gtk_widget_get_state (widget
),
564 rect
.x
, rect
.x
+ rect
.width
,
566 gtk_tree_path_free (root
);
570 return event_handled
;
574 gbf_project_view_class_init (GbfProjectViewClass
*klass
)
576 GObjectClass
*g_object_class
;
577 GtkWidgetClass
*widget_class
;
578 GtkTreeViewClass
*tree_view_class
;
580 g_object_class
= G_OBJECT_CLASS (klass
);
581 widget_class
= GTK_WIDGET_CLASS (klass
);
582 tree_view_class
= GTK_TREE_VIEW_CLASS (klass
);
584 g_object_class
->dispose
= dispose
;
585 widget_class
->destroy
= destroy
;
586 widget_class
->draw
= draw
;
587 tree_view_class
->row_activated
= row_activated
;
589 signals
[URI_ACTIVATED
] =
590 g_signal_new ("uri_activated",
591 GBF_TYPE_PROJECT_VIEW
,
593 G_STRUCT_OFFSET (GbfProjectViewClass
,
596 g_cclosure_marshal_VOID__STRING
,
597 G_TYPE_NONE
, 1, G_TYPE_STRING
);
599 signals
[TARGET_SELECTED
] =
600 g_signal_new ("target_selected",
601 GBF_TYPE_PROJECT_VIEW
,
603 G_STRUCT_OFFSET (GbfProjectViewClass
,
606 g_cclosure_marshal_VOID__POINTER
,
607 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
608 signals
[GROUP_SELECTED
] =
609 g_signal_new ("group_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
[NODE_LOADED
] =
618 g_signal_new ("node-loaded",
619 GBF_TYPE_PROJECT_VIEW
,
621 G_STRUCT_OFFSET (GbfProjectViewClass
,
624 pm_cclosure_marshal_VOID__POINTER_BOOLEAN_BOXED
,
633 is_project_node_visible (GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
637 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
638 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
641 return (data
!= NULL
) && (gbf_tree_data_get_node (data
) != NULL
);
645 gbf_project_view_init (GbfProjectView
*tree
)
647 GtkCellRenderer
*renderer
;
648 GtkTreeViewColumn
*column
;
649 static GtkTargetEntry row_targets
[] = {
650 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET
, 0 }
653 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree
), FALSE
);
654 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (tree
), TRUE
);
655 gtk_tree_view_set_search_column (GTK_TREE_VIEW (tree
), 0);
656 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (tree
),
660 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree
),
663 G_N_ELEMENTS (row_targets
),
665 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tree
),
667 G_N_ELEMENTS (row_targets
),
670 /* set renderer for files column. */
671 column
= gtk_tree_view_column_new ();
672 renderer
= gtk_cell_renderer_pixbuf_new ();
673 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
674 gtk_tree_view_column_set_cell_data_func (column
, renderer
, set_pixbuf
, tree
, NULL
);
676 renderer
= gtk_cell_renderer_text_new ();
677 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
678 gtk_tree_view_column_set_cell_data_func (column
, renderer
, set_text
, tree
, NULL
);
680 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
683 tree
->model
= gbf_project_model_new (NULL
);
684 tree
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (tree
->model
), NULL
));
685 gtk_tree_model_filter_set_visible_func (tree
->filter
, is_project_node_visible
, tree
, NULL
);
687 gtk_tree_view_set_model (GTK_TREE_VIEW (tree
), GTK_TREE_MODEL (tree
->filter
));
691 gbf_project_view_new (void)
693 return GTK_WIDGET (g_object_new (GBF_TYPE_PROJECT_VIEW
, NULL
));
697 gbf_project_view_find_selected (GbfProjectView
*view
, AnjutaProjectNodeType type
)
699 AnjutaProjectNode
*node
= NULL
;
702 g_return_val_if_fail (view
!= NULL
, NULL
);
703 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
705 data
= gbf_project_view_get_first_selected (view
, NULL
);
709 node
= gbf_tree_data_get_node (data
);
711 /* walk up the hierarchy searching for a node of the given type */
712 while ((node
!= NULL
) && (type
!= ANJUTA_PROJECT_UNKNOWN
) && (anjuta_project_node_get_node_type (node
) != type
))
714 node
= anjuta_project_node_parent (node
);
722 gbf_project_view_get_first_selected (GbfProjectView
*view
, GtkTreeIter
* selected
)
724 GtkTreeSelection
*selection
;
725 GbfTreeData
*data
= NULL
;
729 g_return_val_if_fail (view
!= NULL
, NULL
);
730 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
732 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
733 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
738 if (gtk_tree_model_get_iter (model
, &iter
, list
->data
))
742 if (GTK_IS_TREE_MODEL_FILTER (model
))
744 GtkTreeIter child_iter
;
746 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model
), &child_iter
, &iter
);
747 *selected
= child_iter
;
755 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
756 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
759 g_list_foreach (list
, (GFunc
)gtk_tree_path_free
, NULL
);
767 gbf_project_view_set_cursor_to_iter (GbfProjectView
*view
,
768 GtkTreeIter
*selected
)
770 GtkTreePath
*path
= NULL
;
771 GtkTreeIter view_iter
;
773 /* select node if we find it in the view*/
774 if ((selected
!= NULL
) && gtk_tree_model_filter_convert_child_iter_to_iter (
775 GTK_TREE_MODEL_FILTER (view
->filter
), &view_iter
, selected
))
777 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->filter
), &view_iter
);
781 /* Check if it is a shortcut */
786 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), selected
,
787 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
790 if ((data
!= NULL
) && (data
->shortcut
!= NULL
))
792 /* Select the corresponding node */
795 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
->shortcut
))
797 if (gtk_tree_model_filter_convert_child_iter_to_iter (
798 GTK_TREE_MODEL_FILTER (view
->filter
), &view_iter
, &iter
))
800 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->filter
), &view_iter
);
806 /* Try to select root node */
809 GtkTreePath
*root_path
;
811 root_path
= gbf_project_model_get_project_root (view
->model
);
814 path
= gtk_tree_model_filter_convert_child_path_to_path (
815 GTK_TREE_MODEL_FILTER (view
->filter
), root_path
);
816 gtk_tree_path_free (root_path
);
820 /* Take the first node */
823 path
= gtk_tree_path_new_first ();
829 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), path
);
831 gtk_tree_view_set_cursor (GTK_TREE_VIEW (view
), path
, NULL
, FALSE
);
832 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view
), path
, NULL
,
834 gtk_tree_path_free (path
);
840 on_each_get_data (GtkTreeModel
*model
,
845 GList
**selected
= (GList
**)user_data
;
848 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
849 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
852 *selected
= g_list_prepend (*selected
, data
);
856 gbf_project_view_get_all_selected (GbfProjectView
*view
)
858 GtkTreeSelection
*selection
;
859 GList
*selected
= NULL
;
861 g_return_val_if_fail (view
!= NULL
, FALSE
);
862 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
864 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
865 gtk_tree_selection_selected_foreach (selection
, on_each_get_data
, &selected
);
867 return g_list_reverse (selected
);
871 on_each_get_iter (GtkTreeModel
*model
,
876 GList
**selected
= (GList
**)user_data
;
878 *selected
= g_list_prepend (*selected
, gtk_tree_iter_copy (iter
));
882 gbf_project_view_get_all_selected_iter (GbfProjectView
*view
)
884 GtkTreeSelection
*selection
;
885 GList
*selected
= NULL
;
887 g_return_val_if_fail (view
!= NULL
, FALSE
);
888 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
890 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
891 gtk_tree_selection_selected_foreach (selection
, on_each_get_iter
, &selected
);
893 return g_list_reverse (selected
);
897 gbf_project_view_update_shortcut (GbfProjectView
*view
, AnjutaProjectNode
*parent
)
902 /* Get all root node */
903 valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, NULL
);
908 AnjutaProjectNode
* old_node
= NULL
;
910 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
911 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
914 /* Shortcuts are always at the beginning */
915 if (data
->type
!= GBF_TREE_NODE_SHORTCUT
) break;
917 old_node
= gbf_tree_data_get_node (data
);
918 if (old_node
== parent
)
921 gbf_project_view_update_tree (view
, parent
, &child
);
923 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
928 compare_node_name (gconstpointer a
, gconstpointer b
)
930 const AnjutaProjectNode
*node
= (const AnjutaProjectNode
*)a
;
931 const gchar
*name
= (const gchar
*)b
;
933 return g_strcmp0 (anjuta_project_node_get_name (node
), name
);
937 gbf_project_view_update_tree (GbfProjectView
*view
, AnjutaProjectNode
*parent
, GtkTreeIter
*iter
)
942 GbfTreeData
*data
= NULL
;
944 /* Get all new nodes */
945 nodes
= gbf_project_util_all_child (parent
, ANJUTA_PROJECT_UNKNOWN
);
947 /* walk the tree nodes */
948 if (gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, iter
))
950 gboolean valid
= TRUE
;
954 AnjutaProjectNode
* data_node
= NULL
;
956 /* Look for current node */
957 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
958 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
961 data_node
= gbf_tree_data_get_node (data
);
964 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
966 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
970 if (data
->type
== GBF_TREE_NODE_UNKNOWN
)
972 node
= g_list_find_custom (nodes
, data
->name
, compare_node_name
);
976 GtkTreePath
*child_path
;
977 GtkTreeModelFilter
*filter
;
981 expanded
= data
->expanded
;
982 shortcut
= data
->has_shortcut
;
983 data_node
= (AnjutaProjectNode
*)node
->data
;
984 gbf_tree_data_free (data
);
985 data
= gbf_tree_data_new_node (data_node
);
986 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &child
,
987 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
990 /* Node already exist, remove it from the list */
991 nodes
= g_list_delete_link (nodes
, node
);
993 /* Update shortcut */
994 gbf_project_view_update_shortcut (view
, data_node
);
996 /* update recursively */
997 gbf_project_view_update_tree (view
, data_node
, &child
);
1004 gbf_project_model_add_target_shortcut (view
->model
, &iter
, data
, NULL
, &expanded
);
1007 /* Expand shortcut */
1008 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1009 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
1010 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1011 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1012 gtk_tree_path_free (child_path
);
1013 gtk_tree_path_free (path
);
1016 data
->expanded
= expanded
;
1019 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1020 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &child
);
1021 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1022 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1023 expanded
= gtk_tree_view_row_expanded (GTK_TREE_VIEW (view
), child_path
);
1024 gtk_tree_path_free (child_path
);
1025 gtk_tree_path_free (path
);
1028 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1032 node
= g_list_find (nodes
, data_node
);
1035 /* Node already exist, remove it from the list */
1036 nodes
= g_list_delete_link (nodes
, node
);
1038 /* Update shortcut */
1039 gbf_project_view_update_shortcut (view
, data_node
);
1041 /* update recursively */
1042 gbf_project_view_update_tree (view
, data_node
, &child
);
1044 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1048 /* Node has been deleted */
1049 valid
= gbf_project_model_remove (view
->model
, &child
);
1055 /* add the remaining sources, targets and groups */
1056 for (node
= nodes
; node
; node
= node
->next
)
1058 switch (anjuta_project_node_get_node_type (node
->data
))
1060 case ANJUTA_PROJECT_GROUP
:
1061 gbf_project_model_add_target_group (view
->model
, node
->data
, iter
);
1063 case ANJUTA_PROJECT_TARGET
:
1064 gbf_project_model_add_target (view
->model
, node
->data
, iter
);
1066 case ANJUTA_PROJECT_SOURCE
:
1067 gbf_project_model_add_source (view
->model
, node
->data
, iter
);
1069 case ANJUTA_PROJECT_MODULE
:
1070 gbf_project_model_add_module (view
->model
, node
->data
, iter
);
1072 case ANJUTA_PROJECT_PACKAGE
:
1073 gbf_project_model_add_package (view
->model
, node
->data
, iter
);
1075 case ANJUTA_PROJECT_ROOT
:
1076 gbf_project_model_add_root (view
->model
, node
->data
, iter
);
1083 /* Expand parent, needed if the parent hasn't any children when it was created */
1086 /* Check parent data */
1087 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), iter
,
1088 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1093 GtkTreePath
*child_path
;
1094 GtkTreeModelFilter
*filter
;
1096 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1097 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), iter
);
1098 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1099 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1100 gtk_tree_path_free (child_path
);
1101 gtk_tree_path_free (path
);
1102 data
->expanded
= FALSE
;
1107 /* Shorcuts functions
1108 *---------------------------------------------------------------------------*/
1111 gbf_project_view_sort_shortcuts (GbfProjectView
*view
)
1113 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1114 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1115 GTK_SORT_ASCENDING
);
1116 gbf_project_model_sort_shortcuts (view
->model
);
1117 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1118 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1119 GTK_SORT_ASCENDING
);
1124 gbf_project_view_get_shortcut_list (GbfProjectView
*view
)
1127 GtkTreeModel
* model
;
1131 model
= GTK_TREE_MODEL (view
->model
);
1134 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1136 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (model
), &iter
))
1139 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1140 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1143 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
1147 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
->shortcut
))
1152 str
= g_string_new (NULL
);
1158 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1159 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1162 if (data
->node
!= NULL
)
1164 if (str
->len
!= 0) g_string_prepend (str
, "//");
1165 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1168 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1169 list
= g_list_prepend (list
, str
->str
);
1170 g_string_free (str
, FALSE
);
1174 list
= g_list_reverse (list
);
1181 save_expanded_node (GtkTreeView
*view
, GtkTreePath
*path
, gpointer user_data
)
1183 GList
**list
= (GList
**)user_data
;
1184 GtkTreeModel
*model
;
1187 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1189 if (gtk_tree_model_get_iter (model
, &iter
, path
))
1194 str
= g_string_new (NULL
);
1200 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1201 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1204 if (data
->node
!= NULL
)
1206 if (str
->len
!= 0) g_string_prepend (str
, "//");
1207 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1210 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1212 *list
= g_list_prepend (*list
, str
->str
);
1213 g_string_free (str
, FALSE
);
1218 gbf_project_view_get_expanded_list (GbfProjectView
*view
)
1222 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (view
), save_expanded_node
, &list
);
1223 list
= g_list_reverse (list
);
1229 gbf_project_view_remove_all_shortcut (GbfProjectView
* view
)
1231 GtkTreeModel
* model
;
1235 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1237 /* Remove all current shortcuts */
1238 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1243 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1244 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1247 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
1249 valid
= gbf_project_model_remove (GBF_PROJECT_MODEL (model
), &iter
);
1253 /* No more shortcut */
1260 gbf_project_view_set_shortcut_list (GbfProjectView
*view
, GList
*shortcuts
)
1264 gbf_project_model_set_default_shortcut (view
->model
, shortcuts
== NULL
);
1266 for (item
= g_list_first (shortcuts
); item
!= NULL
; item
= g_list_next (item
))
1268 gchar
*name
= (gchar
*)item
->data
;
1271 GtkTreeIter
*parent
= NULL
;
1275 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1276 if (end
!= NULL
) *end
= '\0';
1279 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1283 /* Create proxy node */
1284 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1285 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1286 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1287 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1291 data
->has_shortcut
= TRUE
;
1293 /* Create another proxy at root level to keep shortcut order */
1294 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1295 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, NULL
);
1296 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1297 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1305 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1306 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1308 if (end
== NULL
) data
->has_shortcut
= TRUE
;
1318 while (end
!= NULL
);
1325 gbf_project_view_set_expanded_list (GbfProjectView
*view
, GList
*expand
)
1329 for (item
= g_list_first (expand
); item
!= NULL
; item
= g_list_next (item
))
1331 gchar
*name
= (gchar
*)item
->data
;
1334 GtkTreeIter
*parent
= NULL
;
1338 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1339 if (end
!= NULL
) *end
= '\0';
1342 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1346 /* Create proxy node */
1347 data
= gbf_tree_data_new_proxy (name
, TRUE
);
1348 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1349 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1350 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1357 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1358 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1360 data
->expanded
= TRUE
;
1370 while (end
!= NULL
);
1377 gbf_project_view_get_node_from_iter (GbfProjectView
*view
, GtkTreeIter
*iter
)
1379 return gbf_project_model_get_node (view
->model
, iter
);
1383 gbf_project_view_get_node_from_file (GbfProjectView
*view
, AnjutaProjectNodeType type
, GFile
*file
)
1386 AnjutaProjectNode
*node
= NULL
;
1388 if (gbf_project_model_find_file (view
->model
, &iter
, NULL
, type
, file
))
1391 node
= gbf_project_model_get_node (view
->model
, &iter
);
1398 gbf_project_view_remove_data (GbfProjectView
*view
, GbfTreeData
*data
, GError
**error
)
1402 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
))
1404 gbf_project_model_remove (view
->model
, &iter
);
1415 on_node_loaded (AnjutaPmProject
*sender
, AnjutaProjectNode
*node
, gboolean complete
, GError
*error
, GbfProjectView
*view
)
1419 g_warning ("unable to load node");
1420 g_signal_emit (G_OBJECT (view
), NODE_LOADED
, 0, NULL
, complete
, error
);
1427 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1428 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1429 GTK_SORT_ASCENDING
);
1431 found
= gbf_project_model_find_node (view
->model
, &iter
, NULL
, node
);
1434 if (anjuta_project_node_get_node_type (node
) != ANJUTA_PROJECT_ROOT
)
1436 g_critical ("Unable to find node %s", anjuta_project_node_get_name (node
));
1441 GtkTreePath
*child_path
;
1442 GtkTreeModelFilter
*filter
;
1444 if (!gbf_project_model_find_child_name (view
->model
, &iter
, NULL
, anjuta_project_node_get_name (node
)))
1446 gbf_project_model_add_root (view
->model
, node
, &iter
);
1452 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1453 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1455 if (data
->type
== GBF_TREE_NODE_UNKNOWN
)
1457 /* Replace with real node */
1458 GbfTreeData
*new_data
;
1460 new_data
= gbf_tree_data_new_node (node
);
1461 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1462 GBF_PROJECT_MODEL_COLUMN_DATA
, new_data
,
1464 gbf_tree_data_free (data
);
1466 gbf_project_view_update_tree (view
, node
, &iter
);
1469 /* Expand root node */
1470 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
1471 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1472 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1473 gtk_tree_view_expand_row (GTK_TREE_VIEW (view
), child_path
, FALSE
);
1474 gtk_tree_path_free (child_path
);
1475 gtk_tree_path_free (path
);
1480 gbf_project_view_update_tree (view
, node
, &iter
);
1482 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1483 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1484 GTK_SORT_ASCENDING
);
1486 g_signal_emit (G_OBJECT (view
), signals
[NODE_LOADED
], 0, found
? &iter
: NULL
, complete
, NULL
);
1491 // Add shortcut for all new primary targets
1492 gbf_project_model_set_default_shortcut (view
->model
, TRUE
);
1498 gbf_project_view_set_project (GbfProjectView
*view
, AnjutaPmProject
*project
)
1500 g_signal_connect (project
, "loaded", G_CALLBACK (on_node_loaded
), view
);
1502 gbf_project_model_set_project (view
->model
, project
);
1506 gbf_project_view_set_parent_view (GbfProjectView
*view
,
1507 GbfProjectView
*parent
,
1511 if (view
->model
!= NULL
) g_object_unref (view
->model
);
1512 if (view
->filter
!= NULL
) g_object_unref (view
->model
);
1514 view
->model
= g_object_ref (parent
->model
);
1515 view
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (view
->model
), root
));
1516 gtk_tree_view_set_model (GTK_TREE_VIEW (view
), GTK_TREE_MODEL (view
->filter
));
1520 gbf_project_view_set_visible_func (GbfProjectView
*view
,
1521 GtkTreeModelFilterVisibleFunc func
,
1523 GDestroyNotify destroy
)
1527 gtk_tree_model_filter_set_visible_func (view
->filter
, is_project_node_visible
, view
, NULL
);
1531 gtk_tree_model_filter_set_visible_func (view
->filter
, func
, data
, destroy
);
1533 gtk_tree_model_filter_refilter (view
->filter
);
1537 gbf_project_view_find_file (GbfProjectView
*view
, GtkTreeIter
* iter
, GFile
*file
, GbfTreeNodeType type
)
1539 return gbf_project_model_find_file (view
->model
, iter
, NULL
, type
, file
);
1543 gbf_project_view_get_model (GbfProjectView
*view
)
1549 gbf_project_view_get_project_root (GbfProjectView
*view
, GtkTreeIter
*iter
)
1551 GtkTreeModel
*model
;
1552 GtkTreeModel
*view_model
;
1554 gboolean ok
= FALSE
;
1556 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1558 if (GTK_IS_TREE_MODEL_FILTER (model
))
1560 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
1563 path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
1566 ok
= gtk_tree_model_get_iter (model
, iter
, path
);
1567 gtk_tree_path_free (path
);