1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2019 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /*! \file gschem_messages_dockable.c
22 * \brief Report problems with the current schematic or symbol.
35 #include <math.h> /* for floor(3) */
38 #include "../include/gschem_messages_dockable.h"
43 type_symversion_error
,
51 severity_supplemental_text
52 } GschemMessageSeverity
;
67 static gpointer parent_class
= NULL
;
69 static void class_init (GschemMessagesDockableClass
*class);
70 static void instance_init (GschemMessagesDockable
*messages_dockable
);
71 static void dispose (GObject
*object
);
73 static GtkWidget
*create_widget (GschemDockable
*dockable
);
75 static void clear_weak_refs (GschemMessagesDockable
*messages_dockable
);
79 gschem_messages_dockable_get_type ()
81 static GType type
= 0;
84 static const GTypeInfo info
= {
85 sizeof (GschemMessagesDockableClass
),
87 NULL
, /* base_finalize */
88 (GClassInitFunc
) class_init
,
89 NULL
, /* class_finalize */
90 NULL
, /* class_data */
91 sizeof (GschemMessagesDockable
),
93 (GInstanceInitFunc
) instance_init
,
94 NULL
/* value_table */
97 type
= g_type_register_static (GSCHEM_TYPE_DOCKABLE
,
98 "GschemMessagesDockable",
107 class_init (GschemMessagesDockableClass
*class)
109 parent_class
= g_type_class_peek_parent (class);
111 G_OBJECT_CLASS (class)->dispose
= dispose
;
112 GSCHEM_DOCKABLE_CLASS (class)->create_widget
= create_widget
;
117 instance_init (GschemMessagesDockable
*messages_dockable
)
119 messages_dockable
->store
= gtk_list_store_new (
121 G_TYPE_INT
, /* type */
122 G_TYPE_INT
, /* severity */
123 G_TYPE_STRING
, /* filename */
124 G_TYPE_STRING
, /* refdes */
125 G_TYPE_STRING
, /* message */
126 G_TYPE_STRING
, /* tooltip */
127 G_TYPE_POINTER
, /* object */
128 G_TYPE_BOOLEAN
); /* removed */
133 dispose (GObject
*object
)
135 clear_weak_refs (GSCHEM_MESSAGES_DOCKABLE (object
));
136 g_clear_object (&GSCHEM_MESSAGES_DOCKABLE (object
)->store
);
138 G_OBJECT_CLASS (parent_class
)->dispose (object
);
143 weakref_notify_func (void *dead_obj
, void *user_data
)
145 GschemMessagesDockable
*messages_dockable
=
146 GSCHEM_MESSAGES_DOCKABLE (user_data
);
147 GtkTreeModel
*model
= GTK_TREE_MODEL (messages_dockable
->store
);
150 g_return_if_fail (dead_obj
!= NULL
);
152 /* clear the 'object' field in all matching messages */
153 if (gtk_tree_model_get_iter_first (model
, &iter
))
156 gtk_tree_model_get (model
, &iter
,
160 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
162 COLUMN_REMOVED
, TRUE
,
164 _("<i>Press F5 to update messages</i>"),
166 } while (gtk_tree_model_iter_next (model
, &iter
));
168 /* don't remove the weak reference because this would mess up
169 weakref invocation (and happens automatically, anyway) */
174 add_message (GschemMessagesDockable
*messages_dockable
,
175 gint type
, gint severity
,
176 const gchar
*filename
, const gchar
*refdes
, OBJECT
*obj
,
177 const gchar
*tooltip
,
178 const gchar
*format
, ...)
184 va_start (args
, format
);
185 msg
= g_strdup_vprintf (format
, args
);
188 gtk_list_store_append (messages_dockable
->store
, &iter
);
189 gtk_list_store_set (messages_dockable
->store
, &iter
,
191 COLUMN_SEVERITY
, severity
,
192 COLUMN_FILENAME
, filename
,
193 COLUMN_REFDES
, refdes
,
196 COLUMN_TOOLTIP
, tooltip
,
202 /* duplicate weakrefs don't hurt, so don't bother checking */
203 s_object_weak_ref (obj
, weakref_notify_func
, messages_dockable
);
208 clear_weak_refs (GschemMessagesDockable
*messages_dockable
)
210 GtkTreeModel
*model
= GTK_TREE_MODEL (messages_dockable
->store
);
213 if (gtk_tree_model_get_iter_first (model
, &iter
))
216 gtk_tree_model_get (model
, &iter
,
220 s_object_weak_unref (obj
, weakref_notify_func
, messages_dockable
);
221 } while (gtk_tree_model_iter_next (model
, &iter
));
226 goto_object (GschemToplevel
*w_current
, OBJECT
*obj
)
228 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
230 GschemPageView
*page_view
;
232 g_return_if_fail (obj
!= NULL
);
234 g_return_if_fail (world_get_single_object_bounds (
235 toplevel
, obj
, &x0
, &y0
, &x1
, &y1
));
237 page_view
= gschem_toplevel_get_current_page_view (w_current
);
238 g_return_if_fail (page_view
!= NULL
);
239 gschem_page_view_pan (page_view
, (x0
+ x1
) / 2, (y0
+ y1
) / 2);
244 select_object (GschemToplevel
*w_current
, OBJECT
*obj
)
246 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
247 SELECTION
*selection
= toplevel
->page_current
->selection_list
;
249 g_return_if_fail (obj
!= NULL
);
251 o_redraw_cleanstates (w_current
);
252 o_select_unselect_all (w_current
);
254 g_run_hook_object (w_current
, "%select-objects-hook", obj
);
255 o_selection_add (toplevel
, selection
, obj
);
256 o_attrib_add_selected (w_current
, selection
, obj
);
258 i_set_state (w_current
, SELECT
);
259 i_action_stop (w_current
);
260 i_update_menus (w_current
);
265 confirm_object_symversion (GschemToplevel
*w_current
, OBJECT
*object
)
267 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
270 gboolean symversion_exists
;
273 g_return_if_fail (object
!= NULL
);
274 g_return_if_fail (object
->complex != NULL
);
275 g_return_if_fail (object
->complex->prim_objs
!= NULL
);
276 g_return_if_fail (object
->page
!= NULL
);
278 /* find inherited symversion= attribute */
282 for (const GList
*l
= object
->complex->prim_objs
; l
!= NULL
; l
= l
->next
) {
283 OBJECT
*o_current
= l
->data
;
285 gboolean is_symversion
;
287 /* skip non-text objects, attached attributes, and text which doesn't
288 constitute a valid attribute (e.g. general text placed on the page) */
289 if (o_current
->type
!= OBJ_TEXT
||
290 o_current
->attached_to
!= NULL
||
291 !o_attrib_get_name_value (o_current
, &name
, NULL
))
294 is_symversion
= strcmp (name
, "symversion") == 0;
298 inherited
= o_current
;
303 if (inherited
== NULL
) {
304 s_log_message (_("Can't find inherited symversion attribute\n"));
308 /* search for and update existing symversion= attribute */
310 symversion_exists
= FALSE
;
313 for (const GList
*l
= object
->attribs
; l
!= NULL
; l
= l
->next
) {
314 OBJECT
*attrib
= l
->data
;
317 if (attrib
->type
!= OBJ_TEXT
||
318 !o_attrib_get_name_value (attrib
, &name
, NULL
))
321 if (strcmp (name
, "symversion") == 0) {
322 if (strcmp (attrib
->text
->string
, inherited
->text
->string
) != 0) {
323 o_text_change (w_current
, attrib
, inherited
->text
->string
,
324 attrib
->visibility
, attrib
->show_name_value
);
327 symversion_exists
= TRUE
;
333 /* promote symversion= attribute if it doesn't exist yet */
335 if (!symversion_exists
) {
336 OBJECT
*o_new
= o_object_copy (toplevel
, inherited
);
337 o_set_visibility (toplevel
, o_new
, VISIBLE
);
338 s_page_append (toplevel
, object
->page
, o_new
);
339 o_attrib_attach (toplevel
, o_new
, object
, TRUE
);
340 g_run_hook_object (w_current
, "%add-objects-hook", o_new
);
342 SELECTION
*selection
= object
->page
->selection_list
;
343 if (g_list_find (geda_list_get_glist (selection
), object
) != NULL
) {
344 g_run_hook_object (w_current
, "%select-objects-hook", o_new
);
345 o_selection_add (toplevel
, selection
, o_new
);
346 o_attrib_add_selected (w_current
, selection
, o_new
);
353 gschem_toplevel_page_content_changed (w_current
, object
->page
);
354 o_undo_savestate_old (w_current
, UNDO_ALL
, _("Confirm Symbol Version"));
359 /******************************************************************************/
363 icon_cell_data_func (GtkTreeViewColumn
*tree_column
, GtkCellRenderer
*cell
,
364 GtkTreeModel
*tree_model
, GtkTreeIter
*iter
,
368 gtk_tree_model_get (tree_model
, iter
,
369 COLUMN_SEVERITY
, &severity
,
374 severity
== severity_error
? GTK_STOCK_DIALOG_ERROR
:
375 severity
== severity_warning
? GTK_STOCK_DIALOG_WARNING
:
376 severity
== severity_message
? GTK_STOCK_DIALOG_INFO
: "",
382 tree_selection_changed (GtkTreeSelection
*selection
, gpointer user_data
)
388 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
391 gtk_tree_model_get (model
, &iter
,
396 goto_object (GSCHEM_DOCKABLE (user_data
)->w_current
, obj
);
401 tree_view_row_activated (GtkTreeView
*tree_view
, GtkTreePath
*path
,
402 GtkTreeViewColumn
*column
, gpointer user_data
)
404 GtkTreeModel
*model
= gtk_tree_view_get_model (tree_view
);
408 g_return_if_fail (gtk_tree_model_get_iter (model
, &iter
, path
));
410 gtk_tree_model_get (model
, &iter
,
415 select_object (GSCHEM_DOCKABLE (user_data
)->w_current
, obj
);
420 get_message_object (GschemMessagesDockable
*messages_dockable
)
422 GtkTreeView
*tree_view
= GTK_TREE_VIEW (messages_dockable
->tree_view
);
423 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (tree_view
);
428 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
431 gtk_tree_model_get (model
, &iter
,
439 select_item_activate (GtkMenuItem
*menu_item
, gpointer user_data
)
441 GschemMessagesDockable
*messages_dockable
=
442 GSCHEM_MESSAGES_DOCKABLE (user_data
);
444 OBJECT
*obj
= get_message_object (messages_dockable
);
446 select_object (GSCHEM_DOCKABLE (user_data
)->w_current
, obj
);
451 confirm_item_activate (GtkMenuItem
*menu_item
, gpointer user_data
)
453 GschemMessagesDockable
*messages_dockable
=
454 GSCHEM_MESSAGES_DOCKABLE (user_data
);
456 OBJECT
*obj
= get_message_object (messages_dockable
);
458 confirm_object_symversion (GSCHEM_DOCKABLE (user_data
)->w_current
, obj
);
463 create_menu (GschemMessagesDockable
*messages_dockable
)
465 GtkWidget
*menu
, *item
;
466 g_return_if_fail (messages_dockable
->menu
== NULL
);
468 menu
= messages_dockable
->menu
= gtk_menu_new ();
470 item
= messages_dockable
->select_item
=
471 gtk_menu_item_new_with_mnemonic (_("_Select Object"));
472 g_signal_connect (item
, "activate",
473 G_CALLBACK (select_item_activate
), messages_dockable
);
474 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
476 item
= messages_dockable
->confirm_item
=
477 gtk_menu_item_new_with_mnemonic (_("_Confirm Symbol Version"));
478 g_signal_connect (item
, "activate",
479 G_CALLBACK (confirm_item_activate
), messages_dockable
);
480 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
482 gtk_widget_show_all (menu
);
484 /* make sure the menu will be destroyed when the widget is destroyed and
485 moves between screens correctly if the widgets moves between screens */
486 gtk_menu_attach_to_widget (
487 GTK_MENU (menu
), messages_dockable
->tree_view
, NULL
);
492 menu_position_func (GtkMenu
*menu
, gint
*x
, gint
*y
, gboolean
*push_in
,
495 gint
*pos
= user_data
;
503 popup (GschemMessagesDockable
*messages_dockable
,
504 GtkTreeModel
*model
, GtkTreeIter
*iter
,
505 GdkEventButton
*event
)
510 gtk_tree_model_get (model
, iter
,
512 COLUMN_SEVERITY
, &severity
,
516 if (severity
== severity_supplemental_text
|| obj
== NULL
)
517 /* there's no popup for extra lines and removed items */
520 if (messages_dockable
->menu
== NULL
)
521 create_menu (messages_dockable
);
523 gtk_widget_set_sensitive (messages_dockable
->select_item
, obj
!= NULL
);
524 gtk_widget_set_sensitive (messages_dockable
->confirm_item
,
525 type
== type_symversion
);
528 gtk_menu_popup (GTK_MENU (messages_dockable
->menu
), NULL
, NULL
,
529 NULL
, NULL
, event
->button
, event
->time
);
531 GtkTreeView
*tree_view
= GTK_TREE_VIEW (messages_dockable
->tree_view
);
532 GtkTreePath
*path
= gtk_tree_model_get_path (model
, iter
);
536 gtk_tree_view_get_cell_area (tree_view
, path
, NULL
, &rect
);
537 gtk_tree_path_free (path
);
539 (void) gdk_window_get_origin (gtk_tree_view_get_bin_window (tree_view
),
542 pos
[1] += rect
.y
+ rect
.height
;
544 gtk_menu_popup (GTK_MENU (messages_dockable
->menu
), NULL
, NULL
,
545 menu_position_func
, pos
, 0, gtk_get_current_event_time ());
546 gtk_menu_shell_select_first (GTK_MENU_SHELL (messages_dockable
->menu
),
553 tree_view_button_press_event (GtkWidget
*widget
, GdkEventButton
*event
,
556 GschemMessagesDockable
*messages_dockable
=
557 GSCHEM_MESSAGES_DOCKABLE (user_data
);
559 GtkTreeView
*tree_view
= GTK_TREE_VIEW (messages_dockable
->tree_view
);
560 GtkTreePath
*path
= NULL
;
561 GtkTreeModel
*model
= gtk_tree_view_get_model (tree_view
);
563 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (tree_view
);
565 /* only show popup if this is a single right click */
566 if (event
->button
!= 3 || event
->type
!= GDK_BUTTON_PRESS
)
569 /* coordinates are expected to be relative to bin window */
570 if (event
->window
!= gtk_tree_view_get_bin_window (tree_view
))
573 if (!gtk_tree_view_get_path_at_pos (tree_view
, event
->x
, event
->y
,
574 &path
, NULL
, NULL
, NULL
) ||
575 !gtk_tree_model_get_iter (model
, &iter
, path
)) {
576 gtk_tree_path_free (path
);
580 gtk_tree_selection_select_path (selection
, path
);
581 gtk_tree_path_free (path
);
583 popup (messages_dockable
, model
, &iter
, event
);
589 tree_view_popup_menu (GtkWidget
*widget
, gpointer user_data
)
591 GschemMessagesDockable
*messages_dockable
=
592 GSCHEM_MESSAGES_DOCKABLE (user_data
);
594 GtkTreeSelection
*selection
= gtk_tree_view_get_selection (
595 GTK_TREE_VIEW (messages_dockable
->tree_view
));
599 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
))
602 popup (messages_dockable
, model
, &iter
, NULL
);
608 create_widget (GschemDockable
*dockable
)
610 GschemMessagesDockable
*messages_dockable
=
611 GSCHEM_MESSAGES_DOCKABLE (dockable
);
613 GtkWidget
*tree_view
;
614 GtkTreeSelection
*selection
;
615 GtkTreeViewColumn
*column
;
616 GtkCellRenderer
*renderer
;
619 tree_view
= GTK_WIDGET (
620 g_object_new (GTK_TYPE_TREE_VIEW
,
622 "headers-visible", FALSE
,
623 "model", GTK_TREE_MODEL (messages_dockable
->store
),
624 "tooltip-column", COLUMN_TOOLTIP
,
626 messages_dockable
->tree_view
= tree_view
;
628 g_signal_connect (tree_view
, "row-activated",
629 G_CALLBACK (tree_view_row_activated
), messages_dockable
);
630 g_signal_connect (tree_view
, "button-press-event",
631 G_CALLBACK (tree_view_button_press_event
),
633 g_signal_connect (tree_view
, "popup-menu",
634 G_CALLBACK (tree_view_popup_menu
), messages_dockable
);
636 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view
));
637 g_signal_connect (selection
, "changed",
638 G_CALLBACK (tree_selection_changed
), messages_dockable
);
641 /* filename column */
642 column
= gtk_tree_view_column_new ();
643 gtk_tree_view_column_set_title (column
, _("Filename"));
644 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view
), column
);
646 renderer
= gtk_cell_renderer_pixbuf_new ();
647 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
648 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
649 icon_cell_data_func
, NULL
, NULL
);
651 renderer
= gtk_cell_renderer_text_new ();
652 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
653 gtk_tree_view_column_add_attribute (column
, renderer
,
654 "text", COLUMN_FILENAME
);
655 g_object_set (renderer
, "foreground", "#aaa", NULL
);
656 gtk_tree_view_column_add_attribute (column
, renderer
,
657 "foreground-set", COLUMN_REMOVED
);
660 column
= gtk_tree_view_column_new ();
661 gtk_tree_view_column_set_title (column
, _("Comp/Pin"));
662 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view
), column
);
664 renderer
= gtk_cell_renderer_text_new ();
665 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
666 gtk_tree_view_column_add_attribute (column
, renderer
,
667 "text", COLUMN_REFDES
);
668 g_object_set (renderer
, "foreground", "#aaa", NULL
);
669 gtk_tree_view_column_add_attribute (column
, renderer
,
670 "foreground-set", COLUMN_REMOVED
);
673 column
= gtk_tree_view_column_new ();
674 gtk_tree_view_column_set_title (column
, _("Message"));
675 gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view
), column
);
677 renderer
= gtk_cell_renderer_text_new ();
678 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
679 gtk_tree_view_column_add_attribute (column
, renderer
,
680 "text", COLUMN_MESSAGE
);
681 g_object_set (renderer
, "foreground", "#aaa", NULL
);
682 gtk_tree_view_column_add_attribute (column
, renderer
,
683 "foreground-set", COLUMN_REMOVED
);
686 scrolled
= gtk_scrolled_window_new (NULL
, NULL
);
687 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled
),
688 GTK_POLICY_AUTOMATIC
,
690 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled
),
692 gtk_container_add (GTK_CONTAINER (scrolled
), tree_view
);
694 gtk_widget_show_all (scrolled
);
699 /******************************************************************************/
703 check_floating_symversion (GschemMessagesDockable
*messages_dockable
,
704 const gchar
*filename
)
706 GschemToplevel
*w_current
= GSCHEM_DOCKABLE (messages_dockable
)->w_current
;
707 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
709 char *symversion
= o_attrib_search_floating_attribs_by_name (
710 s_page_objects (toplevel
->page_current
), "symversion", 0);
712 if (symversion
== NULL
)
716 double symversion_value
= strtod (symversion
, &endptr
);
718 if (symversion_value
== 0 && symversion
== endptr
)
719 add_message (messages_dockable
,
720 type_other
, severity_warning
, filename
, "", NULL
, _(
721 "See http://wiki.geda-project.org/geda:master_attributes_list#symversion for "
722 "the semantics of the symversion= attribute."),
723 _("Invalid symversion= attribute \"%s\""),
730 /*! \brief Check symversion of a component.
732 * Compares the symversion= attribute attached to a component in the
733 * schematic with the symversion= attribute inherited from the symbol.
736 check_symversion (GschemMessagesDockable
*messages_dockable
,
737 const gchar
*filename
, const char *refdes
, OBJECT
*object
)
740 char *outside
= NULL
;
741 double inside_value
= -1.0;
742 double outside_value
= -1.0;
743 char *err_check
= NULL
;
744 int inside_present
= FALSE
;
745 int outside_present
= FALSE
;
746 double inside_major
, inside_minor
;
747 double outside_major
, outside_minor
;
749 g_return_if_fail (object
!= NULL
);
750 g_return_if_fail ((object
->type
== OBJ_COMPLEX
||
751 object
->type
== OBJ_PLACEHOLDER
));
752 g_return_if_fail (object
->complex != NULL
);
754 /* first look on the inside for the symversion= attribute */
755 inside
= o_attrib_search_inherited_attribs_by_name (object
, "symversion", 0);
757 /* now look for the symversion= attached to object */
758 outside
= o_attrib_search_attached_attribs_by_name (object
, "symversion", 0);
762 inside_value
= strtod(inside
, &err_check
);
763 if (inside_value
== 0 && inside
== err_check
)
765 add_message (messages_dockable
,
766 type_symversion_error
, severity_warning
,
767 filename
, refdes
, object
,
768 _("This is an error in the symbol and should be fixed by "
769 "the library author."),
770 _("Symbol version parse error: could not parse attribute "
771 "\"symversion=%s\" in symbol file \"%s\""),
772 inside
, object
->complex_basename
);
775 inside_present
= TRUE
;
777 inside_present
= FALSE
; /* attribute not inside */
782 outside_value
= strtod(outside
, &err_check
);
783 if (outside_value
== 0 && outside
== err_check
)
785 add_message (messages_dockable
,
786 type_symversion_error
, severity_warning
,
787 filename
, refdes
, object
, NULL
,
788 _("Symbol version parse error: could not parse attribute "
789 "\"symversion=%s\" attached to symbol \"%s\""),
790 outside
, object
->complex_basename
);
793 outside_present
= TRUE
;
795 outside_present
= FALSE
; /* attribute not outside */
799 printf("%s:\n\tinside: %.1f outside: %.1f\n\n", object
->name
,
800 inside_value
, outside_value
);
803 /* symversion= is not present anywhere */
804 if (!inside_present
&& !outside_present
)
806 /* symbol is legacy and versioned okay */
810 /* No symversion inside, but a version is outside, this is a weird case */
811 if (!inside_present
&& outside_present
)
813 add_message (messages_dockable
,
814 type_symversion_error
, severity_warning
,
815 filename
, refdes
, object
, NULL
,
816 _("Symbol version oddity: "
817 "symversion=%s attached to instantiated symbol, "
818 "but no symversion= attribute inside symbol file \"%s\""),
819 outside
, object
->complex_basename
);
823 /* inside & not outside is a valid case, means symbol in library is newer */
824 /* also if inside_value is greater than outside_value, then symbol in */
825 /* library is newer */
826 if ((inside_present
&& !outside_present
) ||
827 ((inside_present
&& outside_present
) && (inside_value
> outside_value
)))
829 /* break up the version values into major.minor numbers */
830 inside_major
= floor(inside_value
);
831 inside_minor
= inside_value
- inside_major
;
835 outside_major
= floor(outside_value
);
836 outside_minor
= outside_value
- outside_major
;
838 /* symversion was not attached to the symbol, set all to zero */
845 printf("i: %f %f %f\n", inside_value
, inside_major
, inside_minor
);
846 printf("o: %f %f %f\n", outside_value
, outside_major
, outside_minor
);
849 const char *tooltip
= _(
850 "The symbol has changed in the library, and its author has updated the "
851 "symversion= attribute in order to make you aware of this fact.\n\n"
852 "<i>Major</i> version changes usually indicate that things like pin "
853 "endpoints have changed which need some manual fixing of the schematic.\n"
854 "<i>Minor</i> version changes should be reviewed but don't usually "
855 "necessitate fixing.\n\n"
856 "Once you have verified that your schematic works correctly with the new "
857 "version of the symbol, you can update the component's symversion= attribute "
858 "to match the library version (or right-click and select \"Confirm Symbol "
859 "Version\") in order to hide this message.");
861 if (inside_major
> outside_major
)
863 add_message (messages_dockable
,
864 type_symversion
, severity_warning
,
865 filename
, refdes
, object
, tooltip
,
866 _("Major version change: symbol \"%s\" in library (%s) "
867 "is newer than instantiated symbol (%s)"),
868 object
->complex_basename
,
869 inside
!= NULL
? inside
: _("no version"),
870 outside
!= NULL
? outside
: _("no version"));
872 /* don't bother checking minor changes if there are major ones */
876 if (inside_minor
> outside_minor
)
878 add_message (messages_dockable
,
879 type_symversion
, severity_message
,
880 filename
, refdes
, object
, tooltip
,
881 _("Minor version change: symbol \"%s\" in library (%s) "
882 "is newer than instantiated symbol (%s)"),
883 object
->complex_basename
,
884 inside
!= NULL
? inside
: _("no version"),
885 outside
!= NULL
? outside
: _("no version"));
888 add_message (messages_dockable
,
889 type_symversion
, severity_warning
,
890 filename
, refdes
, object
, tooltip
,
891 _("Symbol version mismatch: symbol \"%s\" in library (%s) "
892 "is newer than instantiated symbol (%s)"),
893 object
->complex_basename
,
894 inside
!= NULL
? inside
: _("no version"),
895 outside
!= NULL
? outside
: _("no version"));
901 /* outside value is greater than inside value, this is weird case */
902 if ((inside_present
&& outside_present
) && (outside_value
> inside_value
))
904 add_message (messages_dockable
,
905 type_symversion
, severity_warning
, filename
, refdes
, object
,
906 _("This probably means you are trying to load a schematic "
907 "with an older (and probably incompatible) version of the "
909 _("Symbol version oddity: instantiated symbol (%s) "
910 "is newer than symbol \"%s\" in library (%s)"),
911 object
->complex_basename
,
912 inside
!= NULL
? inside
: _("no version"),
913 outside
!= NULL
? outside
: _("no version"));
917 /* if inside_value and outside_value match, then symbol versions are okay */
926 check_symbol (GschemMessagesDockable
*messages_dockable
,
927 const gchar
*filename
, OBJECT
*obj
)
933 g_return_if_fail (obj
!= NULL
);
934 g_return_if_fail (obj
->type
== OBJ_COMPLEX
|| obj
->type
== OBJ_PLACEHOLDER
);
936 if (obj
->complex_embedded
)
939 symlist
= s_clib_search (obj
->complex_basename
, CLIB_EXACT
);
940 len
= g_list_length (symlist
);
941 g_list_free (symlist
);
943 refdes
= o_attrib_search_object_attribs_by_name (obj
, "refdes", 0);
945 refdes
= g_strdup (_("(unknown)"));
948 add_message (messages_dockable
,
949 type_other
, severity_error
, filename
, refdes
, obj
, NULL
,
950 _("symbol \"%s\" not found"),
951 obj
->complex_basename
);
953 add_message (messages_dockable
,
954 type_other
, severity_warning
, filename
, refdes
, obj
, NULL
,
955 _("There are %d symbols with name \"%s\" in the library."),
956 len
, obj
->complex_basename
);
957 add_message (messages_dockable
,
958 type_other
, severity_supplemental_text
, "", "", obj
, NULL
,
959 _("Picking one at random--this may not be what you want..."));
963 check_symversion (messages_dockable
, filename
, refdes
, obj
);
970 has_severity (GschemMessagesDockable
*messages_dockable
,
971 GschemMessageSeverity severity
)
973 GtkTreeModel
*tree_model
= GTK_TREE_MODEL (messages_dockable
->store
);
976 if (gtk_tree_model_get_iter_first (tree_model
, &iter
))
979 gtk_tree_model_get (tree_model
, &iter
,
984 } while (gtk_tree_model_iter_next (tree_model
, &iter
));
991 update_messages (GschemMessagesDockable
*messages_dockable
)
993 GschemToplevel
*w_current
= GSCHEM_DOCKABLE (messages_dockable
)->w_current
;
994 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
995 PAGE
*page
= toplevel
->page_current
;
996 g_return_if_fail (page
!= NULL
);
998 gchar
*basename
= g_path_get_basename (page
->page_filename
);
1000 clear_weak_refs (messages_dockable
);
1001 gtk_list_store_clear (messages_dockable
->store
);
1003 check_floating_symversion (messages_dockable
, basename
);
1005 for (const GList
*l
= s_page_objects (page
); l
!= NULL
; l
= l
->next
) {
1006 OBJECT
*obj
= (OBJECT
*) l
->data
;
1007 if (obj
->type
== OBJ_COMPLEX
|| obj
->type
== OBJ_PLACEHOLDER
)
1008 check_symbol (messages_dockable
, basename
, obj
);
1013 /* If there were warnings, make sure the messages are visible.
1014 Try not to focus the dockable, though, as this might confuse users. */
1015 if (has_severity (messages_dockable
, severity_warning
)) {
1016 GtkWidget
*widget
, *notebook
;
1017 switch (gschem_dockable_get_state (w_current
->messages_dockable
)) {
1018 case GSCHEM_DOCKABLE_STATE_DOCKED_LEFT
:
1019 case GSCHEM_DOCKABLE_STATE_DOCKED_BOTTOM
:
1020 case GSCHEM_DOCKABLE_STATE_DOCKED_RIGHT
:
1021 widget
= w_current
->messages_dockable
->widget
;
1022 notebook
= gtk_widget_get_parent (widget
);
1023 if (GTK_IS_NOTEBOOK (notebook
)) {
1024 gint i
= gtk_notebook_page_num (GTK_NOTEBOOK (notebook
), widget
);
1026 gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook
), i
);
1029 case GSCHEM_DOCKABLE_STATE_WINDOW
:
1033 gschem_dockable_present (w_current
->messages_dockable
);
1040 x_messages_page_changed (GschemToplevel
*w_current
)
1042 GschemMessagesDockable
*messages_dockable
=
1043 GSCHEM_MESSAGES_DOCKABLE (w_current
->messages_dockable
);
1045 update_messages (messages_dockable
);
1050 x_messages_update (GschemToplevel
*w_current
)
1052 GschemMessagesDockable
*messages_dockable
=
1053 GSCHEM_MESSAGES_DOCKABLE (w_current
->messages_dockable
);
1055 update_messages (messages_dockable
);