/*! \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 #2
0
/*! \brief Create a string representation of the text object
 *  \par Function Description
 *  This function takes a text \a object and return a string
 *  according to the file format definition.
 *
 *  \param [in] object the text object
 *  \return the string representation of the text object
 */
gchar*
geda_text_object_to_buffer (const GedaObject *object)
{
  const gchar *string;

  g_return_val_if_fail (object != NULL, NULL);
  g_return_val_if_fail (object->text != NULL, NULL);
  g_return_val_if_fail (object->type == OBJ_TEXT, NULL);

  string = geda_text_object_get_string (object);

  g_return_val_if_fail (string != NULL, NULL);

  return g_strdup_printf ("%c %d %d %d %d %d %d %d %d %d\n%s",
                          OBJ_TEXT,
                          geda_text_object_get_x (object),
                          geda_text_object_get_y (object),
                          geda_object_get_color (object),
                          geda_text_object_get_size (object),
                          geda_object_get_visible (object),
                          object->show_name_value,
                          geda_text_object_get_angle (object),
                          geda_text_object_get_alignment (object),
                          o_text_num_lines (string),
                          string);
}
/*! \brief places object in the store so the user can see them
 *
 *  \param [in] state
 *  \param [in] objects the list of objects to put in the store
 */
static void
assign_store (GschemFindTextState *state, GSList *objects)
{
  GSList *object_iter;

  g_return_if_fail (state != NULL);
  g_return_if_fail (state->store != NULL);

  clear_store (state);

  object_iter = objects;

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

    object_iter = g_slist_next (object_iter);

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

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

    if (object->type != OBJ_TEXT) {
      g_warning ("expecting a text object");
      continue;
    }

    str = geda_text_object_get_string (object);

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

    s_object_weak_ref (object, (NotifyFunc) object_weakref_cb, state);

    gtk_list_store_append (state->store, &tree_iter);

    basename = g_path_get_basename (s_page_get_filename (object->page));

    gtk_list_store_set (state->store,
                        &tree_iter,
                        COLUMN_FILENAME, basename,
                        COLUMN_STRING, str,
                        COLUMN_OBJECT, object,
                        -1);

    g_free (basename);
  }
}
Example #4
0
/*! \brief Function to test, whether the OBJECT matches the autotext criterias
 *  \par Function Description
 *  The criterias are those of the autonumber text dialog. The function decides
 *  whether the <B>OBJECT</B> has to be renumberd, ignored or taken care of when
 *  renumbering all other objects.
 *  \return one of these integer values: <B>AUTONUMBER_IGNORE</B>,
 *  <B>AUTONUMBER_RESPECT</B> or <B>AUTONUMBER_RENUMBER</B> and the current number
 *  of the text object in <B>*number</B>.
 */
gint autonumber_match(AUTONUMBER_TEXT *autotext, OBJECT *o_current, gint *number)
{
  gint i, len, isnumbered=1;
  const gchar *str = NULL;

  len = strlen(autotext->current_searchtext);
  /* first find out whether we can ignore that object */
  if (o_current->type != OBJ_TEXT)  /* text object */
    return AUTONUMBER_IGNORE;

  str = geda_text_object_get_string (o_current);

  if (!(strlen(str) - len > 0)
      || !g_str_has_prefix(str, autotext->current_searchtext))
    return AUTONUMBER_IGNORE;

  /* the string object matches with its leading characters to the searchtext */
  /* now look for the extension, either a number or the "?" */
  if (g_str_has_suffix (str,"?")) {
    isnumbered = 0;
    /* There must not be any character between the "?" and the searchtext */
    if (strlen(str) != len+1)
      return AUTONUMBER_IGNORE;
  }
  else {
    if (!isdigit( (int) (str[len]) )) /* has at least one digit */
      return AUTONUMBER_IGNORE;

    for (i=len+1; str[i]; i++) /* and only digits */
      if (!isdigit( (int) (str[i]) ))
	return AUTONUMBER_IGNORE;
  }

  /* we have six cases, 3 from focus multiplied by 2 selection cases */
  if ((autotext->root_page || autotext->scope_number == SCOPE_HIERARCHY)
      && (o_current->selected
	  || autotext->scope_number == SCOPE_HIERARCHY || autotext->scope_number == SCOPE_PAGE)
      && (!isnumbered || (autotext->scope_overwrite)))
    return AUTONUMBER_RENUMBER;

  if (isnumbered
      && !(autotext->scope_skip == SCOPE_SELECTED
	   && !(o_current->selected)  && autotext->root_page)) {
    sscanf(&(str[len])," %d", number);
    return AUTONUMBER_RESPECT; /* numbered objects which we don't renumber */
  }
  else
    return AUTONUMBER_IGNORE;  /* unnumbered objects outside the focus */
}
/*! \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 #6
0
/*! \brief Handles all the options of the autonumber text dialog
 *  \par Function Description
 *  This function is the master of all autonumber code. It receives the options of
 *  the the autonumber text dialog in an <B>AUTONUMBER_TEXT</B> structure.
 *  First it collects all pages of a hierarchical schematic.
 *  Second it gets all matching text elements for the searchtext.
 *  Then it renumbers all text elements of all schematic pages. The renumbering
 *  follows the rules of the parameters given in the autonumber text dialog.
 */
void autonumber_text_autonumber(AUTONUMBER_TEXT *autotext)
{
  GList *pages;
  GList *searchtext_list=NULL;
  GList *text_item, *obj_item, *page_item;
  OBJECT *o_current;
  GschemToplevel *w_current;
  gchar *searchtext;
  gchar *scope_text;
  gchar *new_searchtext;
  gint i, number, slot;
  GList *o_list = NULL;
  const GList *iter;

  w_current = autotext->w_current;
  autotext->current_searchtext = NULL;
  autotext->root_page = 1;
  autotext->used_numbers = NULL;
  autotext->free_slots = NULL;
  autotext->used_slots = NULL;

  scope_text = g_list_first(autotext->scope_text)->data;

  /* Step1: get all pages of the hierarchy */
  pages = s_hierarchy_traversepages (w_current->toplevel,
                                     w_current->toplevel->page_current,
                                     HIERARCHY_NODUPS);

  /*  g_list_foreach(pages, (GFunc) s_hierarchy_print_page, NULL); */

  /* Step2: if searchtext has an asterisk at the end we have to find
     all matching searchtextes.

     Example:  "refdes=*" will match each text that starts with "refdes="
     and has a trailing "?" or a trailing number if the "all"-option is set.
     We get a list of possible prefixes: refdes=R, refdes=C.

     If there is only one search pattern, it becomes a single item
     in the searchtext list */

  if (strlen(scope_text) == 0) {
    s_log_message(_("No searchstring given in autonumber text.\n"));
    return; /* error */
  }
  else if (g_str_has_suffix(scope_text,"?") == TRUE) {
    /* single searchtext, strip of the "?" */
    searchtext = g_strndup(scope_text, strlen(scope_text)-1);
    searchtext_list=g_list_append (searchtext_list, searchtext);
  }
  else if (g_str_has_suffix(scope_text,"*") == TRUE) {
    /* strip of the "*" */
    searchtext = g_strndup(scope_text, strlen(scope_text)-1);
    /* collect all the possible searchtexts in all pages of the hierarchy */
    for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) {
      s_page_goto(w_current->toplevel, page_item->data);
      gschem_toplevel_page_changed (w_current);
      /* iterate over all objects an look for matching searchtext's */
      for (iter = s_page_objects (w_current->toplevel->page_current);
           iter != NULL;
           iter = g_list_next (iter)) {
	o_current = iter->data;
	if (o_current->type == OBJ_TEXT) {
	  if (autotext->scope_number == SCOPE_HIERARCHY
	      || autotext->scope_number == SCOPE_PAGE
	      || ((autotext->scope_number == SCOPE_SELECTED) && (o_current->selected))) {
            const gchar *str = geda_text_object_get_string (o_current);
	    if (g_str_has_prefix (str, searchtext)) {
	      /* the beginnig of the current text matches with the searchtext now */
	      /* strip of the trailing [0-9?] chars and add it too the searchtext */
	      for (i = strlen (str)-1;
		   (i >= strlen(searchtext))
		     && (str[i] == '?'
			 || isdigit( (int) (str[i]) ));
		   i--)
		; /* void */

	      new_searchtext = g_strndup (str, i+1);
	      if (g_list_find_custom(searchtext_list, new_searchtext,
				     (GCompareFunc) strcmp) == NULL ) {
		searchtext_list = g_list_append(searchtext_list, new_searchtext);
	      }
	      else {
		g_free(new_searchtext);
	      }
	    }
	  }
	}
      }
      if (autotext->scope_number == SCOPE_SELECTED || autotext->scope_number == SCOPE_PAGE)
	break; /* search only in the first page */
    }
    g_free(searchtext);
  }
  else {
    s_log_message(_("No '*' or '?' given at the end of the autonumber text.\n"));
    return;
  }

  /* Step3: iterate over the search items in the list */
  for (text_item=searchtext_list; text_item !=NULL; text_item=g_list_next(text_item)) {
    autotext->current_searchtext = text_item->data;
    /* printf("autonumber_text_autonumber: searchtext %s\n", autotext->current_searchtext); */
    /* decide whether to renumber page by page or get a global used-list */
    if (autotext->scope_skip == SCOPE_HIERARCHY) {  /* whole hierarchy database */
      /* renumbering all means that no db is required */
      if (!(autotext->scope_number == SCOPE_HIERARCHY
	    && autotext->scope_overwrite)) {
	for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) {
	  autotext->root_page = (pages->data == page_item->data);
	  s_page_goto(w_current->toplevel, page_item->data);
      gschem_toplevel_page_changed (w_current);
	  autonumber_get_used(w_current, autotext);
	}
      }
    }

    /* renumber the elements */
    for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) {
      s_page_goto(w_current->toplevel, page_item->data);
      gschem_toplevel_page_changed (w_current);
      autotext->root_page = (pages->data == page_item->data);
      /* build a page database if we're numbering pagebypage or selection only*/
      if (autotext->scope_skip == SCOPE_PAGE || autotext->scope_skip == SCOPE_SELECTED) {
	autonumber_get_used(w_current, autotext);
      }

      /* RENUMBER CODE FOR ONE PAGE AND ONE SEARCHTEXT*/
      /* 1. get objects to renumber */
      for (iter = s_page_objects (w_current->toplevel->page_current);
           iter != NULL;
           iter = g_list_next (iter)) {
        o_current = iter->data;
	if (autonumber_match(autotext, o_current, &number) == AUTONUMBER_RENUMBER) {
	  /* put number into the used list */
	  o_list = g_list_append(o_list, o_current);
	}
      }

      /* 2. sort object list */
      switch (autotext->order) {
      case AUTONUMBER_SORT_YX:
	o_list=g_list_sort(o_list, autonumber_sort_yx);
	break;
      case AUTONUMBER_SORT_YX_REV:
	o_list=g_list_sort(o_list, autonumber_sort_yx_rev);
	break;
      case AUTONUMBER_SORT_XY:
	o_list=g_list_sort(o_list, autonumber_sort_xy);
	break;
      case AUTONUMBER_SORT_XY_REV:
	o_list=g_list_sort(o_list, autonumber_sort_xy_rev);
	break;
      case AUTONUMBER_SORT_DIAGONAL:
	o_list=g_list_sort(o_list, autonumber_sort_diagonal);
	break;
      default:
	; /* unsorted file order */
      }

      /* 3. renumber/reslot the objects */
      for(obj_item=o_list; obj_item != NULL; obj_item=g_list_next(obj_item)) {
	o_current= obj_item->data;
      	if(autotext->removenum) {
	  autonumber_remove_number(autotext, o_current);
	} else {
	  /* get valid numbers from the database */
	  autonumber_get_new_numbers(autotext, o_current, &number, &slot);
	  /* and apply it. TODO: join these two functions */
	  autonumber_apply_new_text(autotext, o_current, number, slot);
	}
      }
      g_list_free(o_list);
      o_list = NULL;

      /* destroy the page database */
      if (autotext->scope_skip == SCOPE_PAGE
	  || autotext->scope_skip == SCOPE_SELECTED)
	autonumber_clear_database(autotext);

      if (autotext->scope_number == SCOPE_SELECTED
	  || autotext->scope_number == SCOPE_PAGE)
	break; /* only renumber the parent page (the first page) */
    }
    autonumber_clear_database(autotext);   /* cleanup */
  }

  /* cleanup and redraw all*/
  g_list_foreach(searchtext_list, (GFunc) g_free, NULL);
  g_list_free(searchtext_list);
  s_page_goto(w_current->toplevel, pages->data); /* go back to the root page */
  gschem_toplevel_page_changed (w_current);
  gschem_page_view_invalidate_all (gschem_toplevel_get_current_page_view (w_current));
  g_list_free(pages);
  o_undo_savestate_old(w_current, UNDO_ALL);
}