1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 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 x_hierarchy.c
22 * \brief Hierarchy navigation functions.
30 load_source (GschemToplevel
*w_current
, const gchar
*filename
,
33 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
38 g_return_val_if_fail (toplevel
!= NULL
, NULL
);
39 g_return_val_if_fail (toplevel
->page_current
!= NULL
, NULL
);
40 g_return_val_if_fail (filename
!= NULL
, NULL
);
42 s_log_message (_("Searching for source [%s]\n"), filename
);
43 source_path
= s_slib_search_single (filename
);
45 if (source_path
!= NULL
) {
46 page
= x_lowlevel_open_page (w_current
, source_path
);
50 /* Some error occurred while loading the schematic. In this case,
51 x_lowlevel_open_page already displayed an error message. */
54 /* check whether this page is in the parents list */
55 forbear
= toplevel
->page_current
;
56 while (forbear
!= NULL
&& forbear
->pid
!= page
->pid
&& forbear
->up
>= 0)
57 forbear
= s_page_search_by_page_id (toplevel
->pages
, forbear
->up
);
59 if (forbear
!= NULL
&& forbear
->pid
== page
->pid
) {
60 s_log_message (_("Failed to descend into '%s': "
61 "Hierarchy contains a circular dependency.\n"),
65 gtk_message_dialog_new (GTK_WINDOW (w_current
->main_window
),
66 GTK_DIALOG_MODAL
, GTK_MESSAGE_ERROR
,
68 _("Failed to descend into \"%s\"."), filename
);
69 g_object_set (G_OBJECT (dialog
), "secondary-text",
70 _("The hierarchy contains a circular dependency."), NULL
);
71 gtk_window_set_title (GTK_WINDOW (dialog
), _("gschem"));
72 gtk_dialog_run (GTK_DIALOG (dialog
));
73 gtk_widget_destroy (dialog
);
77 /* Has a new page with this name already been created? */
78 for (const GList
*l
= geda_list_get_glist(toplevel
->pages
);
79 l
!= NULL
; l
= l
->next
) {
80 PAGE
*page
= (PAGE
*) l
->data
;
81 const gchar
*sep
= strrchr (page
->page_filename
, '/');
82 /* FIXME: This may not be correct on platforms with
83 case-insensitive filesystems. */
84 if (page
->up
== toplevel
->page_current
->pid
&& !page
->is_untitled
&&
85 sep
!= NULL
&& strcmp (sep
+ 1, filename
) == 0)
86 /* page control has been set before, just return page */
90 if (!x_dialog_confirm_create (
91 GTK_WINDOW (w_current
->main_window
),
92 _("The subschematic \"%s\" doesn't appear to exist.\n\n"
93 "Do you want to create a new schematic with this name?"),
97 page
= x_fileselect_create (w_current
, s_slib_getdir (0), filename
);
102 if (*page_control
== 0) {
103 page_control_counter
++;
104 *page_control
= page_control_counter
;
106 page
->page_control
= *page_control
;
107 page
->up
= toplevel
->page_current
->pid
;
114 get_source_filenames (GschemToplevel
*w_current
, OBJECT
*object
)
118 int looking_inside
= FALSE
;
120 char *current_filename
= NULL
;
121 GSList
*filenames
= NULL
;
123 /* only allow going into symbols */
124 if (object
->type
!= OBJ_COMPLEX
)
127 attrib
= o_attrib_search_attached_attribs_by_name (object
, "source", count
);
129 /* if above is null, then look inside symbol */
130 if (attrib
== NULL
) {
132 o_attrib_search_inherited_attribs_by_name (object
, "source", count
);
133 looking_inside
= TRUE
;
136 while (attrib
!= NULL
) {
137 /* look for source=filename,filename, ... */
139 current_filename
= u_basic_breakup_string (attrib
, ',', pcount
);
141 /* loop over all filenames */
142 while (current_filename
!= NULL
) {
143 filenames
= g_slist_prepend (filenames
, current_filename
);
145 current_filename
= u_basic_breakup_string (attrib
, ',', pcount
);
149 g_free (current_filename
);
152 attrib
= looking_inside
?
153 o_attrib_search_inherited_attribs_by_name (object
, "source", count
) :
154 o_attrib_search_attached_attribs_by_name (object
, "source", count
);
157 return g_slist_reverse (filenames
);
162 x_hierarchy_down_schematic (GschemToplevel
*w_current
, OBJECT
*object
)
164 GSList
*filenames
= get_source_filenames (w_current
, object
);
165 int page_control
= 0;
166 PAGE
*first_page
= NULL
;
168 for (const GSList
*l
= filenames
; l
!= NULL
; l
= l
->next
) {
169 PAGE
*page
= load_source (w_current
, (gchar
*) l
->data
, &page_control
);
171 if (first_page
== NULL
)
175 g_slist_free_full (filenames
, g_free
);
177 if (first_page
== NULL
)
180 x_window_set_current_page (w_current
, first_page
);
185 /*! \bug may cause problems with non-directory symbols */
187 x_hierarchy_down_symbol (GschemToplevel
*w_current
, OBJECT
*object
)
189 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
190 const CLibSymbol
*sym
;
194 /* only allow going into symbols */
195 if (object
->type
!= OBJ_COMPLEX
)
198 if (object
->complex_embedded
) {
199 s_log_message (_("Cannot descend into embedded symbol!\n"));
203 s_log_message (_("Searching for symbol [%s]\n"), object
->complex_basename
);
204 sym
= s_clib_get_symbol_by_name (object
->complex_basename
);
208 filename
= s_clib_symbol_get_filename (sym
);
209 if (filename
== NULL
) {
210 s_log_message (_("Symbol is not a real file. Symbol cannot be loaded.\n"));
214 page
= x_lowlevel_open_page (w_current
, filename
);
218 /* Some error occurred while loading the symbol. In this case,
219 x_lowlevel_open_page already displayed an error message. */
222 page_control_counter
++;
223 page
->page_control
= page_control_counter
;
224 /* change link to parent page even if the page existed since we can
225 come here from any parent and must come back to the same page */
226 page
->up
= toplevel
->page_current
->pid
;
228 x_window_set_current_page (w_current
, page
);
234 x_hierarchy_up (GschemToplevel
*w_current
)
236 TOPLEVEL
*toplevel
= gschem_toplevel_get_toplevel (w_current
);
237 PAGE
*page
= toplevel
->page_current
;
239 g_return_val_if_fail (page
!= NULL
, FALSE
);
242 s_log_message (_("There are no schematics above the current one!\n"));
246 parent
= s_page_search_by_page_id (toplevel
->pages
, page
->up
);
247 if (parent
== NULL
) {
248 s_log_message (_("Cannot find any schematics above the current one!\n"));
252 if (!page
->is_untitled
) {
253 gchar
*lowercase_filename
= g_ascii_strdown (page
->page_filename
, -1);
254 gboolean is_symbol
= g_str_has_suffix (lowercase_filename
, ".sym");
255 g_free (lowercase_filename
);
257 if (is_symbol
&& !x_highlevel_close_page (w_current
, page
))
261 x_window_set_current_page (w_current
, parent
);