Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / project-wizard / property.c
blob88054f1b96d62c76adefcaed0a5bf4f17e5afe00
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 property.c
4 Copyright (C) 2004 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Project properties, used in middle pages
24 *---------------------------------------------------------------------------*/
26 #include <config.h>
28 #include "property.h"
30 #include <glib/gdir.h>
32 #include <gnome.h>
33 #include <glib/gi18n.h>
34 #include <libgnomevfs/gnome-vfs-utils.h>
36 #include <string.h>
37 #include <stdlib.h>
39 #include <libanjuta/anjuta-debug.h>
41 /*---------------------------------------------------------------------------*/
43 #define STRING_CHUNK_SIZE 256
45 /*---------------------------------------------------------------------------*/
47 struct _NPWPage
49 GNode* list;
50 GStringChunk* string_pool;
51 GMemChunk* data_pool;
52 GMemChunk* item_pool;
53 NPWValueHeap* value;
54 gchar* name;
55 gchar* label;
56 gchar* description;
59 struct _NPWProperty {
60 NPWPropertyType type;
61 NPWPropertyType restriction;
62 NPWPropertyOptions options;
63 gchar* label;
64 gchar* description;
65 gchar* defvalue;
66 NPWValue* value;
67 GtkWidget* widget;
68 NPWPage* owner;
69 GSList* item;
72 struct _NPWItem {
73 const gchar* name;
74 const gchar* label;
77 static const gchar* NPWPropertyTypeString[] = {
78 "hidden",
79 "boolean",
80 "integer",
81 "string",
82 "list",
83 "directory",
84 "file",
85 "icon"
88 static const gchar* NPWPropertyRestrictionString[] = {
89 "filename"
92 /* Property object
93 *---------------------------------------------------------------------------*/
95 static NPWPropertyType
96 npw_property_type_from_string (const gchar* type)
98 gint i;
100 for (i = 0; i < NPW_LAST_PROPERTY; i++)
102 if (strcmp (NPWPropertyTypeString[i], type) == 0)
104 return (NPWPropertyType)(i + 1);
108 return NPW_UNKNOWN_PROPERTY;
111 static NPWPropertyRestriction
112 npw_property_restriction_from_string (const gchar* restriction)
115 if (restriction != NULL)
117 gint i;
119 for (i = 0; i < NPW_LAST_RESTRICTION; i++)
121 if (strcmp (NPWPropertyRestrictionString[i], restriction) == 0)
123 return (NPWPropertyRestriction)(i + 1);
128 return NPW_NO_RESTRICTION;
131 NPWProperty*
132 npw_property_new (NPWPage* owner)
134 NPWProperty* this;
136 g_return_val_if_fail (owner, NULL);
138 this = g_chunk_new0(NPWProperty, owner->data_pool);
139 this->owner = owner;
140 this->type = NPW_UNKNOWN_PROPERTY;
141 this->restriction = NPW_NO_RESTRICTION;
142 this->item = NULL;
143 /* value is set to NULL */
144 g_node_append_data (owner->list, this);
146 return this;
149 void
150 npw_property_free (NPWProperty* this)
152 GNode* node;
154 if (this->item != NULL)
156 g_slist_free (this->item);
158 node = g_node_find_child (this->owner->list, G_TRAVERSE_ALL, this);
159 if (node != NULL)
161 g_node_destroy (node);
162 /* Memory allocated in string pool and data pool is not free */
166 void
167 npw_property_set_type (NPWProperty* this, NPWPropertyType type)
169 this->type = type;
172 void
173 npw_property_set_string_type (NPWProperty* this, const gchar* type)
175 npw_property_set_type (this, npw_property_type_from_string (type));
179 NPWPropertyType
180 npw_property_get_type (const NPWProperty* this)
182 return this->type;
185 void
186 npw_property_set_restriction (NPWProperty* this, NPWPropertyRestriction restriction)
188 this->restriction = restriction;
191 void
192 npw_property_set_string_restriction (NPWProperty* this, const gchar* restriction)
194 npw_property_set_restriction (this, npw_property_restriction_from_string (restriction));
197 NPWPropertyRestriction
198 npw_property_get_restriction (const NPWProperty* this)
200 return this->restriction;
203 gboolean
204 npw_property_is_valid_restriction (const NPWProperty* this)
206 const gchar *value;
208 switch (this->restriction)
210 case NPW_FILENAME_RESTRICTION:
211 value = npw_property_get_value (this);
213 /* First character should be letters, digit or '_' */
214 if (value == NULL) return TRUE;
215 if (!isalnum (*value) && (*value != '_'))
216 return FALSE;
218 /* Following characters should be letters, digit or '_'
219 * or '-' or '.' */
220 for (value++; *value != '\0'; value++)
222 if (!isalnum (*value)
223 && (*value != '_')
224 && (*value != '-')
225 && (*value != '.'))
226 return FALSE;
228 break;
229 default:
230 break;
233 return TRUE;
236 void
237 npw_property_set_name (NPWProperty* this, const gchar* name)
239 this->value = npw_value_heap_find_value (this->owner->value, name);
242 const gchar*
243 npw_property_get_name (const NPWProperty* this)
245 return npw_value_heap_get_name (this->owner->value, this->value);
248 void
249 npw_property_set_label (NPWProperty* this, const gchar* label)
251 this->label = g_string_chunk_insert (this->owner->string_pool, label);
254 const gchar*
255 npw_property_get_label (const NPWProperty* this)
257 return this->label;
260 void
261 npw_property_set_description (NPWProperty* this, const gchar* description)
263 this->description = g_string_chunk_insert (this->owner->string_pool, description);
266 const gchar*
267 npw_property_get_description (const NPWProperty* this)
269 return this->description;
272 static void
273 cb_boolean_button_toggled (GtkButton *button, gpointer data)
275 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
276 gtk_button_set_label (button, _("Yes"));
277 else
278 gtk_button_set_label (button, _("No"));
281 GtkWidget*
282 npw_property_create_widget (NPWProperty* this)
284 GtkWidget* entry;
285 const gchar* value;
287 value = npw_property_get_value (this);
288 switch (this->type)
290 case NPW_BOOLEAN_PROPERTY:
291 entry = gtk_toggle_button_new_with_label (_("No"));
292 g_signal_connect (G_OBJECT (entry), "toggled",
293 G_CALLBACK (cb_boolean_button_toggled), NULL);
294 if (value)
296 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (entry),
297 (gboolean)atoi (value));
299 break;
300 case NPW_INTEGER_PROPERTY:
301 entry = gtk_spin_button_new (NULL, 1, 0);
302 if (value)
304 gtk_spin_button_set_value (GTK_SPIN_BUTTON (entry), atoi (value));
306 break;
307 case NPW_STRING_PROPERTY:
308 entry = gtk_entry_new ();
309 if (value) gtk_entry_set_text (GTK_ENTRY (entry), value);
310 break;
311 case NPW_DIRECTORY_PROPERTY:
312 entry = gtk_file_chooser_button_new (_("Choose directory"),
313 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
314 if (value)
316 gchar* uri = gnome_vfs_make_uri_from_input (value);
317 gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (entry), uri);
318 g_free (uri);
320 break;
321 case NPW_FILE_PROPERTY:
322 entry = gtk_file_chooser_button_new (_("Choose file"),
323 GTK_FILE_CHOOSER_ACTION_OPEN);
324 if (value)
326 gchar* uri = gnome_vfs_make_uri_from_input (value);
327 gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (entry), uri);
328 g_free (uri);
330 break;
331 case NPW_ICON_PROPERTY:
332 entry = gnome_icon_entry_new("icon_choice", _("Icon choice"));
333 if (value) gnome_icon_entry_set_filename (GNOME_ICON_ENTRY (entry), value);
334 break;
335 case NPW_LIST_PROPERTY:
337 GSList* node;
338 gboolean get_value = FALSE;
340 entry = gtk_combo_box_entry_new_text ();
341 for (node = this->item; node != NULL; node = node->next)
343 gtk_combo_box_append_text (GTK_COMBO_BOX (entry), _(((NPWItem *)node->data)->label));
344 if ((value != NULL) && !get_value && (strcmp (value, ((NPWItem *)node->data)->name) == 0))
346 value = _(((NPWItem *)node->data)->label);
347 get_value = TRUE;
350 if (!(this->options & NPW_EDITABLE_OPTION))
352 gtk_editable_set_editable (GTK_EDITABLE (GTK_BIN (entry)->child), FALSE);
354 if (value) gtk_entry_set_text (GTK_ENTRY (GTK_BIN (entry)->child), value);
355 break;
357 default:
358 return NULL;
360 this->widget = entry;
362 return entry;
365 void
366 npw_property_set_widget (NPWProperty* this, GtkWidget* widget)
368 this->widget = widget;
371 GtkWidget*
372 npw_property_get_widget (const NPWProperty* this)
374 return this->widget;
377 void
378 npw_property_set_default (NPWProperty* this, const gchar* value)
380 /* Check if the default property is valid */
381 if (value && (this->options & NPW_EXIST_SET_OPTION) && !(this->options & NPW_EXIST_OPTION))
383 /* a file or directory with the same name shouldn't exist */
384 if (g_file_test (value, G_FILE_TEST_EXISTS))
386 char* buffer;
387 guint i;
389 /* Allocate memory for the string and a decimal number */
390 buffer = g_new (char, strlen(value) + 8);
391 /* Give up after 1000000 tries */
392 for (i = 1; i < 1000000; i++)
394 sprintf(buffer,"%s%d",value, i);
395 if (!g_file_test (buffer, G_FILE_TEST_EXISTS)) break;
397 this->defvalue = g_string_chunk_insert (this->owner->string_pool, buffer);
398 g_free (buffer);
400 return;
403 /* This function could be used with value = defvalue to only check
404 * the default property */
405 if (this->defvalue != value)
407 this->defvalue = (value == NULL) ? NULL : g_string_chunk_insert (this->owner->string_pool, value);
411 static gboolean
412 npw_property_set_value_from_widget (NPWProperty* this, NPWValueTag tag)
414 gchar* alloc_value = NULL;
415 const gchar* value = NULL;
416 gboolean ok;
418 switch (this->type)
420 case NPW_INTEGER_PROPERTY:
421 alloc_value = g_strdup_printf("%d", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (this->widget)));
422 value = alloc_value;
423 break;
424 case NPW_BOOLEAN_PROPERTY:
425 alloc_value = g_strdup_printf("%d", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (this->widget)));
426 value = alloc_value;
427 break;
428 case NPW_STRING_PROPERTY:
429 value = gtk_entry_get_text (GTK_ENTRY (this->widget));
430 break;
431 case NPW_DIRECTORY_PROPERTY:
432 case NPW_FILE_PROPERTY:
433 alloc_value = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (this->widget));
434 value = alloc_value;
435 break;
436 case NPW_ICON_PROPERTY:
437 alloc_value = gnome_icon_entry_get_filename (GNOME_ICON_ENTRY (this->widget));
438 value = alloc_value;
439 break;
440 case NPW_LIST_PROPERTY:
442 GSList* node;
444 value = gtk_entry_get_text (GTK_ENTRY (GTK_BIN (this->widget)->child));
445 for (node = this->item; node != NULL; node = node->next)
447 if (strcmp (value, _(((NPWItem *)node->data)->label)) == 0)
449 value = ((NPWItem *)node->data)->name;
450 break;
453 break;
455 default:
456 /* Hidden property */
457 value = this->defvalue;
458 break;
461 /* Check and mark default value (will not be saved) */
462 if ((value) && (this->defvalue) && (strcmp (value, this->defvalue) == 0))
464 tag |= NPW_DEFAULT_VALUE;
467 ok = npw_value_heap_set_value (this->owner->value, this->value, value, tag);
468 if (alloc_value != NULL) g_free (alloc_value);
470 return ok;
473 gboolean
474 npw_property_update_value_from_widget (NPWProperty* this)
476 return npw_property_set_value_from_widget (this, NPW_VALID_VALUE);
479 gboolean
480 npw_property_save_value_from_widget (NPWProperty* this)
482 return npw_property_set_value_from_widget (this, NPW_OLD_VALUE);
485 gboolean
486 npw_property_remove_value (NPWProperty* this)
488 return npw_value_heap_set_value (this->owner->value, this->value, NULL, NPW_EMPTY_VALUE);
491 const char*
492 npw_property_get_value (const NPWProperty* this)
494 NPWValueTag tag;
496 tag = npw_value_heap_get_tag (this->owner->value, this->value);
497 if ((tag == NPW_EMPTY_VALUE) || (tag & NPW_DEFAULT_VALUE))
499 return this->defvalue;
501 else
503 /* Only value entered by user could replace default value */
504 return npw_value_heap_get_value (this->owner->value, this->value);
508 gboolean
509 npw_property_add_list_item (NPWProperty* this, const gchar* name, const gchar* label)
511 NPWItem* item;
513 item = g_chunk_new (NPWItem, this->owner->item_pool);
514 item->name = g_string_chunk_insert (this->owner->string_pool, name);
515 item->label = g_string_chunk_insert (this->owner->string_pool, label);
517 this->item = g_slist_append (this->item, item);
519 return TRUE;
522 void
523 npw_property_set_mandatory_option (NPWProperty* this, gboolean value)
525 if (value)
527 this->options |= NPW_MANDATORY_OPTION;
529 else
531 this->options &= ~NPW_MANDATORY_OPTION;
535 void
536 npw_property_set_summary_option (NPWProperty* this, gboolean value)
538 if (value)
540 this->options |= NPW_SUMMARY_OPTION;
542 else
544 this->options &= ~NPW_SUMMARY_OPTION;
548 void
549 npw_property_set_editable_option (NPWProperty* this, gboolean value)
551 if (value)
553 this->options |= NPW_EDITABLE_OPTION;
555 else
557 this->options &= ~NPW_EDITABLE_OPTION;
561 NPWPropertyOptions
562 npw_property_get_options (const NPWProperty* this)
564 return this->options;
567 void
568 npw_property_set_exist_option (NPWProperty* this, NPWPropertyBooleanValue value)
570 switch (value)
572 case NPW_TRUE:
573 this->options |= NPW_EXIST_OPTION | NPW_EXIST_SET_OPTION;
574 break;
575 case NPW_FALSE:
576 this->options &= ~NPW_EXIST_OPTION;
577 this->options |= NPW_EXIST_SET_OPTION;
578 npw_property_set_default (this, this->defvalue);
579 break;
580 case NPW_DEFAULT:
581 this->options &= ~(NPW_EXIST_OPTION | NPW_EXIST_SET_OPTION);
582 break;
586 NPWPropertyBooleanValue
587 npw_property_get_exist_option (const NPWProperty* this)
589 return this->options & NPW_EXIST_SET_OPTION ? (this->options & NPW_EXIST_OPTION ? NPW_TRUE : NPW_FALSE) : NPW_DEFAULT;
592 /* Page object = list of properties
593 *---------------------------------------------------------------------------*/
595 NPWPage*
596 npw_page_new (NPWValueHeap* value)
598 NPWPage* this;
600 this = g_new0(NPWPage, 1);
601 this->string_pool = g_string_chunk_new (STRING_CHUNK_SIZE);
602 this->data_pool = g_mem_chunk_new ("property pool", sizeof (NPWProperty), STRING_CHUNK_SIZE * sizeof (NPWProperty) / 4, G_ALLOC_ONLY);
603 this->item_pool = g_mem_chunk_new ("item pool", sizeof (NPWItem), STRING_CHUNK_SIZE * sizeof (NPWItem) / 4, G_ALLOC_ONLY);
604 this->list = g_node_new (NULL);
605 this->value = value;
607 return this;
610 void
611 npw_page_free (NPWPage* this)
613 g_return_if_fail (this != NULL);
615 g_string_chunk_free (this->string_pool);
616 g_mem_chunk_destroy (this->data_pool);
617 g_mem_chunk_destroy (this->item_pool);
618 g_node_destroy (this->list);
619 g_free (this);
622 void
623 npw_page_set_name (NPWPage* this, const gchar* name)
625 this->name = g_string_chunk_insert (this->string_pool, name);
628 const gchar*
629 npw_page_get_name (const NPWPage* this)
631 return this->name;
634 void
635 npw_page_set_label (NPWPage* this, const gchar* label)
637 this->label = g_string_chunk_insert (this->string_pool, label);
640 const gchar*
641 npw_page_get_label (const NPWPage* this)
643 return this->label;
646 void
647 npw_page_set_description (NPWPage* this, const gchar* description)
649 this->description = g_string_chunk_insert (this->string_pool, description);
652 const gchar*
653 npw_page_get_description (const NPWPage* this)
655 return this->description;
658 typedef struct _PageForeachPropertyData
660 NPWPropertyForeachFunc func;
661 gpointer data;
662 } PageForeachPropertyData;
664 static void
665 cb_page_foreach_property (GNode* node, gpointer data)
667 PageForeachPropertyData* d = (PageForeachPropertyData *)data;
669 (d->func)((NPWProperty*)node->data, d->data);
672 void
673 npw_page_foreach_property (const NPWPage* this, NPWPropertyForeachFunc func, gpointer data)
675 PageForeachPropertyData d;
677 d.func = func;
678 d.data = data;
679 g_node_children_foreach (this->list, G_TRAVERSE_LEAFS, cb_page_foreach_property, &d);