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"
51 static guint signals
[LAST_SIGNAL
] = { 0 };
53 /* Project model filter with drag and drop support
54 *---------------------------------------------------------------------------*/
57 GtkTreeModelFilter parent
;
58 } PmProjectModelFilter
;
61 GtkTreeModelFilterClass parent_class
;
62 } PmProjectModelFilterClass
;
64 #define PM_TYPE_PROJECT_MODEL_FILTER (pm_project_model_filter_get_type ())
65 #define PM_PROJECT_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PM_TYPE_PROJECT_MODEL_FILTER, PmProjectModelFilter))
69 pm_project_model_filter_class_init (PmProjectModelFilterClass
*class)
74 pm_project_model_filter_init (PmProjectModelFilter
*model
)
79 idrag_source_row_draggable (GtkTreeDragSource
*drag_source
, GtkTreePath
*path
)
83 gboolean retval
= FALSE
;
85 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source
), &iter
, path
))
88 gtk_tree_model_get (GTK_TREE_MODEL (drag_source
), &iter
,
89 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
92 if (data
->is_shortcut
) {
93 /* shortcuts can be moved */
96 } else if (data
->type
== GBF_TREE_NODE_TARGET
) {
97 /* don't allow duplicate shortcuts */
98 if (data
->shortcut
== NULL
)
106 idrag_source_drag_data_delete (GtkTreeDragSource
*drag_source
, GtkTreePath
*path
)
112 idrag_dest_drag_data_received (GtkTreeDragDest
*drag_dest
,
114 GtkSelectionData
*selection_data
)
116 GtkTreeModel
*src_model
= NULL
;
117 GtkTreePath
*src_path
= NULL
;
118 GtkTreeModel
*project_model
;
119 gboolean retval
= FALSE
;
121 if (GTK_IS_TREE_MODEL_FILTER (drag_dest
))
123 project_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (drag_dest
));
127 project_model
= GTK_TREE_MODEL (drag_dest
);
129 g_return_val_if_fail (GBF_IS_PROJECT_MODEL (project_model
), FALSE
);
131 if (gtk_tree_get_row_drag_data (selection_data
,
134 src_model
== GTK_TREE_MODEL (project_model
)) {
137 GbfTreeData
*data
= NULL
;
139 if (gtk_tree_model_get_iter (src_model
, &iter
, src_path
)) {
140 gtk_tree_model_get (src_model
, &iter
,
141 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
145 GtkTreePath
*child_path
;
147 child_path
= gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (drag_dest
), dest
);
148 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
150 gbf_project_model_move_target_shortcut (GBF_PROJECT_MODEL (project_model
),
151 &iter
, data
, child_path
);
155 gbf_project_model_add_target_shortcut (GBF_PROJECT_MODEL (project_model
),
156 NULL
, data
, child_path
, NULL
);
158 gtk_tree_path_free (child_path
);
165 gtk_tree_path_free (src_path
);
171 idrag_dest_row_drop_possible (GtkTreeDragDest
*drag_dest
,
172 GtkTreePath
*dest_path
,
173 GtkSelectionData
*selection_data
)
175 GtkTreeModel
*src_model
;
176 GtkTreeModel
*project_model
;
177 GtkTreePath
*src_path
;
179 gboolean retval
= FALSE
;
181 //g_return_val_if_fail (GBF_IS_PROJECT_MODEL (drag_dest), FALSE);
183 if (GTK_IS_TREE_MODEL_FILTER (drag_dest
))
185 project_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (drag_dest
));
189 project_model
= GTK_TREE_MODEL (drag_dest
);
192 if (!gtk_tree_get_row_drag_data (selection_data
,
200 if (gtk_tree_model_get_iter (src_model
, &iter
, src_path
))
202 GbfTreeData
*data
= NULL
;
204 gtk_tree_model_get (src_model
, &iter
,
205 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
209 /* can only drag to ourselves and only new toplevel nodes will
211 if (src_model
== project_model
&&
212 gtk_tree_path_get_depth (dest_path
) == 1)
214 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
220 GtkTreePath
*root_path
;
221 GtkTreePath
*child_path
;
223 root_path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model
));
224 child_path
= gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (drag_dest
), dest_path
);
225 retval
= gtk_tree_path_compare (child_path
, root_path
) <= 0;
226 gtk_tree_path_free (child_path
);
227 gtk_tree_path_free (root_path
);
232 gtk_tree_path_free (src_path
);
238 pm_project_model_filter_drag_source_iface_init (GtkTreeDragSourceIface
*iface
)
240 iface
->row_draggable
= idrag_source_row_draggable
;
241 iface
->drag_data_delete
= idrag_source_drag_data_delete
;
245 pm_project_model_filter_drag_dest_iface_init (GtkTreeDragDestIface
*iface
)
247 iface
->drag_data_received
= idrag_dest_drag_data_received
;
248 iface
->row_drop_possible
= idrag_dest_row_drop_possible
;
251 static GType
pm_project_model_filter_get_type (void);
253 G_DEFINE_TYPE_WITH_CODE (PmProjectModelFilter
,
254 pm_project_model_filter
,
255 GTK_TYPE_TREE_MODEL_FILTER
,
256 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE
,
257 pm_project_model_filter_drag_source_iface_init
)
258 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST
,
259 pm_project_model_filter_drag_dest_iface_init
));
262 static GtkTreeModel
*
263 pm_project_model_filter_new (GtkTreeModel
*child_model
,
266 PmProjectModelFilter
*model
;
268 model
= g_object_new (PM_TYPE_PROJECT_MODEL_FILTER
,
269 "child-model", child_model
,
270 "virtual-root", root
,
273 return GTK_TREE_MODEL (model
);
280 static void gbf_project_view_class_init (GbfProjectViewClass
*klass
);
281 static void gbf_project_view_init (GbfProjectView
*tree
);
282 static void destroy (GtkWidget
*object
);
284 static void set_pixbuf (GtkCellLayout
*layout
,
285 GtkCellRenderer
*cell
,
289 static void set_text (GtkCellLayout
*layout
,
290 GtkCellRenderer
*cell
,
296 G_DEFINE_TYPE(GbfProjectView
, gbf_project_view
, GTK_TYPE_TREE_VIEW
);
299 row_activated (GtkTreeView
*tree_view
,
301 GtkTreeViewColumn
*column
)
306 AnjutaProjectNode
*node
;
308 model
= gtk_tree_view_get_model (tree_view
);
310 gtk_tree_model_get_iter (GTK_TREE_MODEL (model
), &iter
, path
);
312 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
313 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
316 node
= gbf_tree_data_get_node (data
);
319 switch (anjuta_project_node_get_node_type (node
))
321 case ANJUTA_PROJECT_GROUP
:
322 case ANJUTA_PROJECT_ROOT
:
323 case ANJUTA_PROJECT_TARGET
:
324 case ANJUTA_PROJECT_MODULE
:
325 case ANJUTA_PROJECT_PACKAGE
:
326 if (!gtk_tree_view_row_expanded (tree_view
, path
))
328 gtk_tree_view_expand_row (tree_view
, path
, FALSE
);
332 gtk_tree_view_collapse_row (tree_view
, path
);
336 g_signal_emit (G_OBJECT (tree_view
),
337 signals
[NODE_SELECTED
], 0,
344 static void on_node_loaded (AnjutaPmProject
*sender
, AnjutaProjectNode
*node
, gboolean complete
, GError
*error
, GbfProjectView
*view
);
347 dispose (GObject
*object
)
349 GbfProjectView
*view
;
351 view
= GBF_PROJECT_VIEW (object
);
355 g_object_unref (G_OBJECT (view
->filter
));
360 AnjutaPmProject
*old_project
;
362 old_project
= gbf_project_model_get_project (view
->model
);
363 if (old_project
!= NULL
)
365 g_signal_handlers_disconnect_by_func (old_project
, G_CALLBACK (on_node_loaded
), view
);
367 g_object_unref (G_OBJECT (view
->model
));
371 G_OBJECT_CLASS (gbf_project_view_parent_class
)->dispose (object
);
375 destroy (GtkWidget
*object
)
377 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
)
378 (* GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->destroy
) (object
);
382 get_icon (GFile
*file
)
384 const gchar
** icon_names
;
385 GtkIconInfo
* icon_info
;
387 GdkPixbuf
* pixbuf
= NULL
;
388 GFileInfo
* file_info
;
389 GError
*error
= NULL
;
391 file_info
= g_file_query_info (file
,
392 G_FILE_ATTRIBUTE_STANDARD_ICON
,
393 G_FILE_QUERY_INFO_NONE
,
397 if (file_info
!= NULL
)
399 icon
= g_file_info_get_icon(file_info
);
400 g_object_get (icon
, "names", &icon_names
, NULL
);
401 icon_info
= gtk_icon_theme_choose_icon (gtk_icon_theme_get_default(),
404 GTK_ICON_LOOKUP_GENERIC_FALLBACK
);
405 if (icon_info
!= NULL
)
407 pixbuf
= gtk_icon_info_load_icon (icon_info
, NULL
);
408 gtk_icon_info_free(icon_info
);
410 g_object_unref (file_info
);
415 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
416 GTK_STOCK_MISSING_IMAGE
,
418 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
426 set_pixbuf (GtkCellLayout
*layout
,
427 GtkCellRenderer
*cell
,
432 GbfTreeData
*data
= NULL
;
433 GdkPixbuf
*pixbuf
= NULL
;
435 gtk_tree_model_get (model
, iter
,
436 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
437 g_return_if_fail (data
!= NULL
);
438 /* FIXME: segmentation fault with shortcut when corresponding
439 * data is removed before the shortcut, so data = NULL.
440 * Perhaps we can add a GtkTreeReference to the shortcut
441 * node to remove the shortcut when the node is destroyed */
443 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
445 data
= data
->shortcut
;
447 switch (data
->type
) {
448 case GBF_TREE_NODE_SOURCE
:
450 pixbuf
= get_icon (data
->source
);
453 case GBF_TREE_NODE_ROOT
:
454 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
457 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
460 case GBF_TREE_NODE_GROUP
:
461 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
464 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
467 case GBF_TREE_NODE_TARGET
:
469 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
472 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
476 case GBF_TREE_NODE_MODULE
:
478 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
479 GTK_STOCK_DND_MULTIPLE
,
481 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
485 case GBF_TREE_NODE_PACKAGE
:
487 pixbuf
= gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
490 GTK_ICON_LOOKUP_GENERIC_FALLBACK
,
495 /* Can reach this if type = GBF_TREE_NODE_SHORTCUT. It
496 * means a shortcut with the original data removed */
500 g_object_set (GTK_CELL_RENDERER (cell
), "pixbuf", pixbuf
, NULL
);
502 g_object_unref (pixbuf
);
506 set_text (GtkCellLayout
*layout
,
507 GtkCellRenderer
*cell
,
514 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
515 /* data can be NULL just after gtk_tree_store_insert before
516 calling gtk_tree_store_set */
517 g_object_set (GTK_CELL_RENDERER (cell
), "text",
518 data
== NULL
? "" : data
->name
, NULL
);
522 search_equal_func (GtkTreeModel
*model
, gint column
,
523 const gchar
*key
, GtkTreeIter
*iter
,
529 gtk_tree_model_get (model
, iter
, GBF_PROJECT_MODEL_COLUMN_DATA
, &data
, -1);
530 if (strncmp (data
->name
, key
, strlen (key
)) == 0)
536 draw (GtkWidget
*widget
, cairo_t
*cr
)
538 GtkTreeModel
*view_model
;
539 GtkTreeModel
*model
= NULL
;
540 GtkTreeView
*tree_view
;
541 gint event_handled
= FALSE
;
543 if (GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw
!= NULL
)
544 GTK_WIDGET_CLASS (gbf_project_view_parent_class
)->draw (widget
, cr
);
546 tree_view
= GTK_TREE_VIEW (widget
);
547 view_model
= gtk_tree_view_get_model (tree_view
);
548 if (GTK_IS_TREE_MODEL_FILTER (view_model
))
550 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
552 if (gtk_cairo_should_draw_window (cr
, gtk_tree_view_get_bin_window (tree_view
)) &&
553 model
&& GBF_IS_PROJECT_MODEL (model
)) {
557 /* paint an horizontal ruler to separate the project
558 * tree from the target shortcuts */
560 root
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
562 if (view_model
!= model
)
565 GtkTreePath
*child_path
;
567 child_path
= gtk_tree_model_filter_convert_child_path_to_path (GTK_TREE_MODEL_FILTER (view_model
), root
);
568 gtk_tree_path_free (root
);
571 gtk_tree_view_get_background_area (
572 tree_view
, root
, gtk_tree_view_get_column (tree_view
, 0), &rect
);
573 gtk_render_line (gtk_widget_get_style_context (widget
),
576 rect
.x
+ rect
.width
, rect
.y
);
577 gtk_tree_path_free (root
);
581 return event_handled
;
585 gbf_project_view_class_init (GbfProjectViewClass
*klass
)
587 GObjectClass
*g_object_class
;
588 GtkWidgetClass
*widget_class
;
589 GtkTreeViewClass
*tree_view_class
;
591 g_object_class
= G_OBJECT_CLASS (klass
);
592 widget_class
= GTK_WIDGET_CLASS (klass
);
593 tree_view_class
= GTK_TREE_VIEW_CLASS (klass
);
595 g_object_class
->dispose
= dispose
;
596 widget_class
->destroy
= destroy
;
597 widget_class
->draw
= draw
;
598 tree_view_class
->row_activated
= row_activated
;
600 signals
[NODE_SELECTED
] =
601 g_signal_new ("node-selected",
602 GBF_TYPE_PROJECT_VIEW
,
604 G_STRUCT_OFFSET (GbfProjectViewClass
,
607 g_cclosure_marshal_VOID__POINTER
,
608 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
609 signals
[NODE_LOADED
] =
610 g_signal_new ("node-loaded",
611 GBF_TYPE_PROJECT_VIEW
,
613 G_STRUCT_OFFSET (GbfProjectViewClass
,
616 pm_cclosure_marshal_VOID__POINTER_BOOLEAN_BOXED
,
625 is_project_node_visible (GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
629 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
630 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
633 return (data
!= NULL
) && (gbf_tree_data_get_node (data
) != NULL
);
637 gbf_project_view_init (GbfProjectView
*tree
)
639 GtkTreeViewColumn
*column
;
640 static GtkTargetEntry row_targets
[] = {
641 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET
, 0 }
644 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree
), FALSE
);
645 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (tree
), TRUE
);
646 gtk_tree_view_set_search_column (GTK_TREE_VIEW (tree
), 0);
647 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (tree
),
651 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree
),
654 G_N_ELEMENTS (row_targets
),
656 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tree
),
658 G_N_ELEMENTS (row_targets
),
661 /* set renderer for files column. */
662 column
= gtk_tree_view_column_new ();
663 pm_setup_project_renderer (GTK_CELL_LAYOUT (column
));
664 gtk_tree_view_append_column (GTK_TREE_VIEW (tree
), column
);
667 tree
->model
= gbf_project_model_new (NULL
);
668 tree
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (tree
->model
), NULL
));
669 gtk_tree_model_filter_set_visible_func (tree
->filter
, is_project_node_visible
, tree
, NULL
);
671 gtk_tree_view_set_model (GTK_TREE_VIEW (tree
), GTK_TREE_MODEL (tree
->filter
));
675 gbf_project_view_new (void)
677 return GTK_WIDGET (g_object_new (GBF_TYPE_PROJECT_VIEW
, NULL
));
681 gbf_project_view_find_selected (GbfProjectView
*view
, AnjutaProjectNodeType type
)
683 AnjutaProjectNode
*node
= NULL
;
686 g_return_val_if_fail (view
!= NULL
, NULL
);
687 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
689 data
= gbf_project_view_get_first_selected (view
, NULL
);
693 node
= gbf_tree_data_get_node (data
);
695 /* walk up the hierarchy searching for a node of the given type */
696 while ((node
!= NULL
) && (type
!= ANJUTA_PROJECT_UNKNOWN
) && (anjuta_project_node_get_node_type (node
) != type
))
698 node
= anjuta_project_node_parent (node
);
706 gbf_project_view_find_selected_state (GtkTreeView
*view
,
707 AnjutaProjectNodeState state
)
709 AnjutaProjectNode
*node
= NULL
;
712 g_return_val_if_fail (view
!= NULL
, NULL
);
713 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
715 data
= gbf_project_view_get_first_selected (GBF_PROJECT_VIEW (view
), NULL
);
719 node
= gbf_tree_data_get_node (data
);
721 /* walk up the hierarchy searching for a node of the given type */
722 while ((node
!= NULL
) && (state
!= 0) && !(anjuta_project_node_get_state (node
) & state
))
724 node
= anjuta_project_node_parent (node
);
732 gbf_project_view_get_first_selected (GbfProjectView
*view
, GtkTreeIter
* selected
)
734 GtkTreeSelection
*selection
;
735 GbfTreeData
*data
= NULL
;
739 g_return_val_if_fail (view
!= NULL
, NULL
);
740 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), NULL
);
742 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
743 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
748 if (gtk_tree_model_get_iter (model
, &iter
, list
->data
))
752 if (GTK_IS_TREE_MODEL_FILTER (model
))
754 GtkTreeIter child_iter
;
756 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model
), &child_iter
, &iter
);
757 *selected
= child_iter
;
765 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
766 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
769 g_list_foreach (list
, (GFunc
)gtk_tree_path_free
, NULL
);
777 gbf_project_view_set_cursor_to_iter (GbfProjectView
*view
,
778 GtkTreeIter
*selected
)
780 GtkTreeIter view_iter
;
782 if (pm_convert_project_iter_to_model_iter (GTK_TREE_MODEL (view
->filter
), &view_iter
, selected
))
786 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->filter
), &view_iter
);
789 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), path
);
791 gtk_tree_view_set_cursor (GTK_TREE_VIEW (view
), path
, NULL
, FALSE
);
792 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view
), path
, NULL
,
794 gtk_tree_path_free (path
);
801 on_each_get_data (GtkTreeModel
*model
,
806 GList
**selected
= (GList
**)user_data
;
809 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
810 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
813 *selected
= g_list_prepend (*selected
, data
);
817 gbf_project_view_get_all_selected (GbfProjectView
*view
)
819 GtkTreeSelection
*selection
;
820 GList
*selected
= NULL
;
822 g_return_val_if_fail (view
!= NULL
, FALSE
);
823 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
825 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
826 gtk_tree_selection_selected_foreach (selection
, on_each_get_data
, &selected
);
828 return g_list_reverse (selected
);
832 on_each_get_iter (GtkTreeModel
*model
,
837 GList
**selected
= (GList
**)user_data
;
839 *selected
= g_list_prepend (*selected
, gtk_tree_iter_copy (iter
));
843 gbf_project_view_get_all_selected_iter (GbfProjectView
*view
)
845 GtkTreeSelection
*selection
;
846 GList
*selected
= NULL
;
848 g_return_val_if_fail (view
!= NULL
, FALSE
);
849 g_return_val_if_fail (GBF_IS_PROJECT_VIEW (view
), FALSE
);
851 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
852 gtk_tree_selection_selected_foreach (selection
, on_each_get_iter
, &selected
);
854 return g_list_reverse (selected
);
858 gbf_project_view_update_shortcut (GbfProjectView
*view
, AnjutaProjectNode
*parent
)
863 /* Get all root node */
864 valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, NULL
);
869 AnjutaProjectNode
* old_node
= NULL
;
871 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
872 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
875 /* Shortcuts are always at the beginning */
876 if (data
->type
!= GBF_TREE_NODE_SHORTCUT
) break;
878 old_node
= gbf_tree_data_get_node (data
);
879 if (old_node
== parent
)
882 gbf_project_view_update_tree (view
, parent
, &child
);
884 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
889 compare_node_name (gconstpointer a
, gconstpointer b
)
891 const AnjutaProjectNode
*node
= (const AnjutaProjectNode
*)a
;
892 const gchar
*name
= (const gchar
*)b
;
894 return g_strcmp0 (anjuta_project_node_get_name (node
), name
);
898 list_visible_children (AnjutaProjectNode
*parent
)
900 AnjutaProjectNode
*node
;
903 for (node
= anjuta_project_node_first_child (parent
); node
!= NULL
; node
= anjuta_project_node_next_sibling (node
))
905 if (anjuta_project_node_get_full_type (node
) & ANJUTA_PROJECT_FRAME
) continue;
906 if (anjuta_project_node_get_node_type (node
) != ANJUTA_PROJECT_OBJECT
)
908 list
= g_list_prepend (list
, node
);
912 /* object node are hidden, get their children instead */
913 GList
*children
= list_visible_children (node
);
915 children
= g_list_reverse (children
);
916 list
= g_list_concat (children
, list
);
919 list
= g_list_reverse (list
);
925 gbf_project_view_update_tree (GbfProjectView
*view
, AnjutaProjectNode
*parent
, GtkTreeIter
*iter
)
930 GbfTreeData
*data
= NULL
;
932 /* Get all new nodes */
933 nodes
= list_visible_children (parent
);
935 /* walk the tree nodes */
936 if (gtk_tree_model_iter_children (GTK_TREE_MODEL (view
->model
), &child
, iter
))
938 gboolean valid
= TRUE
;
942 AnjutaProjectNode
* data_node
= NULL
;
944 /* Look for current node */
945 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &child
,
946 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
949 data_node
= gbf_tree_data_get_node (data
);
952 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
954 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
958 if (data
->type
== GBF_TREE_NODE_UNKNOWN
)
960 node
= g_list_find_custom (nodes
, data
->name
, compare_node_name
);
964 GtkTreePath
*child_path
;
965 GtkTreeModelFilter
*filter
;
969 expanded
= data
->expanded
;
970 shortcut
= data
->has_shortcut
;
971 data_node
= (AnjutaProjectNode
*)node
->data
;
972 gbf_tree_data_free (data
);
973 data
= gbf_tree_data_new_node (data_node
);
974 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &child
,
975 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
978 /* Node already exist, remove it from the list */
979 nodes
= g_list_delete_link (nodes
, node
);
981 /* Update shortcut */
982 gbf_project_view_update_shortcut (view
, data_node
);
984 /* update recursively */
985 gbf_project_view_update_tree (view
, data_node
, &child
);
992 gbf_project_model_add_target_shortcut (view
->model
, &iter
, data
, NULL
, &expanded
);
995 /* Expand shortcut */
996 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
997 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
998 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
999 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1000 gtk_tree_path_free (child_path
);
1001 gtk_tree_path_free (path
);
1004 data
->expanded
= expanded
;
1007 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1008 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &child
);
1009 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1010 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1011 expanded
= gtk_tree_view_row_expanded (GTK_TREE_VIEW (view
), child_path
);
1012 gtk_tree_path_free (child_path
);
1013 gtk_tree_path_free (path
);
1016 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1020 node
= g_list_find (nodes
, data_node
);
1023 /* Node already exist, remove it from the list */
1024 nodes
= g_list_delete_link (nodes
, node
);
1026 /* Update shortcut */
1027 gbf_project_view_update_shortcut (view
, data_node
);
1029 /* update recursively */
1030 gbf_project_view_update_tree (view
, data_node
, &child
);
1032 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (view
->model
), &child
);
1036 /* Node has been deleted */
1037 valid
= gbf_project_model_remove (view
->model
, &child
);
1043 /* add the remaining sources, targets and groups */
1044 for (node
= nodes
; node
; node
= node
->next
)
1046 gbf_project_model_add_node (view
->model
, node
->data
, iter
, 0);
1049 g_list_free (nodes
);
1051 /* Expand parent, needed if the parent hasn't any children when it was created */
1054 /* Check parent data */
1055 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), iter
,
1056 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1061 GtkTreePath
*child_path
;
1062 GtkTreeModelFilter
*filter
;
1064 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1065 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), iter
);
1066 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1067 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view
), child_path
);
1068 gtk_tree_path_free (child_path
);
1069 gtk_tree_path_free (path
);
1070 data
->expanded
= FALSE
;
1075 /* Shorcuts functions
1076 *---------------------------------------------------------------------------*/
1079 gbf_project_view_sort_shortcuts (GbfProjectView
*view
)
1081 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1082 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1083 GTK_SORT_ASCENDING
);
1084 gbf_project_model_sort_shortcuts (view
->model
);
1085 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1086 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1087 GTK_SORT_ASCENDING
);
1092 gbf_project_view_get_shortcut_list (GbfProjectView
*view
)
1095 GtkTreeModel
* model
;
1099 model
= GTK_TREE_MODEL (view
->model
);
1102 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1104 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL (model
), &iter
))
1107 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1108 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1111 if ((data
->type
== GBF_TREE_NODE_SHORTCUT
) && (data
->shortcut
!= NULL
))
1115 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
->shortcut
))
1120 str
= g_string_new (NULL
);
1126 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1127 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1130 if (data
->node
!= NULL
)
1132 if (str
->len
!= 0) g_string_prepend (str
, "//");
1133 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1136 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1137 list
= g_list_prepend (list
, str
->str
);
1138 g_string_free (str
, FALSE
);
1142 list
= g_list_reverse (list
);
1149 save_expanded_node (GtkTreeView
*view
, GtkTreePath
*path
, gpointer user_data
)
1151 GList
**list
= (GList
**)user_data
;
1152 GtkTreeModel
*model
;
1155 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1157 if (gtk_tree_model_get_iter (model
, &iter
, path
))
1162 str
= g_string_new (NULL
);
1168 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1169 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1172 if (data
->node
!= NULL
)
1174 if (str
->len
!= 0) g_string_prepend (str
, "//");
1175 g_string_prepend (str
, anjuta_project_node_get_name (data
->node
));
1178 while (gtk_tree_model_iter_parent (model
, &iter
, &child
));
1180 *list
= g_list_prepend (*list
, str
->str
);
1181 g_string_free (str
, FALSE
);
1186 gbf_project_view_get_expanded_list (GbfProjectView
*view
)
1190 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (view
), save_expanded_node
, &list
);
1191 list
= g_list_reverse (list
);
1197 gbf_project_view_remove_all_shortcut (GbfProjectView
* view
)
1199 GtkTreeModel
* model
;
1203 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1205 /* Remove all current shortcuts */
1206 for (valid
= gtk_tree_model_iter_children (GTK_TREE_MODEL (model
), &iter
, NULL
);
1211 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
1212 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1215 if (data
->type
== GBF_TREE_NODE_SHORTCUT
)
1217 valid
= gbf_project_model_remove (GBF_PROJECT_MODEL (model
), &iter
);
1221 /* No more shortcut */
1228 gbf_project_view_set_shortcut_list (GbfProjectView
*view
, GList
*shortcuts
)
1232 gbf_project_model_set_default_shortcut (view
->model
, shortcuts
== NULL
);
1234 for (item
= g_list_first (shortcuts
); item
!= NULL
; item
= g_list_next (item
))
1236 gchar
*name
= (gchar
*)item
->data
;
1239 GtkTreeIter
*parent
= NULL
;
1243 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1244 if (end
!= NULL
) *end
= '\0';
1247 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1251 /* Create proxy node */
1252 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1253 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1254 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1255 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1259 data
->has_shortcut
= TRUE
;
1261 /* Create another proxy at root level to keep shortcut order */
1262 data
= gbf_tree_data_new_proxy (name
, FALSE
);
1263 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, NULL
);
1264 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1265 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1273 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1274 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1276 if (end
== NULL
) data
->has_shortcut
= TRUE
;
1286 while (end
!= NULL
);
1293 gbf_project_view_set_expanded_list (GbfProjectView
*view
, GList
*expand
)
1297 for (item
= g_list_first (expand
); item
!= NULL
; item
= g_list_next (item
))
1299 gchar
*name
= (gchar
*)item
->data
;
1302 GtkTreeIter
*parent
= NULL
;
1306 end
= strstr (name
, "/" "/"); /* Avoid troubles with auto indent */
1307 if (end
!= NULL
) *end
= '\0';
1310 if (!gbf_project_model_find_child_name (view
->model
, &iter
, parent
, name
))
1314 /* Create proxy node */
1315 data
= gbf_tree_data_new_proxy (name
, TRUE
);
1316 gtk_tree_store_append (GTK_TREE_STORE (view
->model
), &iter
, parent
);
1317 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1318 GBF_PROJECT_MODEL_COLUMN_DATA
, data
,
1325 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1326 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1328 data
->expanded
= TRUE
;
1338 while (end
!= NULL
);
1345 gbf_project_view_get_node_from_iter (GbfProjectView
*view
, GtkTreeIter
*iter
)
1347 return gbf_project_model_get_node (view
->model
, iter
);
1351 gbf_project_view_get_node_from_file (GbfProjectView
*view
, AnjutaProjectNodeType type
, GFile
*file
)
1354 AnjutaProjectNode
*node
= NULL
;
1356 if (gbf_project_model_find_file (view
->model
, &iter
, NULL
, gbf_tree_node_type_from_project (type
), file
))
1359 node
= gbf_project_model_get_node (view
->model
, &iter
);
1366 gbf_project_view_remove_data (GbfProjectView
*view
, GbfTreeData
*data
, GError
**error
)
1370 if (gbf_project_model_find_tree_data (view
->model
, &iter
, data
))
1372 gbf_project_model_remove (view
->model
, &iter
);
1383 on_node_loaded (AnjutaPmProject
*sender
, AnjutaProjectNode
*node
, gboolean complete
, GError
*error
, GbfProjectView
*view
)
1387 g_warning ("unable to load node");
1388 g_signal_emit (G_OBJECT (view
), NODE_LOADED
, 0, NULL
, complete
, error
);
1395 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1396 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID
,
1397 GTK_SORT_ASCENDING
);
1399 found
= gbf_project_model_find_node (view
->model
, &iter
, NULL
, node
);
1402 if (anjuta_project_node_parent (node
) != NULL
)
1404 g_critical ("Unable to find node %s", anjuta_project_node_get_name (node
));
1409 GtkTreePath
*child_path
;
1410 GtkTreeModelFilter
*filter
;
1412 if (!gbf_project_model_find_child_name (view
->model
, &iter
, NULL
, anjuta_project_node_get_name (node
)))
1414 gbf_project_model_add_node (view
->model
, node
, NULL
, 0);
1415 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view
->model
), &iter
);
1420 GbfTreeData
*new_data
;
1422 /* Replace with new node */
1423 gtk_tree_model_get (GTK_TREE_MODEL (view
->model
), &iter
,
1424 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1426 new_data
= gbf_tree_data_new_node (node
);
1427 gtk_tree_store_set (GTK_TREE_STORE (view
->model
), &iter
,
1428 GBF_PROJECT_MODEL_COLUMN_DATA
, new_data
,
1430 gbf_tree_data_free (data
);
1431 gbf_project_view_update_tree (view
, node
, &iter
);
1434 /* Expand root node */
1435 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (view
->model
), &iter
);
1436 filter
= GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (view
)));
1437 child_path
= gtk_tree_model_filter_convert_child_path_to_path (filter
, path
);
1438 if (child_path
!= NULL
) gtk_tree_view_expand_row (GTK_TREE_VIEW (view
), child_path
, FALSE
);
1439 gtk_tree_path_free (child_path
);
1440 gtk_tree_path_free (path
);
1445 gbf_project_view_update_tree (view
, node
, &iter
);
1447 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (view
->model
),
1448 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
1449 GTK_SORT_ASCENDING
);
1451 g_signal_emit (G_OBJECT (view
), signals
[NODE_LOADED
], 0, found
? &iter
: NULL
, complete
, NULL
);
1456 // Add shortcut for all new primary targets
1457 gbf_project_model_set_default_shortcut (view
->model
, TRUE
);
1463 gbf_project_view_set_project (GbfProjectView
*view
, AnjutaPmProject
*project
)
1465 AnjutaPmProject
*old_project
;
1467 old_project
= gbf_project_model_get_project (view
->model
);
1468 if (old_project
!= NULL
)
1470 g_signal_handlers_disconnect_by_func (old_project
, G_CALLBACK (on_node_loaded
), view
);
1473 g_signal_connect (project
, "loaded", G_CALLBACK (on_node_loaded
), view
);
1475 gbf_project_model_set_project (view
->model
, project
);
1479 gbf_project_view_set_parent_view (GbfProjectView
*view
,
1480 GbfProjectView
*parent
,
1484 if (view
->model
!= NULL
) g_object_unref (view
->model
);
1485 if (view
->filter
!= NULL
) g_object_unref (view
->model
);
1487 view
->model
= g_object_ref (parent
->model
);
1488 view
->filter
= GTK_TREE_MODEL_FILTER (pm_project_model_filter_new (GTK_TREE_MODEL (view
->model
), root
));
1489 gtk_tree_view_set_model (GTK_TREE_VIEW (view
), GTK_TREE_MODEL (view
->filter
));
1493 gbf_project_view_set_visible_func (GbfProjectView
*view
,
1494 GtkTreeModelFilterVisibleFunc func
,
1496 GDestroyNotify destroy
)
1500 gtk_tree_model_filter_set_visible_func (view
->filter
, is_project_node_visible
, view
, NULL
);
1504 gtk_tree_model_filter_set_visible_func (view
->filter
, func
, data
, destroy
);
1506 gtk_tree_model_filter_refilter (view
->filter
);
1510 gbf_project_view_find_file (GbfProjectView
*view
, GtkTreeIter
* iter
, GFile
*file
, GbfTreeNodeType type
)
1512 return gbf_project_model_find_file (view
->model
, iter
, NULL
, type
, file
);
1516 gbf_project_view_get_model (GbfProjectView
*view
)
1522 gbf_project_view_get_project_root (GbfProjectView
*view
, GtkTreeIter
*iter
)
1524 GtkTreeModel
*model
;
1525 GtkTreeModel
*view_model
;
1527 gboolean ok
= FALSE
;
1529 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1531 if (GTK_IS_TREE_MODEL_FILTER (model
))
1533 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (view_model
));
1536 path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (model
));
1539 ok
= gtk_tree_model_get_iter (model
, iter
, path
);
1540 gtk_tree_path_free (path
);
1547 *---------------------------------------------------------------------------*/
1550 pm_setup_project_renderer (GtkCellLayout
*layout
)
1552 GtkCellRenderer
*renderer
;
1554 renderer
= gtk_cell_renderer_pixbuf_new ();
1555 gtk_cell_layout_pack_start (layout
, renderer
, FALSE
);
1556 gtk_cell_layout_set_cell_data_func (layout
, renderer
, set_pixbuf
, NULL
, NULL
);
1558 renderer
= gtk_cell_renderer_text_new ();
1559 gtk_cell_layout_pack_start (layout
, renderer
, FALSE
);
1560 gtk_cell_layout_set_cell_data_func (layout
, renderer
, set_text
, NULL
, NULL
);
1566 pm_convert_project_iter_to_model_iter (GtkTreeModel
*model
,
1567 GtkTreeIter
*model_iter
,
1568 GtkTreeIter
*project_iter
)
1570 gboolean found
= TRUE
;
1572 g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model
), FALSE
);
1574 /* Check if we can find a direct correspondance */
1575 if ((project_iter
== NULL
) || !gtk_tree_model_filter_convert_child_iter_to_iter (
1576 GTK_TREE_MODEL_FILTER (model
), model_iter
, project_iter
))
1578 GtkTreeModel
*project_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model
));
1582 /* Check if it is a shortcut or a child of a shortcut */
1583 if (project_iter
!= NULL
)
1587 gtk_tree_model_get (project_model
, project_iter
,
1588 GBF_PROJECT_MODEL_COLUMN_DATA
, &data
,
1591 if ((data
!= NULL
) && (data
->node
!= NULL
))
1593 /* Select the corresponding node */
1597 gboolean valid
= FALSE
;
1599 path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model
));
1602 valid
= gtk_tree_model_get_iter (project_model
, &root
, path
);
1603 gtk_tree_path_free (path
);
1606 if (valid
&& gbf_project_model_find_node (GBF_PROJECT_MODEL (project_model
), &iter
, &root
, data
->node
))
1608 found
= gtk_tree_model_filter_convert_child_iter_to_iter (
1609 GTK_TREE_MODEL_FILTER (model
), model_iter
, &iter
);
1614 /* Try to select root node */
1618 GtkTreePath
*root_path
;
1620 root_path
= gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model
));
1624 path
= gtk_tree_model_filter_convert_child_path_to_path (
1625 GTK_TREE_MODEL_FILTER (model
), root_path
);
1628 found
= gtk_tree_model_get_iter (model
, model_iter
, path
);
1629 gtk_tree_path_free (path
);
1631 gtk_tree_path_free (root_path
);
1635 /* Take the first node */
1638 found
= gtk_tree_model_get_iter_first (model
, model_iter
);