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