1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 * anjuta-environment-editor.c
4 * Copyright (C) 2011 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
21 #include "anjuta-environment-editor.h"
22 #include <glib/gi18n.h>
33 ENV_DEFAULT_VALUE_COLUMN
,
38 #define ENV_USER_COLOR "black"
39 #define ENV_DEFAULT_COLOR "gray"
42 struct _AnjutaEnvironmentEditor
50 GtkTreeView
*treeview
;
51 GtkWidget
*edit_button
;
52 GtkWidget
*remove_button
;
56 G_DEFINE_TYPE (AnjutaEnvironmentEditor
, anjuta_environment_editor
, GTK_TYPE_BIN
);
60 *---------------------------------------------------------------------------*/
65 anjuta_gtk_tree_model_find_string (GtkTreeModel
*model
, GtkTreeIter
*parent
,
66 GtkTreeIter
*iter
, guint col
, const gchar
*value
)
70 gboolean found
= FALSE
;
72 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), FALSE
);
73 g_return_val_if_fail (iter
!= NULL
, FALSE
);
74 g_return_val_if_fail (value
!= NULL
, FALSE
);
78 valid
= gtk_tree_model_get_iter_first (model
, iter
);
82 valid
= gtk_tree_model_iter_children (model
, iter
, parent
);
89 gtk_tree_model_get (model
, iter
, col
, &mvalue
, -1);
90 found
= (mvalue
!= NULL
) && (strcmp (mvalue
, value
) == 0);
94 if (gtk_tree_model_iter_has_child (model
, iter
))
98 found
= anjuta_gtk_tree_model_find_string (model
, iter
,
106 valid
= gtk_tree_model_iter_next (model
, iter
);
113 *---------------------------------------------------------------------------*/
116 load_environment_variables (AnjutaEnvironmentEditor
*editor
, GtkListStore
*store
)
122 /* Load current environment variables */
127 for (; *var
!= NULL
; var
++)
129 const gchar
*value
= g_getenv (*var
);
130 gtk_list_store_prepend (store
, &iter
);
131 gtk_list_store_set (store
, &iter
,
132 ENV_NAME_COLUMN
, *var
,
133 ENV_VALUE_COLUMN
, value
,
134 ENV_DEFAULT_VALUE_COLUMN
, value
,
135 ENV_COLOR_COLUMN
, ENV_DEFAULT_COLOR
,
141 /* Load user environment variables */
142 var
= editor
->variables
;
145 for (; *var
!= NULL
; var
++)
149 value
= g_strsplit (*var
, "=", 2);
152 if (anjuta_gtk_tree_model_find_string (GTK_TREE_MODEL (store
),
153 NULL
, &iter
, ENV_NAME_COLUMN
,
156 gtk_list_store_set (store
, &iter
,
157 ENV_VALUE_COLUMN
, value
[1],
158 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
163 gtk_list_store_prepend (store
, &iter
);
164 gtk_list_store_set (store
, &iter
,
165 ENV_NAME_COLUMN
, value
[0],
166 ENV_VALUE_COLUMN
, value
[1],
167 ENV_DEFAULT_VALUE_COLUMN
, NULL
,
168 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
178 /* Implement GtkWidget functions
179 *---------------------------------------------------------------------------*/
182 anjuta_environment_editor_size_allocate (GtkWidget
*widget
,
183 GtkAllocation
*allocation
)
188 bin
= GTK_BIN (widget
);
189 child
= gtk_bin_get_child (bin
);
190 if ((child
!= NULL
) && gtk_widget_get_visible (child
))
192 gtk_widget_set_allocation (widget
, allocation
);
193 gtk_widget_size_allocate (child
, allocation
);
198 anjuta_environment_editor_get_preferred_width (GtkWidget
*widget
,
205 bin
= GTK_BIN (widget
);
206 child
= gtk_bin_get_child (bin
);
207 gtk_widget_get_preferred_width (child
, minimum_size
, natural_size
);
211 anjuta_environment_editor_get_preferred_height (GtkWidget
*widget
,
218 bin
= GTK_BIN (widget
);
219 child
= gtk_bin_get_child (bin
);
220 gtk_widget_get_preferred_height (child
, minimum_size
, natural_size
);
224 on_environment_selection_changed (GtkTreeSelection
*selection
, AnjutaEnvironmentEditor
*editor
)
230 if (selection
== NULL
)
232 selection
= gtk_tree_view_get_selection (editor
->treeview
);
235 selected
= gtk_tree_selection_get_selected (selection
, &model
, &iter
);
242 gtk_tree_model_get (model
, &iter
,
243 ENV_DEFAULT_VALUE_COLUMN
, &value
,
244 ENV_COLOR_COLUMN
, &color
,
247 restore
= (strcmp (color
, ENV_USER_COLOR
) == 0) && (value
!= NULL
);
248 gtk_button_set_label (GTK_BUTTON (editor
->remove_button
), restore
? GTK_STOCK_REVERT_TO_SAVED
: GTK_STOCK_DELETE
);
252 gtk_widget_set_sensitive (editor
->remove_button
, selected
);
253 gtk_widget_set_sensitive (editor
->edit_button
, selected
);
257 on_environment_add_button (GtkButton
*button
, GtkTreeView
*view
)
261 GtkTreeViewColumn
*column
;
263 GtkTreeSelection
* sel
;
265 model
= GTK_LIST_STORE (gtk_tree_view_get_model (view
));
267 sel
= gtk_tree_view_get_selection (view
);
268 if (gtk_tree_selection_get_selected (sel
, NULL
, &iter
))
271 gtk_list_store_insert_after (model
, &niter
, &iter
);
276 gtk_list_store_prepend (model
, &iter
);
279 gtk_list_store_set (model
, &iter
, ENV_NAME_COLUMN
, "",
280 ENV_VALUE_COLUMN
, "",
281 ENV_DEFAULT_VALUE_COLUMN
, NULL
,
282 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
285 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (model
), &iter
);
286 column
= gtk_tree_view_get_column (view
, ENV_NAME_COLUMN
);
287 gtk_tree_view_scroll_to_cell (view
, path
, column
, FALSE
, 0, 0);
288 gtk_tree_view_set_cursor (view
, path
, column
,TRUE
);
289 gtk_tree_path_free (path
);
293 on_environment_edit_button (GtkButton
*button
, GtkTreeView
*view
)
296 GtkTreeSelection
* sel
;
298 sel
= gtk_tree_view_get_selection (view
);
299 if (gtk_tree_selection_get_selected (sel
, NULL
, &iter
))
303 GtkTreeViewColumn
*column
;
305 model
= GTK_LIST_STORE (gtk_tree_view_get_model (view
));
306 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (model
), &iter
);
307 column
= gtk_tree_view_get_column (view
, ENV_VALUE_COLUMN
);
308 gtk_tree_view_scroll_to_cell (view
, path
, column
, FALSE
, 0, 0);
309 gtk_tree_view_set_cursor (view
, path
, column
,TRUE
);
310 gtk_tree_path_free (path
);
315 on_environment_remove_button (GtkButton
*button
, AnjutaEnvironmentEditor
*editor
)
318 GtkTreeSelection
* sel
;
319 GtkTreeView
*view
= editor
->treeview
;
321 sel
= gtk_tree_view_get_selection (view
);
322 if (gtk_tree_selection_get_selected (sel
, NULL
, &iter
))
325 GtkTreeViewColumn
*column
;
329 model
= GTK_LIST_STORE (gtk_tree_view_get_model (view
));
331 /* Display variable */
332 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (model
), &iter
);
333 column
= gtk_tree_view_get_column (view
, ENV_NAME_COLUMN
);
334 gtk_tree_view_scroll_to_cell (view
, path
, column
, FALSE
, 0, 0);
335 gtk_tree_path_free (path
);
337 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
338 ENV_COLOR_COLUMN
, &color
,
340 if (strcmp(color
, ENV_USER_COLOR
) == 0)
342 /* Remove an user variable */
345 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
346 ENV_DEFAULT_VALUE_COLUMN
, &value
,
351 /* Restore default environment variable */
352 gtk_list_store_set (model
, &iter
, ENV_VALUE_COLUMN
, value
,
353 ENV_COLOR_COLUMN
, ENV_DEFAULT_COLOR
,
358 gtk_list_store_remove (model
, &iter
);
364 /* Replace value with an empty one */
365 gtk_list_store_set (model
, &iter
, ENV_VALUE_COLUMN
, NULL
,
366 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
369 on_environment_selection_changed (sel
, editor
);
374 move_to_environment_value (gpointer data
)
376 GtkTreeView
*view
= GTK_TREE_VIEW (data
);
377 GtkTreeSelection
* sel
;
380 GtkTreeViewColumn
*column
;
382 sel
= gtk_tree_view_get_selection (view
);
383 if (gtk_tree_selection_get_selected (sel
, &model
, &iter
))
387 path
= gtk_tree_model_get_path (model
, &iter
);
388 column
= gtk_tree_view_get_column (view
, ENV_VALUE_COLUMN
);
389 gtk_tree_view_set_cursor (view
, path
, column
, TRUE
);
390 gtk_tree_path_free (path
);
397 on_environment_variable_edited (GtkCellRendererText
*cell
,
400 AnjutaEnvironmentEditor
*editor
)
406 GtkTreeView
*view
= editor
->treeview
;
408 text
= g_strstrip (text
);
410 model
= GTK_LIST_STORE (gtk_tree_view_get_model (view
));
412 valid
= gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model
), &iter
, path
);
419 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
420 ENV_NAME_COLUMN
, &name
,
421 ENV_VALUE_COLUMN
, &value
,
422 ENV_DEFAULT_VALUE_COLUMN
, &def_value
,
425 if (strcmp(name
, text
) != 0)
428 if (def_value
!= NULL
)
430 /* Remove current variable */
431 gtk_list_store_set (model
, &iter
, ENV_VALUE_COLUMN
, NULL
,
432 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
436 /* Search variable with new name */
437 if (anjuta_gtk_tree_model_find_string (GTK_TREE_MODEL (model
),
438 NULL
, &niter
, ENV_NAME_COLUMN
,
441 if (def_value
== NULL
)
443 gtk_list_store_remove (model
, &iter
);
445 gtk_list_store_set (model
, &niter
,
446 ENV_VALUE_COLUMN
, value
,
447 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
452 if (def_value
!= NULL
)
454 gtk_list_store_insert_after (model
, &niter
, &iter
);
455 gtk_list_store_set (model
, &niter
, ENV_NAME_COLUMN
, text
,
456 ENV_VALUE_COLUMN
, value
,
457 ENV_DEFAULT_VALUE_COLUMN
, NULL
,
458 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
463 gtk_list_store_set (model
, &iter
, ENV_NAME_COLUMN
, text
,
467 g_idle_add (move_to_environment_value
, view
);
476 on_environment_value_edited (GtkCellRendererText
*cell
,
479 AnjutaEnvironmentEditor
*editor
)
483 GtkTreeView
*view
= editor
->treeview
;
485 text
= g_strstrip (text
);
487 model
= GTK_LIST_STORE (gtk_tree_view_get_model (view
));
488 if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model
), &iter
, path
))
490 gtk_list_store_set (model
, &iter
, ENV_VALUE_COLUMN
, text
,
491 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
493 on_environment_selection_changed (NULL
, editor
);
497 /* Implement GtkWidget functions
498 *---------------------------------------------------------------------------*/
501 anjuta_environment_editor_dispose (GObject
*object
)
503 AnjutaEnvironmentEditor
* editor
= ANJUTA_ENVIRONMENT_EDITOR (object
);
505 if (editor
->model
!= NULL
) g_object_unref (editor
->model
);
507 G_OBJECT_CLASS (anjuta_environment_editor_parent_class
)->dispose (object
);
511 anjuta_environment_editor_finalize (GObject
*object
)
513 AnjutaEnvironmentEditor
* editor
= ANJUTA_ENVIRONMENT_EDITOR (object
);
515 g_strfreev (editor
->variables
);
516 editor
->variables
= NULL
;
518 G_OBJECT_CLASS (anjuta_environment_editor_parent_class
)->finalize (object
);
522 anjuta_environment_editor_init (AnjutaEnvironmentEditor
*editor
)
529 GtkWidget
*add_button
;
530 GtkWidget
*edit_button
;
531 GtkWidget
*remove_button
;
533 GtkTreeViewColumn
* column
;
534 GtkCellRenderer
* renderer
;
535 GtkTreeSelection
*selection
;
537 editor
->variables
= NULL
;
539 gtk_widget_set_has_window (GTK_WIDGET (editor
), FALSE
);
540 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (editor
), FALSE
);
542 /* Create all needed widgets */
543 expander
= gtk_expander_new (_("Environment Variables:"));
544 gtk_container_add (GTK_CONTAINER (editor
), expander
);
545 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 6);
546 gtk_box_set_homogeneous (GTK_BOX (hbox
), FALSE
);
547 gtk_container_add (GTK_CONTAINER (expander
), hbox
);
548 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
549 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
), GTK_SHADOW_OUT
);
550 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
552 gtk_box_pack_start (GTK_BOX (hbox
), scrolled
, TRUE
, TRUE
, 0);
553 treeview
= gtk_tree_view_new ();
554 gtk_container_add (GTK_CONTAINER (scrolled
), treeview
);
555 editor
->treeview
= GTK_TREE_VIEW (treeview
);
557 vbutton
= gtk_button_box_new (GTK_ORIENTATION_VERTICAL
);
558 gtk_button_box_set_layout (GTK_BUTTON_BOX (vbutton
), GTK_BUTTONBOX_START
);
559 gtk_box_set_spacing (GTK_BOX (vbutton
), 6);
560 gtk_box_pack_start (GTK_BOX (hbox
), vbutton
, FALSE
, FALSE
, 0);
561 add_button
= gtk_button_new_from_stock (GTK_STOCK_NEW
);
562 gtk_container_add (GTK_CONTAINER (vbutton
), add_button
);
563 edit_button
= gtk_button_new_from_stock (GTK_STOCK_EDIT
);
564 gtk_container_add (GTK_CONTAINER (vbutton
), edit_button
);
565 editor
->edit_button
= edit_button
;
566 remove_button
= gtk_button_new_from_stock (GTK_STOCK_DELETE
);
567 gtk_container_add (GTK_CONTAINER (vbutton
), remove_button
);
568 editor
->remove_button
= remove_button
;
570 gtk_widget_show_all (GTK_WIDGET (editor
));
572 /* Fill environment variable list */
573 model
= GTK_TREE_MODEL (gtk_list_store_new (ENV_N_COLUMNS
,
579 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview
), model
);
580 load_environment_variables (editor
, GTK_LIST_STORE (model
));
581 editor
->model
= g_object_ref (model
);
583 renderer
= gtk_cell_renderer_text_new ();
584 g_signal_connect(renderer
, "edited", (GCallback
) on_environment_variable_edited
, editor
);
585 g_object_set(renderer
, "editable", TRUE
, NULL
);
586 column
= gtk_tree_view_column_new_with_attributes (_("Name"), renderer
,
587 "text", ENV_NAME_COLUMN
,
588 "foreground", ENV_COLOR_COLUMN
,
590 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
591 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
592 renderer
= gtk_cell_renderer_text_new ();
593 g_object_set(renderer
, "editable", TRUE
, NULL
);
594 g_signal_connect(renderer
, "edited", (GCallback
) on_environment_value_edited
, editor
);
595 column
= gtk_tree_view_column_new_with_attributes (_("Value"), renderer
,
596 "text", ENV_VALUE_COLUMN
,
597 "foreground", ENV_COLOR_COLUMN
,
599 gtk_tree_view_column_set_sizing (column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
600 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
602 /* Connect signals */
603 g_signal_connect (G_OBJECT (add_button
), "clicked", G_CALLBACK (on_environment_add_button
), editor
->treeview
);
604 g_signal_connect (G_OBJECT (edit_button
), "clicked", G_CALLBACK (on_environment_edit_button
), editor
->treeview
);
605 g_signal_connect (G_OBJECT (remove_button
), "clicked", G_CALLBACK (on_environment_remove_button
), editor
);
606 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
607 g_signal_connect (selection
, "changed", G_CALLBACK (on_environment_selection_changed
), editor
);
609 on_environment_selection_changed (NULL
, editor
);
613 anjuta_environment_editor_class_init (AnjutaEnvironmentEditorClass
*klass
)
615 GObjectClass
* object_class
= G_OBJECT_CLASS (klass
);
616 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (klass
);
620 * AnjutaEnvironmentEditor::changed:
621 * @widget: the AnjutaEnvironmentEditor that received the signal
623 * The ::changed signal is emitted when an environment variable
624 * is changed (include deleted variables)
626 g_signal_new ("changed",
627 G_OBJECT_CLASS_TYPE (klass
),
629 G_STRUCT_OFFSET (AnjutaEnvironmentEditorClass
, changed
),
631 g_cclosure_marshal_VOID__VOID
,
634 object_class
->dispose
= anjuta_environment_editor_dispose
;
635 object_class
->finalize
= anjuta_environment_editor_finalize
;
637 widget_class
->size_allocate
= anjuta_environment_editor_size_allocate
;
638 widget_class
->get_preferred_width
= anjuta_environment_editor_get_preferred_width
;
639 widget_class
->get_preferred_height
= anjuta_environment_editor_get_preferred_height
;
643 *---------------------------------------------------------------------------*/
646 * anjuta_environment_editor_new:
648 * Returns: A new AnjutaEnvironmentEditor widget
651 anjuta_environment_editor_new (void)
653 return GTK_WIDGET (g_object_new (ANJUTA_TYPE_ENVIRONMENT_EDITOR
, NULL
));
657 * anjuta_environment_editor_set_variable:
658 * @editor: A AnjutaEnvironmentEditor widget
659 * @variable: Environment variable name and value
661 * Set environment variable.
664 anjuta_environment_editor_set_variable (AnjutaEnvironmentEditor
*editor
, const gchar
*variable
)
673 model
= editor
->model
;
675 /* Check is variable is already existing */
676 equal
= strchr (variable
, '=');
677 len
= equal
!= NULL
? equal
- variable
: 0;
679 for (valid
= gtk_tree_model_get_iter_first (model
, &iter
); valid
; valid
= gtk_tree_model_iter_next (model
, &iter
))
681 gtk_tree_model_get (editor
->model
, &iter
,
682 ENV_NAME_COLUMN
, &name
,
684 if (((len
== 0) && (strcmp (name
, variable
) == 0)) ||
685 ((len
!= 0) && (strncmp (name
, variable
, len
) == 0) && (name
[len
] == '\0')))
693 if (!valid
) gtk_list_store_insert_after (GTK_LIST_STORE (model
), &iter
, NULL
);
697 name
= g_strdup (variable
);
698 if (len
!= 0) name
[len
] = '\0';
704 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
, ENV_NAME_COLUMN
, name
,
705 ENV_VALUE_COLUMN
, equal
,
706 ENV_COLOR_COLUMN
, ENV_USER_COLOR
,
712 * anjuta_environment_editor_get_all_variables:
713 * @editor: A AnjutaEnvironmentEditor widget
715 * Returns: A list of all environment variables in a string array.
718 anjuta_environment_editor_get_all_variables (AnjutaEnvironmentEditor
*editor
)
725 all_var
= g_new (gchar
*, gtk_tree_model_iter_n_children (editor
->model
, NULL
) + 1);
728 for (valid
= gtk_tree_model_get_iter_first (editor
->model
, &iter
); valid
; valid
= gtk_tree_model_iter_next (editor
->model
, &iter
))
734 gtk_tree_model_get (editor
->model
, &iter
,
735 ENV_NAME_COLUMN
, &name
,
736 ENV_VALUE_COLUMN
, &value
,
737 ENV_COLOR_COLUMN
, &color
,
740 var
= g_strconcat(name
, "=", value
, NULL
);
752 * anjuta_environment_editor_get_modified_variables:
753 * @editor: A AnjutaEnvironmentEditor widget
755 * Returns: A list of modified environment variables in a string array.
758 anjuta_environment_editor_get_modified_variables (AnjutaEnvironmentEditor
*editor
)
765 /* Allocated a too big array: able to save all environment variables
766 * while we need to save only variables modified by user but it
767 * shouldn't be that big anyway and checking exactly which variable
768 * need to be saved will take more time */
769 mod_var
= g_new (gchar
*, gtk_tree_model_iter_n_children (editor
->model
, NULL
) + 1);
772 for (valid
= gtk_tree_model_get_iter_first (editor
->model
, &iter
); valid
; valid
= gtk_tree_model_iter_next (editor
->model
, &iter
))
778 gtk_tree_model_get (editor
->model
, &iter
,
779 ENV_NAME_COLUMN
, &name
,
780 ENV_VALUE_COLUMN
, &value
,
781 ENV_COLOR_COLUMN
, &color
,
784 /* Save only variables modified by user */
785 if (strcmp(color
, ENV_USER_COLOR
) == 0)
787 *var
= g_strconcat(name
, "=", value
, NULL
);
800 * anjuta_environment_editor_reset:
801 * @editor: A AnjutaEnvironmentEditor widget
803 * Remove all variables modified by the user
806 anjuta_environment_editor_reset (AnjutaEnvironmentEditor
*editor
)
808 gtk_list_store_clear (GTK_LIST_STORE (editor
->model
));
809 load_environment_variables (editor
, GTK_LIST_STORE (editor
->model
));