1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2010 SĂ©bastien Granjoux
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.
27 #include "project-marshal.h"
28 #include <libanjuta/anjuta-debug.h>
29 #include <libanjuta/interfaces/ianjuta-project-backend.h>
30 #include <libanjuta/interfaces/ianjuta-project-manager.h>
31 #include "project-model.h"
32 #include "project-view.h"
37 *---------------------------------------------------------------------------*/
40 *---------------------------------------------------------------------------*/
48 static unsigned int signals
[LAST_SIGNAL
] = { 0 };
51 on_pm_project_load_incomplete (AnjutaProjectNode
*node
, AnjutaPmProject
*project
)
53 gint state
= anjuta_project_node_get_state (node
);
55 /* Get capabilities for all existing node */
56 project
->node_capabilities
|= state
;
58 if ((state
& ANJUTA_PROJECT_INCOMPLETE
) && !(state
& ANJUTA_PROJECT_LOADING
))
60 //g_message ("incomplete node %s", anjuta_project_node_get_name (node));
61 project
->incomplete_node
++;
62 anjuta_project_node_set_state (node
, ANJUTA_PROJECT_LOADING
);
63 //g_message ("load incomplete %p", node);
64 ianjuta_project_load_node (project
->project
, node
, NULL
);
69 pm_command_load_complete (AnjutaPmProject
*project
, AnjutaProjectNode
*node
, GError
*error
)
71 gboolean complete
= FALSE
;
73 //g_message ("pm_command_load_complete %p", node);
76 if (project
->root
== node
)
78 project
->incomplete_node
= 0;
81 // Check for incompletely loaded object and load them
82 if (anjuta_project_node_get_state (node
) & ANJUTA_PROJECT_INCOMPLETE
)
84 project
->incomplete_node
--;
85 //g_message ("remaining node %d", project->incomplete_node);
87 anjuta_project_node_clear_state (node
, ANJUTA_PROJECT_LOADING
| ANJUTA_PROJECT_INCOMPLETE
);
88 anjuta_project_node_foreach (node
, G_POST_ORDER
, (AnjutaProjectNodeForeachFunc
)on_pm_project_load_incomplete
, project
);
90 complete
= !project
->loaded
&& (project
->incomplete_node
== 0);
91 if (complete
) project
->loaded
= TRUE
;
94 //g_message ("pm_command_load_complete %d is loaded %d", complete, ianjuta_project_is_loaded (project->project, NULL));
95 g_signal_emit (G_OBJECT (project
), signals
[LOADED
], 0, node
, complete
, error
);
102 on_file_changed (IAnjutaProject
*sender
, AnjutaProjectNode
*node
, AnjutaPmProject
*project
)
104 ianjuta_project_load_node (project
->project
, node
, NULL
);
108 on_node_loaded (IAnjutaProject
*sender
, AnjutaProjectNode
*node
, GError
*error
, AnjutaPmProject
*project
)
110 pm_command_load_complete (project
, node
, error
);
114 on_node_changed (IAnjutaProject
*sender
, AnjutaProjectNode
*node
, GError
*error
, AnjutaPmProject
*project
)
116 ianjuta_project_save_node (project
->project
, node
, NULL
);
120 *---------------------------------------------------------------------------*/
123 anjuta_pm_project_load_with_backend (AnjutaPmProject
*project
, GFile
*file
, AnjutaPluginHandle
*backend
, GError
**error
)
125 AnjutaPluginManager
*plugin_manager
;
126 IAnjutaProjectBackend
*plugin
;
127 GValue value
= {0, };
129 plugin_manager
= anjuta_shell_get_plugin_manager (project
->plugin
->shell
, NULL
);
130 plugin
= (IAnjutaProjectBackend
*)anjuta_plugin_manager_get_plugin_by_handle (plugin_manager
, backend
);
133 DEBUG_PRINT ("%s", "Creating new gbf project\n");
134 project
->project
= ianjuta_project_backend_new_project (plugin
, file
, NULL
);
135 if (!project
->project
)
138 g_warning ("project creation failed\n");
142 project
->backend
=backend
;
144 g_signal_connect (G_OBJECT (project
->project
),
146 G_CALLBACK (on_file_changed
),
148 g_signal_connect (G_OBJECT (project
->project
),
150 G_CALLBACK (on_node_loaded
),
152 g_signal_connect (G_OBJECT (project
->project
),
154 G_CALLBACK (on_node_changed
),
157 /* Export project root shell variable */
158 g_value_init (&value
, G_TYPE_OBJECT
);
159 g_value_set_object (&value
, project
->project
);
160 anjuta_shell_add_value (project
->plugin
->shell
,
161 IANJUTA_PROJECT_MANAGER_CURRENT_PROJECT
,
163 g_value_unset(&value
);
164 g_value_init (&value
, G_TYPE_STRING
);
165 g_value_set_string (&value
, ANJUTA_PLUGIN_PROJECT_MANAGER (project
->plugin
)->project_root_uri
);
166 anjuta_shell_add_value (project
->plugin
->shell
,
167 IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI
,
169 g_value_unset(&value
);
171 project
->root
= ianjuta_project_get_root (project
->project
, NULL
);
172 ianjuta_project_load_node (project
->project
, project
->root
, NULL
);
179 anjuta_pm_project_load (AnjutaPmProject
*project
, GFile
*file
, GError
**error
)
181 AnjutaPluginManager
*plugin_manager
;
183 IAnjutaProjectBackend
*backend
;
184 AnjutaPluginHandle
*backend_handle
;
187 g_return_val_if_fail (file
!= NULL
, FALSE
);
189 DEBUG_PRINT ("loading gbf backend…\n");
190 plugin_manager
= anjuta_shell_get_plugin_manager (project
->plugin
->shell
, NULL
);
192 if (!anjuta_plugin_manager_is_active_plugin (plugin_manager
, "IAnjutaProjectBackend"))
194 GList
*handles
= NULL
;
196 handles
= anjuta_plugin_manager_query (plugin_manager
,
199 "IAnjutaProjectBackend",
202 for (desc
= g_list_first (handles
); desc
!= NULL
; desc
= g_list_next (desc
)) {
203 IAnjutaProjectBackend
*plugin
;
206 backend_handle
= (AnjutaPluginHandle
*)desc
->data
;
207 plugin
= (IAnjutaProjectBackend
*)anjuta_plugin_manager_get_plugin_by_handle (plugin_manager
, backend_handle
);
209 backend_val
= ianjuta_project_backend_probe (plugin
, file
, NULL
);
210 if (backend_val
> found
)
217 g_list_free (handles
);
221 /* A backend is already loaded, use it */
222 backend
= IANJUTA_PROJECT_BACKEND (anjuta_shell_get_object (project
->plugin
->shell
,
223 "IAnjutaProjectBackend", NULL
));
225 g_object_ref (backend
);
231 g_warning ("no backend available for this project\n");
236 backend_handle
= anjuta_plugin_manager_get_plugin_handle (plugin_manager
, G_OBJECT(backend
));
238 return anjuta_pm_project_load_with_backend (project
, file
, backend_handle
, error
);
242 anjuta_pm_project_unload (AnjutaPmProject
*project
, GError
**error
)
244 /* Remove value from Anjuta shell */
245 anjuta_shell_remove_value (project
->plugin
->shell
,
246 IANJUTA_PROJECT_MANAGER_CURRENT_PROJECT
,
249 if (project
->project
) g_object_unref (project
->project
);
250 project
->project
= NULL
;
251 project
->backend
= NULL
;
252 project
->root
= NULL
;
253 project
->loaded
= FALSE
;
254 project
->node_capabilities
= 0;
256 /* Remove project properties dialogs */
257 if (project
->properties_dialog
!= NULL
) gtk_widget_destroy (project
->properties_dialog
);
258 project
->properties_dialog
= NULL
;
264 anjuta_pm_project_refresh (AnjutaPmProject
*project
, GError
**error
)
266 return ianjuta_project_load_node (project
->project
, project
->root
, error
);
270 anjuta_pm_project_get_capabilities (AnjutaPmProject
*project
)
274 if (project
->project
!= NULL
)
278 for (item
= anjuta_pm_project_get_node_info (project
); item
!= NULL
; item
= g_list_next (item
))
280 AnjutaProjectNodeInfo
*info
= (AnjutaProjectNodeInfo
*)item
->data
;
282 switch (info
->type
& ANJUTA_PROJECT_TYPE_MASK
)
284 case ANJUTA_PROJECT_GROUP
:
285 caps
|= ANJUTA_PROJECT_CAN_ADD_GROUP
;
287 case ANJUTA_PROJECT_TARGET
:
288 caps
|= ANJUTA_PROJECT_CAN_ADD_TARGET
;
290 case ANJUTA_PROJECT_SOURCE
:
291 caps
|= ANJUTA_PROJECT_CAN_ADD_SOURCE
;
293 case ANJUTA_PROJECT_MODULE
:
294 caps
|= ANJUTA_PROJECT_CAN_ADD_MODULE
;
296 case ANJUTA_PROJECT_PACKAGE
:
297 caps
|= ANJUTA_PROJECT_CAN_ADD_PACKAGE
;
305 /* Make sure that at least one node can do it */
306 caps
&= project
->node_capabilities
;
312 anjuta_pm_project_get_node_info (AnjutaPmProject
*project
)
314 g_return_val_if_fail (project
->project
!= NULL
, NULL
);
316 return ianjuta_project_get_node_info (project
->project
, NULL
);
320 anjuta_pm_project_get_root (AnjutaPmProject
*project
)
322 return project
->root
;
326 anjuta_pm_project_get_packages (AnjutaPmProject
*project
)
328 AnjutaProjectNode
*module
;
332 g_return_val_if_fail (project
!= NULL
, NULL
);
334 all
= g_hash_table_new (g_str_hash
, g_str_equal
);
336 for (module
= anjuta_project_node_first_child (project
->root
); module
!= NULL
; module
= anjuta_project_node_next_sibling (module
))
338 if (anjuta_project_node_get_node_type(module
) == ANJUTA_PROJECT_MODULE
)
340 AnjutaProjectNode
*package
;
342 for (package
= anjuta_project_node_first_child (module
); package
!= NULL
; package
= anjuta_project_node_next_sibling (package
))
344 if (anjuta_project_node_get_node_type (package
) == ANJUTA_PROJECT_PACKAGE
)
346 g_hash_table_replace (all
, (gpointer
)anjuta_project_node_get_name (package
), NULL
);
352 packages
= g_hash_table_get_keys (all
);
353 g_hash_table_destroy (all
);
359 anjuta_pm_project_add_group (AnjutaPmProject
*project
, AnjutaProjectNode
*parent
, AnjutaProjectNode
*sibling
, const gchar
*name
, GError
**error
)
361 AnjutaProjectNode
*node
;
363 g_return_val_if_fail (project
->project
!= NULL
, NULL
);
365 node
= ianjuta_project_add_node_before (project
->project
, parent
, sibling
, ANJUTA_PROJECT_GROUP
, NULL
, name
, error
);
371 anjuta_pm_project_add_target (AnjutaPmProject
*project
, AnjutaProjectNode
*parent
, AnjutaProjectNode
*sibling
, const gchar
*name
, AnjutaProjectNodeType type
, GError
**error
)
373 AnjutaProjectNode
*node
;
375 g_return_val_if_fail (project
->project
!= NULL
, NULL
);
377 node
= ianjuta_project_add_node_before (project
->project
, parent
, sibling
, ANJUTA_PROJECT_TARGET
| type
, NULL
, name
, error
);
383 anjuta_pm_project_add_source (AnjutaPmProject
*project
, AnjutaProjectNode
*parent
, AnjutaProjectNode
*sibling
, const gchar
*name
, GError
**error
)
385 AnjutaProjectNode
*node
;
389 g_return_val_if_fail (project
->project
!= NULL
, NULL
);
391 scheme
= g_uri_parse_scheme (name
);
395 file
= g_file_new_for_uri (name
);
398 node
= ianjuta_project_add_node_before (project
->project
, parent
, sibling
, ANJUTA_PROJECT_SOURCE
, file
, file
== NULL
? name
: NULL
, error
);
404 anjuta_pm_project_remove (AnjutaPmProject
*project
, AnjutaProjectNode
*node
, GError
**error
)
406 return ianjuta_project_remove_node (project
->project
, node
, error
);
410 anjuta_pm_project_is_open (AnjutaPmProject
*project
)
412 return (project
->project
!= NULL
) && (project
->root
!= NULL
);
416 anjuta_pm_project_get_backend (AnjutaPmProject
*project
)
418 return project
->backend
;
422 anjuta_pm_project_get_project (AnjutaPmProject
*project
)
424 return project
->project
;
428 find_module (AnjutaProjectNode
*node
, gpointer data
)
430 gboolean found
= FALSE
;
432 if (anjuta_project_node_get_node_type (node
) == ANJUTA_PROJECT_MODULE
)
434 const gchar
*name
= anjuta_project_node_get_name (node
);
436 found
= g_strcmp0 (name
, (const gchar
*)data
) == 0;
443 anjuta_pm_project_get_module (AnjutaPmProject
*project
, const gchar
*name
)
445 AnjutaProjectNode
*root
;
446 AnjutaProjectNode
*module
;
448 root
= ianjuta_project_get_root (project
->project
, NULL
);
450 module
= anjuta_project_node_children_traverse (root
, find_module
, (gpointer
)name
);
456 *---------------------------------------------------------------------------*/
458 G_DEFINE_TYPE (AnjutaPmProject
, anjuta_pm_project
, G_TYPE_OBJECT
);
461 anjuta_pm_project_init (AnjutaPmProject
*project
)
463 project
->plugin
= NULL
;
464 project
->loaded
= FALSE
;
466 project
->properties_dialog
= NULL
;
470 anjuta_pm_project_finalize (GObject
*object
)
472 G_OBJECT_CLASS (anjuta_pm_project_parent_class
)->finalize (object
);
476 anjuta_pm_project_class_init (AnjutaPmProjectClass
*klass
)
478 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
480 object_class
->finalize
= anjuta_pm_project_finalize
;
483 /*Change both signal to use marshal_VOID__POINTER_BOXED
484 adding a AnjutaProjectNode pointer corresponding to the
486 Such marshal doesn't exist as glib marshal, so look in the
487 symbol db plugin how to add new marshal => done
489 This new argument can be used in the plugin object in
490 order to add corresponding shortcut when the project
491 is loaded and a new node is loaded.
492 The plugin should probably get the GFile from the
493 AnjutaProjectNode object and then use a function
494 in project-view.c to create the corresponding shortcut*/
496 signals
[LOADED
] = g_signal_new ("loaded",
497 G_OBJECT_CLASS_TYPE (object_class
),
499 G_STRUCT_OFFSET (AnjutaPmProjectClass
, loaded
),
501 pm_cclosure_marshal_VOID__POINTER_BOOLEAN_BOXED
,
509 /* Constructor & Destructor
510 *---------------------------------------------------------------------------*/
513 anjuta_pm_project_new (AnjutaPlugin
*plugin
)
515 AnjutaPmProject
*project
;
517 project
= g_object_new (ANJUTA_TYPE_PM_PROJECT
, NULL
);
518 project
->plugin
= plugin
;
524 anjuta_pm_project_free (AnjutaPmProject
* project
)
526 g_object_unref (project
);