1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
2 /* amp-group.c
3 *
4 * Copyright (C) 2010 Sébastien Granjoux
5 *
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.
10 *
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.
15 *
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.
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "amp-group.h"
28
29 #include "amp-node.h"
30 #include "amp-source.h"
31 #include "am-scanner.h"
32 #include "am-properties.h"
33 #include "am-writer.h"
34
35
36 #include <libanjuta/interfaces/ianjuta-project.h>
37
38 #include <libanjuta/anjuta-debug.h>
39
40 #include <glib/gi18n.h>
41
42 #include <memory.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 /* Types
47 *---------------------------------------------------------------------------*/
48
49 G_DEFINE_DYNAMIC_TYPE (AmpGroupNode, amp_group_node, AMP_TYPE_NODE);
50
51
52 /* Helper functions
53 *---------------------------------------------------------------------------*/
54
55 static void
error_set(GError ** error,gint code,const gchar * message)56 error_set (GError **error, gint code, const gchar *message)
57 {
58 if (error != NULL) {
59 if (*error != NULL) {
60 gchar *tmp;
61
62 /* error already created, just change the code
63 * and prepend the string */
64 (*error)->code = code;
65 tmp = (*error)->message;
66 (*error)->message = g_strconcat (message, "\n\n", tmp, NULL);
67 g_free (tmp);
68
69 } else {
70 *error = g_error_new_literal (IANJUTA_PROJECT_ERROR,
71 code,
72 message);
73 }
74 }
75 }
76
77 /* Private functions
78 *---------------------------------------------------------------------------*/
79
80 /* Find if pkg-config modules are used in group targets */
81 static gboolean
project_load_group_module(AmpProject * project,AmpGroupNode * group)82 project_load_group_module (AmpProject *project, AmpGroupNode *group)
83 {
84 AnjutaProjectNode *target;
85 AnjutaProjectProperty *prop;
86 gchar **group_cpp = NULL;
87
88 prop = amp_node_get_property_from_token (ANJUTA_PROJECT_NODE (group), AM_TOKEN__CPPFLAGS, 0);
89 if (prop && (prop->value != NULL)) group_cpp = g_strsplit_set (prop->value, " \t", 0);
90
91 /* Check all targets */
92 for (target = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (group)); target != NULL; target = anjuta_project_node_next_sibling (target))
93 {
94 gint type = anjuta_project_node_get_full_type (target) & (ANJUTA_PROJECT_ID_MASK | ANJUTA_PROJECT_TYPE_MASK);
95 gchar **target_lib = NULL;
96 gchar **target_cpp = NULL;
97
98 prop = NULL;
99 switch (type)
100 {
101 case ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PROGRAM:
102 prop = amp_node_get_property_from_token (target, AM_TOKEN_TARGET_LDADD, 0);
103 break;
104 case ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_STATICLIB:
105 case ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_SHAREDLIB:
106 case ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_LT_MODULE:
107 prop = amp_node_get_property_from_token (target, AM_TOKEN_TARGET_LIBADD, 0);
108 break;
109 default:
110 break;
111 }
112 if (prop && (prop->value != NULL)) target_lib = g_strsplit_set (prop->value, " \t", 0);
113
114 /* Check if targets use libraries */
115 if (target_lib != NULL)
116 {
117 AnjutaProjectNode *module;
118
119 prop = amp_node_get_property_from_token (target, AM_TOKEN_TARGET_CPPFLAGS, 0);
120 if (prop && (prop->value != NULL)) target_cpp = g_strsplit_set (prop->value, " \t", 0);
121
122 for (module = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (project)); module != NULL; module = anjuta_project_node_next_sibling (module))
123 {
124 if (anjuta_project_node_get_node_type (module) == ANJUTA_PROJECT_MODULE)
125 {
126 const gchar *name = anjuta_project_node_get_name (module);
127 gchar *lib_flags = g_strconcat ("$(", name, "_LIBS)", NULL);
128 gchar **flags;
129
130 for (flags = target_lib; *flags != NULL; flags++)
131 {
132
133 if (strcmp (*flags, lib_flags) == 0)
134 {
135 gchar *cpp_flags = g_strconcat ("$(", name, "_CFLAGS)", NULL);
136 gchar **cflags;
137 gboolean found = FALSE;
138
139 if (group_cpp != NULL)
140 {
141 for (cflags = group_cpp; *cflags != NULL; cflags++)
142 {
143 if (strcmp (*cflags, cpp_flags) == 0)
144 {
145 found = TRUE;
146 break;
147 }
148 }
149 }
150 if ((target_cpp != NULL) && !found)
151 {
152 for (cflags = target_cpp; *cflags != NULL; cflags++)
153 {
154 if (strcmp (*cflags, cpp_flags) == 0)
155 {
156 found = TRUE;
157 break;
158 }
159 }
160 }
161 if (found)
162 {
163 /* Add new module */
164 AnjutaProjectNode *new_module;
165
166 new_module = amp_node_new_valid (target, ANJUTA_PROJECT_MODULE, NULL, name, NULL);
167 anjuta_project_node_append (target, new_module);
168 }
169 g_free (cpp_flags);
170 }
171 }
172 g_free (lib_flags);
173 }
174 }
175 g_strfreev (target_cpp);
176 g_strfreev (target_lib);
177 }
178 }
179 g_strfreev (group_cpp);
180
181 return TRUE;
182 }
183
184
185 extern const gchar *valid_am_makefiles[];
186
187 static AmpGroupNode*
project_load_makefile(AmpProject * project,AmpGroupNode * group)188 project_load_makefile (AmpProject *project, AmpGroupNode *group)
189 {
190 const gchar **filename;
191 AnjutaTokenFile *tfile;
192 GFile *makefile = NULL;
193 GFile *file = anjuta_project_node_get_file ((AnjutaProjectNode *)group);
194
195 /* Find makefile name
196 * It has to be in the config_files list with .am extension */
197 for (filename = valid_am_makefiles; *filename != NULL; filename++)
198 {
199 makefile = g_file_get_child (file, *filename);
200 if (file_type (file, *filename) == G_FILE_TYPE_REGULAR)
201 {
202 gchar *final_filename = g_strdup (*filename);
203 gchar *ptr;
204 GFile *final_file;
205 AnjutaToken *token;
206
207 ptr = g_strrstr (final_filename,".am");
208 if (ptr != NULL) *ptr = '\0';
209 final_file = g_file_get_child (file, final_filename);
210 g_free (final_filename);
211
212 token = amp_project_get_config_token (project, final_file);
213 g_object_unref (final_file);
214 if (token != NULL)
215 {
216 amp_group_node_add_token (group, token, AM_GROUP_TOKEN_CONFIGURE);
217 break;
218 }
219 }
220 g_object_unref (makefile);
221 }
222
223 if (*filename == NULL)
224 {
225 /* Unable to find automake file */
226 return group;
227 }
228
229 /* Parse makefile.am */
230 DEBUG_PRINT ("Parse: %s", g_file_get_uri (makefile));
231 tfile = amp_group_node_set_makefile (group, makefile, project);
232
233 project_load_group_module (project, group);
234
235 return group;
236 }
237
238
239 /* Variable object
240 *---------------------------------------------------------------------------*/
241
242 AmpVariable*
amp_variable_new(gchar * name,AnjutaTokenType assign,AnjutaToken * value)243 amp_variable_new (gchar *name, AnjutaTokenType assign, AnjutaToken *value)
244 {
245 AmpVariable *variable = NULL;
246
247 g_return_val_if_fail (name != NULL, NULL);
248
249 variable = g_slice_new0(AmpVariable);
250 variable->name = g_strdup (name);
251 variable->assign = assign;
252 variable->value = value;
253
254 return variable;
255 }
256
257 static void
amp_variable_free(AmpVariable * variable)258 amp_variable_free (AmpVariable *variable)
259 {
260 g_free (variable->name);
261
262 g_slice_free (AmpVariable, variable);
263 }
264
265
266
267 /* Group objects
268 *---------------------------------------------------------------------------*/
269
270
271 void
amp_group_node_add_token(AmpGroupNode * group,AnjutaToken * token,AmpGroupNodeTokenCategory category)272 amp_group_node_add_token (AmpGroupNode *group, AnjutaToken *token, AmpGroupNodeTokenCategory category)
273 {
274 if (token != NULL) group->tokens[category] = g_list_prepend (group->tokens[category], token);
275 }
276
277 void
amp_group_node_remove_token(AmpGroupNode * group,AnjutaToken * token)278 amp_group_node_remove_token (AmpGroupNode *group, AnjutaToken *token)
279 {
280 gint i;
281
282 for (i = 0; i < AM_GROUP_TOKEN_LAST; i++)
283 {
284 group->tokens[i] = g_list_remove (group->tokens[i], token);
285 }
286 }
287
288 GList *
amp_group_node_get_token(AmpGroupNode * group,AmpGroupNodeTokenCategory category)289 amp_group_node_get_token (AmpGroupNode *group, AmpGroupNodeTokenCategory category)
290 {
291 return group->tokens[category];
292 }
293
294 GList *
amp_group_node_get_all_token(AmpGroupNode * group)295 amp_group_node_get_all_token (AmpGroupNode *group)
296 {
297 gint i;
298 GList *tokens = NULL;
299
300 for (i = 0; i < AM_GROUP_TOKEN_LAST; i++)
301 {
302 tokens = g_list_concat (tokens, g_list_copy (group->tokens[i]));
303 }
304
305 return tokens;
306 }
307
308 AnjutaToken*
amp_group_node_get_first_token(AmpGroupNode * group,AmpGroupNodeTokenCategory category)309 amp_group_node_get_first_token (AmpGroupNode *group, AmpGroupNodeTokenCategory category)
310 {
311 GList *list;
312
313 list = amp_group_node_get_token (group, category);
314 if (list == NULL) return NULL;
315
316 return (AnjutaToken *)list->data;
317 }
318
319 void
amp_group_node_set_dist_only(AmpGroupNode * group,gboolean dist_only)320 amp_group_node_set_dist_only (AmpGroupNode *group, gboolean dist_only)
321 {
322 group->dist_only = dist_only;
323 }
324
325 static void
on_group_monitor_changed(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type,gpointer data)326 on_group_monitor_changed (GFileMonitor *monitor,
327 GFile *file,
328 GFile *other_file,
329 GFileMonitorEvent event_type,
330 gpointer data)
331 {
332 AnjutaProjectNode *node = ANJUTA_PROJECT_NODE (data);
333 AnjutaProjectNode *root;
334
335 switch (event_type) {
336 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
337 case G_FILE_MONITOR_EVENT_CHANGED:
338 case G_FILE_MONITOR_EVENT_DELETED:
339 /* project can be NULL, if the node is dummy node because the
340 * original one is reloaded. */
341 root = anjuta_project_node_root (node);
342 if (root != NULL) g_signal_emit_by_name (G_OBJECT (root), "file-changed", data);
343 break;
344 default:
345 break;
346 }
347 }
348
349 static void
amp_group_node_update_preset_variable(AmpGroupNode * group)350 amp_group_node_update_preset_variable (AmpGroupNode *group)
351 {
352 gchar *path;
353 AnjutaToken *value;
354 AmpVariable *var;
355 GFile *root;
356 GFile *file;
357 AnjutaProjectNode *node;
358
359 if (group->preset_token != NULL) anjuta_token_free (group->preset_token);
360 group->preset_token = anjuta_token_new_static (ANJUTA_TOKEN_FILE, NULL);
361
362 /* Get project root */
363 for (node = ANJUTA_PROJECT_NODE (group); anjuta_project_node_parent (node) != NULL; node = anjuta_project_node_parent (node));
364 root = anjuta_project_node_get_file (node);
365
366 /* Set source directory variables */
367 file = anjuta_project_node_get_file (group);
368 value = anjuta_token_insert_token_list (FALSE, NULL,
369 ANJUTA_TOKEN_LIST, NULL,
370 ANJUTA_TOKEN_ARGUMENT, NULL,
371 ANJUTA_TOKEN_CONTENT, ".",
372 NULL);
373 anjuta_token_append_child (group->preset_token, value);
374 var = amp_variable_new ("srcdir", 0, value);
375 g_hash_table_insert (group->variables, var->name, var);
376 var = amp_variable_new ("builddir", 0, value);
377 g_hash_table_insert (group->variables, var->name, var);
378
379 path = g_file_get_path (file);
380 value = anjuta_token_insert_token_list (FALSE, NULL,
381 ANJUTA_TOKEN_LIST, NULL,
382 ANJUTA_TOKEN_ARGUMENT, NULL,
383 ANJUTA_TOKEN_CONTENT, path,
384 NULL);
385 g_free (path);
386 anjuta_token_append_child (group->preset_token, value);
387 var = amp_variable_new ("abs_srcdir", 0, value);
388 g_hash_table_insert (group->variables, var->name, var);
389 var = amp_variable_new ("abs_builddir", 0, value);
390 g_hash_table_insert (group->variables, var->name, var);
391
392 path = get_relative_path (file, root);
393 value = anjuta_token_insert_token_list (FALSE, NULL,
394 ANJUTA_TOKEN_LIST, NULL,
395 ANJUTA_TOKEN_ARGUMENT, NULL,
396 ANJUTA_TOKEN_CONTENT, path,
397 NULL);
398 g_free (path);
399 anjuta_token_append_child (group->preset_token, value);
400 var = amp_variable_new ("top_srcdir", 0, value);
401 g_hash_table_insert (group->variables, var->name, var);
402 var = amp_variable_new ("top_builddir", 0, value);
403 g_hash_table_insert (group->variables, var->name, var);
404
405 path = g_file_get_path (root);
406 value = anjuta_token_insert_token_list (FALSE, NULL,
407 ANJUTA_TOKEN_LIST, NULL,
408 ANJUTA_TOKEN_ARGUMENT, NULL,
409 ANJUTA_TOKEN_CONTENT, path,
410 NULL);
411 g_free (path);
412 anjuta_token_append_child (group->preset_token, value);
413 var = amp_variable_new ("abs_top_srcdir", 0, value);
414 g_hash_table_insert (group->variables, var->name, var);
415 var = amp_variable_new ("abs_top_builddir", 0, value);
416 g_hash_table_insert (group->variables, var->name, var);
417 }
418
419 AnjutaTokenFile*
amp_group_node_set_makefile(AmpGroupNode * group,GFile * makefile,AmpProject * project)420 amp_group_node_set_makefile (AmpGroupNode *group, GFile *makefile, AmpProject *project)
421 {
422 if (group->makefile != NULL) g_object_unref (group->makefile);
423 if (group->tfile != NULL) anjuta_token_file_free (group->tfile);
424 if (makefile != NULL)
425 {
426 AnjutaToken *token;
427 AmpAmScanner *scanner;
428 AnjutaProjectNode *source;
429
430 group->makefile = g_object_ref (makefile);
431 group->tfile = anjuta_token_file_new (makefile);
432 source = amp_source_node_new (makefile, ANJUTA_PROJECT_PROJECT | ANJUTA_PROJECT_FRAME | ANJUTA_PROJECT_READ_ONLY);
433 anjuta_project_node_append (ANJUTA_PROJECT_NODE (group), source);
434
435 token = anjuta_token_file_load (group->tfile, NULL);
436 amp_project_add_file (project, makefile, group->tfile);
437
438 amp_group_node_update_preset_variable (group);
439
440 scanner = amp_am_scanner_new (project, group);
441 group->make_token = amp_am_scanner_parse_token (scanner, anjuta_token_new_static (ANJUTA_TOKEN_FILE, NULL), token, makefile, NULL);
442 amp_am_scanner_free (scanner);
443
444 group->monitor = g_file_monitor_file (makefile,
445 G_FILE_MONITOR_NONE,
446 NULL,
447 NULL);
448 if (group->monitor != NULL)
449 {
450 g_signal_connect (G_OBJECT (group->monitor),
451 "changed",
452 G_CALLBACK (on_group_monitor_changed),
453 group);
454 }
455 }
456 else
457 {
458 group->makefile = NULL;
459 group->tfile = NULL;
460 group->make_token = NULL;
461 if (group->monitor) g_object_unref (group->monitor);
462 group->monitor = NULL;
463 }
464
465 return group->tfile;
466 }
467
468 AnjutaToken*
amp_group_node_get_makefile_token(AmpGroupNode * group)469 amp_group_node_get_makefile_token (AmpGroupNode *group)
470 {
471 return group->make_token;
472 }
473
474 AnjutaTokenFile *
amp_group_node_get_make_token_file(AmpGroupNode * group)475 amp_group_node_get_make_token_file (AmpGroupNode *group)
476 {
477 return group->tfile;
478 }
479
480 gboolean
amp_group_node_update_makefile(AmpGroupNode * group,AnjutaToken * token)481 amp_group_node_update_makefile (AmpGroupNode *group, AnjutaToken *token)
482 {
483 return anjuta_token_file_update (group->tfile, token);
484 }
485
486 gchar *
amp_group_node_get_makefile_name(AmpGroupNode * group)487 amp_group_node_get_makefile_name (AmpGroupNode *group)
488 {
489 gchar *basename = NULL;
490
491 if (group->makefile != NULL)
492 {
493 basename = g_file_get_basename (group->makefile);
494 }
495
496 return basename;
497 }
498
499 void
amp_group_node_update_node(AmpGroupNode * group,AmpGroupNode * new_group)500 amp_group_node_update_node (AmpGroupNode *group, AmpGroupNode *new_group)
501 {
502 gint i;
503 GHashTable *hash;
504
505 if (group->monitor != NULL)
506 {
507 g_object_unref (group->monitor);
508 group->monitor = NULL;
509 }
510 if (group->makefile != NULL)
511 {
512 g_object_unref (group->makefile);
513 group->monitor = NULL;
514 }
515 if (group->preset_token != NULL)
516 {
517 anjuta_token_free (group->preset_token);
518 group->preset_token = NULL;
519 }
520 if (group->tfile) anjuta_token_file_free (group->tfile);
521 for (i = 0; i < AM_GROUP_TOKEN_LAST; i++)
522 {
523 if (group->tokens[i] != NULL) g_list_free (group->tokens[i]);
524 }
525 if (group->variables) g_hash_table_remove_all (group->variables);
526
527 group->dist_only = new_group->dist_only;
528 group->makefile = new_group->makefile;
529 new_group->makefile = NULL;
530 group->tfile = new_group->tfile;
531 new_group->tfile = NULL;
532 group->make_token = new_group->make_token;
533 new_group->make_token = NULL;
534 group->preset_token = new_group->preset_token;
535 new_group->preset_token = NULL;
536 memcpy (group->tokens, new_group->tokens, sizeof (group->tokens));
537 memset (new_group->tokens, 0, sizeof (new_group->tokens));
538 hash = group->variables;
539 group->variables = new_group->variables;
540 new_group->variables = hash;
541
542 if (group->makefile != NULL)
543 {
544 group->monitor = g_file_monitor_file (group->makefile,
545 G_FILE_MONITOR_NONE,
546 NULL,
547 NULL);
548 if (group->monitor != NULL)
549 {
550 g_signal_connect (G_OBJECT (group->monitor),
551 "changed",
552 G_CALLBACK (on_group_monitor_changed),
553 group);
554 }
555 }
556 }
557
558 void
amp_group_node_update_variable(AmpGroupNode * group,AnjutaToken * variable)559 amp_group_node_update_variable (AmpGroupNode *group, AnjutaToken *variable)
560 {
561 AnjutaToken *arg;
562 char *name = NULL;
563 AnjutaToken *value = NULL;
564 AmpVariable *var;
565
566 arg = anjuta_token_first_item (variable);
567 name = g_strstrip (anjuta_token_evaluate (arg));
568 value = anjuta_token_last_item (variable);
569
570 var = (AmpVariable *)g_hash_table_lookup (group->variables, name);
571 if (var != NULL)
572 {
573 var->value = value;
574 }
575 else
576 {
577 var = amp_variable_new (name, 0, value);
578 g_hash_table_insert (group->variables, var->name, var);
579 }
580
581 if (name) g_free (name);
582 }
583
584 AnjutaToken*
amp_group_node_get_variable_token(AmpGroupNode * group,const gchar * name)585 amp_group_node_get_variable_token (AmpGroupNode *group, const gchar *name)
586 {
587 AmpVariable *var;
588
589 var = g_hash_table_lookup (group->variables, name);
590
591 return var != NULL ? var->value : NULL;
592 }
593
594 gboolean
amp_group_node_set_file(AmpGroupNode * group,GFile * new_file)595 amp_group_node_set_file (AmpGroupNode *group, GFile *new_file)
596 {
597 if (group->base.file != NULL) g_object_unref (group->base.file);
598 g_free (group->base.name);
599 group->base.name = NULL;
600 group->base.file = g_object_ref (new_file);
601
602 return TRUE;
603 }
604
605 AmpGroupNode*
amp_group_node_new(GFile * file,const gchar * name,gboolean dist_only)606 amp_group_node_new (GFile *file, const gchar *name, gboolean dist_only)
607 {
608 AmpGroupNode *node = NULL;
609
610 node = g_object_new (AMP_TYPE_GROUP_NODE, NULL);
611 node->base.file = g_object_ref (file);
612 node->base.name = g_strdup (name);
613 node->dist_only = dist_only;
614 memset (node->tokens, 0, sizeof (node->tokens));
615
616 return node;
617 }
618
619 AmpGroupNode*
amp_group_node_new_valid(GFile * file,const gchar * name,gboolean dist_only,GError ** error)620 amp_group_node_new_valid (GFile *file, const gchar *name, gboolean dist_only, GError **error)
621 {
622 /* Validate group name */
623 if (!name || strlen (name) <= 0)
624 {
625 g_free (name);
626 error_set (error, IANJUTA_PROJECT_ERROR_VALIDATION_FAILED,
627 _("Please specify group name"));
628 return NULL;
629 }
630 {
631 gboolean failed = FALSE;
632 const gchar *ptr = name;
633 while (*ptr) {
634 if (!isalnum (*ptr) && (strchr ("#$:%+,-.=@^_`~/", *ptr) == NULL))
635 failed = TRUE;
636 ptr++;
637 }
638 if (failed) {
639 g_free (name);
640 error_set (error, IANJUTA_PROJECT_ERROR_VALIDATION_FAILED,
641 _("Group name can only contain alphanumeric or \"#$:%+,-.=@^_`~/\" characters"));
642 return NULL;
643 }
644 }
645
646 return amp_group_node_new (file, name, dist_only);
647 }
648
649 void
amp_group_node_free(AmpGroupNode * node)650 amp_group_node_free (AmpGroupNode *node)
651 {
652 g_object_unref (G_OBJECT (node));
653 }
654
655 /* AmpNode implementation
656 *---------------------------------------------------------------------------*/
657
658 static gboolean
amp_group_node_load(AmpNode * group,AmpNode * parent,AmpProject * project,GError ** error)659 amp_group_node_load (AmpNode *group, AmpNode *parent, AmpProject *project, GError **error)
660 {
661 if (project_load_makefile (project, AMP_GROUP_NODE (group)) == NULL)
662 {
663 g_set_error (error, IANJUTA_PROJECT_ERROR,
664 IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
665 _("Project doesn't exist or invalid path"));
666
667 return FALSE;
668 }
669
670 return TRUE;
671 }
672
673 static gboolean
amp_group_node_save(AmpNode * group,AmpNode * parent,AmpProject * project,GError ** error)674 amp_group_node_save (AmpNode *group, AmpNode *parent, AmpProject *project, GError **error)
675 {
676 AnjutaTokenFile *tfile;
677 AnjutaProjectNode *child;
678 gboolean ok = TRUE;
679 GFile *directory;
680
681 /* Check if Makefile.am is missing, it happens in po directory by example */
682 if (AMP_GROUP_NODE (group)->makefile == NULL) return FALSE;
683
684 /* Create directory */
685 directory = g_file_get_parent (AMP_GROUP_NODE (group)->makefile);
686 g_file_make_directory (directory, NULL, NULL);
687 g_object_unref (directory);
688
689 /* Save group */
690 tfile = AMP_GROUP_NODE (group)->tfile;
691 if (tfile == NULL)
692 {
693 /* Create an empty makefile */
694 g_file_replace_contents (AMP_GROUP_NODE (group)->makefile, "", 0, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, NULL);
695
696 return TRUE;
697 }
698
699 if (anjuta_token_file_is_dirty (tfile))
700 {
701 if (!anjuta_token_file_save (tfile, error)) return FALSE;
702 }
703
704 /* Save all children */
705 for (child = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (group)); child != NULL; child = anjuta_project_node_next_sibling (child))
706 {
707 /* Try to save all children even if some fail */
708 if (!amp_node_save (AMP_NODE (child), group, project, error)) ok = FALSE;
709 }
710
711 return ok;
712 }
713
714 static gboolean
amp_group_node_update(AmpNode * node,AmpNode * new_node)715 amp_group_node_update (AmpNode *node, AmpNode *new_node)
716 {
717 amp_group_node_update_node (AMP_GROUP_NODE (node), AMP_GROUP_NODE (new_node));
718
719 return TRUE;
720 }
721
722 static AmpNode *
amp_group_node_copy(AmpNode * old_node)723 amp_group_node_copy (AmpNode *old_node)
724 {
725 AmpNode *new_node;
726
727 new_node = AMP_NODE_CLASS (amp_group_node_parent_class)->copy (old_node);
728 amp_group_node_add_token (AMP_GROUP_NODE (new_node), amp_group_node_get_first_token (AMP_GROUP_NODE (old_node), AM_GROUP_TOKEN_CONFIGURE), AM_GROUP_TOKEN_CONFIGURE);
729 amp_group_node_add_token (AMP_GROUP_NODE (new_node), amp_group_node_get_first_token (AMP_GROUP_NODE (old_node), AM_GROUP_TOKEN_SUBDIRS), AM_GROUP_TOKEN_SUBDIRS);
730 amp_group_node_add_token (AMP_GROUP_NODE (new_node), amp_group_node_get_first_token (AMP_GROUP_NODE (old_node), AM_GROUP_TOKEN_DIST_SUBDIRS), AM_GROUP_TOKEN_DIST_SUBDIRS);
731
732 return new_node;
733 }
734
735 static gboolean
amp_group_node_write(AmpNode * node,AmpNode * parent,AmpProject * project,GError ** error)736 amp_group_node_write (AmpNode *node, AmpNode *parent, AmpProject *project, GError **error)
737 {
738 return amp_group_node_create_token (project, AMP_GROUP_NODE (node), error);
739 }
740
741 static gboolean
amp_group_node_erase(AmpNode * node,AmpNode * parent,AmpProject * project,GError ** error)742 amp_group_node_erase (AmpNode *node, AmpNode *parent, AmpProject *project, GError **error)
743 {
744 return amp_group_node_delete_token (project, AMP_GROUP_NODE (node), error);
745 }
746
747
748
749 /* GObjet implementation
750 *---------------------------------------------------------------------------*/
751
752 static void
amp_group_node_init(AmpGroupNode * node)753 amp_group_node_init (AmpGroupNode *node)
754 {
755 node->base.type = ANJUTA_PROJECT_GROUP;
756 node->base.properties_info = amp_get_group_property_list();
757 node->base.state = ANJUTA_PROJECT_CAN_ADD_GROUP |
758 ANJUTA_PROJECT_CAN_ADD_TARGET |
759 ANJUTA_PROJECT_CAN_REMOVE |
760 ANJUTA_PROJECT_CAN_SAVE;
761 node->dist_only = FALSE;
762 node->variables = NULL;
763 node->makefile = NULL;
764 node->variables = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)amp_variable_free);
765 node->monitor = NULL;
766 memset (node->tokens, 0, sizeof (node->tokens));
767 node->preset_token = NULL;
768 }
769
770 static void
amp_group_node_dispose(GObject * object)771 amp_group_node_dispose (GObject *object)
772 {
773 AmpGroupNode *node = AMP_GROUP_NODE (object);
774
775 if (node->monitor) g_object_unref (node->monitor);
776 node->monitor = NULL;
777
778 if (node->preset_token) anjuta_token_free (node->preset_token);
779 node->preset_token = NULL;
780
781 G_OBJECT_CLASS (amp_group_node_parent_class)->dispose (object);
782 }
783
784 static void
amp_group_node_finalize(GObject * object)785 amp_group_node_finalize (GObject *object)
786 {
787 AmpGroupNode *node = AMP_GROUP_NODE (object);
788 gint i;
789
790 if (node->tfile) anjuta_token_file_free (node->tfile);
791 if (node->makefile) g_object_unref (node->makefile);
792
793 for (i = 0; i < AM_GROUP_TOKEN_LAST; i++)
794 {
795 if (node->tokens[i] != NULL) g_list_free (node->tokens[i]);
796 }
797 if (node->variables) g_hash_table_destroy (node->variables);
798
799 G_OBJECT_CLASS (amp_group_node_parent_class)->finalize (object);
800 }
801
802 static void
amp_group_node_class_init(AmpGroupNodeClass * klass)803 amp_group_node_class_init (AmpGroupNodeClass *klass)
804 {
805 GObjectClass* object_class = G_OBJECT_CLASS (klass);
806 AmpNodeClass* node_class;
807
808 object_class->finalize = amp_group_node_finalize;
809 object_class->dispose = amp_group_node_dispose;
810
811 node_class = AMP_NODE_CLASS (klass);
812 node_class->load = amp_group_node_load;
813 node_class->save = amp_group_node_save;
814 node_class->update = amp_group_node_update;
815 node_class->copy = amp_group_node_copy;
816 node_class->write = amp_group_node_write;
817 node_class->erase = amp_group_node_erase;
818 }
819
820 static void
amp_group_node_class_finalize(AmpGroupNodeClass * klass)821 amp_group_node_class_finalize (AmpGroupNodeClass *klass)
822 {
823 }
824
825 void
amp_group_node_register(GTypeModule * module)826 amp_group_node_register (GTypeModule *module)
827 {
828 amp_group_node_register_type (module);
829 }
830