libgeda

o_attrib.c

Go to the documentation of this file.
00001 /* gEDA - GPL Electronic Design Automation
00002  * libgeda - gEDA's library
00003  * Copyright (C) 1998-2010 Ales Hvezda
00004  * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00043 #include <config.h>
00044 #include <missing.h>
00045 
00046 #include <stdio.h>
00047 #ifdef HAVE_STRING_H
00048 #include <string.h>
00049 #endif
00050 #include <math.h>
00051 
00052 #include "libgeda_priv.h"
00053 
00054 #ifdef HAVE_LIBDMALLOC
00055 #include <dmalloc.h>
00056 #endif
00057 
00058 
00068 void o_attrib_add(TOPLEVEL *toplevel, OBJECT *object, OBJECT *item)
00069 {
00070   /* Add link from item to attrib listing */
00071   item->attached_to = object;
00072   object->attribs = g_list_append (object->attribs, item);
00073 
00074   o_attrib_emit_attribs_changed (toplevel, object);
00075 }
00076 
00077 
00088 gboolean o_attrib_is_attached (TOPLEVEL *toplevel, 
00089                                OBJECT *attrib, OBJECT *object)
00090 {
00091   if (attrib == NULL || object == NULL)
00092     return FALSE;
00093 
00094   if (attrib->attached_to == object)
00095     return TRUE;
00096 
00097   return FALSE;
00098 }
00099 
00100 
00110 void o_attrib_attach (TOPLEVEL *toplevel, OBJECT *attrib, OBJECT *object,
00111                       int set_color)
00112 {
00113   g_return_if_fail (attrib != NULL);
00114   g_return_if_fail (object != NULL);
00115 
00116   /* is the object already part of the list ? */
00117   if (g_list_find (object->attribs, attrib)) {
00118     g_warning ("Attribute [%s] already attached\n", attrib->text->string);
00119     return;
00120   }
00121 
00122   if (attrib->type != OBJ_TEXT) {
00123     g_warning (_("Attempt to attach non text item as an attribute!\n"));
00124     return;
00125   }
00126 
00127   if (attrib->attached_to != NULL) {
00128     g_warning (_("Attempt to attach attribute [%s] to more than one object\n"),
00129                 attrib->text->string);
00130     return;
00131   }
00132 
00133   o_attrib_add (toplevel, object, attrib);
00134 
00135   if (set_color)
00136     o_set_color (toplevel, attrib, ATTRIBUTE_COLOR);
00137 }
00138 
00139 
00149 void o_attrib_attach_list (TOPLEVEL *toplevel,
00150                            GList *attr_list, OBJECT *object, int set_color)
00151 {
00152   GList *iter;
00153 
00154   for (iter = attr_list; iter != NULL; iter = g_list_next (iter))
00155     o_attrib_attach (toplevel, iter->data, object, set_color);
00156 }
00157 
00158 
00166 void o_attrib_detach_all(TOPLEVEL *toplevel, OBJECT *object)
00167 {
00168   OBJECT *a_current;
00169   GList *a_iter;
00170 
00171   o_attrib_freeze_hooks (toplevel, object);
00172 
00173   for (a_iter = object->attribs; a_iter != NULL;
00174        a_iter = g_list_next (a_iter)) {
00175     a_current = a_iter->data;
00176 
00177     a_current->attached_to = NULL;
00178     o_set_color (toplevel, a_current, DETACHED_ATTRIBUTE_COLOR);
00179     o_attrib_emit_attribs_changed (toplevel, object);
00180   }
00181 
00182   g_list_free (object->attribs);
00183   object->attribs = NULL;
00184 
00185   o_attrib_thaw_hooks (toplevel, object);
00186 }
00187 
00194 void o_attrib_print(GList *attributes)
00195 {
00196   OBJECT *a_current;
00197   GList *a_iter;
00198 
00199   a_iter = attributes;
00200 
00201   while (a_iter != NULL) {
00202     a_current = a_iter->data;
00203     printf("Attribute points to: %s\n", a_current->name);
00204     if (a_current->text) {
00205       printf("\tText is: %s\n", a_current->text->string);
00206     }
00207 
00208     a_iter = g_list_next (a_iter);
00209   }
00210 }
00211 
00222 void o_attrib_remove(TOPLEVEL *toplevel, GList **list, OBJECT *remove)
00223 {
00224   OBJECT *attached_to;
00225 
00226   g_return_if_fail (remove != NULL);
00227 
00228   attached_to = remove->attached_to;
00229   remove->attached_to = NULL;
00230 
00231   *list = g_list_remove (*list, remove);
00232 
00233   o_attrib_emit_attribs_changed (toplevel, attached_to);
00234 }
00235 
00247 GList *o_read_attribs (TOPLEVEL *toplevel,
00248                        OBJECT *object_to_get_attribs,
00249                        TextBuffer *tb,
00250                        unsigned int release_ver, unsigned int fileformat_ver, GError ** err)
00251 {
00252   GList *object_list = NULL;
00253   OBJECT *new_obj;
00254   const char *line = NULL;
00255   char objtype;
00256   int ATTACH=FALSE;
00257 
00258   while (1) {
00259 
00260     line = s_textbuffer_next_line (tb);
00261     if (line == NULL) break;
00262 
00263     sscanf(line, "%c", &objtype);
00264     switch (objtype) {
00265 
00266       case(OBJ_LINE):
00267         if ((new_obj = o_line_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00268           goto error;
00269         object_list = g_list_prepend (object_list, new_obj);
00270         break;
00271 
00272 
00273       case(OBJ_NET):
00274         if ((new_obj = o_net_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00275           goto error;
00276         object_list = g_list_prepend (object_list, new_obj);
00277         break;
00278 
00279       case(OBJ_BUS):
00280         if ((new_obj = o_bus_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00281           goto error;
00282         object_list = g_list_prepend (object_list, new_obj);
00283         break;
00284 
00285       case(OBJ_BOX):
00286         if ((new_obj = o_box_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00287           goto error;
00288         object_list = g_list_prepend (object_list, new_obj);
00289         break;
00290 
00291       case(OBJ_CIRCLE):
00292         if ((new_obj = o_circle_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00293           goto error;
00294         object_list = g_list_prepend (object_list, new_obj);
00295         break;
00296 
00297       case(OBJ_COMPLEX):
00298       case(OBJ_PLACEHOLDER):
00299         if ((new_obj = o_complex_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00300           goto error;
00301         object_list = g_list_prepend (object_list, new_obj);
00302         break;
00303 
00304       case(OBJ_PATH):
00305         new_obj = o_path_read (toplevel, line, tb, release_ver, fileformat_ver, err);
00306         if (new_obj == NULL)
00307           goto error;
00308         object_list = g_list_prepend (object_list, new_obj);
00309         break;
00310 
00311       case(OBJ_PIN):
00312         if ((new_obj = o_pin_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00313           goto error;
00314         object_list = g_list_prepend (object_list, new_obj);
00315         break;
00316 
00317       case(OBJ_ARC):
00318         if ((new_obj = o_arc_read (toplevel, line, release_ver, fileformat_ver, err)) == NULL)
00319           goto error;
00320         object_list = g_list_prepend (object_list, new_obj);
00321         break;
00322 
00323       case(OBJ_TEXT):
00324         new_obj = o_text_read (toplevel, line, tb, release_ver, fileformat_ver, err);
00325         if (new_obj == NULL)
00326           goto error;
00327         object_list = g_list_prepend (object_list, new_obj);
00328         ATTACH=TRUE;
00329 
00330         break;
00331 
00332       case(ENDATTACH_ATTR):
00333         return object_list;
00334         break;
00335     }
00336 
00337     if (ATTACH) {
00338       o_attrib_attach (toplevel, new_obj, object_to_get_attribs, FALSE);
00339       ATTACH=FALSE;
00340     } else {
00341       g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Tried to attach a non-text item as an attribute"));
00342       goto error;
00343     }
00344   }
00345 
00346   /* The attribute list wasn't terminated, so it's a parse error! */
00347   g_set_error (err, EDA_ERROR, EDA_ERROR_PARSE,
00348                _("Unexpected end-of-file in attribute list"));
00349 
00350 error:
00351   s_delete_object_glist(toplevel, object_list);
00352   return NULL;
00353 }
00354 
00355 
00378 gboolean
00379 o_attrib_string_get_name_value (const gchar *string, gchar **name_ptr, gchar **value_ptr)
00380 {
00381   gchar *ptr, *prev_char, *next_char;
00382 
00383   if (name_ptr != NULL)
00384     *name_ptr = NULL;
00385   if (value_ptr != NULL)
00386     *value_ptr = NULL;
00387 
00388   g_return_val_if_fail (string != NULL, FALSE);
00389 
00390   ptr = g_utf8_strchr (string, -1, g_utf8_get_char ("="));
00391   if (ptr == NULL) {
00392     return FALSE;
00393   }
00394 
00395   prev_char = g_utf8_find_prev_char (string, ptr);
00396   next_char = g_utf8_find_next_char (ptr, NULL);
00397   if (prev_char == NULL || *prev_char == ' ' ||
00398       next_char == NULL || *next_char == ' ' || *next_char == '\0' ) {
00399     return FALSE;
00400   }
00401 
00402   if (name_ptr != NULL) {
00403     *name_ptr = g_strndup (string, (ptr - string));
00404   }
00405 
00406   if (value_ptr != NULL) {
00407     *value_ptr = g_strdup (next_char);
00408   }
00409 
00410   return TRUE;
00411 }
00412 
00413 
00423 gboolean
00424 o_attrib_get_name_value (OBJECT *attrib, gchar **name_ptr, gchar **value_ptr)
00425 {
00426   g_return_val_if_fail (attrib->type == OBJ_TEXT, FALSE);
00427 
00428   return o_attrib_string_get_name_value (attrib->text->string,
00429                                          name_ptr, value_ptr);
00430 }
00431 
00432 
00443 GList *o_attrib_find_floating_attribs (const GList *list)
00444 {
00445   GList *floating_attributes = NULL;
00446   const GList *iter;
00447   OBJECT *o_current;
00448 
00449   for (iter = list; iter != NULL; iter = g_list_next (iter)) {
00450     o_current = iter->data;
00451 
00452     /* Skip non text objects, attached attributes and text which doesn't
00453      * constitute a valid attributes (e.g. general text placed on the page)
00454      */
00455     if (o_current->type == OBJ_TEXT &&
00456         o_current->attached_to == NULL &&
00457         o_attrib_get_name_value (o_current, NULL, NULL)) {
00458 
00459       floating_attributes = g_list_prepend (floating_attributes, o_current);
00460     }
00461   }
00462 
00463   return g_list_reverse (floating_attributes);
00464 }
00465 
00466 
00479 OBJECT *o_attrib_find_attrib_by_name (const GList *list, char *name, int count)
00480 {
00481   OBJECT *a_current;
00482   const GList *iter;
00483   char *found_name;
00484   int internal_counter = 0;
00485 
00486   for (iter = list; iter != NULL; iter = g_list_next (iter)) {
00487     a_current = iter->data;
00488 
00489     g_return_val_if_fail (a_current->type == OBJ_TEXT, NULL);
00490 
00491     if (!o_attrib_get_name_value (a_current, &found_name, NULL))
00492       continue;
00493 
00494     if (strcmp (name, found_name) == 0) {
00495       if (internal_counter == count) {
00496         g_free (found_name);
00497         return a_current;
00498       }
00499       internal_counter++;
00500     }
00501 
00502     g_free (found_name);
00503   }
00504 
00505   return NULL;
00506 }
00507 
00508 
00521 static char *o_attrib_search_attrib_list_by_name (const GList *list, char *name, int counter)
00522 {
00523   OBJECT *attrib;
00524   char *value = NULL;
00525 
00526   attrib = o_attrib_find_attrib_by_name (list, name, counter);
00527 
00528   if (attrib != NULL)
00529     o_attrib_get_name_value (attrib, NULL, &value);
00530 
00531   return value;
00532 }
00533 
00534 
00550 char *o_attrib_search_floating_attribs_by_name (const GList *list, char *name, int counter)
00551 {
00552   char *result;
00553   GList *attributes;
00554 
00555   attributes = o_attrib_find_floating_attribs (list);
00556   result = o_attrib_search_attrib_list_by_name (attributes, name, counter);
00557   g_list_free (attributes);
00558 
00559   return result;
00560 }
00561 
00562 
00578 char *o_attrib_search_attached_attribs_by_name (OBJECT *object, char *name, int counter)
00579 {
00580   return o_attrib_search_attrib_list_by_name (object->attribs, name, counter);
00581 }
00582 
00583 
00599 char *o_attrib_search_inherited_attribs_by_name (OBJECT *object, char *name, int counter)
00600 {
00601   g_return_val_if_fail (object->type == OBJ_COMPLEX ||
00602                         object->type == OBJ_PLACEHOLDER, NULL);
00603 
00604   return o_attrib_search_floating_attribs_by_name (object->complex->prim_objs, name, counter);
00605 }
00606 
00607 
00623 char *o_attrib_search_object_attribs_by_name (OBJECT *object, char *name, int counter)
00624 {
00625   char *result;
00626   GList *attributes;
00627 
00628   attributes = o_attrib_return_attribs (object);
00629   result = o_attrib_search_attrib_list_by_name (attributes, name, counter);
00630   g_list_free (attributes);
00631 
00632   return result;
00633 }
00634 
00635 
00650 GList * o_attrib_return_attribs (OBJECT *object)
00651 {
00652   GList *attribs = NULL;
00653   GList *inherited_attribs;
00654   OBJECT *a_current;
00655   GList *a_iter;
00656 
00657   g_return_val_if_fail (object != NULL, NULL);
00658 
00659   /* Directly attached attributes */
00660   for (a_iter = object->attribs; a_iter != NULL;
00661        a_iter = g_list_next (a_iter)) {
00662     a_current = a_iter->data;
00663 
00664     if (a_current->type != OBJ_TEXT)
00665       continue;
00666 
00667     /* Don't add invalid attributes to the list */
00668     if (!o_attrib_get_name_value (a_current, NULL, NULL))
00669       continue;
00670 
00671     attribs = g_list_prepend (attribs, a_current);
00672   }
00673 
00674   attribs = g_list_reverse (attribs);
00675 
00676   /* Inherited attributes (inside complex objects) */
00677   if (object->type == OBJ_COMPLEX ||
00678       object->type == OBJ_PLACEHOLDER) {
00679 
00680     inherited_attribs =
00681       o_attrib_find_floating_attribs (object->complex->prim_objs);
00682 
00683     attribs = g_list_concat (attribs, inherited_attribs);
00684   }
00685 
00686   return attribs;
00687 }
00688 
00689 
00698 int o_attrib_is_inherited (OBJECT *attrib)
00699 {
00700   return (attrib->attached_to == NULL &&
00701           attrib->parent != NULL);
00702 }
00703 
00704 
00705 typedef struct {
00706   AttribsChangedFunc func;
00707   void *data;
00708 } AttribsChangedHook;
00709 
00710 
00711 void o_attrib_append_attribs_changed_hook (TOPLEVEL *toplevel,
00712                                            AttribsChangedFunc func,
00713                                            void *data)
00714 {
00715   AttribsChangedHook *new_hook;
00716 
00717   new_hook = g_new0 (AttribsChangedHook, 1);
00718   new_hook->func = func;
00719   new_hook->data = data;
00720 
00721   toplevel->attribs_changed_hooks =
00722     g_list_append (toplevel->attribs_changed_hooks, new_hook);
00723 }
00724 
00725 
00726 static void call_attribs_changed_hook (gpointer data, gpointer user_data)
00727 {
00728   AttribsChangedHook *hook = data;
00729   OBJECT *object = user_data;
00730 
00731   hook->func (hook->data, object);
00732 }
00733 
00734 
00735 void o_attrib_emit_attribs_changed (TOPLEVEL *toplevel, OBJECT *object)
00736 {
00737   if (object->attrib_notify_freeze_count > 0) {
00738     object->attrib_notify_pending = 1;
00739     return;
00740   }
00741 
00742 //  printf ("The attributes of object %p have changed\n", object);
00743 
00744   object->attrib_notify_pending = 0;
00745 
00746   g_list_foreach (toplevel->attribs_changed_hooks,
00747                   call_attribs_changed_hook, object);
00748 }
00749 
00750 void o_attrib_freeze_hooks (TOPLEVEL *toplevel, OBJECT *object)
00751 {
00752   object->attrib_notify_freeze_count ++;
00753 }
00754 
00755 void o_attrib_thaw_hooks (TOPLEVEL *toplevel, OBJECT *object)
00756 {
00757   g_return_if_fail (object->attrib_notify_freeze_count > 0);
00758 
00759   object->attrib_notify_freeze_count --;
00760 
00761   if (object->attrib_notify_freeze_count == 0 &&
00762       object->attrib_notify_pending)
00763     o_attrib_emit_attribs_changed (toplevel, object);
00764 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines