Updated Spanish translation
[anjuta-git-plugin.git] / plugins / tools / tool.c
bloba08758847c7e2944a7acca03dedd9292a1319b97
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 tool.c
4 Copyright (C) 2005 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 * Keep all external tool data (ATPUserTool)
23 * All tools belong to a list (ATPToolList) which take care of allocating
24 * memory for them. This tool list is implemented with a linked list of all
25 * tools and a hash table to allow a fast access to a tool from its name.
27 * It is possible to read tools configuration from differents files (typically
28 * a file in a system directory and another one in an user directory) and to
29 * have the same tools (= same name) defined in both files. In this case
30 * both are in the list and each tool have a different storage number and are
31 * linked with a pointer named over.
33 * It is not possible to ordered tool with different storage order. But to
34 * emulate this function, it is possible to create new tools with the same
35 * data in the right storage location.
36 *---------------------------------------------------------------------------*/
38 #include <config.h>
40 #include "tool.h"
42 #include "execute.h"
44 #include <libanjuta/anjuta-ui.h>
46 /*---------------------------------------------------------------------------*/
48 #define STRING_CHUNK_SIZE 256
50 /*---------------------------------------------------------------------------*/
52 struct _ATPUserTool
54 gchar *name;
55 gchar *command; /* Command and parameters are in two variables */
56 gchar *param;
57 gchar *working_dir;
58 ATPToolFlag flags;
59 ATPOutputType output;
60 ATPOutputType error;
61 ATPInputType input;
62 gchar *input_string;
63 ATPToolStore storage;
64 GtkWidget* menu_item;
65 guint accel_key;
66 GdkModifierType accel_mods;
67 gchar *icon;
68 ATPToolList *owner;
69 ATPUserTool *over; /* Same tool in another storage */
70 ATPUserTool *next; /* Next tool in the list */
71 ATPUserTool *prev; /* Previous tool in the list */
74 /* Tools helper functions (map enum to string)
75 *---------------------------------------------------------------------------*/
77 ATPEnumType output_type_list[] = {
78 {ATP_TOUT_SAME, "Same than output"},
79 {ATP_TOUT_COMMON_PANE, "Existing message pane"},
80 {ATP_TOUT_NEW_PANE, "New message pane"},
81 {ATP_TOUT_NEW_BUFFER, "New buffer"},
82 {ATP_TOUT_REPLACE_BUFFER, "Replace buffer"},
83 {ATP_TOUT_INSERT_BUFFER, "Insert in buffer"},
84 {ATP_TOUT_APPEND_BUFFER, "Append to buffer"},
85 {ATP_TOUT_REPLACE_SELECTION, "Replace selection"},
86 {ATP_TOUT_POPUP_DIALOG, "Popup dialog"},
87 {ATP_TOUT_NULL, "Discard output"},
88 {-1, NULL}
91 ATPEnumType input_type_list[] = {
92 {ATP_TIN_NONE, "None"},
93 {ATP_TIN_BUFFER, "Current buffer"},
94 {ATP_TIN_SELECTION, "Current selection"},
95 {ATP_TIN_STRING, "String"},
96 {ATP_TIN_FILE, "File"},
97 {-1, NULL}
100 /*---------------------------------------------------------------------------*/
102 const ATPEnumType* atp_get_output_type_list (void)
104 return &output_type_list[1];
107 const ATPEnumType* atp_get_error_type_list (void)
109 return &output_type_list[0];
112 const ATPEnumType* atp_get_input_type_list (void)
114 return &input_type_list[0];
117 /* Return a copy of the name without mnemonic (underscore) */
118 gchar*
119 atp_remove_mnemonic (const gchar* label)
121 const char *src;
122 char *dst;
123 char *without;
125 without = g_new (char, strlen(label) + 1);
126 dst = without;
127 for (src = label; *src != '\0'; ++src)
129 if (*src == '_')
131 /* Remove single underscore */
132 ++src;
134 *dst++ = *src;
136 *dst = *src;
138 return without;
141 /* Tool object
143 *---------------------------------------------------------------------------*/
145 /* Private functions
146 *---------------------------------------------------------------------------*/
148 /* Remove tool from list but doesn't remove from hash table */
150 static gboolean
151 atp_user_tool_remove_list (ATPUserTool* this)
153 g_return_val_if_fail (this, FALSE);
154 g_return_val_if_fail (this->owner, FALSE);
156 /* Remove from storage list */
157 if (this->owner->list == this)
159 /* First tool in the list */
160 this->owner->list = this->next;
161 if (this->next != NULL)
163 this->next->prev = NULL;
166 else
168 if (this->next != NULL)
170 this->next->prev = this->prev;
172 if (this->prev != NULL)
174 this->prev->next = this->next;
177 this->next = NULL;
178 this->prev = NULL;
180 return TRUE;
183 /* Add tool in list but doesn't add in hash table */
185 static gboolean
186 atp_user_tool_append_list (ATPUserTool *this, ATPUserTool *tool)
188 g_return_val_if_fail (tool, FALSE);
190 /* Keep storage type ordered */
191 if (this == NULL)
193 ATPUserTool* first;
194 /* Insert at the beginning of list (with right storage) */
195 for (first = tool->owner->list; first != NULL; first = first->next)
197 if (first->storage >= tool->storage) break;
198 this = first;
202 /* If this is NULL insert at the beginning of the list */
203 if (this == NULL)
205 tool->next = tool->owner->list;
206 if (tool->next != NULL)
207 tool->next->prev = tool;
208 tool->owner->list = tool;
209 tool->prev = NULL;
211 else if ((this->storage == tool->storage) || (this->next == NULL) || (this->next->storage >= tool->storage))
213 /* Insert tool in list */
214 tool->prev = this;
215 tool->next = this->next;
216 this->next = tool;
217 if (tool->next)
219 tool->next->prev = tool;
222 else if (this->storage < tool->storage)
224 ATPUserTool *prev;
225 /* Insert tool at the beginning of storage list */
226 atp_user_tool_append_list (NULL, tool);
228 /* Create new tool with the right storage and reorder them */
229 for (prev = tool;(prev = atp_user_tool_previous (prev)) != this;)
231 ATPUserTool *clone;
233 clone = atp_user_tool_new (this->owner, prev->name, tool->storage);
234 atp_user_tool_append_list (tool, clone);
237 else
239 /* Unable to handle this case */
240 g_return_val_if_reached (FALSE);
241 return FALSE;
244 return TRUE;
247 /* Remove from hash table and list */
249 static gboolean
250 atp_user_tool_remove (ATPUserTool *this)
252 if (this->name != NULL)
254 /* Remove from hash table */
255 ATPUserTool *first;
257 first = (ATPUserTool *)g_hash_table_lookup (this->owner->hash, this->name);
258 if (first == NULL)
260 /* Unable to find tool */
261 g_return_val_if_reached (FALSE);
263 if (first == this)
265 if (this->over == NULL)
267 g_hash_table_remove (this->owner->hash, this->name);
269 else
271 g_hash_table_replace (this->owner->hash, this->name, this->over);
274 else
276 for (; first->over != this; first = first->over)
278 if (first == NULL)
280 /* Unable to find tool */
281 return FALSE;
284 first->over = this->over;
288 /* Remove from list */
289 return atp_user_tool_remove_list (this);
292 /* Replace tool name */
294 static gboolean
295 atp_user_tool_replace_name (ATPUserTool *this, const gchar *name)
297 if ((name != NULL) && (g_hash_table_lookup (this->owner->hash, name) != NULL))
299 /* Name already exist */
300 return FALSE;
303 if (this->name != NULL)
305 ATPUserTool *first;
307 first = (ATPUserTool *) g_hash_table_lookup (this->owner->hash, this->name);
309 if (first->over == NULL)
311 g_return_val_if_fail (first == this, FALSE);
313 g_hash_table_remove (this->owner->hash, this->name);
315 else
317 /* Remove tool from override list */
318 if (first == this)
320 g_hash_table_replace (this->owner->hash, this->name, this->over);
321 this->over = NULL;
323 else
325 ATPUserTool *tool;
327 for (tool = first; tool->over != this; tool = tool->over)
329 /* Tool not in list */
330 g_return_val_if_fail (tool->over != NULL, FALSE);
332 tool->over = this->over;
337 /* Add in list */
338 this->name = name == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, name);
339 if (name != NULL)
341 /* Add name in hash table */
342 g_hash_table_insert (this->owner->hash, this->name, this);
345 return TRUE;
348 /* Creation and Destruction
349 *---------------------------------------------------------------------------*/
351 /* Create a tool with corresponding name and storage
352 * but does NOT add it in the list */
354 ATPUserTool *
355 atp_user_tool_new (ATPToolList *list, const gchar *name, ATPToolStore storage)
357 ATPUserTool *first;
358 ATPUserTool *tool;
360 g_return_val_if_fail (list, NULL);
362 if (name)
364 /* Search tool in hash table */
365 first = (ATPUserTool *) g_hash_table_lookup (list->hash, name);
366 if (first != NULL)
368 /* Search tool in the list */
369 for(tool = first;; tool = tool->over)
371 if (tool->storage == storage)
373 /* Tool already exist */
375 return NULL;
377 else if (tool->storage > storage)
379 /* Add tool before */
380 g_return_val_if_fail (tool == first, NULL);
382 tool = g_chunk_new0(ATPUserTool, list->data_pool);
383 tool->over = first;
384 tool->flags = ATP_TOOL_ENABLE;
385 tool->name = first->name;
386 g_hash_table_replace (list->hash, tool->name, tool);
387 break;
389 else if ((tool->over == NULL) || (tool->over->storage > storage))
391 /* Add tool after, using previous values as default */
392 first = g_chunk_new(ATPUserTool, list->data_pool);
393 memcpy(first, tool, sizeof (ATPUserTool));
394 first->over = tool->over;
395 tool->over = first;
396 tool->menu_item = NULL;
397 tool = tool->over;
398 break;
402 else
404 /* Create new tool */
405 tool = g_chunk_new0(ATPUserTool, list->data_pool);
406 tool->flags = ATP_TOOL_ENABLE;
407 tool->name = g_string_chunk_insert_const (list->string_pool, name);
408 g_hash_table_insert (list->hash, tool->name, tool);
411 else
413 /* Create stand alone tool */
414 tool = g_chunk_new0(ATPUserTool, list->data_pool);
415 tool->flags = ATP_TOOL_ENABLE;
418 /* Set default values */
419 tool->storage = storage;
420 tool->owner = list;
422 return tool;
425 void
426 atp_user_tool_free (ATPUserTool *this)
428 g_return_if_fail (this->owner);
430 atp_user_tool_remove (this);
431 atp_user_tool_deactivate (this);
433 g_chunk_free (this, this->owner->data_pool);
437 /* Access tool data
438 *---------------------------------------------------------------------------*/
440 gboolean
441 atp_user_tool_set_name (ATPUserTool *this, const gchar *value)
443 if ((value != this->name) && ((value == NULL) || (this->name == NULL) || (strcmp (value, this->name) != 0)))
445 return atp_user_tool_replace_name (this, value);
448 return TRUE;
451 const gchar*
452 atp_user_tool_get_name (const ATPUserTool* this)
454 return this->name;
457 void
458 atp_user_tool_set_command (ATPUserTool* this, const gchar* value)
460 this->command = value == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, value);
463 const gchar*
464 atp_user_tool_get_command (const ATPUserTool* this)
466 return this->command;
469 void
470 atp_user_tool_set_param (ATPUserTool* this, const gchar* value)
472 this->param = value == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, value);
475 const gchar*
476 atp_user_tool_get_param (const ATPUserTool* this)
478 return this->param;
481 void
482 atp_user_tool_set_working_dir (ATPUserTool* this, const gchar* value)
484 this->working_dir = value == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, value);
487 const gchar*
488 atp_user_tool_get_working_dir (const ATPUserTool* this)
490 return this->working_dir;
493 void
494 atp_user_tool_set_flag (ATPUserTool* this, ATPToolFlag flag)
496 switch (flag & ATP_OPERATION)
498 case ATP_SET:
499 this->flags |= flag;
500 break;
501 case ATP_CLEAR:
502 this->flags &= ~flag;
503 break;
504 case ATP_TOGGLE:
505 this->flags ^= flag;
506 break;
507 default:
508 g_return_if_reached();
511 if ((flag & ATP_TOOL_ENABLE) && (this->menu_item != NULL))
513 /* Enable or disable menu item */
514 gtk_widget_set_sensitive (this->menu_item, this->flags & ATP_TOOL_ENABLE);
518 gboolean
519 atp_user_tool_get_flag (const ATPUserTool* this, ATPToolFlag flag)
521 return this->flags & flag ? TRUE : FALSE;
524 void
525 atp_user_tool_set_output (ATPUserTool *this, ATPOutputType output)
527 this->output = output;
530 ATPOutputType
531 atp_user_tool_get_output (const ATPUserTool *this)
533 return this->output;
536 void
537 atp_user_tool_set_error (ATPUserTool *this, ATPOutputType error)
539 this->error = error;
542 ATPOutputType
543 atp_user_tool_get_error (const ATPUserTool *this )
545 return this->error;
548 void
549 atp_user_tool_set_input (ATPUserTool *this, ATPInputType type, const gchar* value)
551 this->input = type;
552 this->input_string = value == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, value);
555 ATPInputType
556 atp_user_tool_get_input (const ATPUserTool *this )
558 return this->input;
561 const gchar*
562 atp_user_tool_get_input_string (const ATPUserTool *this )
564 return this->input_string;
567 void
568 atp_user_tool_set_accelerator (ATPUserTool *this, guint key, GdkModifierType mods)
570 this->accel_key = key;
571 this->accel_mods = mods;
574 gboolean
575 atp_user_tool_get_accelerator (const ATPUserTool *this, guint *key, GdkModifierType *mods)
577 *key = this->accel_key;
578 *mods = this->accel_mods;
580 return this->accel_key != 0;
583 void atp_user_tool_set_icon (ATPUserTool *this, const gchar* value)
585 this->icon = value == NULL ? NULL : g_string_chunk_insert_const (this->owner->string_pool, value);
588 const gchar* atp_user_tool_get_icon (const ATPUserTool *this)
590 return this->icon;
593 ATPToolStore atp_user_tool_get_storage (const ATPUserTool *this)
595 return this->storage;
598 ATPPlugin*
599 atp_user_tool_get_plugin (ATPUserTool* this)
601 return this->owner->plugin;
604 gboolean
605 atp_user_tool_is_valid (const ATPUserTool* this)
607 return (this->command != NULL);
610 /* Additional tool functions
611 *---------------------------------------------------------------------------*/
613 ATPUserTool*
614 atp_user_tool_next (ATPUserTool *this)
616 while ((this = this->next))
618 /* Skip unnamed and overridden tool */
619 if ((this->name != NULL) && (this->over == NULL)) break;
622 return this;
625 ATPUserTool*
626 atp_user_tool_next_in_same_storage (ATPUserTool *this)
628 ATPToolStore storage;
630 storage = this->storage;
631 while ((this = this->next))
633 /* Skip unnamed */
634 if (this->storage != storage) return NULL;
635 if (this->name != NULL) break;
638 return this;
641 ATPUserTool*
642 atp_user_tool_previous (ATPUserTool *this)
644 while ((this = this->prev))
646 /* Skip unnamed and overridden tool */
647 if ((this->name != NULL) && (this->over == NULL)) break;
650 return this;
653 ATPUserTool*
654 atp_user_tool_override (const ATPUserTool *this)
656 ATPUserTool* tool;
658 for (tool = g_hash_table_lookup (this->owner->hash, this->name);
659 tool != NULL; tool = tool->over)
661 if (tool->over == this) return tool;
664 return NULL;
667 ATPUserTool*
668 atp_user_tool_append_new (ATPUserTool *this, const gchar *name, ATPToolStore storage)
670 ATPUserTool *tool;
672 g_return_val_if_fail (this, NULL);
674 /* Create tool */
675 tool = atp_user_tool_new (this->owner, name, storage);
676 if (tool)
678 atp_user_tool_append_list (this, tool);
681 return tool;
684 ATPUserTool*
685 atp_user_tool_clone_new (ATPUserTool *this, ATPToolStore storage)
687 ATPUserTool *tool;
689 g_return_val_if_fail (this, NULL);
691 /* Create tool */
692 tool = atp_user_tool_new (this->owner, this->name, storage);
693 if (tool)
695 ATPUserTool *prev;
697 prev = atp_user_tool_previous (this);
698 atp_user_tool_append_list (prev, tool);
701 return tool;
704 gboolean
705 atp_user_tool_move_after (ATPUserTool *this, ATPUserTool *position)
707 g_return_val_if_fail (this, FALSE);
709 if (!atp_user_tool_remove_list (this)) return FALSE;
710 return atp_user_tool_append_list (position, this);
713 void
714 atp_user_tool_deactivate (ATPUserTool* this)
716 /* accelerator is destroyed with the widget */
717 if (this->menu_item)
719 gtk_widget_destroy (this->menu_item);
720 this->menu_item = NULL;
724 gboolean
725 atp_user_tool_activate (ATPUserTool *this, GtkMenu *submenu, GtkAccelGroup *group)
727 /* Remove previous menu */
728 atp_user_tool_deactivate (this);
730 /* Create new menu item */
731 this->menu_item = gtk_image_menu_item_new_with_mnemonic (this->name);
732 gtk_widget_set_sensitive (this->menu_item, this->flags & ATP_TOOL_ENABLE);
734 /* Add icon */
735 if ((this->menu_item != NULL) && (this->icon != NULL))
737 GdkPixbuf *pixbuf;
738 GdkPixbuf *scaled_pixbuf;
739 gint height, width;
741 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (this->menu_item), GTK_ICON_SIZE_MENU, &width, &height);
743 pixbuf = gdk_pixbuf_new_from_file (this->icon, NULL);
744 if (pixbuf)
746 GtkWidget* icon;
748 scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
749 icon = gtk_image_new_from_pixbuf (scaled_pixbuf);
750 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (this->menu_item), icon);
751 g_object_unref (pixbuf);
752 g_object_unref (scaled_pixbuf);
756 g_signal_connect (G_OBJECT (this->menu_item), "activate", G_CALLBACK (atp_user_tool_execute), this);
758 if (this->accel_key != 0)
760 gtk_widget_add_accelerator(this->menu_item, "activate", group, this->accel_key, this->accel_mods, GTK_ACCEL_VISIBLE);
763 gtk_menu_shell_append (GTK_MENU_SHELL (submenu), this->menu_item);
764 gtk_widget_show(this->menu_item);
766 return TRUE;
769 /* Tool list object containing all tools
770 *---------------------------------------------------------------------------*/
772 ATPToolList *
773 atp_tool_list_construct (ATPToolList* this, ATPPlugin* plugin)
775 this->plugin = plugin;
776 this->ui = anjuta_shell_get_ui (ANJUTA_PLUGIN(plugin)->shell, NULL);
777 this->list = NULL;
778 this->hash = g_hash_table_new (g_str_hash, g_str_equal);
779 this->string_pool = g_string_chunk_new (STRING_CHUNK_SIZE);
780 this->data_pool = g_mem_chunk_new ("tool pool", sizeof (ATPUserTool), STRING_CHUNK_SIZE * sizeof (ATPUserTool) / 4, G_ALLOC_AND_FREE);
782 return this;
785 void atp_tool_list_destroy (ATPToolList* this)
787 g_hash_table_destroy (this->hash);
788 g_string_chunk_free (this->string_pool);
789 g_mem_chunk_destroy (this->data_pool);
792 /*---------------------------------------------------------------------------*/
794 ATPUserTool *
795 atp_tool_list_last (ATPToolList *this)
797 ATPUserTool *tool;
798 ATPUserTool *last;
800 last = NULL;
801 for (tool = this->list; tool != NULL; tool = tool->next)
803 /* Skip tool not registered */
804 if (tool->name != NULL)
806 last = tool;
810 return last;
813 static ATPUserTool *
814 atp_tool_list_last_in_storage (const ATPToolList *this, ATPToolStore storage)
816 ATPUserTool *tool;
817 ATPUserTool *last;
819 last = NULL;
820 for (tool = this->list; tool != NULL; tool = tool->next)
822 if (tool->storage > storage) break;
823 /* Skip tool not registered */
824 if (tool->name != NULL)
826 last = tool;
830 return last;
833 ATPUserTool*
834 atp_tool_list_first (ATPToolList *this)
836 ATPUserTool *tool;
838 for (tool = this->list; tool != NULL; tool = tool->next)
840 /* Skip unnamed and overridden tool*/
841 if ((tool->name != NULL) && (tool->over == NULL))
843 return tool;
847 return NULL;
850 ATPUserTool*
851 atp_tool_list_first_in_storage (ATPToolList *this, ATPToolStore storage)
853 ATPUserTool *tool;
855 for (tool = this->list; tool != NULL; tool = tool->next)
857 /* Skip unamed tool */
858 if ((tool->name != NULL) && (tool->storage == storage))
860 return tool;
864 return NULL;
867 ATPUserTool *
868 atp_tool_list_append_new (ATPToolList *this, const gchar *name, ATPToolStore storage)
870 ATPUserTool *tool;
872 g_return_val_if_fail (this, NULL);
874 /* Create tool */
875 tool = atp_user_tool_new (this, name, storage);
877 /* Add it in one of the storage list if necessary */
878 if (tool)
880 atp_user_tool_append_list (atp_tool_list_last_in_storage (this, storage), tool);
883 return tool;
886 gboolean atp_tool_list_activate (ATPToolList *this)
888 ATPUserTool *next;
889 GtkMenu* menu;
890 GtkAccelGroup* group;
892 menu = GTK_MENU (gtk_menu_item_get_submenu (GTK_MENU_ITEM (gtk_ui_manager_get_widget (GTK_UI_MANAGER(this->ui), MENU_PLACEHOLDER))));
893 group = anjuta_ui_get_accel_group(this->ui);
895 for (next = atp_tool_list_first (this); next != NULL; next = atp_user_tool_next (next))
897 atp_user_tool_activate (next, menu, group);
900 return TRUE;