Example #1
0
/*! \brief consolidate all net objects
 *  \par Function Description
 *  This function consolidates all net objects in a page until no more
 *  consolidations are possible.
 *
 *  \param toplevel  The TOPLEVEL object.
 *  \param page      The PAGE to consolidate nets in.
 */
void o_net_consolidate(TOPLEVEL *toplevel, PAGE *page)
{
  OBJECT *o_current;
  const GList *iter;
  int status = 0;

  g_return_if_fail (toplevel != NULL);
  g_return_if_fail (page != NULL);

  iter = s_page_objects (page);

  while (iter != NULL) {
    o_current = (OBJECT *)iter->data;

    if (o_current->type == OBJ_NET) {
      status = o_net_consolidate_segments(toplevel, o_current);
    }

    if (status == -1) {
      iter = s_page_objects (page);
      status = 0;
    } else {
      iter = g_list_next (iter);
    }
  }
}
Example #2
0
/*! \brief Updates the preview widget.
 *  \par Function Description
 *  This function update the preview: if the preview is active and a
 *  filename has been given, it opens the file and display
 *  it. Otherwise it display a blank page.
 *
 *  \param [in] preview The preview widget.
 */
static void
preview_update (Preview *preview)
{
  GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
  TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
  int left, top, right, bottom;
  int width, height;

  if (preview_toplevel->page_current == NULL) {
    return;
  }
  
  /* delete old preview, create new page */
  /* it would be better to just resets current page - Fix me */
  s_page_delete (preview_toplevel, preview_toplevel->page_current);
  s_page_goto (preview_toplevel, s_page_new (preview_toplevel, "preview"));
  
  if (preview->active) {
    g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
    if (preview->filename != NULL) {
      /* open up file in current page */
      f_open_flags (preview_toplevel, preview_toplevel->page_current,
                    preview->filename,
                    F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
      /* test value returned by f_open... - Fix me */
      /* we should display something if there an error occured - Fix me */
    }
    if (preview->buffer != NULL) {

      /* Load the data buffer */
      s_page_append_list (preview_toplevel, preview_toplevel->page_current,
                          o_read_buffer (preview_toplevel,
                                         NULL, preview->buffer, -1,
                                         _("Preview Buffer")));
    }
  }

  if (world_get_object_glist_bounds (preview_toplevel,
                                     s_page_objects (preview_toplevel->page_current),
                                     &left, &top,
                                     &right, &bottom)) {
    /* Clamp the canvas size to the extents of the page being previewed */
    width = right - left;
    height = bottom - top;
    preview_toplevel->init_left   = left  - ((double)width * OVER_ZOOM_FACTOR);
    preview_toplevel->init_right  = right + ((double)width * OVER_ZOOM_FACTOR);
    preview_toplevel->init_top    = top    - ((double)height * OVER_ZOOM_FACTOR);
    preview_toplevel->init_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
  }

  /* display current page (possibly empty) */
  a_zoom_extents (preview_w_current,
                  s_page_objects (preview_toplevel->page_current),
                  A_PAN_DONT_REDRAW);
  o_invalidate_all (preview_w_current);
  
}
Example #3
0
/*! \brief Completes initialitation of the widget after realization.
 *  \par Function Description
 *  This function terminates the initialization of preview's GSCHEM_TOPLEVEL
 *  and TOPLEVEL environments after the widget has been realized.
 *
 *  It creates a preview page in the TOPLEVEL environment.
 *
 *  \param [in] widget    The preview widget.
 *  \param [in] user_data Unused user data.
 */
static void
preview_callback_realize (GtkWidget *widget,
                          gpointer user_data)
{
  Preview *preview = PREVIEW (widget);
  GSCHEM_TOPLEVEL *preview_w_current = preview->preview_w_current;
  TOPLEVEL *preview_toplevel = preview_w_current->toplevel;
  PAGE *preview_page;

  preview_w_current->window = preview_w_current->drawing_area->window;
  gtk_widget_grab_focus (preview_w_current->drawing_area);

  preview_toplevel->width  = preview_w_current->drawing_area->allocation.width;
  preview_toplevel->height = preview_w_current->drawing_area->allocation.height;
  preview_w_current->win_width  = preview_toplevel->width;
  preview_w_current->win_height = preview_toplevel->height;

  preview_w_current->drawable = preview_w_current->window;

  x_window_setup_gc (preview_w_current);

  preview_page = s_page_new (preview_toplevel, "unknown");
  s_page_goto (preview_toplevel, preview_page);

  a_zoom_extents(preview_w_current,
                 s_page_objects (preview_page),
                 A_PAN_DONT_REDRAW);

  o_invalidate_all (preview_w_current);

}
Example #4
0
/* otherwise unembed all components in all pages */
void
s_util_embed(TOPLEVEL *pr_current, int embed_mode)
{
  GList *p_iter, *o_iter;

  for (p_iter = geda_list_get_glist (pr_current->pages);
       p_iter != NULL;
       p_iter = g_list_next (p_iter)) {
    PAGE *p_current = p_iter->data;

    /* Cast removes const qualifier from return value of
     * s_page_objects() */
    for (o_iter = (GList *) s_page_objects (p_current);
         o_iter != NULL;
         o_iter = g_list_next (o_iter)) {

      OBJECT *o_current = o_iter->data;

      if (o_current->type == OBJ_COMPLEX ||
                o_current->type == OBJ_PICTURE) {
        if (embed_mode == TRUE) {
          o_embed(pr_current, o_current);
        } else {
          o_unembed(pr_current, o_current);
        }
      }

    }
  }
}
Example #5
0
/* Actually draws a page.  If page is NULL, uses the first open page. */
static void
export_draw_page (PAGE *page)
{
  const GList *contents;
  GList *iter;
  cairo_t *cr;

  cr = eda_renderer_get_cairo_context (renderer);

  if (page == NULL) {
    const GList *pages = geda_list_get_glist (toplevel->pages);
    g_assert (pages != NULL && pages->data != NULL);
    page = (PAGE *) pages->data;
  }

  /* Draw background */
  eda_cairo_set_source_color (cr, OUTPUT_BACKGROUND_COLOR,
                              eda_renderer_get_color_map (renderer));
  cairo_paint (cr);

  /* Draw objects & cues */
  contents = s_page_objects (page);
  for (iter = (GList *) contents; iter != NULL; iter = g_list_next (iter))
    eda_renderer_draw (renderer, (OBJECT *) iter->data);
  for (iter = (GList *) contents; iter != NULL; iter = g_list_next (iter))
    eda_renderer_draw_cues (renderer, (OBJECT *) iter->data);
}
/*! \brief get the subpages of a schematic page
 *
 *  if any subpages are not loaded, this function will load them.
 *
 *  \param [in] page the parent page
 *  \return a list of all the subpages
 */
static GList*
get_subpages (PAGE *page)
{
  const GList *object_iter;
  GList *page_list = NULL;

  g_return_val_if_fail (page != NULL, NULL);

  object_iter = s_page_objects (page);

  while (object_iter != NULL) {
    char *attrib;
    char **filenames;
    char **iter;
    OBJECT *object = (OBJECT*) object_iter->data;

    object_iter = g_list_next (object_iter);

    if (object == NULL) {
      g_warning ("NULL object encountered");
      continue;
    }

    if (object->type != OBJ_COMPLEX) {
      continue;
    }

    attrib = o_attrib_search_attached_attribs_by_name (object,
                                                       "source",
                                                       0);

    if (attrib == NULL) {
      attrib = o_attrib_search_inherited_attribs_by_name (object,
                                                          "source",
                                                          0);
    }

    if (attrib == NULL) {
      continue;
    }

    filenames = g_strsplit (attrib, ",", 0);

    if (filenames == NULL) {
      continue;
    }

    for (iter = filenames; *iter != NULL; iter++) {
      PAGE *subpage = s_hierarchy_load_subpage (page, *iter, NULL);

      if (subpage != NULL) {
        page_list = g_list_prepend (page_list, subpage);
      }
    }

    g_strfreev (filenames);
  }

  return g_list_reverse (page_list);
}
/*! \brief Find all text objects that match a pattern
 *
 *  \param pages the list of pages to search
 *  \param text the pattern to match
 *  \return a list of objects that match the given pattern
 */
static GSList*
find_objects_using_pattern (GSList *pages, const char *text)
{
  GSList *object_list = NULL;
  GSList *page_iter = pages;
  GPatternSpec *pattern;

  g_return_val_if_fail (text != NULL, NULL);

  pattern = g_pattern_spec_new (text);

  while (page_iter != NULL) {
    const GList *object_iter;
    PAGE *page = (PAGE*) page_iter->data;

    page_iter = g_slist_next (page_iter);

    if (page == NULL) {
      g_warning ("NULL page encountered");
      continue;
    }

    object_iter = s_page_objects (page);

    while (object_iter != NULL) {
      OBJECT *object = (OBJECT*) object_iter->data;
      const char *str;

      object_iter = g_list_next (object_iter);

      if (object == NULL) {
        g_warning ("NULL object encountered");
        continue;
      }

      if (object->type != OBJ_TEXT) {
        continue;
      }

      if (!(o_is_visible (page->toplevel, object) || page->toplevel->show_hidden_text)) {
        continue;
      }

      str = geda_text_object_get_string (object);

      if (str == NULL) {
        g_warning ("NULL string encountered");
        continue;
      }

      if (g_pattern_match_string (pattern, str)) {
        object_list = g_slist_prepend (object_list, object);
      }
    }
  }

  g_pattern_spec_free (pattern);

  return g_slist_reverse (object_list);
}
Example #8
0
/*! \brief Verify the entire design
 *
 * This function loops through all components in the
 * design looking for components which are placeholders.
 *
 *  Placeholders are inserted into the object list when
 *  no symbol file is found.  If this function finds a
 *  placeholder, it warns the user.
 *
 *  \param toplevel pointer to the toplevel object to be verified
 */
void s_toplevel_verify_design (TOPLEVEL *toplevel)
{
    GList *p_iter;
    const GList *o_iter;

    int missing_sym_flag = 0;

    for (p_iter = geda_list_get_glist (toplevel->pages);
            p_iter != NULL;
            p_iter = g_list_next (p_iter)) {
        PAGE *p_current = p_iter->data;

        for (o_iter = s_page_objects (p_current);
                o_iter != NULL;
                o_iter = g_list_next (o_iter)) {
            OBJECT *o_current = o_iter->data;

            /* --- look for object, and verify that it has a symbol file attached. ---- */
            if (o_current->type == OBJ_PLACEHOLDER) {
                missing_sym_flag = 1;  /* flag to signal that problem exists.  */
            }
        }
    }

    if (missing_sym_flag) {
        x_dialog_missing_sym();  /* dialog gives user option to quit */
    }
}
Example #9
0
void s_traverse_start(TOPLEVEL * pr_current)
{
  GList *iter;
  PAGE *p_current;

  for ( iter = geda_list_get_glist( pr_current->pages );
        iter != NULL;
        iter = g_list_next( iter ) ) {

    p_current = (PAGE *)iter->data;

    /* only traverse pages which are toplevel, ie not underneath */
    if (p_current->page_control == 0) {
      pr_current->page_current = p_current;
      s_traverse_sheet (pr_current, s_page_objects (p_current), NULL);
    }
  }

  /* now that all the sheets have been read, go through and do the */
  /* post processing work */
  s_netlist_post_process(pr_current, netlist_head);

  /* Now match the graphical netlist with the net names already assigned */
  s_netlist_name_named_nets(pr_current, netlist_head,
                            graphical_netlist_head);

  if (verbose_mode) {
    printf("\nInternal netlist representation:\n\n");
    s_netlist_print(netlist_head);
  }
}
Example #10
0
/*! \brief Get a list of symbols used.
 *  \par Function Description
 *
 *  Scan a #TOPLEVEL structure's object list looking for symbols, and
 *  return them in a list.
 *
 *  \warning The #CLibSymbol instances in the \b GList returned belong
 *  to the component library, and should be considered constants; they
 *  should not be manipulated or free()'d.  On the other hand, the \b
 *  GList returned must be freed with \b g_list_free() when no longer
 *  needed.  Note that the values returned will be invalidated by a
 *  call to s_clib_free() or s_clib_refresh().
 *
 *  \bug Only includes components which are not embedded, but they
 *  should (probably) also appear in the list.
 *
 *  \param toplevel #TOPLEVEL structure to scan.
 *  \return GList of symbols.
 */
GList *s_toplevel_get_symbols (const TOPLEVEL *toplevel)
{
  GList *result = NULL;
  GList *iter = NULL;
  OBJECT *o = NULL;
  PAGE *page;
  GList *symlist = NULL;
  CLibSymbol *sym = NULL;
  const GList *p_iter;
  const GList *o_iter;

  g_return_val_if_fail ((toplevel != NULL), NULL);

  for ( p_iter = geda_list_get_glist( toplevel->pages );
        p_iter != NULL;
        p_iter = g_list_next( p_iter )) {
    page = (PAGE *)p_iter->data;
    for (o_iter = s_page_objects (page);
         o_iter != NULL;
         o_iter = g_list_next (o_iter)) {
      o = (OBJECT *)o_iter->data;
      if (o->type != OBJ_COMPLEX) continue;
      if (o->complex_basename == NULL)  continue;

      /* Since we're not looking at embedded symbols, the first
       * component with the given name will be the one we need.
       * N.b. we don't use s_clib_get_symbol_by_name() because it's
       * spammeh. */
      symlist = s_clib_search (o->complex_basename, CLIB_EXACT);
      if (symlist == NULL) continue;
      sym = (CLibSymbol *) symlist->data;
      g_list_free (symlist);

      /* We do the list insertion by evilly comparing pointers.  This
       * is okay, because we always take the first symbol with the
       * given name, and symbol pointers don't change while this
       * function is running (we hope).  Note that this creates a
       * sorted list.*/
      for (iter = result;
           iter != NULL;
           iter = g_list_next(iter)) {
        if (iter->data == sym) {
          break; /* Already in list */
        }
        if (compare_symbol_name (iter->data, sym) > 0) {
          /* not in list yet, and gone past point where it should go */
          result = g_list_insert_before (result, iter, sym);
          break;
        }
      }
      if (iter == NULL) {
        /* not in list yet, and at end of list */
        result = g_list_append (result, sym);
      }
    }
  }

  return result;
}
Example #11
0
CPINLIST *s_traverse_component(TOPLEVEL * pr_current, OBJECT * component,
			       char *hierarchy_tag)
{
  CPINLIST *cpinlist_head = NULL;
  CPINLIST *cpins = NULL;
  NET *nets_head = NULL;
  NET *nets = NULL;
  GList *iter;

  cpinlist_head = cpins = s_cpinlist_add(NULL);
  cpins->plid = -1;

  for (iter = component->complex->prim_objs;
       iter != NULL;
       iter = g_list_next (iter)) {
    OBJECT *o_current = iter->data;

    /* Ignore objects which aren't net pins */
    if (o_current->type != OBJ_PIN ||
        o_current->pin_type != PIN_TYPE_NET)
      continue;

    /* add cpin node */
    cpins = s_cpinlist_add(cpins);
    cpins->plid = o_current->sid;
    cpins->type = o_current->pin_type;

    cpins->pin_number =
      o_attrib_search_object_attribs_by_name (o_current, "pinnumber", 0);

    cpins->pin_label =
      o_attrib_search_object_attribs_by_name (o_current, "pinlabel", 0);

    /* head nets node */
    /* is this really need */
    nets_head = nets = s_net_add(NULL);
    nets->nid = -1;

    /* This avoids us adding an unnamed net for an unconnected pin */
    if (o_current->conn_list != NULL) {
      s_traverse_net (pr_current, nets, TRUE,
		      o_current, hierarchy_tag, cpins->type);
      s_traverse_clear_all_visited (s_page_objects (pr_current->page_current));
    }

    cpins->nets = nets_head;
    /* s_net_print(nets); */
  }


  return (cpinlist_head);
}
Example #12
0
/*! \brief Return the objects in a page.
 *  \par Function Description
 *  Returns an object smob list with all the objects in the given page.
 *  \param [in] page_smob Page to look at.
 *  \return the object smob list with the objects in the page.
 *
 */
SCM g_get_objects_in_page(SCM page_smob) {

    TOPLEVEL *toplevel;
    PAGE *page;
    OBJECT *object;
    const GList *iter;
    SCM return_list=SCM_EOL;

    /* Get toplevel and the page */
    SCM_ASSERT (g_get_data_from_page_smob (page_smob, &toplevel, &page),
                page_smob, SCM_ARG1, "add-component");

    if (page && s_page_objects (page)) {
        iter = s_page_objects (page);
        while (iter != NULL) {
            object = (OBJECT *)iter->data;
            return_list = scm_cons (g_make_object_smob(toplevel, object),
                                    return_list);
            iter = g_list_next (iter);
        }
    }

    return return_list;
}
Example #13
0
static gboolean
preview_event_configure (GtkWidget         *widget,
                         GdkEventConfigure *event,
                         gpointer           user_data)
{
  gboolean retval;
  GSCHEM_TOPLEVEL *preview_w_current = PREVIEW (widget)->preview_w_current;
  PAGE     *preview_page = preview_w_current->toplevel->page_current;

  retval = x_event_configure (widget, event, preview_w_current);
  if (preview_page != NULL) {
    a_zoom_extents(preview_w_current, s_page_objects (preview_page), 0);
  }
  return retval;
}
Example #14
0
int
s_check_all(TOPLEVEL *pr_current)
{
  GList *iter;
  PAGE *p_current;
  int return_status=0;


  for ( iter = geda_list_get_glist( pr_current->pages );
        iter != NULL;
        iter = g_list_next( iter ) ) {

    p_current = (PAGE *)iter->data;

    if (s_page_objects (p_current)) {
      return_status = return_status +
        s_check_symbol (pr_current, p_current,
                        s_page_objects (p_current));
      if (!quiet_mode) s_log_message("\n");
    }
  }

  return(return_status);
}
Example #15
0
/*! \brief Export a figure-style PDF file of the current page.
 * \par Function Description
 * Exports the current page as a PDF file to \a filename.  The export
 * is carried out using a page size matching the size of the visible
 * extents of the schematic page.
 *
 * \param w_current A #GschemToplevel structure.
 * \param filename  The filename for generated PDF.
 *
 * \returns TRUE if the operation was successful.
 */
gboolean
x_print_export_pdf (GschemToplevel *w_current,
                    const gchar *filename)
{
  cairo_surface_t *surface;
  cairo_status_t cr_status;
  cairo_t *cr;
  int status, wx_min, wy_min, wx_max, wy_max;
  double width, height;

  /* First, calculate a transformation matrix for the cairo
   * context. We want to center the extents of the page in the
   * available page area. */
  status = world_get_object_glist_bounds (w_current->toplevel,
                                          s_page_objects (w_current->toplevel->page_current),
                                          &wx_min, &wy_min, &wx_max, &wy_max);
  if (status) {
    width  = (wx_max - wx_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI;
    height = (wy_max - wy_min) * DEFAULT_ADOBE_PDF_PPI / DEFAULT_GSCHEM_PPI;
  } else {
    /* Fallback size if there are no drawable objects */
    width = height = DEFAULT_PDF_SIZE;
  }

  surface = cairo_pdf_surface_create (filename, width, height);
  cr = cairo_create (surface);

  x_print_draw_page (w_current->toplevel, w_current->toplevel->page_current,
                     cr, NULL, width, height,
                     w_current->toplevel->image_color, FALSE);

  cairo_destroy (cr);
  cairo_surface_finish (surface);

  cr_status = cairo_surface_status (surface);
  if (cr_status != CAIRO_STATUS_SUCCESS) {
    g_warning (_("Failed to write PDF to '%1$s': %2$s\n"),
               filename,
               cairo_status_to_string (cr_status));
    return FALSE;
  }

  cairo_surface_destroy (surface);
  return TRUE;
}
Example #16
0
/*! \brief Create a default page setup for a schematic page.
 * \par Function Description
 * Creates and returns a new #GtkPageSetup for \a page, taking into
 * account the requested \a paper_size_name.  If \a paper_size_name is
 * NULL, the system default paper size is used. The \a orientation may
 * be LANDSCAPE, PORTRAIT or AUTOLAYOUT.  If \a AUTOLAYOUT is chosen,
 * the page orientation that best fits the page contents is chosen.
 *
 * \param toplevel A #TOPLEVEL structure.
 * \param page     The #PAGE to generate a page setup for.
 * \param paper_size_name   The name of the paper size to use.
 * \param orientation       The paper orientation to use.
 *
 * \returns A newly-created page setup.
 */
static GtkPageSetup *
x_print_default_page_setup (TOPLEVEL *toplevel, PAGE *page)
{
  GtkPageSetup *setup = gtk_page_setup_new ();
  GtkPaperSize *papersize;
  int status, wx_min, wy_min, wx_max, wy_max;
  EdaConfig *cfg;
  gchar *paper, *orientation;

  /* Get configuration values */
  cfg =         eda_config_get_context_for_path (s_page_get_filename (page));
  paper =       eda_config_get_string (cfg, CFG_GROUP_PRINTING,
                                       CFG_KEY_PRINTING_PAPER, NULL);
  orientation = eda_config_get_string (cfg, CFG_GROUP_PRINTING,
                                       CFG_KEY_PRINTING_ORIENTATION, NULL);

  /* If the paper size is valid, set it up with default margins. */
  papersize = gtk_paper_size_new (paper);
  if (papersize != NULL) {
    gtk_page_setup_set_paper_size_and_default_margins (setup, papersize);
  }

  if (g_strcmp0 (orientation, "landscape") == 0) {
    gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
  } else if (g_strcmp0 (orientation, "portrait") == 0) {
    gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT);
  } else if (orientation == NULL
             || g_strcmp0 (orientation, "auto") == 0) {
    /* Automatically choose the orientation that fits best */
    status = world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                            &wx_min, &wy_min, &wx_max, &wy_max);
    if (!status || (wx_max - wx_min) > (wy_max - wy_min)) {
      /* Default to landscape */
      gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_LANDSCAPE);
    } else {
      gtk_page_setup_set_orientation (setup, GTK_PAGE_ORIENTATION_PORTRAIT);
    }
  }

  g_free (paper);
  g_free (orientation);
  return setup;
}
Example #17
0
/* still highly temp and doesn't work right */
SCM g_get_toplevel_attribute(SCM scm_wanted_attrib)
{
  const GList *p_iter;
  PAGE *p_current;
  char *wanted_attrib;
  char *attrib_value = NULL;
  SCM scm_return_value;
  TOPLEVEL *toplevel = edascm_c_current_toplevel ();

  SCM_ASSERT(scm_is_string (scm_wanted_attrib),
             scm_wanted_attrib, SCM_ARG1, "gnetlist:get-toplevel-attribute");

  wanted_attrib = scm_to_utf8_string (scm_wanted_attrib);

  for (p_iter = geda_list_get_glist (toplevel->pages); p_iter != NULL;
       p_iter = g_list_next (p_iter)) {
    p_current = p_iter->data;

    /* only look for first occurrance of the attribute on each page */
    attrib_value =
      o_attrib_search_floating_attribs_by_name (s_page_objects (p_current),
                                                wanted_attrib, 0);

    /* Stop when we find the first one */
    if (attrib_value != NULL)
      break;
  }

  free (wanted_attrib);

  if (attrib_value != NULL) {
    scm_return_value = scm_from_utf8_string (attrib_value);
    g_free (attrib_value);
  } else {
    scm_return_value = scm_from_utf8_string ("not found");
  }

  return (scm_return_value);
}
Example #18
0
/*! \brief Search for first TOPLEVEL attribute.
 *  \par Function Description
 *  This function searches all loaded pages for the first
 *  TOPLEVEL attribute found.
 *  The caller is responsible for freeing the returned value.
 *  See #o_attrib_search_toplevel() for other comments.
 *
 *  \param [in] page_list  Page list to search through.
 *  \param [in] name       Character string name to search for.
 *  \return Character string from the found attribute, NULL otherwise.
 */
char *o_attrib_search_toplevel_all(GedaPageList *page_list, char *name)
{
  const GList *iter;
  PAGE *p_current;
  char *ret_value=NULL;

  iter = geda_list_get_glist( page_list );

  while( iter != NULL ) {
    p_current = (PAGE *)iter->data;

    /* only look for first occurrance of the attribute */
    ret_value = o_attrib_search_toplevel (s_page_objects (p_current), name, 0);

    if (ret_value != NULL) {
      return(ret_value);
    }

    iter = g_list_next( iter );
  }

  return(NULL);
}
Example #19
0
/*! \brief Do autosave on all pages that are marked.
 *  \par Function Description
 *  Looks for pages with the do_autosave_backup flag activated and
 *  autosaves them.
 *
 *  \param [in] w_current  The GSCHEM_TOPLEVEL object to search for autosave's.
 */
void o_autosave_backups(GSCHEM_TOPLEVEL *w_current)
{
  TOPLEVEL *toplevel = w_current->toplevel;
  GList *iter;
  PAGE *p_save, *p_current;
  gchar *backup_filename;
  gchar *real_filename;
  gchar *only_filename;
  gchar *dirname;
  mode_t saved_umask;
  mode_t mask;
  struct stat st;

  /* save current page */
  p_save = toplevel->page_current;

  for ( iter = geda_list_get_glist( toplevel->pages );
        iter != NULL;
        iter = g_list_next( iter ) ) {

    p_current = (PAGE *)iter->data;

    if (p_current->do_autosave_backup == 0) {
      continue;
    }
    if (p_current->ops_since_last_backup != 0) {
      /* make p_current the current page of toplevel */
      s_page_goto (toplevel, p_current);

      /* Get the real filename and file permissions */
      real_filename = follow_symlinks (p_current->page_filename, NULL);

      if (real_filename == NULL) {
        s_log_message (_("o_autosave_backups: Can't get the real filename of %s."), p_current->page_filename);
      } else {
        /* Get the directory in which the real filename lives */
        dirname = g_path_get_dirname (real_filename);
        only_filename = g_path_get_basename(real_filename);

        backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
                                          dirname, G_DIR_SEPARATOR, only_filename);

        /* If there is not an existing file with that name, compute the
         * permissions and uid/gid that we will use for the newly-created file.
         */

        if (stat (real_filename, &st) != 0) {
#if defined(HAVE_GETUID) && defined(HAVE_GETGID)
            struct stat dir_st;
            int result;
#endif

            /* Use default permissions */
            saved_umask = umask(0);
            st.st_mode = 0666 & ~saved_umask;
            umask(saved_umask);
#if defined(HAVE_GETUID) && defined(HAVE_GETGID)
            st.st_uid = getuid ();

            result = stat (dirname, &dir_st);

            if (result == 0 && (dir_st.st_mode & S_ISGID))
              st.st_gid = dir_st.st_gid;
            else
              st.st_gid = getgid ();
#endif
          }
        g_free (dirname);
        g_free (only_filename);
        g_free (real_filename);

        /* Make the backup file writable before saving a new one */
        if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) &&
             (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
          saved_umask = umask(0);
          if (chmod(backup_filename, (S_IWRITE|S_IWGRP|S_IWOTH) &
                    ((~saved_umask) & 0777)) != 0) {
            s_log_message (_("Could NOT set previous backup file [%s] read-write\n"),
                           backup_filename);
          }
          umask(saved_umask);
        }

        if (o_save (toplevel,
                    s_page_objects (toplevel->page_current),
                    backup_filename, NULL)) {

          p_current->ops_since_last_backup = 0;
                p_current->do_autosave_backup = 0;

          /* Make the backup file readonly so a 'rm *' command will ask
             the user before deleting it */
          saved_umask = umask(0);
          mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
          mask = (~mask)&0777;
          mask &= ((~saved_umask) & 0777);
          if (chmod(backup_filename,mask) != 0) {
            s_log_message (_("Could NOT set backup file [%s] readonly\n"),
                           backup_filename);
          }
          umask(saved_umask);
        } else {
          s_log_message (_("Could NOT save backup file [%s]\n"),
                         backup_filename);
        }
        g_free (backup_filename);
      }
    }
  }
  /* restore current page */
  s_page_goto (toplevel, p_save);
}
Example #20
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *
 *  <B>flag</B> can be one of the following values:
 *  <DL>
 *    <DT>*</DT><DD>UNDO_ALL
 *    <DT>*</DT><DD>UNDO_VIEWPORT_ONLY
 *  </DL>
 */
void
o_undo_savestate (GschemToplevel *w_current, PAGE *page, int flag)
{
  TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
  char *filename = NULL;
  GList *object_list = NULL;
  int levels;
  UNDO *u_current;
  UNDO *u_current_next;

  GschemPageView *view = gschem_toplevel_get_current_page_view (w_current);
  g_return_if_fail (view != NULL);

  g_return_if_fail (page != NULL);

  GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view);

  /* save autosave backups if necessary */
  o_autosave_backups(w_current);

  if (w_current->undo_control == FALSE) {
    return;
  }

  if (flag == UNDO_ALL) {

    /* Increment the number of operations since last backup if
       auto-save is enabled */
    if (toplevel->auto_save_interval != 0) {
      page->ops_since_last_backup++;
    }

    /* HACK */
    /* Before we save the undo state, consolidate nets as necessary */

    /* This is where the net consolidation call would have been
     * triggered before it was removed from o_save_buffer().
     */
    if (toplevel->net_consolidate == TRUE)
      geda_net_object_consolidate (toplevel, page);
  }

  if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) {

    filename = g_strdup_printf("%s%cgschem.save%d_%d.sch",
                               tmp_path, G_DIR_SEPARATOR,
                               prog_pid, undo_file_index++);

    /* Changed from f_save to o_save when adding backup copy creation. */
    /* f_save manages the creaton of backup copies.
       This way, f_save is called only when saving a file, and not when
       saving an undo backup copy */
    o_save (toplevel, s_page_objects (page), filename, NULL);

  } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) {
    object_list = o_glist_copy_all (toplevel,
                                    s_page_objects (page),
                                    object_list);
  }

  /* Clear Anything above current */
  if (page->undo_current) {
    s_undo_remove_rest(toplevel, page->undo_current->next);
    page->undo_current->next = NULL;
  } else { /* undo current is NULL */
    s_undo_remove_rest(toplevel, page->undo_bottom);
    page->undo_bottom = NULL;
  }

  page->undo_tos = page->undo_current;

  if (geometry != NULL) {
    page->undo_tos = s_undo_add(page->undo_tos,
                                flag, filename, object_list,
                                (geometry->viewport_left + geometry->viewport_right) / 2,
                                (geometry->viewport_top + geometry->viewport_bottom) / 2,
                                /* scale */
                                max (((double) abs (geometry->viewport_right - geometry->viewport_left) / geometry->screen_width),
                                  ((double) abs (geometry->viewport_top - geometry->viewport_bottom) / geometry->screen_height)),
                                page->page_control,
                                page->up);
  } else {
    page->undo_tos = s_undo_add(page->undo_tos,
                                flag, filename, object_list,
                                0, /* center x */
                                0, /* center y */
                                0, /* scale */
                                page->page_control,
                                page->up);
  }

  page->undo_current =
      page->undo_tos;

  if (page->undo_bottom == NULL) {
    page->undo_bottom =
        page->undo_tos;
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("BOTTOM: %s\n", page->undo_bottom->filename);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif

  g_free(filename);

  /* Now go through and see if we need to free/remove some undo levels */
  /* so we stay within the limits */

  /* only check history every 10 undo savestates */
  if (undo_file_index % 10) {
    return;
  }

  levels = s_undo_levels(page->undo_bottom);

#if DEBUG
  printf("levels: %d\n", levels);
#endif

  if (levels >= w_current->undo_levels + UNDO_PADDING) {
    levels = levels - w_current->undo_levels;

#if DEBUG
    printf("Trimming: %d levels\n", levels);
#endif

    u_current = page->undo_bottom;

    while (levels > 0) {
      /* Because we use a pad you are always guaranteed to never */
      /* exhaust the list */
      g_assert (u_current != NULL);

      u_current_next = u_current->next;

      if (u_current->filename) {
#if DEBUG
        printf("Freeing: %s\n", u_current->filename);
#endif
        unlink(u_current->filename);
        g_free(u_current->filename);
      }

      if (u_current->object_list) {
        geda_object_list_delete (toplevel, u_current->object_list);
        u_current->object_list = NULL;
      }

      u_current->next = NULL;
      u_current->prev = NULL;
      g_free(u_current);

      u_current = u_current_next;
      levels--;
    }

    g_assert (u_current != NULL);
    u_current->prev = NULL;
    page->undo_bottom = u_current;

#if DEBUG
    printf("New current is: %s\n", u_current->filename);
#endif
  }

#if DEBUG
  printf("\n\n---Undo----\n");
  s_undo_print_all(page->undo_bottom);
  printf("BOTTOM: %s\n", page->undo_bottom->filename);
  printf("TOS: %s\n", page->undo_tos->filename);
  printf("CURRENT: %s\n", page->undo_current->filename);
  printf("----\n");
#endif

}
/*! \brief Find all text objects that match a regex
 *
 *  \param pages the list of pages to search
 *  \param text the regex to match
 *  \return a list of objects that match the given regex
 */
static GSList*
find_objects_using_regex (GSList *pages, const char *text, GError **error)
{
  GError *ierror = NULL;
  GSList *object_list = NULL;
  GSList *page_iter = pages;
  GRegex *regex;

  g_return_val_if_fail (text != NULL, NULL);

  regex = g_regex_new (text,
                       (GRegexCompileFlags) 0,
                       (GRegexMatchFlags) 0,
                       &ierror);

  if (ierror != NULL) {
    g_propagate_error (error, ierror);
    return NULL;
  }

  while (page_iter != NULL) {
    const GList *object_iter;
    PAGE *page = (PAGE*) page_iter->data;

    page_iter = g_slist_next (page_iter);

    if (page == NULL) {
      g_warning ("NULL page encountered");
      continue;
    }

    object_iter = s_page_objects (page);

    while (object_iter != NULL) {
      OBJECT *object = (OBJECT*) object_iter->data;
      const char *str;

      object_iter = g_list_next (object_iter);

      if (object == NULL) {
        g_warning ("NULL object encountered");
        continue;
      }

      if (object->type != OBJ_TEXT) {
        continue;
      }

      if (!(o_is_visible (page->toplevel, object) || page->toplevel->show_hidden_text)) {
        continue;
      }

      str = geda_text_object_get_string (object);

      if (str == NULL) {
        g_warning ("NULL string encountered");
        continue;
      }

      if (g_regex_match (regex, str, (GRegexMatchFlags) 0, NULL)) {
        object_list = g_slist_prepend (object_list, object);
      }
    }
  }

  g_regex_unref (regex);

  return g_slist_reverse (object_list);
}
Example #22
0
/*! \brief Find page hierarchy below a page.
 *  \par Function Description
 *  This function traverses the hierarchy tree of pages and returns a
 *  flat list of pages that are below \a p_current. There are two \a
 *  flags that can be used to control the way that the return value is
 *  constructed: <B>HIERARCHY_NODUPS</B> returns a list without
 *  duplicate pages, and <B>HIERARCHY_POSTORDER</B> traverses the
 *  hierarchy tree and returns a postorder list instead of preorder.
 *
 *  \param toplevel The TOPLEVEL structure.
 *  \param p_current The PAGE to traverse hierarchy for.
 *  \param flags Flags controlling form of return value.
 *  \return A GList of PAGE pointers.
 *
 *  \warning
 *  Caller must destroy returned GList with g_list_free().
 */
GList *
s_hierarchy_traversepages (TOPLEVEL *toplevel, PAGE *p_current, gint flags)
{
  OBJECT *o_current;
  PAGE *child_page;
  char *filename = NULL;
  static GList *pages = NULL;
  const GList *iter;

  g_return_val_if_fail ((toplevel != NULL), NULL);
  g_return_val_if_fail ((p_current != NULL), NULL);

  /* init static variables the first time*/
  if (!(flags & HIERARCHY_INNERLOOP)) {
    pages = NULL;
  }

  /* preorder traversing */
  if (!(flags & HIERARCHY_POSTORDER)) {
    /* check whether we already visited this page */
    if ((flags & HIERARCHY_NODUPS)
        && (g_list_find (pages, p_current) != NULL)) {
      return pages;  /* drop the page subtree */
      }
    pages = g_list_append (pages, p_current);
  }

  /* walk throught the page objects and search for underlaying schematics */
  for (iter = s_page_objects (p_current);
       iter != NULL ;
       iter = g_list_next (iter)) {
    o_current = (OBJECT *)iter->data;

    /* only complex things like symbols can contain attributes */
    if (o_current->type != OBJ_COMPLEX) continue;

    filename =
      o_attrib_search_attached_attribs_by_name (o_current, "source", 0);

    /* if above is NULL, then look inside symbol */
    if (filename == NULL) {
      filename =
        o_attrib_search_inherited_attribs_by_name (o_current, "source", 0);
    }

    if (filename == NULL) continue;

    /* we got a schematic source attribute
       lets load the page and dive into it */
    GError *err = NULL;
    child_page =
      s_hierarchy_down_schematic_single (toplevel, filename, p_current, 0,
                                         HIERARCHY_NORMAL_LOAD, &err);
    if (child_page != NULL) {
      /* call the recursive function */
      s_hierarchy_traversepages (toplevel, child_page, flags | HIERARCHY_INNERLOOP);
    } else {
      s_log_message (_("Failed to descend hierarchy into '%1$s': %2$s"),
                     filename, err->message);
      g_error_free (err);
    }

    g_free (filename);
    filename = NULL;
  }

  /* postorder traversing */
  if (flags & HIERARCHY_POSTORDER) {
    /* check whether we already visited this page */
    if ((flags & HIERARCHY_NODUPS)
        && (g_list_find (pages, p_current) != NULL)) {
      return pages;  /* don't append it */
    }
    pages = g_list_append (pages, p_current);
  }

  return pages;
}
Example #23
0
/*! \brief Draw a page.
 * \par Function Description
 * Draws the \a page on the Cairo context \a cr, which should have
 * dimensions \a cr_width and \a cr_height.  If the Pango context \a
 * pc is provided, it is used for rendering of text.  The parameter \a
 * is_color controls whether to enable color printing, and \a
 * is_raster should be set if drawing to a raster surface such as an
 * image.
 *
 * \param toplevel A #TOPLEVEL structure.
 * \param page     The #PAGE to be rendered.
 * \param cr       The Cairo context to render to.
 * \param pc       A Pango context for text rendering, or NULL.
 * \param cr_width The width of the drawing area.
 * \param cr_height The height of the drawing area.
 * \param is_color TRUE if drawing should be in color; FALSE otherwise.
 * \param is_raster TRUE if drawing to a raster image surface; FALSE otherwise.
 */
static void
x_print_draw_page (TOPLEVEL *toplevel, PAGE *page,
                   cairo_t *cr, PangoContext *pc,
                   double cr_width, double cr_height,
                   gboolean is_color, gboolean is_raster)
{
  EdaRenderer *renderer;
  cairo_matrix_t mtx;
  GArray *color_map;
  int status, wx_min, wy_min, wx_max, wy_max;
  double w_width, w_height, scale;
  GList *iter;

  /* First, calculate a transformation matrix for the cairo
   * context. We want to center the extents of the page in the
   * available page area. */
  status = world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                          &wx_min, &wy_min, &wx_max, &wy_max);
  /* If there are no printable objects, draw nothing. */
  if (!status) return;

  w_width = wx_max - wx_min;
  w_height = wy_max - wy_min;
  scale = fmin (cr_width / w_width, cr_height / w_height);
  cairo_matrix_init (&mtx,
                     scale, 0,
                     0, -scale,
                     - (wx_min + 0.5*w_width) * scale + 0.5*cr_width,
                     (wy_min + 0.5*w_height) * scale + 0.5*cr_height);

  /* Second, build the color map.  If no color printing is desired,
   * transform the print color map into a black-and-white color map by
   * making the background color transparent and replacing all other
   * enabled colors with solid black. */
  color_map = g_array_sized_new (FALSE, FALSE, sizeof(GedaColor), MAX_COLORS);
  color_map = g_array_append_vals (color_map, print_colors, MAX_COLORS);
  if (!is_color) {
    int i;
    for (i = 0; i < MAX_COLORS; i++) {
      GedaColor *c = &g_array_index (color_map, GedaColor, i);
      if (!c->enabled) continue;

      /* Disable background color & fully-transparent colors */
      if (c->a == 0 || i == BACKGROUND_COLOR) {
        c->enabled = FALSE;
        continue;
      }

      /* Set any remaining colors solid black */
      c->r = 0;
      c->g = 0;
      c->b = 0;
      c->a = ~0;
    }
  }

  /* Thirdly, create and initialise a renderer */
  renderer = EDA_RENDERER (g_object_new (EDA_TYPE_RENDERER,
                                         "cairo-context", cr,
                                         "pango-context", pc,
                                         "color-map", color_map,
                                         "render-flags", is_raster ? EDA_RENDERER_FLAG_HINTING : 0,
                                         NULL));

  /* Finally, actually do drawing */
  cairo_save (cr);
  cairo_transform (cr, &mtx);

  /* Draw background */
  eda_cairo_set_source_color (cr, BACKGROUND_COLOR, color_map);
  cairo_paint (cr);

  /* Draw all objects and cues */
  for (iter = (GList *) s_page_objects (page);
       iter != NULL;
       iter = g_list_next (iter)) {
    eda_renderer_draw (renderer, (OBJECT *) iter->data);
  }
  for (iter = (GList *) s_page_objects (page);
       iter != NULL;
       iter = g_list_next (iter)) {
    eda_renderer_draw_cues (renderer, (OBJECT *) iter->data);
  }

  cairo_restore (cr);

  g_object_unref (renderer);
  g_array_free (color_map, TRUE);
}
Example #24
0
/* Calculates a page layout.  If page is NULL, uses the first page
 * (this is convenient for single-page rendering).  The required size
 * of the page is returned in extents, and the cairo transformation
 * matrix needed to fit the drawing into the page is returned in mtx.
 * Takes into account all of the margin/orientation/paper settings,
 * and the size of the drawing itself. */
static void
export_layout_page (PAGE *page, cairo_rectangle_t *extents, cairo_matrix_t *mtx)
{
  cairo_rectangle_t drawable;
  int wx_min, wy_min, wx_max, wy_max, w_width, w_height;
  gboolean landscape = FALSE;
  gdouble m[4]; /* Calculated margins */
  gdouble s; /* Calculated scale */
  gdouble slack[2]; /* Calculated alignment slack */

  if (page == NULL) {
    const GList *pages = geda_list_get_glist (toplevel->pages);
    g_assert (pages != NULL && pages->data != NULL);
    page = (PAGE *) pages->data;
  }

  /* Set the margins. If none were provided by the user, get them
   * from the paper size (if a paper size is being used) or just use a
   * sensible default. */
  if (settings.margins[0] >= 0) {
    memcpy (m, settings.margins, 4*sizeof(gdouble));
  } else if (settings.paper != NULL) {
    m[0] = gtk_paper_size_get_default_top_margin (settings.paper, GTK_UNIT_POINTS);
    m[1] = gtk_paper_size_get_default_left_margin (settings.paper, GTK_UNIT_POINTS);
    m[2] = gtk_paper_size_get_default_bottom_margin (settings.paper, GTK_UNIT_POINTS);
    m[3] = gtk_paper_size_get_default_right_margin (settings.paper, GTK_UNIT_POINTS);
  } else {
    m[0] = DEFAULT_MARGIN;
    m[1] = DEFAULT_MARGIN;
    m[2] = DEFAULT_MARGIN;
    m[3] = DEFAULT_MARGIN;
  }

  /* Now calculate extents of objects within page */
  world_get_object_glist_bounds (toplevel, s_page_objects (page),
                                 &wx_min, &wy_min, &wx_max, &wy_max);
  w_width = wx_max - wx_min;
  w_height = wy_max - wy_min;

  /* If a size was specified, use it.  Otherwise, use paper size, if
   * provided.  Fall back to just using the size of the drawing. */
  extents->x = extents->y = 0;
  if (settings.size[0] >= 0) {
    /* get extents from size */

    extents->width = settings.size[0];
    extents->height = settings.size[1];

  } else if (settings.paper != NULL) {
    /* get extents from paper */

    gdouble p_width, p_height;

    /* Select orientation */
    switch (settings.layout) {
    case ORIENTATION_LANDSCAPE:
      landscape = TRUE;
      break;
    case ORIENTATION_PORTRAIT:
      landscape = FALSE;
      break;
    case ORIENTATION_AUTO:
    default:
      landscape = (w_width > w_height);
      break;
    }

    p_width = gtk_paper_size_get_width (settings.paper, GTK_UNIT_POINTS);
    p_height = gtk_paper_size_get_height (settings.paper, GTK_UNIT_POINTS);

    if (landscape) {
      extents->width = p_height;
      extents->height = p_width;
    } else {
      extents->width = p_width;
      extents->height = p_height;
    }
  } else {
    /* get extents from drawing */

    extents->width = w_width * settings.scale; /* in points */
    extents->height = w_height * settings.scale; /* in points */

    /* If the extents were obtained from the drawing, grow the extents
     * rather than shrinking the drawable area.  This ensures that the
     * overall aspect ratio of the image remains correct. */
    extents->width += m[1] + m[3];
    extents->height += m[0] + m[2];
  }

  drawable.x = m[1];
  drawable.y = m[0];

  drawable.width = extents->width - m[1] - m[3];
  drawable.height = extents->height - m[0] - m[2];

  /* Calculate optimum scale */
  s = fmin (drawable.width / w_width, drawable.height / w_height);

  /* Calculate alignment slack */
  slack[0] = fmin (1, fmax (0, settings.align[0])) * (drawable.width - w_width * s);
  slack[1] = fmin (1, fmax (0, settings.align[1])) * (drawable.height - w_height * s);

  /* Finally, create and set a cairo transformation matrix that
   * centres the drawing into the drawable area. */
  cairo_matrix_init (mtx, s, 0, 0, -s,
                     - wx_min * s + drawable.x + slack[0],
                     (wy_min + w_height) * s + drawable.y + slack[1]);
}
Example #25
0
/*! \brief Updates the preview widget.
 *  \par Function Description
 *  This function updates the preview: if the preview is active and a
 *  filename has been given, it opens the file and displays
 *  it. Otherwise it displays a blank page.
 *
 *  \param [in] preview The preview widget.
 */
static void
preview_update (Preview *preview)
{
  int left, top, right, bottom;
  int width, height;
  GError * err = NULL;

  GschemPageView *preview_view = GSCHEM_PAGE_VIEW (preview);

  g_return_if_fail (preview_view != NULL);
  PAGE *preview_page = gschem_page_view_get_page (preview_view);

  if (preview_page == NULL) {
    return;
  }

  TOPLEVEL *preview_toplevel = preview_page->toplevel;

  /* delete old preview */
  s_page_delete_objects (preview_toplevel, preview_page);

  if (preview->active) {
    g_assert ((preview->filename == NULL) || (preview->buffer == NULL));
    if (preview->filename != NULL) {
      /* open up file in current page */
      f_open_flags (preview_toplevel, preview_page,
                    preview->filename,
                    F_OPEN_RC | F_OPEN_RESTORE_CWD, NULL);
      /* test value returned by f_open... - Fix me */
      /* we should display something if there an error occured - Fix me */
    }
    if (preview->buffer != NULL) {
      /* Load the data buffer */
      GList * objects = o_read_buffer (preview_toplevel,
                                       NULL, preview->buffer, -1,
                                       _("Preview Buffer"), &err);

      if (err == NULL) {
        s_page_append_list (preview_toplevel, preview_page,
                            objects);
      }
      else {
        s_page_append (preview_toplevel, preview_page,
                       o_text_new(preview_toplevel, OBJ_TEXT, 2, 100, 100, LOWER_MIDDLE, 0,
                                  err->message, 10, VISIBLE, SHOW_NAME_VALUE));
        g_error_free(err);
      }
    }
  }

  if (world_get_object_glist_bounds (preview_toplevel,
                                     s_page_objects (preview_page),
                                     &left, &top,
                                     &right, &bottom)) {
    /* Clamp the canvas size to the extents of the page being previewed */
    width = right - left;
    height = bottom - top;

    GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (preview_view);
    geometry->world_left   = left   - ((double)width  * OVER_ZOOM_FACTOR);
    geometry->world_right  = right  + ((double)width  * OVER_ZOOM_FACTOR);
    geometry->world_top    = top    - ((double)height * OVER_ZOOM_FACTOR);
    geometry->world_bottom = bottom + ((double)height * OVER_ZOOM_FACTOR);
  }

  /* display current page (possibly empty) */
  gschem_page_view_zoom_extents (preview_view, NULL);
}
Example #26
0
void
s_hierarchy_traverse(TOPLEVEL * pr_current, OBJECT * o_current,
		     NETLIST * netlist)
{
    char *attrib;
    int page_control=-1;
    PAGE *p_current;
    PAGE *child_page;
    int count = 0;
    int pcount = 0;
    int looking_inside = FALSE;
    int loaded_flag = FALSE;
    char *current_filename;
    int graphical=FALSE;

    attrib = o_attrib_search_attached_attribs_by_name (o_current, "source", 0);

    /* if above is null, then look inside symbol */
    if (attrib == NULL) {
	attrib = o_attrib_search_inherited_attribs_by_name (o_current,
	                                                    "source", count);

	looking_inside = TRUE;
#if DEBUG
	printf("going to look inside now\n");
#endif
    }

    graphical = s_hierarchy_graphical_search(o_current, count);
    if (graphical) {
	/* Do not bother traversing the hierarchy if the symbol has an */
	/* graphical attribute attached to it. */
	if (attrib) {
	    g_free(attrib);
 	    attrib = NULL;
	}
    }

    while (attrib) {

	/* look for source=filename,filename, ... */
	pcount = 0;
	current_filename = u_basic_breakup_string(attrib, ',', pcount);

	/* loop over all filenames */
	while (current_filename != NULL) {

	    s_log_message(_("Going to traverse source [%1$s]"),
			  current_filename);

	    /* guts here */
	    /* guts for a single filename */
	    p_current = pr_current->page_current;
#if DEBUG
	    printf("Going down %s\n", current_filename);
#endif
            GError *err = NULL;
	    child_page =
		s_hierarchy_down_schematic_single(pr_current,
						  current_filename,
						  pr_current->page_current,
						  page_control,
                                                  HIERARCHY_FORCE_LOAD,
                                                  &err);

	    if (child_page == NULL) {
              g_warning (_("Failed to load subcircuit '%1$s': %2$s\n"),
                         current_filename, err->message);
              fprintf(stderr, _("ERROR: Failed to load subcircuit '%1$s': %2$s\n"),
                      current_filename, err->message);
              g_error_free (err);
              exit (2);

	    } else {
              page_control = child_page->page_control;
              s_page_goto (pr_current, child_page);

		loaded_flag = TRUE;

		verbose_print("v\n");
		verbose_reset_index();

		netlist->composite_component = TRUE;
		/* can't do the following, don't know why... HACK TODO */
		/*netlist->hierarchy_tag = u_basic_strdup (netlist->component_uref);*/
		s_traverse_sheet (pr_current,
		                  s_page_objects (pr_current->page_current),
		                  netlist->component_uref);

		verbose_print("^");
	    }

	    pr_current->page_current = p_current;

	    g_free(current_filename);
	    pcount++;
	    current_filename = u_basic_breakup_string(attrib, ',', pcount);
	}

	g_free(attrib);

	g_free(current_filename);

	count++;

	/* continue looking outside first */
	if (!looking_inside) {
	    attrib =
		o_attrib_search_attached_attribs_by_name (o_current, "source",
		                                          count);
	}

	/* okay we were looking outside and didn't */
	/* find anything, so now we need to look */
	/* inside the symbol */
	if (!looking_inside && attrib == NULL && !loaded_flag) {
	    looking_inside = TRUE;
#if DEBUG
	    printf("switching to go to look inside\n");
#endif
	}

	if (looking_inside) {
#if DEBUG
	    printf("looking inside\n");
#endif
	    attrib =
	        o_attrib_search_inherited_attribs_by_name (o_current,
	                                                   "source", count);
	}

        graphical = s_hierarchy_graphical_search(o_current, count);
        if (graphical) {
	  /* Do not bother looking further in the hierarchy if the symbol */
          /* has an graphical attribute attached to it. */
	  if (attrib) {
	     g_free(attrib);
	     attrib = NULL;
          }
       }
    }
}
Example #27
0
/*! \todo Finish function documentation!!!
 *  \brief
 *  \par Function Description
 *
 *  \todo Only descends into the first source schematic
 *
 */
int o_edit_find_text (GSCHEM_TOPLEVEL *w_current, const GList *o_list,
                      char *stext, int descend, int skip)
{
  TOPLEVEL *toplevel = w_current->toplevel;
  char *attrib = NULL;
  int count = 0;
  PAGE *parent = NULL;
  char *current_filename = NULL;
  int page_control = 0;
  int pcount = 0;
  int rv;
  int x1, y1, x2, y2;
  int text_screen_height;
  const GList *iter;

  OBJECT *o_current;

  skiplast = skip;

  iter = o_list;
  while (iter != NULL) {
    o_current = (OBJECT *)iter->data;

    if (descend) {
      if (o_current->type == OBJ_COMPLEX) {
        parent = toplevel->page_current;
        attrib = o_attrib_search_attached_attribs_by_name (o_current,
                                                           "source", count);

        /* if above is null, then look inside symbol */
        if (attrib == NULL) {
          attrib = o_attrib_search_inherited_attribs_by_name (o_current,
                                                              "source", count);
          /*          looking_inside = TRUE; */
        }

        if (attrib) {
          pcount = 0;
          current_filename = u_basic_breakup_string(attrib, ',', pcount);
          if (current_filename != NULL) {
            PAGE *child_page =
              s_hierarchy_down_schematic_single(toplevel,
                                                current_filename,
                                                parent,
                                                page_control,
                                                HIERARCHY_NORMAL_LOAD);

            if (child_page != NULL) {
              page_control = child_page->page_control;
              rv = o_edit_find_text (w_current,
                                     s_page_objects (child_page),
                                     stext, descend, skiplast);
              if (!rv) {
                s_page_goto( toplevel, child_page );
                return 0;
              }
            }
          }
        }
      }
    }

    if (o_current->type == OBJ_TEXT) {
      const gchar *str = o_text_get_string (toplevel, o_current);
     /* replaced strcmp with strstr to simplify the search */
      if (strstr (str,stext)) {
        if (!skiplast) {
          a_zoom(w_current, ZOOM_FULL, DONTCARE, A_PAN_DONT_REDRAW);
          world_get_single_object_bounds (toplevel, o_current, &x1, &y1, &x2, &y2);
          text_screen_height = SCREENabs (w_current, y2 - y1);
          /* this code will zoom/pan till the text screen height is about */
          /* 50 pixels high, perhaps a future enhancement will be to make */
          /* this number configurable */
          while (text_screen_height < 50) {
            a_zoom(w_current, ZOOM_IN, DONTCARE, A_PAN_DONT_REDRAW);
            text_screen_height = SCREENabs (w_current, y2 - y1);
          }
          a_pan_general(w_current,
                        o_current->text->x, o_current->text->y,
                        1, 0);

	  /* Make sure the titlebar and scrollbars are up-to-date */
	  x_window_set_current_page(w_current, 
                                    w_current->toplevel->page_current );

          last_o = o_current;
          break;
        }
        if (last_o == o_current) {
          skiplast = 0;
        }

      } /* if (strstr(o_current->text->string,stext)) */
    } /* if (o_current->type == OBJ_TEXT) */
    iter = g_list_next (iter);

    if (iter == NULL) {
      return 1;
    }
  }
  return (iter == NULL);
}
Example #28
0
/*! \brief Attach attribute to object.
 *
 * Attach the name=value pair to the OBJECT "object". This function
 * was stolen from gschem/src/o_attrib.c:o_attrib_add_attrib and
 * hacked for gattrib.
 * \param toplevel TOPLEVEL to operate on
 * \param text_string
 * \param visibility
 * \param show_name_value
 * \param object
 * \returns pointer to the object
 * \todo Does it need to return OBJECT?
 */
OBJECT *
s_object_attrib_add_attrib_in_object (TOPLEVEL *toplevel,
                                      char *text_string,
                                      int visibility,
                                      int show_name_value,
                                      OBJECT * object)
{
  int world_x = -1, world_y = -1;
  int color;
  int left, right, top, bottom;
  OBJECT *o_current;
  OBJECT *new_obj;

  o_current = object;

  /* creating a toplevel or unattached attribute */
  if (o_current) {
    /* get coordinates of where to place the text object */
    switch (o_current->type) {
    case (OBJ_COMPLEX):
      world_x = o_current->complex->x;
      world_y = o_current->complex->y;
      color = ATTRIBUTE_COLOR;
      break;

    case (OBJ_NET):
      world_x = o_current->complex->x;
      world_y = o_current->complex->y;
      color = ATTRIBUTE_COLOR;
      break;

    default:
      fprintf(stderr, _("In s_object_attrib_add_attrib_in_object, trying to add attrib to non-complex or non-net!\n"));
      exit(-1);
    }
  } else {    /* This must be a floating attrib, but what is that !?!?!?!?!  */
    world_get_object_glist_bounds (toplevel,
                                   s_page_objects (toplevel->page_current),
                                   &left, &top, &right, &bottom);

    /* this really is the lower left hand corner */
    world_x = left;
    world_y = top;

    /* printf("%d %d\n", world_x, world_y); */
    color = DETACHED_ATTRIBUTE_COLOR;
  }

  /* first create text item */
#if DEBUG
  printf("===  In s_object_attrib_add_attrib_in_object, about to attach new text attrib with properties:\n");
  printf("     color = %d\n", color);
  printf("     text_string = %s \n", text_string);
  printf("     text_size = %d \n", toplevel->text_size);
  printf("     visibility = %d \n", visibility);
  printf("     show_name_value = %d \n", show_name_value);
#endif

  new_obj = o_text_new (toplevel, color, world_x, world_y,
                        LOWER_LEFT, 0, /* zero is angle */
                        text_string, DEFAULT_TEXT_SIZE,
                        visibility, show_name_value);
  s_page_append (toplevel, toplevel->page_current, new_obj);

  /* now toplevel->page_current->object_tail contains new text item */

  /* now attach the attribute to the object (if o_current is not NULL) */
  /* remember that o_current contains the object to get the attribute */
  if (o_current) {
    o_attrib_attach (toplevel, new_obj, o_current, FALSE);
  }

  o_selection_add (toplevel,
                   toplevel->page_current->selection_list, new_obj);


  toplevel->page_current->CHANGED = 1;

  return new_obj;
}
Example #29
0
/*! \brief Save the schematic file
 *  \par Function Description
 *  This function saves the current schematic file in the toplevel object.
 *
 *  \param [in,out] toplevel  The TOPLEVEL object containing the schematic.
 *  \param [in]      filename  The file name to save the schematic to.
 *  \param [in,out] err       #GError structure for error reporting, or
 *                            NULL to disable error reporting
 *  \return 1 on success, 0 on failure.
 */
int f_save(TOPLEVEL *toplevel, PAGE *page, const char *filename, GError **err)
{
  gchar *backup_filename;
  gchar *real_filename;
  gchar *only_filename;
  gchar *dirname;
  mode_t saved_umask, mask;
  struct stat st;
  GError *tmp_err = NULL;

  /* Get the real filename and file permissions */
  real_filename = follow_symlinks (filename, &tmp_err);

  if (real_filename == NULL) {
    g_set_error (err, tmp_err->domain, tmp_err->code,
                 _("Can't get the real filename of %s: %s"),
                 filename,
                 tmp_err->message);
    return 0;
  }
  
  /* Get the directory in which the real filename lives */
  dirname = g_path_get_dirname (real_filename);
  only_filename = g_path_get_basename(real_filename);  

  /* Do a backup if it's not an undo file backup and it was never saved. */
  if (page->saved_since_first_loaded == 0) {
    if ( (g_file_test (real_filename, G_FILE_TEST_EXISTS)) && 
	 (!g_file_test(real_filename, G_FILE_TEST_IS_DIR)) )
    {
      backup_filename = g_strdup_printf("%s%c%s~", dirname, 
					G_DIR_SEPARATOR, only_filename);

      /* Make the backup file read-write before saving a new one */
      if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && 
	   (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
	if (chmod(backup_filename, S_IREAD|S_IWRITE) != 0) {
	  s_log_message (_("Could NOT set previous backup file [%s] read-write\n"),
			 backup_filename);
	}
      }
	
      if (rename(real_filename, backup_filename) != 0) {
	s_log_message (_("Can't save backup file: %s."), backup_filename);
      }
      else {
	/* Make the backup file readonly so a 'rm *' command will ask 
	   the user before deleting it */
	saved_umask = umask(0);
	mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
	mask = (~mask)&0777;
	mask &= ((~saved_umask) & 0777);
	if (chmod(backup_filename, mask) != 0) {
	  s_log_message (_("Could NOT set backup file [%s] readonly\n"),
                         backup_filename);
	}
	umask(saved_umask);
      }

      g_free(backup_filename);
    }
  }
    /* If there is not an existing file with that name, compute the
     * permissions and uid/gid that we will use for the newly-created file.
     */
       
  if (stat (real_filename, &st) != 0)
  {
    struct stat dir_st;
    int result;
    
    /* Use default permissions */
    saved_umask = umask(0);
    st.st_mode = 0666 & ~saved_umask;
    umask(saved_umask);
#ifdef HAVE_CHOWN
    st.st_uid = getuid ();
    
    result = stat (dirname, &dir_st);
    
    if (result == 0 && (dir_st.st_mode & S_ISGID))
	  st.st_gid = dir_st.st_gid;
    else
    st.st_gid = getgid ();
#endif /* HAVE_CHOWN */
  }
  g_free (dirname);
  g_free (only_filename);
  
  if (o_save (toplevel, s_page_objects (page), real_filename, &tmp_err)) {

    page->saved_since_first_loaded = 1;

    /* Reset the last saved timer */
    g_get_current_time (&page->last_load_or_save_time);
    page->ops_since_last_backup = 0;
    page->do_autosave_backup = 0;

    /* Restore permissions. */
    chmod (real_filename, st.st_mode);
#ifdef HAVE_CHOWN
    if (chown (real_filename, st.st_uid, st.st_gid)) {
      /* Error occured with chown */
#warning FIXME: What do we do?
    }
#endif

    g_free (real_filename);
    return 1;
  }
  else {
    g_set_error (err, tmp_err->domain, tmp_err->code,
                 _("Could NOT save file: %s"), tmp_err->message);
    g_clear_error (&tmp_err);
    g_free (real_filename);
    return 0;
  }
}
Example #30
0
/*! \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;
}