1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * anjuta-environment-editor.c
4  * Copyright (C) 2011 Sebastien Granjoux
5  *
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.
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
14  *  GNU General Public License for more details.
15  *
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
19  */
20 
21 #include "anjuta-environment-editor.h"
22 #include <glib/gi18n.h>
23 
24 enum
25 {
26 	CHANGED,
27 	LAST_SIGNAL
28 };
29 
30 enum {
31 	ENV_NAME_COLUMN = 0,
32 	ENV_VALUE_COLUMN,
33 	ENV_DEFAULT_VALUE_COLUMN,
34 	ENV_COLOR_COLUMN,
35 	ENV_N_COLUMNS
36 };
37 
38 #define ENV_USER_COLOR	"black"
39 #define ENV_DEFAULT_COLOR "gray"
40 
41 
42 struct _AnjutaEnvironmentEditor
43 {
44 	GtkBin parent;
45 
46 	gchar **variables;
47 
48 	GtkTreeModel *model;
49 
50 	GtkTreeView *treeview;
51 	GtkWidget *edit_button;
52 	GtkWidget *remove_button;
53 };
54 
55 
56 G_DEFINE_TYPE (AnjutaEnvironmentEditor, anjuta_environment_editor, GTK_TYPE_BIN);
57 
58 
59 /* Helpers functions
60  *---------------------------------------------------------------------------*/
61 
62 #include <string.h>
63 
64 static gboolean
anjuta_gtk_tree_model_find_string(GtkTreeModel * model,GtkTreeIter * parent,GtkTreeIter * iter,guint col,const gchar * value)65 anjuta_gtk_tree_model_find_string (GtkTreeModel *model, GtkTreeIter *parent,
66 		GtkTreeIter *iter, guint col, const gchar *value)
67 
68 {
69 	gboolean valid;
70 	gboolean found = FALSE;
71 
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);
75 
76 	if (!parent)
77 	{
78 		valid = gtk_tree_model_get_iter_first (model, iter);
79 	}
80 	else
81 	{
82 		valid = gtk_tree_model_iter_children (model, iter, parent);
83 	}
84 
85 	while (valid)
86 	{
87 		gchar *mvalue;
88 
89 		gtk_tree_model_get (model, iter, col, &mvalue, -1);
90 		found = (mvalue != NULL) && (strcmp (mvalue, value) == 0);
91 		g_free (mvalue);
92 		if (found) break;
93 
94 		if (gtk_tree_model_iter_has_child (model, iter))
95 		{
96 			GtkTreeIter citer;
97 
98 			found = anjuta_gtk_tree_model_find_string (model, iter,
99 														   &citer, col, value);
100 			if (found)
101 			{
102 				*iter = citer;
103 				break;
104 			}
105 		}
106 		valid = gtk_tree_model_iter_next (model, iter);
107 	}
108 
109 	return found;
110 }
111 
112 /* Private functions
113  *---------------------------------------------------------------------------*/
114 
115 static void
load_environment_variables(AnjutaEnvironmentEditor * editor,GtkListStore * store)116 load_environment_variables (AnjutaEnvironmentEditor *editor, GtkListStore *store)
117 {
118 	GtkTreeIter iter;
119 	gchar **var;
120 	gchar **list;
121 
122 	/* Load current environment variables */
123 	list = g_listenv();
124 	var = list;
125 	if (var)
126 	{
127 		for (; *var != NULL; var++)
128 		{
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,
136 								-1);
137 		}
138 	}
139 	g_strfreev (list);
140 
141 	/* Load user environment variables */
142 	var = editor->variables;
143 	if (var)
144 	{
145 		for (; *var != NULL; var++)
146 		{
147 			gchar ** value;
148 
149 			value = g_strsplit (*var, "=", 2);
150 			if (value)
151 			{
152 				if (anjuta_gtk_tree_model_find_string (GTK_TREE_MODEL (store),
153 													NULL, &iter, ENV_NAME_COLUMN,
154 													value[0]))
155 				{
156 					gtk_list_store_set (store, &iter,
157 									ENV_VALUE_COLUMN, value[1],
158 									ENV_COLOR_COLUMN, ENV_USER_COLOR,
159 									-1);
160 				}
161 				else
162 				{
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,
169 										-1);
170 				}
171 				g_strfreev (value);
172 			}
173 		}
174 	}
175 }
176 
177 
178 /* Implement GtkWidget functions
179  *---------------------------------------------------------------------------*/
180 
181 static void
anjuta_environment_editor_size_allocate(GtkWidget * widget,GtkAllocation * allocation)182 anjuta_environment_editor_size_allocate (GtkWidget     *widget,
183                                          GtkAllocation *allocation)
184 {
185 	GtkBin *bin;
186 	GtkWidget *child;
187 
188 	bin = GTK_BIN (widget);
189 	child = gtk_bin_get_child (bin);
190 	if ((child != NULL) && gtk_widget_get_visible (child))
191 	{
192 		gtk_widget_set_allocation (widget, allocation);
193 		gtk_widget_size_allocate (child, allocation);
194 	}
195 }
196 
197 static void
anjuta_environment_editor_get_preferred_width(GtkWidget * widget,gint * minimum_size,gint * natural_size)198 anjuta_environment_editor_get_preferred_width (GtkWidget *widget,
199                                gint      *minimum_size,
200                                gint      *natural_size)
201 {
202 	GtkBin *bin;
203 	GtkWidget *child;
204 
205 	bin = GTK_BIN (widget);
206 	child = gtk_bin_get_child (bin);
207 	gtk_widget_get_preferred_width (child, minimum_size, natural_size);
208 }
209 
210 static void
anjuta_environment_editor_get_preferred_height(GtkWidget * widget,gint * minimum_size,gint * natural_size)211 anjuta_environment_editor_get_preferred_height (GtkWidget *widget,
212                                 gint      *minimum_size,
213                                 gint      *natural_size)
214 {
215 	GtkBin *bin;
216 	GtkWidget *child;
217 
218 	bin = GTK_BIN (widget);
219 	child = gtk_bin_get_child (bin);
220 	gtk_widget_get_preferred_height (child, minimum_size, natural_size);
221 }
222 
223 static void
on_environment_selection_changed(GtkTreeSelection * selection,AnjutaEnvironmentEditor * editor)224 on_environment_selection_changed (GtkTreeSelection *selection, AnjutaEnvironmentEditor *editor)
225 {
226 	GtkTreeIter iter;
227 	GtkTreeModel *model;
228 	gboolean selected;
229 
230 	if (selection == NULL)
231 	{
232 		selection = gtk_tree_view_get_selection (editor->treeview);
233 	}
234 
235 	selected = gtk_tree_selection_get_selected (selection, &model, &iter);
236 	if (selected)
237 	{
238 		gchar *color;
239 		gchar *value;
240 		gboolean restore;
241 
242 		gtk_tree_model_get (model, &iter,
243 							ENV_DEFAULT_VALUE_COLUMN, &value,
244 							ENV_COLOR_COLUMN, &color,
245 							-1);
246 
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);
249 		g_free (color);
250 		g_free (value);
251 	}
252 	gtk_widget_set_sensitive (editor->remove_button, selected);
253 	gtk_widget_set_sensitive (editor->edit_button, selected);
254 }
255 
256 static void
on_environment_add_button(GtkButton * button,GtkTreeView * view)257 on_environment_add_button (GtkButton *button, GtkTreeView *view)
258 {
259 	GtkTreeIter iter;
260 	GtkListStore *model;
261 	GtkTreeViewColumn *column;
262 	GtkTreePath *path;
263 	GtkTreeSelection* sel;
264 
265 	model = GTK_LIST_STORE (gtk_tree_view_get_model (view));
266 
267 	sel = gtk_tree_view_get_selection (view);
268 	if (gtk_tree_selection_get_selected (sel, NULL, &iter))
269 	{
270 		GtkTreeIter niter;
271 		gtk_list_store_insert_after	(model, &niter, &iter);
272 		iter = niter;
273 	}
274 	else
275 	{
276 		gtk_list_store_prepend (model, &iter);
277 	}
278 
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,
283 								-1);
284 
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);
290 }
291 
292 static void
on_environment_edit_button(GtkButton * button,GtkTreeView * view)293 on_environment_edit_button (GtkButton *button, GtkTreeView *view)
294 {
295 	GtkTreeIter iter;
296 	GtkTreeSelection* sel;
297 
298 	sel = gtk_tree_view_get_selection (view);
299 	if (gtk_tree_selection_get_selected (sel, NULL, &iter))
300 	{
301 		GtkListStore *model;
302 		GtkTreePath *path;
303 		GtkTreeViewColumn *column;
304 
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);
311 	}
312 }
313 
314 static void
on_environment_remove_button(GtkButton * button,AnjutaEnvironmentEditor * editor)315 on_environment_remove_button (GtkButton *button, AnjutaEnvironmentEditor *editor)
316 {
317 	GtkTreeIter iter;
318 	GtkTreeSelection* sel;
319 	GtkTreeView *view = editor->treeview;
320 
321 	sel = gtk_tree_view_get_selection (view);
322 	if (gtk_tree_selection_get_selected (sel, NULL, &iter))
323 	{
324 		GtkListStore *model;
325 		GtkTreeViewColumn *column;
326 		GtkTreePath *path;
327 		gchar *color;
328 
329 		model = GTK_LIST_STORE (gtk_tree_view_get_model (view));
330 
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);
336 
337 		gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
338 							ENV_COLOR_COLUMN, &color,
339 							-1);
340 		if (strcmp(color, ENV_USER_COLOR) == 0)
341 		{
342 			/* Remove an user variable */
343 			gchar *value;
344 
345 			gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
346 								ENV_DEFAULT_VALUE_COLUMN, &value,
347 								-1);
348 
349 			if (value != NULL)
350 			{
351 				/* Restore default environment variable */
352 				gtk_list_store_set (model, &iter, ENV_VALUE_COLUMN, value,
353 									ENV_COLOR_COLUMN, ENV_DEFAULT_COLOR,
354 									-1);
355 			}
356 			else
357 			{
358 				gtk_list_store_remove (model, &iter);
359 			}
360 			g_free (value);
361 		}
362 		else
363 		{
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,
367 								-1);
368 		}
369 		on_environment_selection_changed (sel, editor);
370 	}
371 }
372 
373 static gboolean
move_to_environment_value(gpointer data)374 move_to_environment_value (gpointer data)
375 {
376 	GtkTreeView *view = GTK_TREE_VIEW (data);
377 	GtkTreeSelection* sel;
378 	GtkTreeModel *model;
379 	GtkTreeIter iter;
380 	GtkTreeViewColumn *column;
381 
382 	sel = gtk_tree_view_get_selection (view);
383 	if (gtk_tree_selection_get_selected (sel, &model, &iter))
384 	{
385 		GtkTreePath *path;
386 
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);
391 	}
392 
393 	return FALSE;
394 }
395 
396 static void
on_environment_variable_edited(GtkCellRendererText * cell,gchar * path,gchar * text,AnjutaEnvironmentEditor * editor)397 on_environment_variable_edited (GtkCellRendererText *cell,
398 						  gchar *path,
399                           gchar *text,
400                           AnjutaEnvironmentEditor *editor)
401 {
402 	GtkTreeIter iter;
403 	GtkTreeIter niter;
404 	GtkListStore *model;
405 	gboolean valid;
406 	GtkTreeView *view = editor->treeview;
407 
408 	text = g_strstrip (text);
409 
410 	model = GTK_LIST_STORE (gtk_tree_view_get_model (view));
411 
412 	valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model), &iter, path);
413 	if (valid)
414 	{
415 		gchar *name;
416 		gchar *value;
417 		gchar *def_value;
418 
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,
423 							-1);
424 
425 		if (strcmp(name, text) != 0)
426 		{
427 
428 			if (def_value != NULL)
429 			{
430 				/* Remove current variable */
431 				gtk_list_store_set (model, &iter, ENV_VALUE_COLUMN, NULL,
432 									ENV_COLOR_COLUMN, ENV_USER_COLOR,
433 									-1);
434 			}
435 
436 			/* Search variable with new name */
437 			if (anjuta_gtk_tree_model_find_string (GTK_TREE_MODEL (model),
438 												NULL, &niter, ENV_NAME_COLUMN,
439 												text))
440 			{
441 					if (def_value == NULL)
442 					{
443 						gtk_list_store_remove (model, &iter);
444 					}
445 					gtk_list_store_set (model, &niter,
446 										ENV_VALUE_COLUMN, value,
447 										ENV_COLOR_COLUMN, ENV_USER_COLOR,
448 										-1);
449 			}
450 			else
451 			{
452 				if (def_value != NULL)
453 				{
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,
459 										-1);
460 				}
461 				else
462 				{
463 					gtk_list_store_set (model, &iter, ENV_NAME_COLUMN, text,
464 										-1);
465 				}
466 			}
467 			g_idle_add (move_to_environment_value, view);
468 		}
469 		g_free (name);
470 		g_free (def_value);
471 		g_free (value);
472 	}
473 }
474 
475 static void
on_environment_value_edited(GtkCellRendererText * cell,gchar * path,gchar * text,AnjutaEnvironmentEditor * editor)476 on_environment_value_edited (GtkCellRendererText *cell,
477 						  gchar *path,
478                           gchar *text,
479                           AnjutaEnvironmentEditor *editor)
480 {
481 	GtkTreeIter iter;
482 	GtkListStore *model;
483 	GtkTreeView *view = editor->treeview;
484 
485 	text = g_strstrip (text);
486 
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))
489 	{
490 		gtk_list_store_set (model, &iter, ENV_VALUE_COLUMN, text,
491 										ENV_COLOR_COLUMN, ENV_USER_COLOR,
492 										-1);
493 		on_environment_selection_changed (NULL, editor);
494 	}
495 }
496 
497 /* Implement GtkWidget functions
498  *---------------------------------------------------------------------------*/
499 
500 static void
anjuta_environment_editor_dispose(GObject * object)501 anjuta_environment_editor_dispose (GObject *object)
502 {
503 	AnjutaEnvironmentEditor* editor = ANJUTA_ENVIRONMENT_EDITOR (object);
504 
505 	if (editor->model != NULL) g_object_unref (editor->model);
506 
507 	G_OBJECT_CLASS (anjuta_environment_editor_parent_class)->dispose (object);
508 }
509 
510 static void
anjuta_environment_editor_finalize(GObject * object)511 anjuta_environment_editor_finalize (GObject *object)
512 {
513 	AnjutaEnvironmentEditor* editor = ANJUTA_ENVIRONMENT_EDITOR (object);
514 
515 	g_strfreev (editor->variables);
516 	editor->variables = NULL;
517 
518 	G_OBJECT_CLASS (anjuta_environment_editor_parent_class)->finalize (object);
519 }
520 
521 static void
anjuta_environment_editor_init(AnjutaEnvironmentEditor * editor)522 anjuta_environment_editor_init (AnjutaEnvironmentEditor *editor)
523 {
524 	GtkWidget *expander;
525 	GtkWidget *hbox;
526 	GtkWidget *scrolled;
527 	GtkWidget *treeview;
528 	GtkWidget *vbutton;
529 	GtkWidget *add_button;
530 	GtkWidget *edit_button;
531 	GtkWidget *remove_button;
532 	GtkTreeModel *model;
533 	GtkTreeViewColumn* column;
534 	GtkCellRenderer* renderer;
535 	GtkTreeSelection *selection;
536 
537 	editor->variables = NULL;
538 
539 	gtk_widget_set_has_window (GTK_WIDGET (editor), FALSE);
540 	gtk_widget_set_redraw_on_allocate (GTK_WIDGET (editor), FALSE);
541 
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);
551 
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);
556 
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;
569 
570 	gtk_widget_show_all (GTK_WIDGET (editor));
571 
572 	/* Fill environment variable list */
573 	model = GTK_TREE_MODEL (gtk_list_store_new (ENV_N_COLUMNS,
574 												G_TYPE_STRING,
575 												G_TYPE_STRING,
576 												G_TYPE_STRING,
577 												G_TYPE_STRING,
578 												G_TYPE_BOOLEAN));
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);
582 
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,
589 													   NULL);
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,
598 													   NULL);
599 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
600 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
601 
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);
608 
609 	on_environment_selection_changed (NULL, editor);
610 }
611 
612 static void
anjuta_environment_editor_class_init(AnjutaEnvironmentEditorClass * klass)613 anjuta_environment_editor_class_init (AnjutaEnvironmentEditorClass *klass)
614 {
615 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
616 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
617 
618 
619 	/**
620 	 * AnjutaEnvironmentEditor::changed:
621 	 * @widget: the AnjutaEnvironmentEditor that received the signal
622 	 *
623 	 * The ::changed signal is emitted when an environment variable
624 	 * is changed (include deleted variables)
625 	 */
626 	g_signal_new ("changed",
627 	              G_OBJECT_CLASS_TYPE (klass),
628 	              G_SIGNAL_RUN_LAST,
629 	              G_STRUCT_OFFSET (AnjutaEnvironmentEditorClass, changed),
630 	              NULL, NULL,
631 	              g_cclosure_marshal_VOID__VOID,
632 	              G_TYPE_NONE, 0);
633 
634 	object_class->dispose = anjuta_environment_editor_dispose;
635 	object_class->finalize = anjuta_environment_editor_finalize;
636 
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;
640 }
641 
642 /* Public functions
643  *---------------------------------------------------------------------------*/
644 
645 /*
646  * anjuta_environment_editor_new:
647  *
648  * Returns: A new AnjutaEnvironmentEditor widget
649  */
650 GtkWidget*
anjuta_environment_editor_new(void)651 anjuta_environment_editor_new (void)
652 {
653 	return GTK_WIDGET (g_object_new (ANJUTA_TYPE_ENVIRONMENT_EDITOR, NULL));
654 }
655 
656 /*
657  * anjuta_environment_editor_set_variable:
658  * @editor: A AnjutaEnvironmentEditor widget
659  * @variable: Environment variable name and value
660  *
661  * Set environment variable.
662  */
663 void
anjuta_environment_editor_set_variable(AnjutaEnvironmentEditor * editor,const gchar * variable)664 anjuta_environment_editor_set_variable (AnjutaEnvironmentEditor *editor, const gchar *variable)
665 {
666 	GtkTreeIter iter;
667 	GtkTreeModel *model;
668 	gboolean valid;
669 	gchar *name;
670 	const gchar *equal;
671 	guint len;
672 
673 	model = editor->model;
674 
675 	/* Check is variable is already existing */
676 	equal = strchr (variable, '=');
677 	len = equal != NULL ? equal - variable : 0;
678 
679 	for (valid = gtk_tree_model_get_iter_first (model, &iter); valid; valid = gtk_tree_model_iter_next (model, &iter))
680 	{
681 		gtk_tree_model_get (editor->model, &iter,
682 							ENV_NAME_COLUMN, &name,
683 							-1);
684 		if (((len == 0) && (strcmp (name, variable) == 0)) ||
685 		    ((len != 0) && (strncmp (name, variable, len) == 0) && (name[len] == '\0')))
686 		{
687 			break;
688 		}
689 		g_free (name);
690 		name = NULL;
691 	}
692 
693 	if (!valid) gtk_list_store_insert_after (GTK_LIST_STORE (model), &iter, NULL);
694 
695 	if (name == NULL)
696 	{
697 		name = g_strdup (variable);
698 		if (len != 0) name[len] = '\0';
699 	}
700 	if (equal != NULL)
701 	{
702 		equal++;
703 	}
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,
707 								-1);
708 	g_free (name);
709 }
710 
711 /*
712  * anjuta_environment_editor_get_all_variables:
713  * @editor: A AnjutaEnvironmentEditor widget
714  *
715  * Returns: A list of all environment variables in a string array.
716  */
717 gchar**
anjuta_environment_editor_get_all_variables(AnjutaEnvironmentEditor * editor)718 anjuta_environment_editor_get_all_variables (AnjutaEnvironmentEditor *editor)
719 {
720 	gchar **all_var;
721 	gchar *var;
722 	gboolean valid;
723 	GtkTreeIter iter;
724 
725 	all_var = g_new (gchar *, gtk_tree_model_iter_n_children (editor->model, NULL) + 1);
726 	var = *all_var;
727 
728 	for (valid = gtk_tree_model_get_iter_first (editor->model, &iter); valid; valid = gtk_tree_model_iter_next (editor->model, &iter))
729 	{
730 		gchar *name;
731 		gchar *value;
732 		gchar *color;
733 
734 		gtk_tree_model_get (editor->model, &iter,
735 							ENV_NAME_COLUMN, &name,
736 							ENV_VALUE_COLUMN, &value,
737 							ENV_COLOR_COLUMN, &color,
738 							-1);
739 
740 		var = g_strconcat(name, "=", value, NULL);
741 		var++;
742 		g_free (name);
743 		g_free (value);
744 		g_free (color);
745 	}
746 	var = NULL;
747 
748 	return all_var;
749 }
750 
751 /*
752  * anjuta_environment_editor_get_modified_variables:
753  * @editor: A AnjutaEnvironmentEditor widget
754  *
755  * Returns: A list of modified environment variables in a string array.
756  */
757 gchar**
anjuta_environment_editor_get_modified_variables(AnjutaEnvironmentEditor * editor)758 anjuta_environment_editor_get_modified_variables (AnjutaEnvironmentEditor *editor)
759 {
760 	gchar **mod_var;
761 	gchar **var;
762 	gboolean valid;
763 	GtkTreeIter iter;
764 
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);
770 	var = mod_var;
771 
772 	for (valid = gtk_tree_model_get_iter_first (editor->model, &iter); valid; valid = gtk_tree_model_iter_next (editor->model, &iter))
773 	{
774 		gchar *name;
775 		gchar *value;
776 		gchar *color;
777 
778 		gtk_tree_model_get (editor->model, &iter,
779 							ENV_NAME_COLUMN, &name,
780 							ENV_VALUE_COLUMN, &value,
781 							ENV_COLOR_COLUMN, &color,
782 							-1);
783 
784 		/* Save only variables modified by user */
785 		if (strcmp(color, ENV_USER_COLOR) == 0)
786 		{
787 			*var = g_strconcat(name, "=", value, NULL);
788 			var++;
789 		}
790 		g_free (name);
791 		g_free (value);
792 		g_free (color);
793 	}
794 	*var = NULL;
795 
796 	return mod_var;
797 }
798 
799 /*
800  * anjuta_environment_editor_reset:
801  * @editor: A AnjutaEnvironmentEditor widget
802  *
803  * Remove all variables modified by the user
804  */
805 void
anjuta_environment_editor_reset(AnjutaEnvironmentEditor * editor)806 anjuta_environment_editor_reset (AnjutaEnvironmentEditor *editor)
807 {
808 	gtk_list_store_clear (GTK_LIST_STORE (editor->model));
809 	load_environment_variables (editor, GTK_LIST_STORE (editor->model));
810 }
811