/*! \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); }
/*! \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); } }
/*! \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); }
/*! \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); }