/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void s_hierarchy_down_symbol (TOPLEVEL *toplevel, const CLibSymbol *symbol, PAGE *parent) { PAGE *page; gchar *filename; filename = s_clib_symbol_get_filename (symbol); page = s_page_search (toplevel, filename); if (page) { /* change link to parent page since we * can come here from any parent and must * come back to the same page */ page->up = parent->pid; s_page_goto (toplevel, page); g_free (filename); return; } page = s_page_new (toplevel, filename); g_free(filename); s_page_goto (toplevel, page); f_open(toplevel, page, s_page_get_filename (page), NULL); page->up = parent->pid; page_control_counter++; page->page_control = page_control_counter; }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void s_hierarchy_down_symbol (TOPLEVEL *toplevel, const CLibSymbol *symbol, PAGE *parent) { PAGE *page; gchar *filename; filename = s_clib_symbol_get_filename (symbol); page = s_page_search (toplevel, filename); if (page) { s_page_goto (toplevel, page); g_free (filename); return; } page = s_page_new (toplevel, filename); g_free(filename); s_page_goto (toplevel, page); f_open(toplevel, page, page->page_filename, NULL); page->up = parent->pid; page_control_counter++; page->page_control = page_control_counter; }
/*! \brief Load a subpage * * \par Function Description * Implements s_hierarchy_down_schematic(), but without changing variables * related to the UI. * * - Ensures a duplicate page is not loaded * - Does not change the current page * - Does not modify the most recent "up" page * * \param [in] page * \param [in] filename * \param [out] error * \return A pointer to the subpage or NULL if an error occured. */ PAGE* s_hierarchy_load_subpage (PAGE *page, const char *filename, GError **error) { char *string; PAGE *subpage = NULL; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (page != NULL, NULL); SCM string_s = scm_call_1 (scm_c_public_ref ("geda library", "get-source-library-file"), scm_from_utf8_string (filename)); if (scm_is_false (string_s)) { g_set_error (error, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); } else { string = scm_to_utf8_string (string_s); gchar *normalized = f_normalize_filename (string, error); subpage = s_page_search (page->toplevel, normalized); if (subpage == NULL) { int success; subpage = s_page_new (page->toplevel, string); success = f_open (page->toplevel, subpage, s_page_get_filename (subpage), error); if (success) { subpage->page_control = ++page_control_counter; } else { s_page_delete (page->toplevel, subpage); subpage = NULL; } } g_free (normalized); } return subpage; }
/*! \brief Load a subpage * * \par Function Description * Implements s_hierarchy_down_schematic(), but without changing variables * related to the UI. * * - Ensures a duplicate page is not loaded * - Does not change the current page * - Does not modify the most recent "up" page * * \param [in] page * \param [in] filename * \param [out] error * \return A pointer to the subpage or NULL if an error occured. */ PAGE* s_hierarchy_load_subpage (PAGE *page, const char *filename, GError **error) { char *string; PAGE *subpage = NULL; g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (page != NULL, NULL); string = s_slib_search_single (filename); if (string == NULL) { g_set_error (error, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); } else { gchar *normalized = f_normalize_filename (string, error); subpage = s_page_search (page->toplevel, normalized); if (subpage == NULL) { int success; subpage = s_page_new (page->toplevel, string); success = f_open (page->toplevel, subpage, subpage->page_filename, error); if (success) { subpage->page_control = ++page_control_counter; } else { s_page_delete (page->toplevel, subpage); subpage = NULL; } } g_free (normalized); } return subpage; }
/*! \brief Opens a new page from a file. * \par Function Description * This function opens the file whose name is <B>filename</B> in a * new PAGE of <B>toplevel</B>. * * If there is no page for <B>filename</B> in <B>toplevel</B>'s list * of pages, it creates a new PAGE, loads the file in it and returns * a pointer on the new page. Otherwise it returns a pointer on the * existing page. * * If the filename passed is NULL, this function creates an empty, * untitled page. The name of the untitled page is build from * configuration data ('untitled-name') and a counter for uniqueness. * * The opened page becomes the current page of <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] filename The name of the file to open or NULL for a blank page. * \returns A pointer on the new page. * * \bug This code should check to make sure any untitled filename * does not conflict with a file on disk. */ PAGE* x_window_open_page (GschemToplevel *w_current, const gchar *filename) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); PAGE *page; gchar *fn; g_return_val_if_fail (toplevel != NULL, NULL); /* Generate untitled filename if none was specified */ if (filename == NULL) { gchar *cwd, *tmp, *untitled_name; EdaConfig *cfg; cwd = g_get_current_dir (); cfg = eda_config_get_context_for_path (cwd); untitled_name = eda_config_get_string (cfg, "gschem", "default-filename", NULL); tmp = g_strdup_printf ("%s_%d.sch", untitled_name, ++w_current->num_untitled); fn = g_build_filename (cwd, tmp, NULL); g_free (untitled_name); g_free(cwd); g_free(tmp); } else { fn = g_strdup (filename); } /* Return existing page if it is already loaded */ page = s_page_search (toplevel, fn); if ( page != NULL ) { g_free(fn); return page; } page = s_page_new (toplevel, fn); s_page_goto (toplevel, page); gschem_toplevel_page_changed (w_current); /* Load from file if necessary, otherwise just print a message */ if (filename != NULL) { GError *err = NULL; if (!quiet_mode) s_log_message (_("Loading schematic [%s]\n"), fn); if (!f_open (toplevel, page, (gchar *) fn, &err)) { GtkWidget *dialog; g_warning ("%s\n", err->message); dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("<b>An error occurred while loading the requested file.</b>\n\nLoading from '%s' failed: %s. The gschem log may contain more information."), fn, err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (err); } else { gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL)); } } else { if (!quiet_mode) s_log_message (_("New file [%s]\n"), toplevel->page_current->page_filename); g_run_hook_page (w_current, "%new-page-hook", toplevel->page_current); } gschem_page_view_set_page (page_view, toplevel->page_current); o_undo_savestate (w_current, toplevel->page_current, UNDO_ALL); /* This line is generally un-needed, however if some code * wants to open a page, yet not bring it to the front, it is * needed needed to add it into the page manager. Otherwise, * it will get done in x_window_set_current_page(...) */ x_pagesel_update (w_current); /* ??? */ g_free (fn); return page; }
/*! * \brief Search for schematic associated source files and load them. * \par Function Description * This function searches the associated source file refered by the * <B>filename</B> and loads it. If the <B>flag</B> is set to * <B>HIERARCHY_NORMAL_LOAD</B> and the page is already in the list of * pages it will return the <B>pid</B> of that page. * If the <B>flag</B> is set to <B>HIERARCHY_FORCE_LOAD</B> then this * function will load the page again with a new page id. The second case * is mainly used by gnetlist where pushed down schematics MUST be unique. * * \param [in] toplevel The TOPLEVEL object. * \param [in] filename Schematic file name. * \param [in] parent The parent page of the schematic. * \param [in] page_control * \param [in] flag sets whether to force load * \param [out] err Location to return a GError on failure. * \return The page loaded, or NULL if failed. * * \note * This function finds the associated source files and * loads all up * It only works for schematic files though * this is basically push * flag can either be HIERARCHY_NORMAL_LOAD or HIERARCHY_FORCE_LOAD * flag is mainly used by gnetlist where pushed down schematics MUST be unique */ PAGE * s_hierarchy_down_schematic_single(TOPLEVEL *toplevel, const gchar *filename, PAGE *parent, int page_control, int flag, GError **err) { gchar *string; PAGE *found = NULL; PAGE *forbear; g_return_val_if_fail ((toplevel != NULL), NULL); g_return_val_if_fail ((filename != NULL), NULL); g_return_val_if_fail ((parent != NULL), NULL); SCM string_s = scm_call_1 (scm_c_public_ref ("geda library", "get-source-library-file"), scm_from_utf8_string (filename)); if (scm_is_false (string_s)) { g_set_error (err, EDA_ERROR, EDA_ERROR_NOLIB, _("Schematic not found in source library.")); return NULL; } string = scm_to_utf8_string (string_s); switch (flag) { case HIERARCHY_NORMAL_LOAD: { gchar *filename = f_normalize_filename (string, NULL); found = s_page_search (toplevel, filename); g_free (filename); if (found) { /* check whether this page is in the parents list */ for (forbear = parent; forbear != NULL && found->pid != forbear->pid && forbear->up >= 0; forbear = s_page_search_by_page_id (toplevel->pages, forbear->up)) ; /* void */ if (forbear != NULL && found->pid == forbear->pid) { g_set_error (err, EDA_ERROR, EDA_ERROR_LOOP, _("Hierarchy contains a circular dependency.")); return NULL; /* error signal */ } s_page_goto (toplevel, found); if (page_control != 0) { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; } found = s_page_new (toplevel, string); f_open (toplevel, found, s_page_get_filename (found), NULL); } break; case HIERARCHY_FORCE_LOAD: { found = s_page_new (toplevel, string); f_open (toplevel, found, s_page_get_filename (found), NULL); } break; default: g_return_val_if_reached (NULL); } if (page_control == 0) { page_control_counter++; found->page_control = page_control_counter; } else { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; }
/*! \brief Opens a new page from a file. * \par Function Description * This function opens the file whose name is <B>filename</B> in a * new PAGE of <B>toplevel</B>. * * If there is no page for <B>filename</B> in <B>toplevel</B>'s list * of pages, it creates a new PAGE, loads the file in it and returns * a pointer on the new page. Otherwise it returns a pointer on the * existing page. * * If the filename passed is NULL, this function creates an empty, * untitled page. The name of the untitled page is build from * configuration data ('untitled-name') and a counter for uniqueness. * * The opened page becomes the current page of <B>toplevel</B>. * * \param [in] w_current The toplevel environment. * \param [in] filename The name of the file to open or NULL for a blank page. * \returns A pointer on the new page. * * \bug This code should check to make sure any untitled filename * does not conflict with a file on disk. */ PAGE* x_window_open_page (GSCHEM_TOPLEVEL *w_current, const gchar *filename) { TOPLEVEL *toplevel = w_current->toplevel; PAGE *old_current, *page; gchar *fn; g_return_val_if_fail (toplevel != NULL, NULL); /* Generate untitled filename if none was specified */ if (filename == NULL) { gchar *cwd, *tmp; cwd = g_get_current_dir (); tmp = g_strdup_printf ("%s_%d.sch", toplevel->untitled_name, ++w_current->num_untitled); fn = g_build_filename (cwd, tmp, NULL); g_free(cwd); g_free(tmp); } else { fn = g_strdup (filename); } /* Return existing page if it is already loaded */ page = s_page_search (toplevel, fn); if ( page != NULL ) { g_free(fn); return page; } old_current = toplevel->page_current; page = s_page_new (toplevel, fn); s_page_goto (toplevel, page); /* Load from file if necessary, otherwise just print a message */ if (filename != NULL) { GError *err = NULL; if (!quiet_mode) s_log_message (_("Loading schematic [%s]\n"), fn); if (!f_open (toplevel, page, (gchar *) fn, &err)) { GtkWidget *dialog; g_warning ("%s\n", err->message); dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", err->message); gtk_window_set_title (GTK_WINDOW (dialog), _("Failed to load file")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (err); } else { gtk_recent_manager_add_item (recent_manager, g_filename_to_uri(fn, NULL, NULL)); } } else { if (!quiet_mode) s_log_message (_("New file [%s]\n"), toplevel->page_current->page_filename); } if (scm_is_false (scm_hook_empty_p (new_page_hook))) scm_run_hook (new_page_hook, scm_cons (g_make_page_smob (toplevel, page), SCM_EOL)); a_zoom_extents (w_current, s_page_objects (toplevel->page_current), A_PAN_DONT_REDRAW); o_undo_savestate (w_current, UNDO_ALL); if ( old_current != NULL ) s_page_goto (toplevel, old_current); /* This line is generally un-needed, however if some code * wants to open a page, yet not bring it to the front, it is * needed needed to add it into the page manager. Otherwise, * it will get done in x_window_set_current_page(...) */ x_pagesel_update (w_current); /* ??? */ g_free (fn); return page; }
/*! \todo Finish function documentation!!! * \brief Search for schematic associated source files and load them. * \par Function Description * This function searches the associated source file refered by the * <B>filename</B> and loads it. If the <B>flag</B> is set to * <B>HIERARCHY_NORMAL_LOAD</B> and the page is allready in the list of * pages it will return the <B>pid</B> of that page. * If the <B>flag</B> is set to <B>HIERARCHY_FORCE_LOAD</B> then this * function will load the page again with a new page id. The second case * is mainly used by gnetlist where pushed down schematics MUST be unique. * * \param [in] toplevel The TOPLEVEL object. * \param [in] filename Schematic file name. * \param [in] parent The parent page of the schematic. * \param [in] page_control * \param [in] flag * \return The page loaded, or NULL if failed. * * \note * This function goes and finds the associated source files and * loads all up * It only works for schematic files though * this is basically push * flag can either be HIERARCHY_NORMAL_LOAD or HIERARCHY_FORCE_LOAD * flag is mainly used by gnetlist where pushed down schematics MUST be unique */ PAGE * s_hierarchy_down_schematic_single(TOPLEVEL *toplevel, const gchar *filename, PAGE *parent, int page_control, int flag) { gchar *string; PAGE *found = NULL; PAGE *forbear; g_return_val_if_fail ((toplevel != NULL), NULL); g_return_val_if_fail ((filename != NULL), NULL); g_return_val_if_fail ((parent != NULL), NULL); string = s_slib_search_single(filename); if (string == NULL) { return NULL; } switch (flag) { case HIERARCHY_NORMAL_LOAD: { gchar *filename = f_normalize_filename (string, NULL); found = s_page_search (toplevel, filename); g_free (filename); if (found) { /* check whether this page is in the parents list */ for (forbear = parent; forbear != NULL && found->pid != forbear->pid && forbear->up >= 0; forbear = s_page_search_by_page_id (toplevel->pages, forbear->up)) ; /* void */ if (found->pid == forbear->pid) { s_log_message(_("hierarchy loop detected while visiting page:\n" " \"%s\"\n"), found->page_filename); return NULL; /* error signal */ } s_page_goto (toplevel, found); if (page_control != 0) { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; } found = s_page_new (toplevel, string); f_open (toplevel, found, found->page_filename, NULL); } break; case HIERARCHY_FORCE_LOAD: { found = s_page_new (toplevel, string); f_open (toplevel, found, found->page_filename, NULL); } break; } if (page_control == 0) { page_control_counter++; found->page_control = page_control_counter; } else { found->page_control = page_control; } found->up = parent->pid; g_free (string); return found; }