glade: Fix make file some files were not installed
[anjuta.git] / plugins / project-manager / project-model.c
blob6659fd823d149a6f4ae5a748680367ea5607d01c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Copyright (C) 2002 Dave Camp
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
20 * Authors: Dave Camp <dave@ximian.com>
21 * Gustavo Giráldez <gustavo.giraldez@gmx.net>
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include <string.h>
29 #include <glib-object.h>
30 #include <gtk/gtk.h>
31 #include <glib/gi18n.h>
32 #include <gio/gio.h>
35 #include "project.h"
36 #include "project-util.h"
37 #include "project-model.h"
40 struct _GbfProjectModelPrivate {
41 AnjutaPmProject *proj;
42 gulong project_updated_handler;
44 GtkTreeRowReference *root;
45 GtkTreeRowReference *root_group;
46 GList *shortcuts;
48 gboolean default_shortcut; /* Add shortcut for each primary node */
51 enum {
52 PROP_NONE,
53 PROP_PROJECT
57 /* Function prototypes ------------- */
59 static void gbf_project_model_class_init (GbfProjectModelClass *klass);
60 static void gbf_project_model_instance_init (GbfProjectModel *tree);
62 static void load_project (GbfProjectModel *model,
63 AnjutaPmProject *proj);
64 static void insert_empty_node (GbfProjectModel *model);
65 static void unload_project (GbfProjectModel *model);
67 static gint default_sort_func (GtkTreeModel *model,
68 GtkTreeIter *iter_a,
69 GtkTreeIter *iter_b,
70 gpointer user_data);
72 static GtkTreeStoreClass *parent_class = NULL;
75 /* Implementation ---------------- */
77 /* Helper functions */
79 /* Type & interfaces initialization */
81 static void
82 gbf_project_model_class_init_trampoline (gpointer klass,
83 gpointer data)
85 parent_class = g_type_class_ref (GTK_TYPE_TREE_STORE);
86 gbf_project_model_class_init (klass);
89 GType
90 gbf_project_model_get_type (void)
92 static GType object_type = 0;
93 if (object_type == 0) {
94 static const GTypeInfo object_info = {
95 sizeof (GbfProjectModelClass),
96 NULL, /* base_init */
97 NULL, /* base_finalize */
98 gbf_project_model_class_init_trampoline,
99 NULL, /* class_finalize */
100 NULL, /* class_data */
101 sizeof (GbfProjectModel),
102 0, /* n_preallocs */
103 (GInstanceInitFunc) gbf_project_model_instance_init
106 object_type = g_type_register_static (
107 GTK_TYPE_TREE_STORE, "GbfProjectModel",
108 &object_info, 0);
110 return object_type;
113 static void
114 get_property (GObject *object,
115 guint prop_id,
116 GValue *value,
117 GParamSpec *pspec)
119 GbfProjectModel *model = GBF_PROJECT_MODEL (object);
121 switch (prop_id) {
122 case PROP_PROJECT:
123 g_value_set_pointer (value, model->priv->proj);
124 break;
125 default:
126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127 break;
131 static void
132 set_property (GObject *object,
133 guint prop_id,
134 const GValue *value,
135 GParamSpec *pspec)
137 GbfProjectModel *model = GBF_PROJECT_MODEL (object);
139 switch (prop_id) {
140 case PROP_PROJECT:
141 gbf_project_model_set_project (model, g_value_get_pointer (value));
142 break;
143 default:
144 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145 break;
149 static void
150 dispose (GObject *obj)
152 GbfProjectModel *model = GBF_PROJECT_MODEL (obj);
154 if (model->priv->proj) {
155 unload_project (model);
158 G_OBJECT_CLASS (parent_class)->finalize (obj);
161 static void
162 finalize (GObject *obj)
164 GbfProjectModel *model = GBF_PROJECT_MODEL (obj);
166 g_free (model->priv);
168 G_OBJECT_CLASS (parent_class)->dispose (obj);
171 static void
172 gbf_project_model_class_init (GbfProjectModelClass *klass)
174 parent_class = g_type_class_peek_parent (klass);
176 G_OBJECT_CLASS (klass)->dispose = dispose;
177 G_OBJECT_CLASS (klass)->finalize = finalize;
178 G_OBJECT_CLASS (klass)->get_property = get_property;
179 G_OBJECT_CLASS (klass)->set_property = set_property;
181 g_object_class_install_property
182 (G_OBJECT_CLASS (klass), PROP_PROJECT,
183 g_param_spec_pointer ("project",
184 _("Project"),
185 _("GbfProject Object"),
186 G_PARAM_READWRITE));
189 static void
190 gbf_project_model_instance_init (GbfProjectModel *model)
192 static GType types [GBF_PROJECT_MODEL_NUM_COLUMNS];
194 types [GBF_PROJECT_MODEL_COLUMN_DATA] = G_TYPE_POINTER;
196 gtk_tree_store_set_column_types (GTK_TREE_STORE (model),
197 GBF_PROJECT_MODEL_NUM_COLUMNS,
198 types);
200 model->priv = g_new0 (GbfProjectModelPrivate, 1);
201 model->priv->default_shortcut = TRUE;
203 /* sorting function */
204 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
205 default_sort_func,
206 NULL, NULL);
207 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
208 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
209 GTK_SORT_ASCENDING);
211 insert_empty_node (model);
214 /* Model data functions ------------ */
216 /* Remove node without checking its shortcuts */
217 static gboolean
218 gbf_project_model_remove_children (GbfProjectModel *model, GtkTreeIter *iter)
220 GtkTreeIter child;
221 GbfTreeData *data;
222 gboolean valid;
224 /* Free all children */
225 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &child, iter);
226 while (valid)
228 valid = gbf_project_model_remove_children (model, &child);
230 /* Free children node */
231 gtk_tree_model_get (GTK_TREE_MODEL (model), &child,
232 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
233 -1);
234 valid = gtk_tree_store_remove (GTK_TREE_STORE (model), &child);
235 if (data != NULL) gbf_tree_data_free (data);
238 return valid;
241 static gboolean
242 gbf_project_model_invalidate_children (GbfProjectModel *model, GtkTreeIter *iter)
244 GtkTreeIter child;
245 GbfTreeData *data;
246 gboolean valid;
248 /* Mark all children as invalid */
249 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &child, iter);
250 while (valid)
252 valid = gbf_project_model_invalidate_children (model, &child);
254 /* Invalidate children node */
255 gtk_tree_model_get (GTK_TREE_MODEL (model), &child,
256 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
257 -1);
258 gbf_tree_data_invalidate (data);
260 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &child);
263 return valid;
266 static gboolean
267 gbf_project_model_remove_invalid_shortcut (GbfProjectModel *model, GtkTreeIter *iter)
269 GtkTreeIter child;
270 gboolean valid;
271 GbfTreeData *data;
273 /* Get all shortcut */
274 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &child, iter);
275 while (valid)
277 gtk_tree_model_get (GTK_TREE_MODEL (model), &child,
278 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
279 -1);
280 /* Shortcuts are always at the beginning */
281 if (data->type != GBF_TREE_NODE_SHORTCUT) break;
283 if (data->shortcut->type == GBF_TREE_NODE_INVALID)
285 gbf_project_model_remove_children (model, &child);
286 valid = gtk_tree_store_remove (GTK_TREE_STORE (model), &child);
287 if (data != NULL) gbf_tree_data_free (data);
289 else
291 gbf_project_model_remove_invalid_shortcut (model, &child);
292 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &child);
296 return FALSE;
299 /* Sort model
300 *---------------------------------------------------------------------------*/
302 static gint
303 sort_by_name (GtkTreeModel *model,
304 GtkTreeIter *iter_a,
305 GtkTreeIter *iter_b,
306 gpointer user_data)
308 GbfTreeData *data_a, *data_b;
310 gtk_tree_model_get (model, iter_a,
311 GBF_PROJECT_MODEL_COLUMN_DATA, &data_a,
312 -1);
313 gtk_tree_model_get (model, iter_b,
314 GBF_PROJECT_MODEL_COLUMN_DATA, &data_b,
315 -1);
317 return strcmp (data_a->name, data_b->name);
321 static void
322 gbf_project_model_merge (GtkTreeModel *model,
323 GtkTreePath *begin,
324 GtkTreePath *half,
325 GtkTreePath *end,
326 GtkTreeIterCompareFunc compare_func,
327 gpointer user_data)
329 GtkTreeIter right;
330 GtkTreeIter left;
332 if (gtk_tree_model_get_iter (model, &left, begin) &&
333 gtk_tree_model_get_iter (model, &right, half))
335 gint depth;
336 gint ll, lr;
339 /* Get number of elements in both list */
340 ll = (gtk_tree_path_get_indices_with_depth (half, &depth)[depth - 1]
341 - gtk_tree_path_get_indices_with_depth (begin, &depth)[depth - 1]);
342 lr = (gtk_tree_path_get_indices_with_depth (end, &depth)[depth - 1]
343 - gtk_tree_path_get_indices_with_depth (half, &depth)[depth - 1]);
345 while (ll && lr)
347 if (compare_func (model, &left, &right, user_data) <= 0)
349 gtk_tree_model_iter_next (model, &left);
350 ll--;
352 else
354 GtkTreeIter iter;
356 iter = right;
357 gtk_tree_model_iter_next (model, &right);
358 lr--;
359 gtk_tree_store_move_before (GTK_TREE_STORE (model), &iter, &left);
365 /* sort using merge sort */
366 static void
367 gbf_project_model_sort (GtkTreeModel *model,
368 GtkTreePath *begin,
369 GtkTreePath *end,
370 GtkTreeIterCompareFunc compare_func,
371 gpointer user_data)
373 GtkTreePath *half;
374 gint depth;
376 /* Empty list are sorted */
377 if (gtk_tree_path_compare (begin, end) >= 0)
379 return;
382 /* Split the list in two */
383 half = gtk_tree_path_copy (begin);
384 gtk_tree_path_up (half);
385 gtk_tree_path_append_index (half, (gtk_tree_path_get_indices_with_depth (begin, &depth)[depth -1] +
386 gtk_tree_path_get_indices_with_depth (end, &depth)[depth - 1]) / 2);
388 /* List with a single element are sorted too */
389 if (gtk_tree_path_compare (begin, half) < 0)
391 gbf_project_model_sort (model, begin, half, compare_func, user_data);
392 gbf_project_model_sort (model, half, end, compare_func, user_data);
393 gbf_project_model_merge (model, begin, half, end, compare_func, user_data);
396 gtk_tree_path_free (half);
400 /* Public function
401 *---------------------------------------------------------------------------*/
403 gboolean
404 gbf_project_model_remove (GbfProjectModel *model, GtkTreeIter *iter)
406 GtkTreeIter child;
407 GbfTreeData *data;
408 gboolean valid;
410 /* Check if node is not a shortcut. In this case we need to remove
411 * all shortcuts first. */
412 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
413 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
414 -1);
415 if (data->type != GBF_TREE_NODE_SHORTCUT)
417 /* Mark all nodes those will be removed */
418 gbf_project_model_invalidate_children (model, iter);
419 gbf_tree_data_invalidate (data);
421 gbf_project_model_remove_invalid_shortcut (model, NULL);
424 /* Free all children */
425 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &child, iter);
426 while (valid)
428 valid = gbf_project_model_remove_children (model, &child);
431 /* Free parent node */
432 valid = gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
433 if (data != NULL) gbf_tree_data_free (data);
435 return valid;
439 static void
440 gbf_project_model_clear (GbfProjectModel *model)
442 GtkTreeIter child;
443 gboolean valid;
445 valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &child, NULL);
446 while (valid)
448 valid = gbf_project_model_remove (model, &child);
452 static gint
453 default_sort_func (GtkTreeModel *model,
454 GtkTreeIter *iter_a,
455 GtkTreeIter *iter_b,
456 gpointer user_data)
458 GbfTreeData *data_a, *data_b;
459 gint retval = 0;
460 gboolean unsorted_a, unsorted_b;
462 gtk_tree_model_get (model, iter_a,
463 GBF_PROJECT_MODEL_COLUMN_DATA, &data_a,
464 -1);
465 gtk_tree_model_get (model, iter_b,
466 GBF_PROJECT_MODEL_COLUMN_DATA, &data_b,
467 -1);
469 unsorted_a = (data_a->type == GBF_TREE_NODE_SHORTCUT) || (data_a->type == GBF_TREE_NODE_UNKNOWN) || (data_a->is_shortcut);
470 unsorted_b = (data_b->type == GBF_TREE_NODE_SHORTCUT) || (data_b->type == GBF_TREE_NODE_UNKNOWN) || (data_b->is_shortcut);
471 if (unsorted_a && unsorted_b) {
472 GtkTreeIter iter;
473 gboolean valid;
475 /* special case: the order of shortcuts is
476 * user customizable */
477 for (valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
478 valid == TRUE;
479 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
481 GbfTreeData *data;
483 gtk_tree_model_get (model, &iter,
484 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
485 -1);
486 if (data == data_a) {
487 /* a comes first */
488 retval = -1;
489 break;
491 else if (data == data_b) {
492 /* b comes first */
493 retval = 1;
494 break;
498 } else if (unsorted_a && !unsorted_b) {
499 retval = -1;
501 } else if (!unsorted_a && unsorted_b) {
502 retval = 1;
504 } else if (data_a->type == data_b->type) {
505 retval = strcmp (data_a->name, data_b->name);
507 } else {
508 /* assume a->b and check for the opposite cases */
509 retval = -1;
510 retval = data_a->type < data_b->type ? -1 : 1;
513 return retval;
516 void
517 gbf_project_model_add_target_shortcut (GbfProjectModel *model,
518 GtkTreeIter *shortcut,
519 GbfTreeData *target,
520 GtkTreePath *before_path,
521 gboolean *expanded)
523 AnjutaProjectNode *node;
524 GtkTreeIter iter, sibling;
525 GtkTreePath *root_path;
526 GbfTreeData *data;
527 AnjutaProjectNode *parent;
528 gboolean valid = FALSE;
530 if (!target)
531 return;
533 if (expanded != NULL) *expanded = FALSE;
535 root_path = gbf_project_model_get_project_root (model);
536 if ((before_path == NULL) && (target->type != GBF_TREE_NODE_SHORTCUT))
538 /* Check is a proxy node is not already existing. It is used to
539 * save the shortcut order */
541 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, NULL);
542 valid;
543 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
545 GbfTreeData *data;
547 /* Look for current node */
548 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
549 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
550 -1);
552 if (((data->type == GBF_TREE_NODE_UNKNOWN) || (data->type == GBF_TREE_NODE_SHORTCUT)) && (g_strcmp0 (target->name, data->name) == 0))
554 /* Find already existing node and replace it */
555 if (expanded != NULL) *expanded = data->expanded;
556 gbf_tree_data_free (data);
558 data = gbf_tree_data_new_shortcut (target);
559 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
560 GBF_PROJECT_MODEL_COLUMN_DATA, data,
561 -1);
562 break;
566 if (!valid)
568 /* check before_path */
569 if ((before_path == NULL) ||
570 gtk_tree_path_get_depth (before_path) > 1 ||
571 gtk_tree_path_compare (before_path, root_path) > 0)
573 before_path = root_path;
576 /* get the tree iter for the row before which to insert the shortcut */
577 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &sibling, before_path)) {
578 gtk_tree_path_free (root_path);
579 return;
582 if (target->type != GBF_TREE_NODE_SHORTCUT)
584 data = gbf_tree_data_new_shortcut (target);
586 else
588 data = target;
590 gtk_tree_store_insert_before (GTK_TREE_STORE (model), &iter, NULL, &sibling);
591 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
592 GBF_PROJECT_MODEL_COLUMN_DATA, data,
593 -1);
596 /* add sources */
597 parent = gbf_tree_data_get_node (target);
598 for (node = anjuta_project_node_first_child (parent); node; node = anjuta_project_node_next_sibling (node))
599 gbf_project_model_add_node (model, node, &iter, 0);
601 gtk_tree_path_free (root_path);
603 if (shortcut) *shortcut = iter;
606 void
607 gbf_project_model_move_target_shortcut (GbfProjectModel *model,
608 GtkTreeIter *iter,
609 GbfTreeData *shortcut,
610 GtkTreePath *before_path)
612 AnjutaProjectNode *node;
613 GtkTreeIter sibling;
614 GtkTreePath *root_path;
615 GtkTreePath *src_path;
616 AnjutaProjectNode *parent;
618 if (!shortcut)
619 return;
621 root_path = gbf_project_model_get_project_root (model);
623 /* check before_path */
624 if (!before_path ||
625 gtk_tree_path_get_depth (before_path) > 1)
627 /* Missing destination path, use root path */
628 before_path = root_path;
630 else if (gtk_tree_path_compare (before_path, root_path) > 0)
632 /* Destination path outside shortcut are, remove shortcut */
633 gbf_project_model_remove (model, iter);
634 gtk_tree_path_free (root_path);
636 return;
639 /* get the tree iter for the row before which to insert the shortcut */
640 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &sibling, before_path)) {
641 gtk_tree_path_free (root_path);
642 return;
645 src_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
646 if (gtk_tree_path_compare (src_path, before_path) != 0)
648 gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
649 gtk_tree_store_insert_before (GTK_TREE_STORE (model), iter, NULL, &sibling);
650 gtk_tree_store_set (GTK_TREE_STORE (model), iter,
651 GBF_PROJECT_MODEL_COLUMN_DATA, shortcut,
652 -1);
654 /* add sources */
655 parent = gbf_tree_data_get_node (shortcut->shortcut);
656 for (node = anjuta_project_node_first_child (parent); node; node = anjuta_project_node_next_sibling (node))
657 gbf_project_model_add_node (model, node, iter, 0);
661 gtk_tree_path_free (src_path);
662 gtk_tree_path_free (root_path);
666 void
667 gbf_project_model_add_node (GbfProjectModel *model,
668 AnjutaProjectNode *node,
669 GtkTreeIter *parent,
670 AnjutaProjectNodeType only_type)
672 GtkTreeIter iter;
673 GbfTreeData *data = NULL;
674 AnjutaProjectNode *child;
675 AnjutaProjectNodeType child_types[] = {ANJUTA_PROJECT_GROUP,
676 ANJUTA_PROJECT_TARGET,
677 ANJUTA_PROJECT_SOURCE,
678 ANJUTA_PROJECT_MODULE,
679 ANJUTA_PROJECT_PACKAGE,
681 AnjutaProjectNodeType *type;
683 if (node == NULL) return;
686 if (anjuta_project_node_get_full_type (node) & ANJUTA_PROJECT_FRAME) return;
688 if ((only_type == 0) || (anjuta_project_node_get_node_type (node) == only_type))
690 if (anjuta_project_node_get_node_type (node) != ANJUTA_PROJECT_OBJECT)
692 data = gbf_tree_data_new_node (node);
693 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
694 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
695 GBF_PROJECT_MODEL_COLUMN_DATA, data,
696 -1);
698 else
700 /* Hidden node */
701 iter = *parent;
704 /* add children */
705 for (type = child_types; *type != 0; type++)
707 for (child = anjuta_project_node_first_child (node); child != NULL; child = anjuta_project_node_next_sibling (child))
709 gbf_project_model_add_node (model, child, &iter, *type);
713 /* Add shortcut if needed */
714 if ((data != NULL) &&
715 model->priv->default_shortcut &&
716 (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET) &&
717 (anjuta_project_node_get_full_type (node) & ANJUTA_PROJECT_PRIMARY))
719 gbf_project_model_add_target_shortcut (model, NULL, data, NULL, NULL);
722 else if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_OBJECT)
724 /* Add only children */
725 for (child = anjuta_project_node_first_child (node); child != NULL; child = anjuta_project_node_next_sibling (child))
727 gbf_project_model_add_node (model, child, parent, only_type);
732 static void
733 load_project (GbfProjectModel *model, AnjutaPmProject *proj)
735 model->priv->proj = proj;
736 g_object_ref (proj);
738 gbf_project_model_add_node (model, anjuta_pm_project_get_root (proj), NULL, 0);
741 static void
742 insert_empty_node (GbfProjectModel *model)
744 GtkTreeIter iter;
745 GbfTreeData *empty_node;
747 empty_node = gbf_tree_data_new_string (_("No project loaded"));
749 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
750 gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
751 GBF_PROJECT_MODEL_COLUMN_DATA, empty_node,
752 -1);
755 static void
756 unload_project (GbfProjectModel *model)
758 if (model->priv->proj) {
759 gtk_tree_row_reference_free (model->priv->root);
760 model->priv->root = NULL;
762 gbf_project_model_clear (model);
764 g_list_free (model->priv->shortcuts);
765 model->priv->shortcuts = NULL;
767 //g_signal_handler_disconnect (anjuta_pm_project_get_project (model->priv->proj),
768 // model->priv->project_updated_handler);
769 //model->priv->project_updated_handler = 0;
770 model->priv->proj = NULL;
772 insert_empty_node (model);
776 static gboolean
777 recursive_find_tree_data (GtkTreeModel *model,
778 GtkTreeIter *iter,
779 GbfTreeData *data)
781 GtkTreeIter tmp;
782 gboolean retval = FALSE;
784 tmp = *iter;
786 do {
787 GtkTreeIter child;
788 GbfTreeData *tmp_data;
790 gtk_tree_model_get (model, &tmp,
791 GBF_PROJECT_MODEL_COLUMN_DATA, &tmp_data, -1);
792 if (gbf_tree_data_equal (tmp_data, data))
794 *iter = tmp;
795 retval = TRUE;
798 if (gtk_tree_model_iter_children (model, &child, &tmp)) {
799 if (recursive_find_tree_data (model, &child, data)) {
800 *iter = child;
801 retval = TRUE;
805 } while (!retval && gtk_tree_model_iter_next (model, &tmp));
807 return retval;
810 gboolean
811 gbf_project_model_find_tree_data (GbfProjectModel *model,
812 GtkTreeIter *iter,
813 GbfTreeData *data)
815 GtkTreeIter tmp_iter;
816 gboolean retval = FALSE;
818 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &tmp_iter)) {
819 if (recursive_find_tree_data (GTK_TREE_MODEL (model), &tmp_iter, data)) {
820 retval = TRUE;
821 *iter = tmp_iter;
825 return retval;
828 /* Can return shortcut node if exist */
829 gboolean
830 gbf_project_model_find_file (GbfProjectModel *model,
831 GtkTreeIter *found,
832 GtkTreeIter *parent,
833 GbfTreeNodeType type,
834 GFile *file)
836 GtkTreeIter iter;
837 gboolean valid;
839 /* Search for direct children */
840 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, parent); valid == TRUE; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
842 GbfTreeData *data;
844 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
845 GBF_PROJECT_MODEL_COLUMN_DATA, &data, -1);
847 if (gbf_tree_data_equal_file (data, type, file))
849 *found = iter;
850 break;
854 /* Search for children of children */
855 if (!valid)
857 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, parent); valid == TRUE; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
859 if (gbf_project_model_find_file (model, found, &iter, type, file)) break;
863 return valid;
866 gboolean
867 gbf_project_model_find_node (GbfProjectModel *model,
868 GtkTreeIter *found,
869 GtkTreeIter *parent,
870 AnjutaProjectNode *node)
872 GtkTreeIter iter;
873 gboolean valid;
875 /* Search for direct children */
876 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, parent); valid == TRUE; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
878 GbfTreeData *data;
880 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
881 GBF_PROJECT_MODEL_COLUMN_DATA, &data, -1);
883 if (node == gbf_tree_data_get_node (data))
885 *found = iter;
886 break;
890 /* Search for children of children */
891 if (!valid)
893 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, parent); valid == TRUE; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
895 if (gbf_project_model_find_node (model, found, &iter, node)) break;
899 return valid;
902 /* Can return shortcut node if exist */
903 gboolean
904 gbf_project_model_find_child_name (GbfProjectModel *model,
905 GtkTreeIter *found,
906 GtkTreeIter *parent,
907 const gchar *name)
909 GtkTreeIter iter;
910 gboolean valid;
912 /* Search for direct children only */
913 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, parent); valid == TRUE; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
915 GbfTreeData *data;
917 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
918 GBF_PROJECT_MODEL_COLUMN_DATA, &data, -1);
920 if (gbf_tree_data_equal_name (data, name))
922 *found = iter;
923 break;
927 return valid;
930 GbfProjectModel *
931 gbf_project_model_new (AnjutaPmProject *project)
933 return GBF_PROJECT_MODEL (g_object_new (GBF_TYPE_PROJECT_MODEL,
934 "project", project,
935 NULL));
938 void
939 gbf_project_model_set_project (GbfProjectModel *model, AnjutaPmProject *project)
941 g_return_if_fail (model != NULL && GBF_IS_PROJECT_MODEL (model));
943 if (model->priv->proj != project)
945 //unload_project (model);
947 /* project can be NULL */
948 if (project)
949 load_project (model, project);
953 AnjutaPmProject *
954 gbf_project_model_get_project (GbfProjectModel *model)
956 g_return_val_if_fail (model != NULL && GBF_IS_PROJECT_MODEL (model), NULL);
958 return model->priv->proj;
961 GtkTreePath *
962 gbf_project_model_get_project_root (GbfProjectModel *model)
964 GtkTreePath *path = NULL;
966 g_return_val_if_fail (GBF_IS_PROJECT_MODEL (model), NULL);
968 if (model->priv->root == NULL)
970 GtkTreeIter iter;
971 gboolean valid;
973 /* Search root group */
974 for (valid = gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, NULL); valid; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter))
976 GbfTreeData *data;
978 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
979 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
980 -1);
982 if (data->type == GBF_TREE_NODE_ROOT)
984 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
985 model->priv->root = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
989 else
991 path = gtk_tree_row_reference_get_path (model->priv->root);
994 return path;
997 AnjutaProjectNode *
998 gbf_project_model_get_node (GbfProjectModel *model,
999 GtkTreeIter *iter)
1001 GbfTreeData *data = NULL;
1003 gtk_tree_model_get (GTK_TREE_MODEL (model), iter,
1004 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1005 -1);
1007 return gbf_tree_data_get_node (data);
1010 void
1011 gbf_project_model_set_default_shortcut (GbfProjectModel *model,
1012 gboolean enable)
1014 model->priv->default_shortcut = enable;
1017 void
1018 gbf_project_model_sort_shortcuts (GbfProjectModel *model)
1020 GtkTreeIter iter;
1022 /* Get all shortcut */
1023 if (gtk_tree_model_iter_children (GTK_TREE_MODEL (model), &iter, NULL))
1025 GtkTreePath *begin;
1026 GtkTreePath *end;
1027 gboolean valid;
1029 begin = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
1032 GbfTreeData *data;
1034 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
1035 GBF_PROJECT_MODEL_COLUMN_DATA, &data,
1036 -1);
1038 /* Shortcuts are always at the beginning */
1039 if (data->type != GBF_TREE_NODE_SHORTCUT) break;
1041 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
1043 while (valid);
1047 end = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
1048 gbf_project_model_sort (GTK_TREE_MODEL (model), begin, end, sort_by_name, NULL);
1049 gtk_tree_path_free (begin);
1050 gtk_tree_path_free (end);