Added byline
[anjuta.git] / plugins / project-manager / project-view.c
blobf9789e81180dd32bc76baab79484e6e355c0b605
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8; coding: utf-8 -*- */
2 /* project-tree.c
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>
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include <glib/gi18n.h>
32 #include <gdk/gdk.h>
33 #include <gtk/gtk.h>
34 #include <gio/gio.h>
35 #include <string.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"
43 #define ICON_SIZE 16
45 enum {
46 NODE_SELECTED,
47 NODE_LOADED,
48 LAST_SIGNAL
51 static guint signals [LAST_SIGNAL] = { 0 };
53 /* Project model filter with drag and drop support
54 *---------------------------------------------------------------------------*/
56 typedef struct {
57 GtkTreeModelFilter parent;
58 } PmProjectModelFilter;
60 typedef struct {
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))
68 static void
69 pm_project_model_filter_class_init (PmProjectModelFilterClass *class)
73 static void
74 pm_project_model_filter_init (PmProjectModelFilter *model)
78 static gboolean
79 idrag_source_row_draggable (GtkTreeDragSource *drag_source, GtkTreePath *path)
81 GtkTreeIter iter;
82 GbfTreeData *data;
83 gboolean retval = FALSE;
85 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source), &iter, path))
86 return FALSE;
88 gtk_tree_model_get (GTK_TREE_MODEL (drag_source), &iter,
89 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
90 -1);
92 if (data->is_shortcut) {
93 /* shortcuts can be moved */
94 retval = TRUE;
96 } else if (data->type == GBF_TREE_NODE_TARGET) {
97 /* don't allow duplicate shortcuts */
98 if (data->shortcut == NULL)
99 retval = TRUE;
102 return retval;
105 static gboolean
106 idrag_source_drag_data_delete (GtkTreeDragSource *drag_source, GtkTreePath *path)
108 return FALSE;
111 static gboolean
112 idrag_dest_drag_data_received (GtkTreeDragDest *drag_dest,
113 GtkTreePath *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));
125 else
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,
132 &src_model,
133 &src_path) &&
134 src_model == GTK_TREE_MODEL (project_model)) {
136 GtkTreeIter iter;
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,
142 -1);
143 if (data != NULL)
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);
153 else
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);
159 retval = TRUE;
164 if (src_path)
165 gtk_tree_path_free (src_path);
167 return retval;
170 static gboolean
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;
178 GtkTreeIter iter;
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));
187 else
189 project_model = GTK_TREE_MODEL (drag_dest);
192 if (!gtk_tree_get_row_drag_data (selection_data,
193 &src_model,
194 &src_path))
196 return FALSE;
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);
207 if (data != NULL)
209 /* can only drag to ourselves and only new toplevel nodes will
210 * be created */
211 if (src_model == project_model &&
212 gtk_tree_path_get_depth (dest_path) == 1)
214 if (data->type == GBF_TREE_NODE_SHORTCUT)
216 retval = TRUE;
218 else
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);
234 return retval;
237 static void
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;
244 static void
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,
264 GtkTreePath *root)
266 PmProjectModelFilter *model;
268 model = g_object_new (PM_TYPE_PROJECT_MODEL_FILTER,
269 "child-model", child_model,
270 "virtual-root", root,
271 NULL);
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,
286 GtkTreeModel *model,
287 GtkTreeIter *iter,
288 gpointer user_data);
289 static void set_text (GtkCellLayout *layout,
290 GtkCellRenderer *cell,
291 GtkTreeModel *model,
292 GtkTreeIter *iter,
293 gpointer user_data);
296 G_DEFINE_TYPE(GbfProjectView, gbf_project_view, GTK_TYPE_TREE_VIEW);
298 static void
299 row_activated (GtkTreeView *tree_view,
300 GtkTreePath *path,
301 GtkTreeViewColumn *column)
303 GtkTreeModel *model;
304 GtkTreeIter iter;
305 GbfTreeData *data;
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,
314 -1);
316 node = gbf_tree_data_get_node (data);
317 if (node)
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);
330 else
332 gtk_tree_view_collapse_row (tree_view, path);
334 break;
335 default:
336 g_signal_emit (G_OBJECT (tree_view),
337 signals [NODE_SELECTED], 0,
338 node);
339 break;
344 static void on_node_loaded (AnjutaPmProject *sender, AnjutaProjectNode *node, gboolean complete, GError *error, GbfProjectView *view);
346 static void
347 dispose (GObject *object)
349 GbfProjectView *view;
351 view = GBF_PROJECT_VIEW (object);
353 if (view->filter)
355 g_object_unref (G_OBJECT (view->filter));
356 view->filter = NULL;
358 if (view->model)
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));
368 view->model = NULL;
371 G_OBJECT_CLASS (gbf_project_view_parent_class)->dispose (object);
374 static void
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);
381 static GdkPixbuf*
382 get_icon (GFile *file)
384 const gchar** icon_names;
385 GtkIconInfo* icon_info;
386 GIcon* icon;
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,
394 NULL,
395 &error);
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(),
402 icon_names,
403 ICON_SIZE,
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);
413 if (pixbuf == NULL)
415 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
416 GTK_STOCK_MISSING_IMAGE,
417 ICON_SIZE,
418 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
419 NULL);
422 return pixbuf;
425 static void
426 set_pixbuf (GtkCellLayout *layout,
427 GtkCellRenderer *cell,
428 GtkTreeModel *model,
429 GtkTreeIter *iter,
430 gpointer user_data)
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);
451 break;
453 case GBF_TREE_NODE_ROOT:
454 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
455 GTK_STOCK_OPEN,
456 ICON_SIZE,
457 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
458 NULL);
459 break;
460 case GBF_TREE_NODE_GROUP:
461 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
462 GTK_STOCK_DIRECTORY,
463 ICON_SIZE,
464 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
465 NULL);
466 break;
467 case GBF_TREE_NODE_TARGET:
469 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
470 GTK_STOCK_CONVERT,
471 ICON_SIZE,
472 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
473 NULL);
474 break;
476 case GBF_TREE_NODE_MODULE:
478 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
479 GTK_STOCK_DND_MULTIPLE,
480 ICON_SIZE,
481 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
482 NULL);
483 break;
485 case GBF_TREE_NODE_PACKAGE:
487 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
488 GTK_STOCK_DND,
489 ICON_SIZE,
490 GTK_ICON_LOOKUP_GENERIC_FALLBACK,
491 NULL);
492 break;
494 default:
495 /* Can reach this if type = GBF_TREE_NODE_SHORTCUT. It
496 * means a shortcut with the original data removed */
497 pixbuf = NULL;
500 g_object_set (GTK_CELL_RENDERER (cell), "pixbuf", pixbuf, NULL);
501 if (pixbuf)
502 g_object_unref (pixbuf);
505 static void
506 set_text (GtkCellLayout *layout,
507 GtkCellRenderer *cell,
508 GtkTreeModel *model,
509 GtkTreeIter *iter,
510 gpointer user_data)
512 GbfTreeData *data;
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);
521 static gboolean
522 search_equal_func (GtkTreeModel *model, gint column,
523 const gchar *key, GtkTreeIter *iter,
524 gpointer user_data)
526 GbfTreeData *data;
527 gboolean ret = TRUE;
529 gtk_tree_model_get (model, iter, GBF_PROJECT_MODEL_COLUMN_DATA, &data, -1);
530 if (strncmp (data->name, key, strlen (key)) == 0)
531 ret = FALSE;
532 return ret;
535 static gboolean
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)) {
554 GtkTreePath *root;
555 GdkRectangle rect;
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));
561 if (root) {
562 if (view_model != model)
564 /* Convert path */
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);
569 root = child_path;
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),
575 rect.x, rect.y,
576 rect.x + rect.width, rect.y);
577 gtk_tree_path_free (root);
581 return event_handled;
584 static void
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,
603 G_SIGNAL_RUN_LAST,
604 G_STRUCT_OFFSET (GbfProjectViewClass,
605 node_selected),
606 NULL, NULL,
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,
612 G_SIGNAL_RUN_LAST,
613 G_STRUCT_OFFSET (GbfProjectViewClass,
614 node_loaded),
615 NULL, NULL,
616 pm_cclosure_marshal_VOID__POINTER_BOOLEAN_BOXED,
617 G_TYPE_NONE, 3,
618 G_TYPE_POINTER,
619 G_TYPE_BOOLEAN,
620 G_TYPE_ERROR);
624 static gboolean
625 is_project_node_visible (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data)
627 GbfTreeData *data;
629 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
630 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
631 -1);
633 return (data != NULL) && (gbf_tree_data_get_node (data) != NULL);
636 static void
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),
648 search_equal_func,
649 NULL, NULL);
651 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree),
652 GDK_BUTTON1_MASK,
653 row_targets,
654 G_N_ELEMENTS (row_targets),
655 GDK_ACTION_MOVE);
656 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tree),
657 row_targets,
658 G_N_ELEMENTS (row_targets),
659 GDK_ACTION_MOVE);
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);
666 /* Create model */
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));
674 GtkWidget *
675 gbf_project_view_new (void)
677 return GTK_WIDGET (g_object_new (GBF_TYPE_PROJECT_VIEW, NULL));
680 AnjutaProjectNode *
681 gbf_project_view_find_selected (GbfProjectView *view, AnjutaProjectNodeType type)
683 AnjutaProjectNode *node = NULL;
684 GbfTreeData *data;
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);
690 if (data != 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);
702 return node;
705 AnjutaProjectNode *
706 gbf_project_view_find_selected_state (GtkTreeView *view,
707 AnjutaProjectNodeState state)
709 AnjutaProjectNode *node = NULL;
710 GbfTreeData *data;
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);
716 if (data != 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);
728 return node;
731 GbfTreeData *
732 gbf_project_view_get_first_selected (GbfProjectView *view, GtkTreeIter* selected)
734 GtkTreeSelection *selection;
735 GbfTreeData *data = NULL;
736 GtkTreeModel *model;
737 GList *list;
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);
744 if (list != NULL)
746 GtkTreeIter iter;
748 if (gtk_tree_model_get_iter (model, &iter, list->data))
750 if (selected)
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;
759 else
761 *selected = iter;
765 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
766 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
767 -1);
769 g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
770 g_list_free (list);
773 return data;
776 void
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))
784 GtkTreePath *path;
786 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->filter), &view_iter);
787 if (path)
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,
793 TRUE, 0.5, 0.0);
794 gtk_tree_path_free (path);
800 static void
801 on_each_get_data (GtkTreeModel *model,
802 GtkTreePath *path,
803 GtkTreeIter *iter,
804 gpointer user_data)
806 GList **selected = (GList **)user_data;
807 GbfTreeData *data;
809 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
810 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
811 -1);
813 *selected = g_list_prepend (*selected, data);
816 GList *
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);
831 static void
832 on_each_get_iter (GtkTreeModel *model,
833 GtkTreePath *path,
834 GtkTreeIter *iter,
835 gpointer user_data)
837 GList **selected = (GList **)user_data;
839 *selected = g_list_prepend (*selected, gtk_tree_iter_copy (iter));
842 GList *
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);
857 static void
858 gbf_project_view_update_shortcut (GbfProjectView *view, AnjutaProjectNode *parent)
860 GtkTreeIter child;
861 gboolean valid;
863 /* Get all root node */
864 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (view->model), &child, NULL);
866 while (valid)
868 GbfTreeData *data;
869 AnjutaProjectNode* old_node = NULL;
871 gtk_tree_model_get (GTK_TREE_MODEL (view->model), &child,
872 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
873 -1);
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)
881 /* check children */
882 gbf_project_view_update_tree (view, parent, &child);
884 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (view->model), &child);
888 static gint
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);
897 static GList *
898 list_visible_children (AnjutaProjectNode *parent)
900 AnjutaProjectNode *node;
901 GList *list = NULL;
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);
910 else
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);
921 return list;
924 void
925 gbf_project_view_update_tree (GbfProjectView *view, AnjutaProjectNode *parent, GtkTreeIter *iter)
927 GtkTreeIter child;
928 GList *node;
929 GList *nodes;
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;
940 while (valid) {
941 data = NULL;
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,
947 -1);
949 data_node = gbf_tree_data_get_node (data);
951 /* Skip shortcuts */
952 if (data->type == GBF_TREE_NODE_SHORTCUT)
954 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (view->model), &child);
955 continue;
958 if (data->type == GBF_TREE_NODE_UNKNOWN)
960 node = g_list_find_custom (nodes, data->name, compare_node_name);
961 if (node != NULL)
963 GtkTreePath *path;
964 GtkTreePath *child_path;
965 GtkTreeModelFilter *filter;
966 gboolean expanded;
967 gboolean shortcut;
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,
976 -1);
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);
987 if (shortcut)
989 gboolean expanded;
990 GtkTreeIter iter;
992 gbf_project_model_add_target_shortcut (view->model, &iter, data, NULL, &expanded);
993 if (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;
1005 if (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);
1018 else
1020 node = g_list_find (nodes, data_node);
1021 if (node != NULL)
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);
1034 else
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 */
1052 if (iter != NULL)
1054 /* Check parent data */
1055 gtk_tree_model_get (GTK_TREE_MODEL (view->model), iter,
1056 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1057 -1);
1058 if (data->expanded)
1060 GtkTreePath *path;
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 *---------------------------------------------------------------------------*/
1078 void
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);
1091 GList *
1092 gbf_project_view_get_shortcut_list (GbfProjectView *view)
1094 GList *list = NULL;
1095 GtkTreeModel* model;
1096 gboolean valid;
1097 GtkTreeIter iter;
1099 model = GTK_TREE_MODEL (view->model);
1100 if (model != NULL)
1102 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, NULL);
1103 valid == TRUE;
1104 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
1106 GbfTreeData *data;
1107 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
1108 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1109 -1);
1111 if ((data->type == GBF_TREE_NODE_SHORTCUT) && (data->shortcut != NULL))
1113 GtkTreeIter iter;
1115 if (gbf_project_model_find_tree_data (view->model, &iter, data->shortcut))
1117 GString *str;
1118 GtkTreeIter child;
1120 str = g_string_new (NULL);
1123 GbfTreeData *data;
1125 child = iter;
1126 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
1127 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1128 -1);
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);
1145 return list;
1148 static void
1149 save_expanded_node (GtkTreeView *view, GtkTreePath *path, gpointer user_data)
1151 GList **list = (GList **)user_data;
1152 GtkTreeModel *model;
1153 GtkTreeIter iter;
1155 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1157 if (gtk_tree_model_get_iter (model, &iter, path))
1159 GString *str;
1160 GtkTreeIter child;
1162 str = g_string_new (NULL);
1165 GbfTreeData *data;
1167 child = iter;
1168 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
1169 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1170 -1);
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);
1185 GList *
1186 gbf_project_view_get_expanded_list (GbfProjectView *view)
1188 GList *list = NULL;
1190 gtk_tree_view_map_expanded_rows (GTK_TREE_VIEW (view), save_expanded_node, &list);
1191 list = g_list_reverse (list);
1193 return list;
1196 void
1197 gbf_project_view_remove_all_shortcut (GbfProjectView* view)
1199 GtkTreeModel* model;
1200 gboolean valid;
1201 GtkTreeIter iter;
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);
1207 valid == TRUE;)
1209 GbfTreeData *data;
1211 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
1212 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1213 -1);
1215 if (data->type == GBF_TREE_NODE_SHORTCUT)
1217 valid = gbf_project_model_remove (GBF_PROJECT_MODEL (model), &iter);
1219 else
1221 /* No more shortcut */
1222 break;
1227 void
1228 gbf_project_view_set_shortcut_list (GbfProjectView *view, GList *shortcuts)
1230 GList *item;
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;
1237 gchar *end;
1238 GtkTreeIter iter;
1239 GtkTreeIter *parent = NULL;
1243 end = strstr (name, "/" "/"); /* Avoid troubles with auto indent */
1244 if (end != NULL) *end = '\0';
1245 if (*name != '\0')
1247 if (!gbf_project_model_find_child_name (view->model, &iter, parent, name))
1249 GbfTreeData *data;
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,
1256 -1);
1257 if (end == NULL)
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,
1266 -1);
1269 else
1271 GbfTreeData *data;
1273 gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter,
1274 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1275 -1);
1276 if (end == NULL) data->has_shortcut = TRUE;
1278 parent = &iter;
1280 if (end != NULL)
1282 *end = '/';
1283 name = end + 2;
1286 while (end != NULL);
1289 return;
1292 void
1293 gbf_project_view_set_expanded_list (GbfProjectView *view, GList *expand)
1295 GList *item;
1297 for (item = g_list_first (expand); item != NULL; item = g_list_next (item))
1299 gchar *name = (gchar *)item->data;
1300 gchar *end;
1301 GtkTreeIter iter;
1302 GtkTreeIter *parent = NULL;
1306 end = strstr (name, "/" "/"); /* Avoid troubles with auto indent */
1307 if (end != NULL) *end = '\0';
1308 if (*name != '\0')
1310 if (!gbf_project_model_find_child_name (view->model, &iter, parent, name))
1312 GbfTreeData *data;
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,
1319 -1);
1321 else
1323 GbfTreeData *data;
1325 gtk_tree_model_get (GTK_TREE_MODEL (view->model), &iter,
1326 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1327 -1);
1328 data->expanded = TRUE;
1330 parent = &iter;
1332 if (end != NULL)
1334 *end = '/';
1335 name = end + 2;
1338 while (end != NULL);
1341 return;
1344 AnjutaProjectNode *
1345 gbf_project_view_get_node_from_iter (GbfProjectView *view, GtkTreeIter *iter)
1347 return gbf_project_model_get_node (view->model, iter);
1350 AnjutaProjectNode *
1351 gbf_project_view_get_node_from_file (GbfProjectView *view, AnjutaProjectNodeType type, GFile *file)
1353 GtkTreeIter iter;
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);
1362 return node;
1365 gboolean
1366 gbf_project_view_remove_data (GbfProjectView *view, GbfTreeData *data, GError **error)
1368 GtkTreeIter iter;
1370 if (gbf_project_model_find_tree_data (view->model, &iter, data))
1372 gbf_project_model_remove (view->model, &iter);
1374 return TRUE;
1376 else
1378 return FALSE;
1382 static void
1383 on_node_loaded (AnjutaPmProject *sender, AnjutaProjectNode *node, gboolean complete, GError *error, GbfProjectView *view)
1385 if (error != NULL)
1387 g_warning ("unable to load node");
1388 g_signal_emit (G_OBJECT (view), NODE_LOADED, 0, NULL, complete, error);
1390 else
1392 GtkTreeIter iter;
1393 gboolean found;
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);
1400 if (!found)
1402 if (anjuta_project_node_parent (node) != NULL)
1404 g_critical ("Unable to find node %s", anjuta_project_node_get_name (node));
1406 else
1408 GtkTreePath *path;
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);
1417 else
1419 GbfTreeData *data;
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,
1425 -1);
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,
1429 -1);
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);
1443 else
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);
1454 if (complete)
1456 // Add shortcut for all new primary targets
1457 gbf_project_model_set_default_shortcut (view->model, TRUE);
1462 void
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);
1478 void
1479 gbf_project_view_set_parent_view (GbfProjectView *view,
1480 GbfProjectView *parent,
1481 GtkTreePath *root)
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));
1492 void
1493 gbf_project_view_set_visible_func (GbfProjectView *view,
1494 GtkTreeModelFilterVisibleFunc func,
1495 gpointer data,
1496 GDestroyNotify destroy)
1498 if (func == NULL)
1500 gtk_tree_model_filter_set_visible_func (view->filter, is_project_node_visible, view, NULL);
1502 else
1504 gtk_tree_model_filter_set_visible_func (view->filter, func, data, destroy);
1506 gtk_tree_model_filter_refilter (view->filter);
1509 gboolean
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);
1515 GbfProjectModel *
1516 gbf_project_view_get_model (GbfProjectView *view)
1518 return view->model;
1521 gboolean
1522 gbf_project_view_get_project_root (GbfProjectView *view, GtkTreeIter *iter)
1524 GtkTreeModel *model;
1525 GtkTreeModel *view_model;
1526 GtkTreePath *path;
1527 gboolean ok = FALSE;
1529 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1530 view_model = model;
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));
1537 if (path)
1539 ok = gtk_tree_model_get_iter (model, iter, path);
1540 gtk_tree_path_free (path);
1543 return ok;
1546 /* Public functions
1547 *---------------------------------------------------------------------------*/
1549 GtkCellLayout *
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);
1562 return layout;
1565 gboolean
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));
1580 found = FALSE;
1582 /* Check if it is a shortcut or a child of a shortcut */
1583 if (project_iter != NULL)
1585 GbfTreeData *data;
1587 gtk_tree_model_get (project_model, project_iter,
1588 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1589 -1);
1591 if ((data != NULL) && (data->node != NULL))
1593 /* Select the corresponding node */
1594 GtkTreePath *path;
1595 GtkTreeIter root;
1596 GtkTreeIter iter;
1597 gboolean valid = FALSE;
1599 path = gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model));
1600 if (path)
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 */
1615 if (!found)
1618 GtkTreePath *root_path;
1620 root_path = gbf_project_model_get_project_root (GBF_PROJECT_MODEL (project_model));
1621 if (root_path)
1623 GtkTreePath *path;
1624 path = gtk_tree_model_filter_convert_child_path_to_path (
1625 GTK_TREE_MODEL_FILTER (model), root_path);
1626 if (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 */
1636 if (!found)
1638 found = gtk_tree_model_get_iter_first (model, model_iter);
1642 return found;