1 /*
2  * schematic-view.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) 2009-2012  Marc Lorber
18  * Copyright (C) 2013-2014  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 <string.h>
38 #include <math.h>
39 #include <unistd.h>
40 #include <gtk/gtk.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <glib/gi18n.h>
43 #include <sys/time.h>
44 #include <cairo/cairo-features.h>
45 
46 #include "schematic.h"
47 #include "schematic-view.h"
48 #include "part-browser.h"
49 #include "stock.h"
50 #include "oregano.h"
51 #include "load-library.h"
52 #include "netlist-helper.h"
53 #include "dialogs.h"
54 #include "cursors.h"
55 #include "file.h"
56 #include "settings.h"
57 #include "errors.h"
58 #include "engine.h"
59 #include "netlist-editor.h"
60 #include "sheet.h"
61 #include "sheet-item-factory.h"
62 #include "textbox-item.h"
63 #include "log-view.h"
64 #include "log.h"
65 #include "debug.h"
66 
67 #define ZOOM_MIN 0.35
68 #define ZOOM_MAX 3
69 
70 enum { CHANGED, RESET_TOOL, LAST_SIGNAL };
71 
72 typedef enum {
73 	SCHEMATIC_TOOL_ARROW,
74 	SCHEMATIC_TOOL_PART,
75 	SCHEMATIC_TOOL_WIRE,
76 	SCHEMATIC_TOOL_TEXT
77 } SchematicTool;
78 
79 typedef struct
80 {
81 	GtkWidget *log_window;
82 	GtkTextView *log_text;
83 	GtkBuilder *log_gui;
84 } LogInfo;
85 
86 struct _SchematicView
87 {
88 	GObject parent;
89 	GtkWidget *toplevel;
90 	SchematicViewPriv *priv;
91 };
92 
93 struct _SchematicViewClass
94 {
95 	GObjectClass parent_class;
96 
97 	// Signals go here
98 	void (*changed)(SchematicView *schematic_view);
99 	void (*reset_tool)(SchematicView *schematic_view);
100 };
101 
102 struct _SchematicViewPriv
103 {
104 	Schematic *schematic;
105 
106 	Sheet *sheet;
107 
108 	GtkPageSetup *page_setup;
109 	GtkPrintSettings *print_settings;
110 
111 	gboolean empty;
112 
113 	GtkActionGroup *action_group;
114 	GtkUIManager *ui_manager;
115 
116 	gpointer browser;
117 
118 	GtkWidget *logview;
119 	GtkPaned *paned;
120 	guint grid : 1;
121 	SchematicTool tool;
122 	int cursor;
123 
124 	LogInfo *log_info;
125 };
126 
127 G_DEFINE_TYPE (SchematicView, schematic_view, G_TYPE_OBJECT)
128 
129 // Class functions and members.
130 static void schematic_view_init (SchematicView *sv);
131 static void schematic_view_class_init (SchematicViewClass *klass);
132 static void schematic_view_dispose (GObject *object);
133 static void schematic_view_finalize (GObject *object);
134 static void schematic_view_load (SchematicView *sv, Schematic *sm);
135 static void schematic_view_do_load (SchematicView *sv, Schematic *sm, const gboolean reload);
136 static void schematic_view_reload (SchematicView *sv, Schematic *sm);
137 
138 // Signal callbacks.
139 static void title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv);
140 static void set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv);
141 static int delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv);
142 static void data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
143                            GtkSelectionData *selection_data, guint info, guint32 time,
144                            SchematicView *sv);
145 static void item_data_added_callback (Schematic *schematic, ItemData *data, SchematicView *sv);
146 static void item_selection_changed_callback (SheetItem *item, gboolean selected, SchematicView *sv);
147 static void reset_tool_cb (Sheet *sheet, SchematicView *sv);
148 
149 // Misc.
150 static int can_close (SchematicView *sv);
151 static void setup_dnd (SchematicView *sv);
152 static void set_tool (SchematicView *sv, SchematicTool tool);
153 
154 static GList *schematic_view_list = NULL;
155 static GObjectClass *parent_class = NULL;
156 static guint schematic_view_signals[LAST_SIGNAL] = {0};
157 
new_cmd(GtkWidget * widget,Schematic * sv)158 static void new_cmd (GtkWidget *widget, Schematic *sv)
159 {
160 	Schematic *new_sm;
161 	SchematicView *new_sv;
162 
163 	new_sm = schematic_new ();
164 	new_sv = schematic_view_new (new_sm);
165 
166 	gtk_widget_show_all (new_sv->toplevel);
167 }
168 
properties_cmd(GtkWidget * widget,SchematicView * sv)169 static void properties_cmd (GtkWidget *widget, SchematicView *sv)
170 {
171 	Schematic *s;
172 	GtkBuilder *builder;
173 	GError *e = NULL;
174 	GtkWidget *window;
175 	GtkEntry *title, *author;
176 	GtkTextView *comments;
177 	GtkTextBuffer *buffer;
178 	gchar *s_title, *s_author, *s_comments;
179 	gint button;
180 
181 	s = schematic_view_get_schematic (sv);
182 
183 	if ((builder = gtk_builder_new ()) == NULL) {
184 		log_append (schematic_get_log_store (s), _ ("SchematicView"),
185 		            _ ("Could not create properties dialog"));
186 		return;
187 	}
188 	gtk_builder_set_translation_domain (builder, NULL);
189 
190 	if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/properties.ui", &e) <= 0) {
191 		log_append_error (schematic_get_log_store (s), _ ("SchematicView"),
192 		                  _ ("Could not create properties dialog due to issues with " OREGANO_UIDIR
193 		                     "/properties.ui file."),
194 		                  e);
195 		g_clear_error (&e);
196 		return;
197 	}
198 
199 	window = GTK_WIDGET (gtk_builder_get_object (builder, "properties"));
200 	title = GTK_ENTRY (gtk_builder_get_object (builder, "title"));
201 	author = GTK_ENTRY (gtk_builder_get_object (builder, "author"));
202 	comments = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "comments"));
203 	buffer = gtk_text_view_get_buffer (comments);
204 
205 	s_title = schematic_get_title (s);
206 	s_author = schematic_get_author (s);
207 	s_comments = schematic_get_comments (s);
208 
209 	if (s_title)
210 		gtk_entry_set_text (title, s_title);
211 	if (s_author)
212 		gtk_entry_set_text (author, s_author);
213 	if (s_comments)
214 		gtk_text_buffer_set_text (buffer, s_comments, strlen (s_comments));
215 
216 	button = gtk_dialog_run (GTK_DIALOG (window));
217 
218 	if (button == GTK_RESPONSE_OK) {
219 		GtkTextIter start, end;
220 
221 		gtk_text_buffer_get_start_iter (buffer, &start);
222 		gtk_text_buffer_get_end_iter (buffer, &end);
223 
224 		s_title = (gchar *)gtk_entry_get_text (title);
225 		s_author = (gchar *)gtk_entry_get_text (author);
226 		s_comments = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
227 
228 		schematic_set_title (s, s_title);
229 		schematic_set_author (s, s_author);
230 		schematic_set_comments (s, s_comments);
231 
232 		g_free (s_comments);
233 	}
234 
235 	gtk_widget_destroy (window);
236 }
237 
find_file(GtkButton * button,GtkEntry * text)238 static void find_file (GtkButton *button, GtkEntry *text)
239 {
240 	GtkWidget *dialog;
241 
242 	dialog = gtk_file_chooser_dialog_new (_ ("Export to..."),
243 	                                      NULL,
244 	                                      GTK_FILE_CHOOSER_ACTION_SAVE,
245 	                                      _("_Cancel"),
246 	                                      GTK_RESPONSE_CANCEL,
247 	                                      _("_Open"),
248 	                                      GTK_RESPONSE_ACCEPT,
249 	                                      NULL);
250 
251 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
252 		char *filename;
253 
254 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
255 		gtk_entry_set_text (text, filename);
256 		g_free (filename);
257 	}
258 
259 	gtk_widget_destroy (dialog);
260 }
261 
export_cmd(GtkWidget * widget,SchematicView * sv)262 static void export_cmd (GtkWidget *widget, SchematicView *sv)
263 {
264 	Schematic *s;
265 	GtkBuilder *builder;
266 	GError *e = NULL;
267 	GtkWidget *window;
268 	GtkWidget *warning;
269 	GtkWidget *w;
270 	GtkEntry *file = NULL;
271 	GtkComboBoxText *combo;
272 	gint button = GTK_RESPONSE_NONE;
273 	gint formats[5], fc;
274 
275 	s = schematic_view_get_schematic (sv);
276 
277 	if ((builder = gtk_builder_new ()) == NULL) {
278 		log_append (schematic_get_log_store (s), _ ("SchematicView"),
279 		            _ ("Could not create properties dialog"));
280 		return;
281 	}
282 	gtk_builder_set_translation_domain (builder, NULL);
283 
284 	if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/export.ui", &e) <= 0) {
285 		log_append_error (schematic_get_log_store (s), _ ("SchematicView"),
286 		                  _ ("Could not create properties dialog due to issues with " OREGANO_UIDIR
287 		                     "/exportp.ui file."),
288 		                  e);
289 		g_clear_error (&e);
290 		return;
291 	}
292 
293 	window = GTK_WIDGET (gtk_builder_get_object (builder, "export"));
294 
295 	combo = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, "format"));
296 	fc = 0;
297 #ifdef CAIRO_HAS_SVG_SURFACE
298 	gtk_combo_box_text_append_text (combo, "Scalar Vector Graphics (SVG)");
299 	formats[fc++] = 0;
300 #endif
301 #ifdef CAIRO_HAS_PDF_SURFACE
302 	gtk_combo_box_text_append_text (combo, "Portable Document Format (PDF)");
303 	formats[fc++] = 1;
304 #endif
305 #ifdef CAIRO_HAS_PS_SURFACE
306 	gtk_combo_box_text_append_text (combo, "Postscript (PS)");
307 	formats[fc++] = 2;
308 #endif
309 #ifdef CAIRO_HAS_PNG_FUNCTIONS
310 	gtk_combo_box_text_append_text (combo, "Portable Network Graphics (PNG)");
311 	formats[fc++] = 3;
312 #endif
313 
314 	file = GTK_ENTRY (gtk_builder_get_object (builder, "file"));
315 
316 	w = GTK_WIDGET (gtk_builder_get_object (builder, "find"));
317 	g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (find_file), file);
318 
319 	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
320 
321 	button = gtk_dialog_run (GTK_DIALOG (window));
322 
323 	if (button == GTK_RESPONSE_OK) {
324 
325 		if (g_path_skip_root (gtk_entry_get_text (file)) == NULL) {
326 
327 			warning = gtk_message_dialog_new_with_markup (
328 			    NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
329 			    _ ("<span weight=\"bold\" size=\"large\">No filename has "
330 			       "been chosen</span>\n\n"
331 			       "Please, click on the tag, beside, to select an output."));
332 
333 			if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_OK) {
334 				gtk_widget_destroy (GTK_WIDGET (warning));
335 				export_cmd (widget, sv);
336 				gtk_widget_destroy (GTK_WIDGET (window));
337 				return;
338 			}
339 		} else {
340 
341 			int bg = 0;
342 			GtkSpinButton *spinw, *spinh;
343 			int color_scheme = 0;
344 			GtkWidget *w;
345 			int i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
346 
347 			w = GTK_WIDGET (gtk_builder_get_object (builder, "bgwhite"));
348 			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
349 				bg = 1;
350 			w = GTK_WIDGET (gtk_builder_get_object (builder, "bgblack"));
351 			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
352 				bg = 2;
353 			w = GTK_WIDGET (gtk_builder_get_object (builder, "color"));
354 			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
355 				color_scheme = 1;
356 
357 			spinw = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "export_width"));
358 			spinh = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "export_height"));
359 			schematic_export (
360 			    s, gtk_entry_get_text (file), gtk_spin_button_get_value_as_int (spinw),
361 			    gtk_spin_button_get_value_as_int (spinh), bg, color_scheme, formats[i]);
362 		}
363 	}
364 
365 	gtk_widget_destroy (window);
366 }
367 
page_properties_cmd(GtkWidget * widget,SchematicView * sv)368 static void page_properties_cmd (GtkWidget *widget, SchematicView *sv)
369 {
370 	if (sv->priv->page_setup) {
371 		g_object_unref (sv->priv->page_setup);
372 	}
373 
374 	sv->priv->page_setup =
375 	    gtk_print_run_page_setup_dialog (NULL, sv->priv->page_setup, sv->priv->print_settings);
376 }
377 
open_cmd(GtkWidget * widget,SchematicView * sv)378 static void open_cmd (GtkWidget *widget, SchematicView *sv)
379 {
380 	Schematic *new_sm;
381 	SchematicView *new_sv, *t;
382 	char *fname, *uri = NULL;
383 	GList *iter;
384 	GError *e = NULL;
385 
386 	fname = dialog_open_file (sv);
387 	if (!fname)
388 		return;
389 
390 	// Repaint the other schematic windows before loading the new file.
391 	new_sv = NULL;
392 	for (iter = schematic_view_list; iter; iter = iter->next) {
393 		t = SCHEMATIC_VIEW (iter->data);
394 		if (t->priv->empty)
395 			new_sv = t;
396 		gtk_widget_queue_draw (GTK_WIDGET (t->toplevel));
397 	}
398 
399 	while (gtk_events_pending ())
400 		gtk_main_iteration ();
401 
402 	new_sm = schematic_read (fname, &e);
403 	if (e) {
404 		gchar *const msg = g_strdup_printf (_ ("Could not load file \"file://%s\""), fname);
405 		Schematic *old = schematic_view_get_schematic (sv);
406 		log_append_error (schematic_get_log_store (old), _ ("SchematicView"), msg, e);
407 		g_clear_error (&e);
408 		g_free (msg);
409 	}
410 
411 	if (new_sm) {
412 		GtkRecentManager *manager;
413 		GtkRecentInfo *rc;
414 
415 		manager = gtk_recent_manager_get_default ();
416 		uri = g_strdup_printf ("file://%s", fname);
417 
418 		if (uri) {
419 			rc = gtk_recent_manager_lookup_item (manager, uri, &e);
420 			if (e) {
421 				g_clear_error (&e);
422 			} else {
423 				gtk_recent_manager_remove_item (manager, uri, &e);
424 				if (e) {
425 					gchar *const msg =
426 					    g_strdup_printf (_ ("Could not load recent file \"%s\""), uri);
427 					Schematic *old = schematic_view_get_schematic (sv);
428 					log_append_error (schematic_get_log_store (old), _ ("SchematicView"), msg, e);
429 					g_clear_error (&e);
430 					g_free (msg);
431 				}
432 			}
433 			gtk_recent_manager_add_item (manager, uri);
434 			if (rc)
435 				gtk_recent_info_unref (rc);
436 		}
437 
438 		if (!new_sv)
439 			new_sv = schematic_view_new (new_sm);
440 		else
441 			schematic_view_load (new_sv, new_sm);
442 
443 		gtk_widget_show_all (new_sv->toplevel);
444 		schematic_set_filename (new_sm, fname);
445 		schematic_set_title (new_sm, g_path_get_basename (fname));
446 
447 		g_free (uri);
448 	}
449 	g_free (fname);
450 }
451 
oregano_recent_open(GtkRecentChooser * chooser,SchematicView * sv)452 static void oregano_recent_open (GtkRecentChooser *chooser, SchematicView *sv)
453 {
454 	gchar *uri;
455 	const gchar *mime;
456 	GtkRecentInfo *item;
457 	GtkRecentManager *manager;
458 	Schematic *new_sm;
459 	SchematicView *new_sv = NULL;
460 	GError *e = NULL;
461 
462 	uri = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (chooser));
463 	if (!uri)
464 		return;
465 
466 	manager = gtk_recent_manager_get_default ();
467 	item = gtk_recent_manager_lookup_item (manager, uri, NULL);
468 	if (!item)
469 		return;
470 	// remove and re-add in order to update the ordering
471 	gtk_recent_manager_remove_item (manager, uri, &e);
472 	if (e) {
473 		gchar *const msg =
474 		    g_strdup_printf (_ ("Could not load recent file \"%s\"\n%s"), uri, e->message);
475 		oregano_error_with_title (_ ("Could not load recent file"), msg);
476 		g_clear_error (&e);
477 		g_free (msg);
478 	}
479 	gtk_recent_manager_add_item (manager, uri);
480 
481 	mime = gtk_recent_info_get_mime_type (item);
482 	if (!mime || strcmp (mime, "application/x-oregano") != 0) {
483 		gchar *const msg = g_strdup_printf (_ ("Can not handle file with mimetype \"%s\""), mime);
484 		oregano_error_with_title (_ ("Could not load recent file"), msg);
485 		g_clear_error (&e);
486 		g_free (msg);
487 
488 	} else {
489 		new_sm = schematic_read (uri, &e);
490 		if (e) {
491 			oregano_error_with_title (_ ("Could not load recent file"), e->message);
492 			g_clear_error (&e);
493 		}
494 		if (new_sm) {
495 			if (!new_sv)
496 				new_sv = schematic_view_new (new_sm);
497 			else
498 				schematic_view_load (new_sv, new_sm);
499 
500 			gtk_widget_show_all (new_sv->toplevel);
501 			schematic_set_filename (new_sm, uri);
502 			schematic_set_title (new_sm, g_path_get_basename (uri));
503 		}
504 	}
505 
506 	g_free (uri);
507 	gtk_recent_info_unref (item);
508 }
509 
create_recent_chooser_menu(GtkRecentManager * manager)510 static GtkWidget *create_recent_chooser_menu (GtkRecentManager *manager)
511 {
512 	GtkWidget *menu;
513 	GtkRecentFilter *filter;
514 
515 	menu = gtk_recent_chooser_menu_new_for_manager (manager);
516 
517 	gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (menu), 10);
518 
519 	gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (menu), TRUE);
520 	gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu), GTK_RECENT_SORT_MRU);
521 
522 	filter = gtk_recent_filter_new ();
523 	gtk_recent_filter_add_mime_type (filter, "application/x-oregano");
524 	gtk_recent_filter_add_application (filter, g_get_application_name ());
525 	gtk_recent_chooser_add_filter (GTK_RECENT_CHOOSER (menu), filter);
526 	gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (menu), filter);
527 	gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (menu), TRUE);
528 	g_signal_connect (menu, "item-activated", G_CALLBACK (oregano_recent_open), NULL);
529 
530 	gtk_widget_show_all (menu);
531 
532 	return menu;
533 }
534 
display_recent_files(GtkWidget * menu,SchematicView * sv)535 static void display_recent_files (GtkWidget *menu, SchematicView *sv)
536 {
537 	SchematicViewPriv *priv = sv->priv;
538 	GtkWidget *menuitem;
539 	GtkWidget *recentmenu;
540 	GtkRecentManager *manager = NULL;
541 
542 	manager = gtk_recent_manager_get_default ();
543 	menuitem =
544 	    gtk_ui_manager_get_widget (priv->ui_manager, "/MainMenu/MenuFile/DisplayRecentFiles");
545 	recentmenu = create_recent_chooser_menu (manager);
546 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), recentmenu);
547 	gtk_widget_show (menuitem);
548 }
549 
save_cmd(GtkWidget * widget,SchematicView * sv)550 static void save_cmd (GtkWidget *widget, SchematicView *sv)
551 {
552 	Schematic *sm;
553 	char *filename;
554 	GError *e = NULL;
555 	sm = sv->priv->schematic;
556 	filename = schematic_get_filename (sm);
557 
558 	if (filename == NULL || !strcmp (filename, _ ("Untitled.oregano"))) {
559 		dialog_save_as (sv);
560 		return;
561 	} else {
562 		if (!schematic_save_file (sm, &e)) {
563 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
564 			                  _ ("Failed to save schematic file."), e);
565 			g_clear_error (&e);
566 		}
567 	}
568 }
569 
save_as_cmd(GtkWidget * widget,SchematicView * sv)570 static void save_as_cmd (GtkWidget *widget, SchematicView *sv) { dialog_save_as (sv); }
571 
close_cmd(GtkWidget * widget,SchematicView * sv)572 static void close_cmd (GtkWidget *widget, SchematicView *sv)
573 {
574 	if (can_close (sv)) {
575 		NG_DEBUG (" --- not dirty (anymore), do close schematic_view: %p -- vs -- "
576 		          "toplevel: %p",
577 		          sv, schematic_view_get_toplevel (sv));
578 
579 		gtk_widget_destroy (GTK_WIDGET (schematic_view_get_toplevel (sv)));
580 		sv->toplevel = NULL;
581 
582 		g_object_unref (G_OBJECT (sv));
583 	}
584 }
585 
select_all_cmd(GtkWidget * widget,SchematicView * sv)586 static void select_all_cmd (GtkWidget *widget, SchematicView *sv)
587 {
588 	sheet_select_all (sv->priv->sheet, TRUE);
589 }
590 
deselect_all_cmd(GtkWidget * widget,SchematicView * sv)591 static void deselect_all_cmd (GtkWidget *widget, SchematicView *sv)
592 {
593 	sheet_select_all (sv->priv->sheet, FALSE);
594 }
595 
delete_cmd(GtkWidget * widget,SchematicView * sv)596 static void delete_cmd (GtkWidget *widget, SchematicView *sv)
597 {
598 	sheet_delete_selection (sv->priv->sheet);
599 }
600 
rotate_cmd(GtkWidget * widget,SchematicView * sv)601 static void rotate_cmd (GtkWidget *widget, SchematicView *sv)
602 {
603 	if (sv->priv->sheet->state == SHEET_STATE_NONE)
604 		sheet_rotate_selection (sv->priv->sheet, 90);
605 	else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
606 	         sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
607 		sheet_rotate_ghosts (sv->priv->sheet);
608 }
609 
flip_horizontal_cmd(GtkWidget * widget,SchematicView * sv)610 static void flip_horizontal_cmd (GtkWidget *widget, SchematicView *sv)
611 {
612 	if (sv->priv->sheet->state == SHEET_STATE_NONE)
613 		sheet_flip_selection (sv->priv->sheet, TRUE);
614 	else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
615 	         sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
616 		sheet_flip_ghosts (sv->priv->sheet, TRUE);
617 }
618 
flip_vertical_cmd(GtkWidget * widget,SchematicView * sv)619 static void flip_vertical_cmd (GtkWidget *widget, SchematicView *sv)
620 {
621 	if (sv->priv->sheet->state == SHEET_STATE_NONE)
622 		sheet_flip_selection (sv->priv->sheet, FALSE);
623 	else if (sv->priv->sheet->state == SHEET_STATE_FLOAT ||
624 	         sv->priv->sheet->state == SHEET_STATE_FLOAT_START)
625 		sheet_flip_ghosts (sv->priv->sheet, FALSE);
626 }
627 
object_properties_cmd(GtkWidget * widget,SchematicView * sv)628 static void object_properties_cmd (GtkWidget *widget, SchematicView *sv)
629 {
630 	sheet_provide_object_properties (sv->priv->sheet);
631 }
632 
633 /**
634  * copy the currently selected items
635  */
copy_cmd(GtkWidget * widget,SchematicView * sv)636 static void copy_cmd (GtkWidget *widget, SchematicView *sv)
637 {
638 	SheetItem *item;
639 	GList *iter;
640 
641 	if (sv->priv->sheet->state != SHEET_STATE_NONE)
642 		return;
643 
644 	sheet_clear_ghosts (sv->priv->sheet);
645 	clipboard_empty ();
646 
647 	iter = sheet_get_selection (sv->priv->sheet);
648 	for (; iter; iter = iter->next) {
649 		item = iter->data;
650 		clipboard_add_object (G_OBJECT (item));
651 	}
652 
653 	if (clipboard_is_empty ())
654 		gtk_action_set_sensitive (
655 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), FALSE);
656 	else
657 		gtk_action_set_sensitive (
658 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), TRUE);
659 }
660 
661 /**
662  * snip the currently selected items
663  */
cut_cmd(GtkWidget * widget,SchematicView * sv)664 static void cut_cmd (GtkWidget *widget, SchematicView *sv)
665 {
666 	if (sv->priv->sheet->state != SHEET_STATE_NONE)
667 		return;
668 
669 	copy_cmd (NULL, sv);
670 	sheet_delete_selection (sv->priv->sheet);
671 
672 	if (clipboard_is_empty ())
673 		gtk_action_set_sensitive (
674 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), FALSE);
675 	else
676 		gtk_action_set_sensitive (
677 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/Paste"), TRUE);
678 }
679 
paste_objects(gpointer data,Sheet * sheet)680 static void paste_objects (gpointer data, Sheet *sheet) { sheet_item_paste (sheet, data); }
681 
paste_cmd(GtkWidget * widget,SchematicView * sv)682 static void paste_cmd (GtkWidget *widget, SchematicView *sv)
683 {
684 	if (sv->priv->sheet->state != SHEET_STATE_NONE)
685 		return;
686 	if (sheet_get_floating_objects (sv->priv->sheet))
687 		sheet_clear_ghosts (sv->priv->sheet);
688 
689 	sheet_select_all (sv->priv->sheet, FALSE);
690 	clipboard_foreach ((ClipBoardFunction)paste_objects, sv->priv->sheet);
691 	if (sheet_get_floating_objects (sv->priv->sheet))
692 		sheet_connect_part_item_to_floating_group (sv->priv->sheet, (gpointer)sv);
693 }
694 
about_cmd(GtkWidget * widget,Schematic * sm)695 static void about_cmd (GtkWidget *widget, Schematic *sm) { dialog_about (); }
696 
log_cmd(GtkWidget * widget,SchematicView * sv)697 static void log_cmd (GtkWidget *widget, SchematicView *sv) { schematic_view_log_show (sv, TRUE); }
698 
show_label_cmd(GtkToggleAction * toggle,SchematicView * sv)699 static void show_label_cmd (GtkToggleAction *toggle, SchematicView *sv)
700 {
701 	gboolean show;
702 	Schematic *sm;
703 	Netlist netlist;
704 	GError *e = NULL;
705 
706 	show = gtk_toggle_action_get_active (toggle);
707 
708 	// Use of netlist_helper_create
709 	sm = sv->priv->schematic;
710 	netlist_helper_create (sm, &netlist, &e);
711 	if (e != NULL) {
712 		if (g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
713 		    g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
714 		    g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
715 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
716 			                  _ ("Could not create a netlist."), e);
717 		} else {
718 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
719 			                  _ ("Unexpect failure occured."), e);
720 		}
721 		g_clear_error (&e);
722 		return;
723 	}
724 
725 	sheet_show_node_labels (sv->priv->sheet, show);
726 	sheet_update_parts (sv->priv->sheet);
727 }
728 
print_cmd(GtkWidget * widget,SchematicView * sv)729 static void print_cmd (GtkWidget *widget, SchematicView *sv)
730 {
731 	schematic_print (schematic_view_get_schematic (sv), sv->priv->page_setup,
732 	                 sv->priv->print_settings, FALSE);
733 }
734 
print_preview_cmd(GtkWidget * widget,SchematicView * sv)735 static void print_preview_cmd (GtkWidget *widget, SchematicView *sv)
736 {
737 	schematic_print (schematic_view_get_schematic (sv), sv->priv->page_setup,
738 	                 sv->priv->print_settings, TRUE);
739 }
740 
quit_cmd(GtkWidget * widget,SchematicView * sv)741 static void quit_cmd (GtkWidget *widget, SchematicView *sv)
742 {
743 	GList *iter, *copy;
744 
745 	// Duplicate the list as the list is modified during destruction.
746 	copy = g_list_copy (schematic_view_list);
747 
748 	for (iter = copy; iter; iter = iter->next) {
749 		close_cmd (NULL, iter->data);
750 	}
751 
752 	g_list_free (copy);
753 	g_application_quit (g_application_get_default ());
754 }
755 
v_clamp_cmd(SchematicView * sv)756 static void v_clamp_cmd (SchematicView *sv)
757 {
758 	LibraryPart *library_part;
759 	Coords pos;
760 	Sheet *sheet;
761 	Part *part;
762 	GList *lib;
763 	Library *l = NULL;
764 
765 	set_tool (sv, SCHEMATIC_TOOL_PART);
766 	sheet = sv->priv->sheet;
767 
768 	// Find default lib
769 	for (lib = oregano.libraries; lib; lib = lib->next) {
770 		l = (Library *)(lib->data);
771 		if (!g_ascii_strcasecmp (l->name, "Default"))
772 			break;
773 	}
774 
775 	library_part = library_get_part (l, "Test Clamp");
776 
777 	part = part_new_from_library_part (library_part);
778 	if (!part) {
779 		g_warning ("Clamp not found!");
780 		return;
781 	}
782 	pos.x = pos.y = 0;
783 	item_data_set_pos (ITEM_DATA (part), &pos);
784 	item_data_set_property (ITEM_DATA (part), "type", "v");
785 
786 	sheet_select_all (sv->priv->sheet, FALSE);
787 	sheet_clear_ghosts (sv->priv->sheet);
788 	sheet_add_ghost_item (sv->priv->sheet, ITEM_DATA (part));
789 	sheet_connect_part_item_to_floating_group (sheet, (gpointer)sv);
790 }
791 
tool_cmd(GtkAction * action,GtkRadioAction * current,SchematicView * sv)792 static void tool_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
793 {
794 	switch (gtk_radio_action_get_current_value (current)) {
795 	case 0:
796 		set_tool (sv, SCHEMATIC_TOOL_ARROW);
797 		break;
798 	case 1:
799 		set_tool (sv, SCHEMATIC_TOOL_TEXT);
800 		break;
801 	case 2:
802 		set_tool (sv, SCHEMATIC_TOOL_WIRE);
803 		break;
804 	case 3:
805 		v_clamp_cmd (sv);
806 	}
807 }
808 
part_browser_cmd(GtkToggleAction * action,SchematicView * sv)809 static void part_browser_cmd (GtkToggleAction *action, SchematicView *sv)
810 {
811 	part_browser_toggle_visibility (sv);
812 }
813 
grid_toggle_snap_cmd(GtkToggleAction * action,SchematicView * sv)814 static void grid_toggle_snap_cmd (GtkToggleAction *action, SchematicView *sv)
815 {
816 	sv->priv->grid = !sv->priv->grid;
817 
818 	grid_snap (sv->priv->sheet->grid, sv->priv->grid);
819 	grid_show (sv->priv->sheet->grid, sv->priv->grid);
820 }
821 
log_toggle_visibility_cmd(GtkToggleAction * action,SchematicView * sv)822 static void log_toggle_visibility_cmd (GtkToggleAction *action, SchematicView *sv)
823 {
824 	g_return_if_fail (sv);
825 	g_return_if_fail (sv->priv->logview);
826 
827 	GtkAllocation allocation;
828 	gboolean b = gtk_toggle_action_get_active (action);
829 	static int pos = 0;
830 	if (pos == 0)
831 		pos = gtk_paned_get_position (GTK_PANED (sv->priv->paned));
832 
833 	gtk_widget_get_allocation (GTK_WIDGET (sv->priv->paned), &allocation);
834 	gtk_paned_set_position (GTK_PANED (sv->priv->paned), b ? pos : allocation.height);
835 }
836 
smartsearch_cmd(GtkWidget * widget,SchematicView * sv)837 static void smartsearch_cmd (GtkWidget *widget, SchematicView *sv)
838 {
839 	// Perform a research of a part within all librarys
840 	g_print ("TODO: search_smart ()\n");
841 }
842 
netlist_cmd(GtkWidget * widget,SchematicView * sv)843 static void netlist_cmd (GtkWidget *widget, SchematicView *sv)
844 {
845 	Schematic *sm;
846 	gchar *netlist_name;
847 	GError *e = NULL;
848 	OreganoEngine *engine;
849 
850 	g_return_if_fail (sv != NULL);
851 
852 	sm = sv->priv->schematic;
853 
854 	netlist_name = dialog_netlist_file (sv);
855 	if (netlist_name == NULL)
856 		return;
857 
858 	schematic_set_netlist_filename (sm, netlist_name);
859 	engine = oregano_engine_factory_create_engine (oregano.engine, sm);
860 	oregano_engine_generate_netlist (engine, netlist_name, &e);
861 	sheet_update_parts (sv->priv->sheet);
862 
863 	g_free (netlist_name);
864 	g_object_unref (engine);
865 
866 	if (e) {
867 		if (g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_CLAMP) ||
868 		    g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_NO_GND) ||
869 		    g_error_matches (e, OREGANO_ERROR, OREGANO_SIMULATE_ERROR_IO_ERROR)) {
870 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
871 			                  _ ("Could not create a netlist."), e);
872 		} else {
873 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
874 			                  _ ("Unexpect failure occured."), e);
875 		}
876 		g_clear_error (&e);
877 		return;
878 	}
879 }
880 
netlist_view_cmd(GtkWidget * widget,SchematicView * sv)881 static void netlist_view_cmd (GtkWidget *widget, SchematicView *sv)
882 {
883 	netlist_editor_new_from_schematic_view (sv);
884 }
885 
zoom_check(SchematicView * sv)886 static void zoom_check (SchematicView *sv)
887 {
888 	double zoom;
889 
890 	g_return_if_fail (sv != NULL);
891 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
892 
893 	sheet_get_zoom (sv->priv->sheet, &zoom);
894 
895 	gtk_action_set_sensitive (
896 	    gtk_ui_manager_get_action (sv->priv->ui_manager, "/StandardToolbar/ZoomIn"),
897 	    zoom < ZOOM_MAX);
898 	gtk_action_set_sensitive (
899 	    gtk_ui_manager_get_action (sv->priv->ui_manager, "/StandardToolbar/ZoomOut"),
900 	    zoom > ZOOM_MIN);
901 }
902 
zoom_in_cmd(GtkWidget * widget,SchematicView * sv)903 static void zoom_in_cmd (GtkWidget *widget, SchematicView *sv)
904 {
905 	g_return_if_fail (sv != NULL);
906 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
907 
908 	sheet_zoom_step (sv->priv->sheet, 1.1);
909 	zoom_check (sv);
910 }
911 
zoom_out_cmd(GtkWidget * widget,SchematicView * sv)912 static void zoom_out_cmd (GtkWidget *widget, SchematicView *sv)
913 {
914 	g_return_if_fail (sv != NULL);
915 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
916 
917 	sheet_zoom_step (sv->priv->sheet, 0.9);
918 	zoom_check (sv);
919 }
920 
zoom_cmd(GtkAction * action,GtkRadioAction * current,SchematicView * sv)921 static void zoom_cmd (GtkAction *action, GtkRadioAction *current, SchematicView *sv)
922 {
923 	switch (gtk_radio_action_get_current_value (current)) {
924 	case 0:
925 		g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.50, NULL);
926 		break;
927 	case 1:
928 		g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 0.75, NULL);
929 		break;
930 	case 2:
931 		g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.0, NULL);
932 		break;
933 	case 3:
934 		g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.25, NULL);
935 		break;
936 	case 4:
937 		g_object_set (G_OBJECT (sv->priv->sheet), "zoom", 1.5, NULL);
938 		break;
939 	}
940 	zoom_check (sv);
941 }
942 
943 /*
944  * Stretch the sheet horizontally.
945  */
stretch_horizontal_cmd(GtkWidget * widget,SchematicView * sv)946 static void stretch_horizontal_cmd (GtkWidget *widget, SchematicView *sv)
947 {
948 	Schematic *sm;
949 	guint width;
950 
951 	g_return_if_fail (sv != NULL);
952 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
953 
954 	sm = sv->priv->schematic;
955 
956 	g_return_if_fail (sm != NULL);
957 	g_return_if_fail (IS_SCHEMATIC (sm));
958 
959 	width = schematic_get_width (sm);
960 	schematic_set_width (sm, width * (1.0 + SCHEMATIC_STRETCH_FACTOR));
961 
962 	if (sheet_replace (sv)) {
963 		schematic_view_reload (sv, sm);
964 
965 		gtk_widget_show_all (schematic_view_get_toplevel (sv));
966 	}
967 }
968 
969 /*
970  * Stretch the sheet vertically.
971  */
stretch_vertical_cmd(GtkWidget * widget,SchematicView * sv)972 static void stretch_vertical_cmd (GtkWidget *widget, SchematicView *sv)
973 {
974 	Schematic *sm;
975 	guint height;
976 
977 	g_return_if_fail (sv != NULL);
978 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
979 
980 	sm = sv->priv->schematic;
981 
982 	g_return_if_fail (sm != NULL);
983 	g_return_if_fail (IS_SCHEMATIC (sm));
984 
985 	height = schematic_get_height (sm);
986 	schematic_set_height (sm, height * (1.0 + SCHEMATIC_STRETCH_FACTOR));
987 
988 	if (sheet_replace (sv)) {
989 		schematic_view_reload (sv, sm);
990 
991 		gtk_widget_show_all (schematic_view_get_toplevel (sv));
992 	}
993 }
994 
schematic_view_simulate_cmd(GtkWidget * widget,SchematicView * sv)995 void schematic_view_simulate_cmd (GtkWidget *widget, SchematicView *sv)
996 {
997 	Schematic *sm;
998 	SimSettings *sim_settings;
999 
1000 	sm = schematic_view_get_schematic (sv);
1001 	sim_settings = schematic_get_sim_settings (sm);
1002 
1003 	// Before running the simulation for the first time, make
1004 	// sure that the simulation settings are configured (this
1005 	// includes the removal of missing output vectors from
1006 	// previous application runs).
1007 	if (!sim_settings->configured) {
1008 		// The response_callback() function will take care
1009 		// of launching the simulation again when the
1010 		// simulation settings have been accepted.
1011 		sim_settings->simulation_requested = TRUE;
1012 		sim_settings_show (NULL, sv);
1013 		return;
1014 	}
1015 
1016 	simulation_show_progress_bar (NULL, sv);
1017 
1018 	sheet_update_parts (sv->priv->sheet);
1019 	return;
1020 }
1021 
schematic_view_class_init(SchematicViewClass * klass)1022 static void schematic_view_class_init (SchematicViewClass *klass)
1023 {
1024 	GObjectClass *object_class;
1025 
1026 	object_class = G_OBJECT_CLASS (klass);
1027 	parent_class = g_type_class_peek_parent (klass);
1028 	schematic_view_signals[CHANGED] =
1029 	    g_signal_new ("changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
1030 	                  G_STRUCT_OFFSET (SchematicViewClass, changed), NULL, NULL,
1031 	                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1032 	schematic_view_signals[RESET_TOOL] =
1033 	    g_signal_new ("reset_tool", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_FIRST,
1034 	                  G_STRUCT_OFFSET (SchematicViewClass, reset_tool), NULL, NULL,
1035 	                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1036 
1037 	object_class->finalize = schematic_view_finalize;
1038 	object_class->dispose = schematic_view_dispose;
1039 }
1040 
schematic_view_init(SchematicView * sv)1041 static void schematic_view_init (SchematicView *sv)
1042 {
1043 	sv->priv = g_new0 (SchematicViewPriv, 1);
1044 	sv->priv->log_info = g_new0 (LogInfo, 1);
1045 	sv->priv->empty = TRUE;
1046 	sv->priv->schematic = NULL;
1047 	sv->priv->page_setup = NULL;
1048 	sv->priv->print_settings = gtk_print_settings_new ();
1049 	sv->priv->grid = TRUE;
1050 	sv->priv->logview = NULL;
1051 }
1052 
schematic_view_finalize(GObject * object)1053 static void schematic_view_finalize (GObject *object)
1054 {
1055 	SchematicView *sv = SCHEMATIC_VIEW (object);
1056 
1057 	if (sv->priv) {
1058 		if (sv->priv->page_setup) {
1059 			g_object_unref (sv->priv->page_setup);
1060 		}
1061 
1062 		g_object_unref (sv->priv->print_settings);
1063 		g_object_unref (sv->priv->action_group);
1064 		g_object_unref (sv->priv->ui_manager);
1065 		g_object_unref (sv->priv->paned);
1066 
1067 		g_free (sv->priv->log_info);
1068 		g_free (sv->priv);
1069 		sv->priv = NULL;
1070 	}
1071 
1072 	if (sv->toplevel) {
1073 		g_object_unref (G_OBJECT (sv->toplevel));
1074 		sv->toplevel = NULL;
1075 	}
1076 
1077 	G_OBJECT_CLASS (parent_class)->finalize (object);
1078 }
1079 
schematic_view_dispose(GObject * object)1080 static void schematic_view_dispose (GObject *object)
1081 {
1082 	SchematicView *sv = SCHEMATIC_VIEW (object);
1083 
1084 	schematic_view_list = g_list_remove (schematic_view_list, sv);
1085 
1086 	if (sv->toplevel) {
1087 		// Disconnect focus signal
1088 		g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel), G_CALLBACK (set_focus), sv);
1089 
1090 		// Disconnect destroy event from toplevel
1091 		g_signal_handlers_disconnect_by_func (G_OBJECT (sv->toplevel), G_CALLBACK (delete_event), sv);
1092 	}
1093 
1094 	if (sv->priv) {
1095 		if (IS_SHEET (sv->priv->sheet)) {
1096 			// Disconnect sheet's events
1097 			g_signal_handlers_disconnect_by_func (G_OBJECT (sv->priv->sheet),
1098 							      G_CALLBACK (sheet_event_callback), sv->priv->sheet);
1099 		}
1100 
1101 		g_object_unref (G_OBJECT (sv->priv->schematic));
1102 	}
1103 
1104 	G_OBJECT_CLASS (parent_class)->dispose (object);
1105 }
1106 
show_help(GtkWidget * widget,SchematicView * sv)1107 static void show_help (GtkWidget *widget, SchematicView *sv)
1108 {
1109 	GError *e = NULL;
1110 
1111 #if GTK_CHECK_VERSION (3,22,0)
1112 	if (!gtk_show_uri_on_window (GTK_WINDOW (sv->toplevel), "help:oregano", gtk_get_current_event_time (),
1113 #else
1114 	if (!gtk_show_uri (gtk_widget_get_screen (sv->toplevel), "help:oregano", gtk_get_current_event_time (),
1115 #endif
1116      				&e)) {
1117 		NG_DEBUG ("Error %s\n", e->message);
1118 		g_clear_error (&e);
1119 	}
1120 }
1121 
1122 /**
1123  * Get a suitable value for the window size.
1124  *
1125  * Make the window occupy 3/4 of the screen with a padding of 50px in each
1126  * direction
1127  */
get_window_size(GtkWindow * window,GdkRectangle * rect)1128 static void get_window_size (GtkWindow *window, GdkRectangle *rect)
1129 {
1130 	GdkRectangle monitor_rect;
1131 #if GTK_CHECK_VERSION (3,22,0)
1132 	GdkMonitor *monitor;
1133 	GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (window));
1134 #else
1135 	gint monitor;
1136 	GdkScreen *screen = gdk_screen_get_default ();
1137 #endif
1138 
1139 #if GTK_CHECK_VERSION (3,22,0)
1140 	if (display) {
1141 		monitor = gdk_display_get_primary_monitor (display);
1142 		gdk_monitor_get_geometry (monitor, &monitor_rect);
1143 #else
1144 	if (screen) {
1145 		monitor = gdk_screen_get_primary_monitor (screen);
1146 		gdk_screen_get_monitor_geometry (screen, monitor, &monitor_rect);
1147 #endif
1148 
1149 		rect->width = 3 * (monitor_rect.width - 50) / 4;
1150 		rect->height = 3 * (monitor_rect.height - 50) / 4;
1151 	} else {
1152 		g_warning ("No default screen found. Falling back to 1024x768 window size.");
1153 		rect->width = 1024;
1154 		rect->height = 768;
1155 	}
1156 }
1157 
1158 static void set_window_size (SchematicView *sv)
1159 {
1160 	GdkRectangle rect;
1161 
1162 	get_window_size (GTK_WINDOW (sv->toplevel), &rect);
1163 
1164 	gtk_window_set_default_size (GTK_WINDOW (sv->toplevel), rect.width, rect.height);
1165 }
1166 
1167 #include "schematic-view-menu.h"
1168 
1169 SchematicView *schematic_view_new (Schematic *schematic)
1170 {
1171 	SchematicView *sv;
1172 	SchematicViewPriv *priv;
1173 	Schematic *sm;
1174 	GtkWidget *w, *hbox, *vbox;
1175 	GtkWidget *toolbar, *part_browser;
1176 	GtkWidget *logview;
1177 	GtkWidget *logview_scrolled;
1178 	GtkActionGroup *action_group;
1179 	GtkUIManager *ui_manager;
1180 	GtkAccelGroup *accel_group;
1181 	GtkWidget *menubar;
1182 	GtkGrid *grid;
1183 	GtkPaned *paned;
1184 	GError *e = NULL;
1185 	GtkBuilder *builder;
1186 	GdkRectangle window_size;
1187 
1188 	g_return_val_if_fail (schematic, NULL);
1189 	g_return_val_if_fail (IS_SCHEMATIC (schematic), NULL);
1190 
1191 	sv = SCHEMATIC_VIEW (g_object_new (schematic_view_get_type (), NULL));
1192 
1193 	schematic_view_list = g_list_prepend (schematic_view_list, sv);
1194 
1195 	sm = schematic_view_get_schematic (sv);
1196 
1197 	if ((builder = gtk_builder_new ()) == NULL) {
1198 		log_append (schematic_get_log_store (sm), _ ("SchematicView"),
1199 		            _ ("Failed to spawn builder object."));
1200 		return NULL;
1201 	}
1202 	gtk_builder_set_translation_domain (builder, NULL);
1203 
1204 	if (gtk_builder_add_from_file (builder, OREGANO_UIDIR "/oregano-main.ui", &e) <= 0) {
1205 		log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
1206 		                  _ ("Could not create main window from file."), e);
1207 		g_clear_error (&e);
1208 		return NULL;
1209 	}
1210 
1211 	sv->toplevel = GTK_WIDGET (gtk_builder_get_object (builder, "toplevel"));
1212 	grid = GTK_GRID (gtk_builder_get_object (builder, "grid"));
1213 	paned = GTK_PANED (gtk_builder_get_object (builder, "paned"));
1214 	sv->priv->paned = paned;
1215 
1216 	get_window_size (GTK_WINDOW (sv->toplevel), &window_size);
1217 	if (schematic_get_width (schematic) < window_size.width)
1218 		schematic_set_width (schematic, window_size.width);
1219 	if (schematic_get_height (schematic) < window_size.height)
1220 		schematic_set_height (schematic, window_size.height);
1221 
1222 	sv->priv->sheet = SHEET (sheet_new ((double) schematic_get_width (schematic) + SHEET_BORDER, (double) schematic_get_height (schematic) + SHEET_BORDER));
1223 
1224 	g_signal_connect (G_OBJECT (sv->priv->sheet), "event", G_CALLBACK (sheet_event_callback),
1225 	                  sv->priv->sheet);
1226 
1227 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1228 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1229 
1230 	w = gtk_scrolled_window_new (NULL, NULL);
1231 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC,
1232 	                                GTK_POLICY_AUTOMATIC);
1233 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN);
1234 	gtk_widget_set_hexpand (w, TRUE);
1235 	gtk_widget_set_vexpand (w, TRUE);
1236 
1237 	gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (sv->priv->sheet));
1238 	gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 5);
1239 
1240 	part_browser = part_browser_create (sv);
1241 	gtk_widget_set_hexpand (part_browser, FALSE);
1242 	gtk_grid_attach_next_to (grid, part_browser, GTK_WIDGET (paned), GTK_POS_RIGHT, 1, 1);
1243 
1244 	priv = sv->priv;
1245 	priv->log_info->log_window = NULL;
1246 
1247 	priv->action_group = action_group = gtk_action_group_new ("MenuActions");
1248 	gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1249 	gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), sv);
1250 	gtk_action_group_add_radio_actions (action_group, zoom_entries, G_N_ELEMENTS (zoom_entries), 2,
1251 	                                    G_CALLBACK (zoom_cmd), sv);
1252 	gtk_action_group_add_radio_actions (action_group, tools_entries, G_N_ELEMENTS (tools_entries),
1253 	                                    0, G_CALLBACK (tool_cmd), sv);
1254 	g_assert_cmpint (G_N_ELEMENTS (toggle_entries), >=, 4);
1255 	gtk_action_group_add_toggle_actions (action_group, toggle_entries,
1256 	                                     G_N_ELEMENTS (toggle_entries), sv);
1257 
1258 	priv->ui_manager = ui_manager = gtk_ui_manager_new ();
1259 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1260 
1261 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
1262 	gtk_window_add_accel_group (GTK_WINDOW (sv->toplevel), accel_group);
1263 
1264 	if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &e)) {
1265 		g_message ("building menus failed: %s", e->message);
1266 		g_clear_error (&e);
1267 		return NULL;
1268 	}
1269 
1270 	menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
1271 
1272 	// Upgrade the menu bar with the recent files used by oregano
1273 	display_recent_files (menubar, sv);
1274 	gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
1275 
1276 	toolbar = gtk_ui_manager_get_widget (ui_manager, "/StandardToolbar");
1277 	gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
1278 	gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
1279 
1280 	// Fill the window
1281 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
1282 
1283 	gtk_paned_pack1 (paned, vbox, FALSE, TRUE);
1284 	gtk_widget_grab_focus (GTK_WIDGET (sv->priv->sheet));
1285 
1286 	g_signal_connect_after (G_OBJECT (sv->toplevel), "set_focus", G_CALLBACK (set_focus), sv);
1287 	g_signal_connect (G_OBJECT (sv->toplevel), "delete_event", G_CALLBACK (delete_event), sv);
1288 
1289 	sv->priv->logview = logview = GTK_WIDGET (log_view_new ());
1290 	log_view_set_store (LOG_VIEW (logview), schematic_get_log_store (schematic));
1291 
1292 	logview_scrolled = gtk_scrolled_window_new (NULL, NULL);
1293 	gtk_container_add (GTK_CONTAINER (logview_scrolled), logview);
1294 	gtk_paned_pack2 (paned, logview_scrolled, FALSE, TRUE);
1295 
1296 	setup_dnd (sv);
1297 
1298 	// Set default sensitive for items
1299 	gtk_action_set_sensitive (
1300 	    gtk_ui_manager_get_action (ui_manager, "/MainMenu/MenuEdit/ObjectProperties"), FALSE);
1301 	gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager, "/MainMenu/MenuEdit/Paste"),
1302 	                          FALSE);
1303 
1304 	g_signal_connect_object (G_OBJECT (sv), "reset_tool", G_CALLBACK (reset_tool_cb), G_OBJECT (sv),
1305 	                         0);
1306 
1307 	set_window_size (sv);
1308 
1309 	schematic_view_load (sv, schematic);
1310 
1311 	if (!schematic_get_title (sv->priv->schematic)) {
1312 		gtk_window_set_title (GTK_WINDOW (sv->toplevel), _ ("Untitled.oregano"));
1313 	} else {
1314 		gtk_window_set_title (GTK_WINDOW (sv->toplevel), schematic_get_title (sv->priv->schematic));
1315 	}
1316 	schematic_set_filename (sv->priv->schematic, _ ("Untitled.oregano"));
1317 	schematic_set_netlist_filename (sv->priv->schematic, _ ("Untitled.netlist"));
1318 
1319 	gtk_window_set_application (GTK_WINDOW (schematic_view_get_toplevel (sv)),
1320 	                            GTK_APPLICATION (g_application_get_default ()));
1321 
1322 	return sv;
1323 }
1324 
1325 static void schematic_view_load (SchematicView *sv, Schematic *sm)
1326 {
1327 	schematic_view_do_load (sv, sm, FALSE);
1328 }
1329 
1330 static void schematic_view_do_load (SchematicView *sv, Schematic *sm, const gboolean reload)
1331 {
1332 	GList *list;
1333 	g_return_if_fail (sv != NULL);
1334 	g_return_if_fail (sm != NULL);
1335 	g_return_if_fail (IS_SCHEMATIC (sm));
1336 
1337 	if (!reload)
1338 		g_return_if_fail (sv->priv->empty != FALSE);
1339 
1340 	if (!reload && sv->priv->schematic)
1341 		g_object_unref (G_OBJECT (sv->priv->schematic));
1342 
1343 	sv->priv->schematic = sm;
1344 
1345 	if (!reload) {
1346 		g_signal_connect_object (G_OBJECT (sm), "title_changed", G_CALLBACK (title_changed_callback),
1347 					 G_OBJECT (sv), 0);
1348 		g_signal_connect_object (G_OBJECT (sm), "item_data_added",
1349 					 G_CALLBACK (item_data_added_callback), G_OBJECT (sv), 0);
1350 	}
1351 
1352 	list = schematic_get_items (sm);
1353 
1354 	for (; list; list = list->next) {
1355 		g_signal_emit_by_name (G_OBJECT (sm), "item_data_added", list->data);
1356 	}
1357 
1358 	sheet_connect_node_dots_to_signals (sv->priv->sheet);
1359 
1360 	// connect logview with logstore
1361 	if (!reload)
1362 		log_view_set_store (LOG_VIEW (sv->priv->logview), schematic_get_log_store (sm));
1363 
1364 	schematic_set_dirty (sm, FALSE);
1365 
1366 	g_list_free_full (list, g_object_unref);
1367 }
1368 
1369 static void schematic_view_reload (SchematicView *sv, Schematic *sm)
1370 {
1371 	schematic_view_do_load (sv, sm, TRUE);
1372 }
1373 
1374 static void item_selection_changed_callback (SheetItem *item, gboolean selected, SchematicView *sv)
1375 {
1376 	guint length;
1377 
1378 	if (selected) {
1379 		sheet_prepend_selected_object (sv->priv->sheet, item);
1380 	} else {
1381 		sheet_remove_selected_object (sv->priv->sheet, item);
1382 	}
1383 
1384 	length = sheet_get_selected_objects_length (sv->priv->sheet);
1385 	if (length && item_data_has_properties (sheet_item_get_data (item)))
1386 		gtk_action_set_sensitive (
1387 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/ObjectProperties"),
1388 		    TRUE);
1389 	else
1390 		gtk_action_set_sensitive (
1391 		    gtk_ui_manager_get_action (sv->priv->ui_manager, "/MainMenu/MenuEdit/ObjectProperties"),
1392 		    FALSE);
1393 }
1394 
1395 // An ItemData got added; create an Item and set up the neccessary handlers.
1396 static void item_data_added_callback (Schematic *schematic, ItemData *data, SchematicView *sv)
1397 {
1398 	Sheet *sheet;
1399 	SheetItem *item;
1400 
1401 	sheet = sv->priv->sheet;
1402 
1403 	item = sheet_item_factory_create_sheet_item (sheet, data);
1404 
1405 	if (item != NULL) {
1406 		sheet_item_place (item, sv->priv->sheet);
1407 
1408 		g_object_set (G_OBJECT (item), "action_group", sv->priv->action_group, NULL);
1409 
1410 		g_signal_connect (G_OBJECT (item), "selection_changed",
1411 		                  G_CALLBACK (item_selection_changed_callback), sv);
1412 
1413 		sheet_add_item (sheet, item);
1414 		sv->priv->empty = FALSE;
1415 		if (sv->priv->tool == SCHEMATIC_TOOL_PART)
1416 			schematic_view_reset_tool (sv);
1417 
1418 		// refresh _after_ we added it to the Sheet
1419 		// this is required to properly display rotation, flip and others
1420 		item_data_changed (data);
1421 	}
1422 }
1423 
1424 static void title_changed_callback (Schematic *schematic, char *new_title, SchematicView *sv)
1425 {
1426 	g_return_if_fail (schematic != NULL);
1427 	g_return_if_fail (IS_SCHEMATIC (schematic));
1428 	g_return_if_fail (sv != NULL);
1429 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1430 
1431 	gtk_window_set_title (GTK_WINDOW (sv->toplevel), new_title);
1432 }
1433 
1434 static void set_focus (GtkWindow *window, GtkWidget *focus, SchematicView *sv)
1435 {
1436 	g_return_if_fail (sv->priv != NULL);
1437 	g_return_if_fail (sv->priv->sheet != NULL);
1438 
1439 	if (!gtk_window_get_focus (window))
1440 		gtk_widget_grab_focus (GTK_WIDGET (sv->priv->sheet));
1441 }
1442 
1443 static int delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
1444 {
1445 	if (can_close (sv)) {
1446 		g_object_unref (G_OBJECT (sv));
1447 		return FALSE;
1448 	} else
1449 		return TRUE;
1450 }
1451 
1452 static int can_close (SchematicView *sv)
1453 {
1454 	GtkWidget *dialog;
1455 	gchar *text, *filename;
1456 	GError *e = NULL;
1457 	gint result;
1458 
1459 	if (!schematic_is_dirty (schematic_view_get_schematic (sv)))
1460 		return TRUE;
1461 
1462 	filename = schematic_get_filename (sv->priv->schematic);
1463 	text =
1464 	    g_strdup_printf (_ ("<span weight=\"bold\" size=\"large\">Save "
1465 	                        "changes to schematic %s before closing?</span>\n\nIf you don't save, "
1466 	                        "all changes since you last saved will be permanently lost."),
1467 	                     filename ? g_path_get_basename (filename) : NULL);
1468 
1469 	dialog = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
1470 	                                             GTK_BUTTONS_NONE, _ (text), NULL);
1471 
1472 	gtk_dialog_add_buttons (GTK_DIALOG (dialog), _ ("Close _without Saving"), GTK_RESPONSE_NO,
1473 	                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_YES,
1474 	                        NULL);
1475 
1476 	g_free (text);
1477 
1478 	result = gtk_dialog_run (GTK_DIALOG (dialog));
1479 
1480 	gtk_widget_destroy (dialog);
1481 
1482 	switch (result) {
1483 	case GTK_RESPONSE_YES:
1484 		schematic_save_file (sv->priv->schematic, &e);
1485 		if (e) {
1486 			g_clear_error (&e);
1487 		}
1488 		break;
1489 	case GTK_RESPONSE_NO:
1490 		schematic_set_dirty (sv->priv->schematic, FALSE);
1491 		break;
1492 	case GTK_RESPONSE_CANCEL:
1493 	default:
1494 		return FALSE;
1495 	}
1496 	return TRUE;
1497 }
1498 
1499 Sheet *schematic_view_get_sheet (SchematicView *sv)
1500 {
1501 	g_return_val_if_fail (sv != NULL, NULL);
1502 	g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
1503 
1504 	return sv->priv->sheet;
1505 }
1506 
1507 void schematic_view_set_sheet (SchematicView *sv, Sheet *sheet)
1508 {
1509 	g_return_if_fail (sv != NULL);
1510 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1511 
1512 	sv->priv->sheet = sheet;
1513 }
1514 
1515 Schematic *schematic_view_get_schematic (SchematicView *sv)
1516 {
1517 	g_return_val_if_fail (sv != NULL, NULL);
1518 	g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
1519 
1520 	return sv->priv->schematic;
1521 }
1522 
1523 void schematic_view_reset_tool (SchematicView *sv)
1524 {
1525 	g_return_if_fail (sv != NULL);
1526 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1527 
1528 	g_signal_emit_by_name (G_OBJECT (sv), "reset_tool");
1529 }
1530 
1531 static void setup_dnd (SchematicView *sv)
1532 {
1533 	static GtkTargetEntry dnd_types[] = {{"text/uri-list", 0, DRAG_URI_INFO},
1534 	                                     {"x-application/oregano-part", 0, DRAG_PART_INFO}};
1535 	static gint dnd_num_types = sizeof(dnd_types) / sizeof(dnd_types[0]);
1536 
1537 	gtk_drag_dest_set (GTK_WIDGET (sv->priv->sheet),
1538 	                   GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
1539 	                   dnd_types, dnd_num_types, GDK_ACTION_MOVE);
1540 
1541 	g_signal_connect (G_OBJECT (sv->priv->sheet), "drag_data_received", G_CALLBACK (data_received),
1542 	                  "koko");
1543 }
1544 
1545 static void data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
1546                            GtkSelectionData *selection_data, guint info, guint32 time,
1547                            SchematicView *sv)
1548 {
1549 	gchar **files;
1550 	GError *e = NULL;
1551 
1552 	// Extract the filenames from the URI-list we received.
1553 	switch (info) {
1554 	case DRAG_PART_INFO:
1555 		part_browser_dnd (selection_data, x, y);
1556 		break;
1557 	case DRAG_URI_INFO:
1558 		files = g_strsplit ((gchar *)gtk_selection_data_get_data (selection_data), "\n", -1);
1559 		if (files) {
1560 			int i = 0;
1561 			while (files[i]) {
1562 				Schematic *new_sm = NULL;
1563 				int l = strlen (files[i]);
1564 				// Algo remains bad after the split: we agregate back into one \0
1565 				files[i][l - 1] = '\0';
1566 
1567 				if (l <= 0) {
1568 					// Empty file name, ignore!
1569 					i++;
1570 					continue;
1571 				}
1572 
1573 				gchar *fname = files[i];
1574 
1575 				new_sm = schematic_read (fname, &e);
1576 				if (e) {
1577 					//						g_warning ()
1578 					g_clear_error (&e);
1579 				}
1580 				if (new_sm) {
1581 					SchematicView *new_view;
1582 					new_view = schematic_view_new (new_sm);
1583 					if (new_view) {
1584 						gtk_widget_show_all (new_view->toplevel);
1585 						schematic_set_filename (new_sm, fname);
1586 					}
1587 					// schematic_set_title (new_sm, fname);
1588 					while (gtk_events_pending ()) // Show something.
1589 						gtk_main_iteration ();
1590 				}
1591 				i++;
1592 			}
1593 			g_strfreev (files);
1594 		}
1595 	}
1596 	gtk_drag_finish (context, TRUE, TRUE, time);
1597 }
1598 
1599 static void set_tool (SchematicView *sv, SchematicTool tool)
1600 {
1601 	// Switch from this tool...
1602 	switch (sv->priv->tool) {
1603 	case SCHEMATIC_TOOL_ARROW:
1604 		// In case we are handling a floating object, cancel that so that we can
1605 		// change the tool.
1606 		sheet_item_cancel_floating (sv->priv->sheet);
1607 		break;
1608 	case SCHEMATIC_TOOL_WIRE:
1609 		/*if (sv->priv->create_wire_context) {
1610 		                create_wire_exit (sv->priv->create_wire_context);
1611 		                sv->priv->create_wire_context = NULL;
1612 		}*/
1613 		sheet_stop_create_wire (sv->priv->sheet);
1614 		break;
1615 	case SCHEMATIC_TOOL_TEXT:
1616 		textbox_item_cancel_listen (sv->priv->sheet);
1617 		break;
1618 	case SCHEMATIC_TOOL_PART:
1619 		sheet_item_cancel_floating (sv->priv->sheet);
1620 	default:
1621 		break;
1622 	}
1623 
1624 	// ...to this tool.
1625 	switch (tool) {
1626 	case SCHEMATIC_TOOL_ARROW:
1627 		cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_LEFT_PTR);
1628 		sv->priv->sheet->state = SHEET_STATE_NONE;
1629 		break;
1630 	case SCHEMATIC_TOOL_WIRE:
1631 		cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_PENCIL);
1632 		sv->priv->sheet->state = SHEET_STATE_WIRE;
1633 		sheet_initiate_create_wire (sv->priv->sheet);
1634 		break;
1635 	case SCHEMATIC_TOOL_TEXT:
1636 		cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_CARET);
1637 		sv->priv->sheet->state = SHEET_STATE_TEXTBOX_WAIT;
1638 
1639 		textbox_item_listen (sv->priv->sheet);
1640 		break;
1641 	case SCHEMATIC_TOOL_PART:
1642 		cursor_set_widget (GTK_WIDGET (sv->priv->sheet), OREGANO_CURSOR_LEFT_PTR);
1643 	default:
1644 		break;
1645 	}
1646 
1647 	sv->priv->tool = tool;
1648 }
1649 
1650 static void reset_tool_cb (Sheet *sheet, SchematicView *sv)
1651 {
1652 	set_tool (sv, SCHEMATIC_TOOL_ARROW);
1653 
1654 	gtk_radio_action_set_current_value (GTK_RADIO_ACTION (gtk_ui_manager_get_action (
1655 	                                        sv->priv->ui_manager, "/StandardToolbar/Arrow")),
1656 	                                    0);
1657 }
1658 
1659 gpointer schematic_view_get_browser (SchematicView *sv)
1660 {
1661 	g_return_val_if_fail (sv != NULL, NULL);
1662 	g_return_val_if_fail (IS_SCHEMATIC_VIEW (sv), NULL);
1663 
1664 	return sv->priv->browser;
1665 }
1666 
1667 void schematic_view_set_browser (SchematicView *sv, gpointer p)
1668 {
1669 	g_return_if_fail (sv != NULL);
1670 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1671 
1672 	sv->priv->browser = p;
1673 }
1674 
1675 static gboolean log_window_delete_event (GtkWidget *widget, GdkEvent *event, SchematicView *sv)
1676 {
1677 	sv->priv->log_info->log_window = NULL;
1678 	return FALSE;
1679 }
1680 
1681 static void log_window_destroy_event (GtkWidget *widget, SchematicView *sv)
1682 {
1683 	sv->priv->log_info->log_window = NULL;
1684 }
1685 
1686 static void log_window_close_cb (GtkWidget *widget, SchematicView *sv)
1687 {
1688 	gtk_widget_destroy (sv->priv->log_info->log_window);
1689 	sv->priv->log_info->log_window = NULL;
1690 }
1691 
1692 static void log_window_clear_cb (GtkWidget *widget, SchematicView *sv)
1693 {
1694 	GtkTextTagTable *tag;
1695 	GtkTextBuffer *buf;
1696 
1697 	tag = gtk_text_tag_table_new ();
1698 	buf = gtk_text_buffer_new (GTK_TEXT_TAG_TABLE (tag));
1699 
1700 	schematic_log_clear (sv->priv->schematic);
1701 
1702 	gtk_text_view_set_buffer (GTK_TEXT_VIEW (sv->priv->log_info->log_text), GTK_TEXT_BUFFER (buf));
1703 }
1704 
1705 static void log_updated_callback (Schematic *sm, SchematicView *sv)
1706 {
1707 	schematic_view_log_show (sv, FALSE);
1708 }
1709 
1710 void schematic_view_log_show (SchematicView *sv, gboolean explicit)
1711 {
1712 	GtkWidget *w;
1713 	Schematic *sm;
1714 	GError *e = NULL;
1715 
1716 	g_return_if_fail (sv != NULL);
1717 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1718 
1719 	sm = sv->priv->schematic;
1720 
1721 	if ((sv->priv->log_info->log_gui = gtk_builder_new ()) == NULL) {
1722 		log_append (schematic_get_log_store (sm), _ ("SchematicView"),
1723 		            _ ("Could not create the log window."));
1724 		return;
1725 	}
1726 	gtk_builder_set_translation_domain (sv->priv->log_info->log_gui, NULL);
1727 
1728 	if (sv->priv->log_info->log_window == NULL) {
1729 		// Create the log window if not already done.
1730 		if (!explicit && !oregano.show_log)
1731 			return;
1732 
1733 		if (gtk_builder_add_from_file (sv->priv->log_info->log_gui, OREGANO_UIDIR "/log-window.ui",
1734 		                               &e) <= 0) {
1735 
1736 			log_append_error (schematic_get_log_store (sm), _ ("SchematicView"),
1737 			                  _ ("Could not create the log window."), e);
1738 			g_clear_error (&e);
1739 			return;
1740 		}
1741 
1742 		sv->priv->log_info->log_window =
1743 		    GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "log-window"));
1744 		sv->priv->log_info->log_text =
1745 		    GTK_TEXT_VIEW (gtk_builder_get_object (sv->priv->log_info->log_gui, "log-text"));
1746 
1747 		gtk_window_set_default_size (GTK_WINDOW (sv->priv->log_info->log_window), 500, 250);
1748 
1749 		// Delete event.
1750 		g_signal_connect (G_OBJECT (sv->priv->log_info->log_window), "delete_event",
1751 		                  G_CALLBACK (log_window_delete_event), sv);
1752 
1753 		g_signal_connect (G_OBJECT (sv->priv->log_info->log_window), "destroy_event",
1754 		                  G_CALLBACK (log_window_destroy_event), sv);
1755 
1756 		w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "close-button"));
1757 		g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (log_window_close_cb), sv);
1758 
1759 		w = GTK_WIDGET (gtk_builder_get_object (sv->priv->log_info->log_gui, "clear-button"));
1760 		g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (log_window_clear_cb), sv);
1761 		g_signal_connect (G_OBJECT (sm), "log_updated", G_CALLBACK (log_updated_callback), sv);
1762 	} else {
1763 		gdk_window_raise (gtk_widget_get_window (sv->priv->log_info->log_window));
1764 	}
1765 
1766 	gtk_text_view_set_buffer (sv->priv->log_info->log_text, schematic_get_log_text (sm));
1767 
1768 	gtk_widget_show_all (sv->priv->log_info->log_window);
1769 }
1770 
1771 gboolean schematic_view_get_log_window_exists (SchematicView *sv)
1772 {
1773 	if (sv->priv->log_info->log_window != NULL)
1774 		return TRUE;
1775 	else
1776 		return FALSE;
1777 }
1778 
1779 GtkWidget *schematic_view_get_toplevel (SchematicView *sv) { return sv->toplevel; }
1780 
1781 Schematic *schematic_view_get_schematic_from_sheet (Sheet *sheet)
1782 {
1783 	g_return_val_if_fail ((sheet != NULL), NULL);
1784 	g_return_val_if_fail (IS_SHEET (sheet), NULL);
1785 
1786 	GList *iter, *copy;
1787 	Schematic *s = NULL;
1788 	copy = g_list_copy (schematic_view_list); // really needed? probably not
1789 
1790 	for (iter = copy; iter; iter = iter->next) {
1791 		SchematicView *sv = SCHEMATIC_VIEW (iter->data);
1792 		if (sv->priv->sheet == sheet) {
1793 			s = sv->priv->schematic;
1794 			break;
1795 		}
1796 	}
1797 	g_list_free (copy);
1798 	return s;
1799 }
1800 
1801 SchematicView *schematic_view_get_schematicview_from_sheet (Sheet *sheet)
1802 {
1803 	g_return_val_if_fail (sheet, NULL);
1804 	g_return_val_if_fail (IS_SHEET (sheet), NULL);
1805 
1806 	GList *iter, *copy;
1807 	SchematicView *sv = NULL;
1808 
1809 	copy = g_list_copy (schematic_view_list); // really needed? probably not
1810 
1811 	for (iter = copy; iter; iter = iter->next) {
1812 		sv = SCHEMATIC_VIEW (iter->data);
1813 		if (sv->priv->sheet == sheet)
1814 			break;
1815 	}
1816 	g_list_free (copy);
1817 	return sv;
1818 }
1819 
1820 void run_context_menu (SchematicView *sv, GdkEventButton *event)
1821 {
1822 	GtkWidget *menu;
1823 
1824 	g_return_if_fail (sv != NULL);
1825 	g_return_if_fail (IS_SCHEMATIC_VIEW (sv));
1826 
1827 	menu = gtk_ui_manager_get_widget (sv->priv->ui_manager, "/MainPopup");
1828 
1829 	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, sv, event->button, event->time);
1830 }
1831