1 /*
2  * settings.c
3  *
4  *
5  * Authors:
6  *  Richard Hult <rhult@hem.passagen.se>
7  *  Ricardo Markiewicz <rmarkie@fi.uba.ar>
8  *  Andres de Barbara <adebarbara@fi.uba.ar>
9  *  Marc Lorber <lorber.marc@wanadoo.fr>
10  *  Bernhard Schuster <bernhard@ahoi.io>
11  *  Guido Trentalancia <guido@trentalancia.com>
12  *
13  * Web page: https://ahoi.io/project/oregano
14  *
15  * Copyright (C) 1999-2001  Richard Hult
16  * Copyright (C) 2003,2006  Ricardo Markiewicz
17  * Copyright (C) 2008-2012  Marc Lorber
18  * Copyright (C) 2013       Bernhard Schuster
19  * Copyright (C) 2017       Guido Trentalancia
20  *
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License as
23  * published by the Free Software Foundation; either version 2 of the
24  * License, or (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  * General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public
32  * License along with this program; if not, write to the
33  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
34  * Boston, MA 02110-1301, USA.
35  */
36 
37 #include <unistd.h>
38 #include <glib.h>
39 #include <stdio.h>
40 #include <glib/gi18n.h>
41 
42 #include "oregano.h"
43 #include "string.h"
44 #include "settings.h"
45 #include "schematic.h"
46 #include "schematic-view.h"
47 #include "dialogs.h"
48 #include "oregano-utils.h"
49 #include "oregano-config.h"
50 
51 typedef struct
52 {
53 	Schematic *sm;
54 	GtkWidget *pbox; // Property box
55 
56 	GtkWidget *w_show_splash;
57 	GtkWidget *w_show_log;
58 
59 	GtkWidget *w_compress_files;
60 	GtkWidget *w_engine;
61 } Settings;
62 
63 #define SETTINGS(x) ((Settings *)(x))
64 
65 GtkWidget *engine_path;
66 GtkWidget *button[OREGANO_ENGINE_COUNT];
67 
apply_callback(GtkWidget * w,Settings * s)68 static void apply_callback (GtkWidget *w, Settings *s)
69 {
70 	oregano.engine = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (s->w_engine), "id"));
71 	oregano.compress_files = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_compress_files));
72 	if (s->w_show_log)
73 		oregano.show_log = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_show_log));
74 	else
75 		oregano.show_log = FALSE;
76 	oregano.show_splash = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->w_show_splash));
77 
78 	oregano_config_save ();
79 
80 	gtk_widget_destroy (s->pbox);
81 	s->pbox = NULL;
82 }
83 
delete_event_callback(GtkWidget * w,GdkEvent * event,Settings * s)84 static void delete_event_callback (GtkWidget *w, GdkEvent *event, Settings *s)
85 {
86 	apply_callback (w, s);
87 }
88 
set_engine_name(GtkWidget * w,Settings * s)89 static void set_engine_name (GtkWidget *w, Settings *s)
90 {
91 	int engine_id;
92 	gchar *engine_name;
93 
94 	s->w_engine = w;
95 	engine_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (s->w_engine), "id"));
96 
97 	engine_name = oregano_engine_get_engine_name_by_index (engine_id);
98 	if (g_find_program_in_path (engine_name) == NULL) {
99 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button[engine_id]))) {
100 			GString *msg = g_string_new (_ ("Engine <span weight=\"bold\" size=\"large\">"));
101 			msg = g_string_append (msg, engine_name);
102 			msg = g_string_append (msg, _ ("</span> not found\nThe engine is unable to locate "
103 			                               "the external program."));
104 			oregano_warning_with_title (_ ("Warning"), msg->str);
105 			g_string_free (msg, TRUE);
106 			engine_id = (engine_id + 1) % OREGANO_ENGINE_COUNT;
107 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]), TRUE);
108 		} else
109 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[engine_id]), FALSE);
110 	}
111 	g_free (engine_name);
112 }
113 
settings_new(Schematic * sm)114 gpointer settings_new (Schematic *sm)
115 {
116 	Settings *s;
117 
118 	s = g_new0 (Settings, 1);
119 	s->sm = sm;
120 
121 	return s;
122 }
123 
settings_show(GtkWidget * widget,SchematicView * sv)124 void settings_show (GtkWidget *widget, SchematicView *sv)
125 {
126 	gint i;
127 	gboolean engine_available = FALSE;
128 	gchar *engine_name;
129 	GtkWidget *engine_group = NULL;
130 	GtkWidget *w, *pbox, *toplevel;
131 	GtkBuilder *gui;
132 	GError *perror = NULL;
133 	gchar *msg;
134 	Settings *s;
135 	Schematic *sm;
136 
137 	g_return_if_fail (sv != NULL);
138 
139 	for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
140 		engine_name = oregano_engine_get_engine_name_by_index (i);
141 		if (g_find_program_in_path(engine_name) != NULL) {
142 			engine_available = TRUE;
143 		}
144 		g_free (engine_name);
145 	}
146 
147 	if (!engine_available) {
148 		gchar *msg;
149 		msg = g_strdup_printf (_ ("No engine allowing analysis is available.\n"
150 					  "You need to install at least one engine ! \n"
151 					  "spice3, ngspice or gnucap."));
152 		oregano_error_with_title (_ ("Could not create engine settings dialog"), msg);
153 		g_free (msg);
154 	}
155 
156 	if ((gui = gtk_builder_new ()) == NULL) {
157 		oregano_error (_ ("Could not create settings dialog"));
158 		return;
159 	}
160 	gtk_builder_set_translation_domain (gui, NULL);
161 
162 	sm = schematic_view_get_schematic (sv);
163 	s = schematic_get_settings (sm);
164 
165 	// Only allow one instance of the property box per schematic.
166 	if (GTK_WIDGET (SETTINGS (s)->pbox)) {
167 		gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (SETTINGS (s)->pbox)));
168 		return;
169 	}
170 
171 	if (gtk_builder_add_from_file (gui, OREGANO_UIDIR "/settings.ui", &perror) <= 0) {
172 		msg = perror->message;
173 		oregano_error_with_title (_ ("Could not create settings dialog"), msg);
174 		g_error_free (perror);
175 		return;
176 	}
177 
178 	w = toplevel = GTK_WIDGET (gtk_builder_get_object (gui, "toplevel"));
179 	if (!w) {
180 		oregano_error (_ ("Could not create settings dialog"));
181 		return;
182 	}
183 	g_signal_connect (G_OBJECT (w), "delete_event", G_CALLBACK (delete_event_callback), s);
184 
185 	pbox = toplevel;
186 	s->pbox = GTK_WIDGET (pbox);
187 
188 	w = GTK_WIDGET (gtk_builder_get_object (gui, "close_bt"));
189 	g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (apply_callback), s);
190 
191 	w = GTK_WIDGET (gtk_builder_get_object (gui, "splash-enable"));
192 	s->w_show_splash = w;
193 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.show_splash);
194 
195 	w = GTK_WIDGET (gtk_builder_get_object (gui, "compress-enable"));
196 	s->w_compress_files = w;
197 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.compress_files);
198 	if (engine_available) {
199 		w = GTK_WIDGET (gtk_builder_get_object (gui, "log-enable"));
200 		s->w_show_log = w;
201 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), oregano.show_log);
202 	} else {
203 		w = GTK_WIDGET (gtk_builder_get_object (gui, "log-enable"));
204 		s->w_show_log = NULL;
205 		gtk_widget_destroy (w);
206 	}
207 
208 	w = GTK_WIDGET (gtk_builder_get_object (gui, "realtime-enable"));
209 	gtk_widget_set_sensitive (w, FALSE);
210 
211 	if (engine_available) {
212 		w = GTK_WIDGET (gtk_builder_get_object (gui, "engine_table"));
213 		for (i = 0; i < OREGANO_ENGINE_COUNT; i++) {
214 			engine_name = oregano_engine_get_engine_name_by_index (i);
215 			if (engine_group)
216 				button[i] = gtk_radio_button_new_with_label_from_widget (
217 				    GTK_RADIO_BUTTON (engine_group), engine_name);
218 			else
219 				button[i] = engine_group =
220 				    gtk_radio_button_new_with_label_from_widget (NULL, engine_name);
221 			g_free (engine_name);
222 			g_object_set_data (G_OBJECT (button[i]), "id", GUINT_TO_POINTER (i));
223 
224 			gtk_grid_attach (GTK_GRID (w), button[i], 0, i, 1, 1);
225 			g_signal_connect (G_OBJECT (button[i]), "clicked", G_CALLBACK (set_engine_name), s);
226 		}
227 
228 	} else {
229 		w = GTK_WIDGET (gtk_builder_get_object (gui, "label50"));
230 		gtk_widget_destroy (w);
231 	}
232 
233 	// Is the engine available?
234 	// In that case the button is active
235 	engine_name = oregano_engine_get_engine_name_by_index (oregano.engine);
236 	if (g_find_program_in_path (engine_name) != NULL)
237 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]), TRUE);
238 	// Otherwise the button is inactive
239 	else
240 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button[oregano.engine]), FALSE);
241 	g_free (engine_name);
242 
243 	gtk_widget_show_all (toplevel);
244 }
245