1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * umlattribute.c : refactored from uml.c, class.c to final use StdProps
5  *                  PROP_TYPE_DARRAY, a list where each element is a set
6  *                  of properies described by the same StdPropDesc
7  * Copyright (C) 2005 Hans Breuer
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <string.h>
29 
30 #include "uml.h"
31 #include "properties.h"
32 
33 extern PropEnumData _uml_visibilities[];
34 
35 static PropDescription umlattribute_props[] = {
36   { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
37   N_("Name"), NULL, NULL },
38   { "type", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
39   N_("Type"), NULL, NULL },
40   { "value", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
41   N_("Value"), NULL, NULL },
42   { "comment", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
43   N_("Comment"), NULL, NULL },
44   { "visibility", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
45   N_("Visibility"), NULL, _uml_visibilities },
46   { "abstract", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
47   N_("Abstract (?)"), NULL, NULL },
48   { "class_scope", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
49   N_("Class scope (static)"), NULL, NULL },
50 
51   PROP_DESC_END
52 };
53 
54 static PropOffset umlattribute_offsets[] = {
55   { "name", PROP_TYPE_STRING, offsetof(UMLAttribute, name) },
56   { "type", PROP_TYPE_STRING, offsetof(UMLAttribute, type) },
57   { "value", PROP_TYPE_STRING, offsetof(UMLAttribute, value) },
58   { "comment", PROP_TYPE_STRING, offsetof(UMLAttribute, comment) },
59   { "visibility", PROP_TYPE_ENUM, offsetof(UMLAttribute, visibility) },
60   { "abstract", PROP_TYPE_BOOL, offsetof(UMLAttribute, abstract) },
61   { "class_scope", PROP_TYPE_BOOL, offsetof(UMLAttribute, class_scope) },
62   { NULL, 0, 0 },
63 };
64 
65 
66 PropDescDArrayExtra umlattribute_extra = {
67   { umlattribute_props, umlattribute_offsets, "umlattribute" },
68   (NewRecordFunc)uml_attribute_new,
69   (FreeRecordFunc)uml_attribute_destroy
70 };
71 
72 
73 UMLAttribute *
uml_attribute_new(void)74 uml_attribute_new(void)
75 {
76   UMLAttribute *attr;
77   static gint next_id = 1;
78 
79   attr = g_new0(UMLAttribute, 1);
80   attr->internal_id = next_id++;
81   attr->name = g_strdup("");
82   attr->type = g_strdup("");
83   attr->value = NULL;
84   attr->comment = g_strdup("");
85   attr->visibility = UML_PUBLIC;
86   attr->abstract = FALSE;
87   attr->class_scope = FALSE;
88 #if 0 /* setup elsewhere */
89   attr->left_connection = g_new0(ConnectionPoint, 1);
90   attr->right_connection = g_new0(ConnectionPoint, 1);
91 #endif
92   return attr;
93 }
94 
95 /** Copy the data of an attribute into another, but not the connections.
96  * Frees up any strings in the attribute being copied into. */
97 void
uml_attribute_copy_into(UMLAttribute * attr,UMLAttribute * newattr)98 uml_attribute_copy_into(UMLAttribute *attr, UMLAttribute *newattr)
99 {
100   newattr->internal_id = attr->internal_id;
101   if (newattr->name != NULL) {
102     g_free(newattr->name);
103   }
104   newattr->name = g_strdup(attr->name);
105   if (newattr->type != NULL) {
106     g_free(newattr->type);
107   }
108   newattr->type = g_strdup(attr->type);
109 
110   if (newattr->value != NULL) {
111     g_free(newattr->value);
112   }
113   if (attr->value != NULL) {
114     newattr->value = g_strdup(attr->value);
115   } else {
116     newattr->value = NULL;
117   }
118 
119   if (newattr->comment != NULL) {
120     g_free(newattr->comment);
121   }
122   if (attr->comment != NULL)
123     newattr->comment = g_strdup (attr->comment);
124   else
125     newattr->comment = NULL;
126 
127   newattr->visibility = attr->visibility;
128   newattr->abstract = attr->abstract;
129   newattr->class_scope = attr->class_scope;
130 }
131 
132 /** Copy an attribute's content.
133  */
134 UMLAttribute *
uml_attribute_copy(UMLAttribute * attr)135 uml_attribute_copy(UMLAttribute *attr)
136 {
137   UMLAttribute *newattr;
138 
139   newattr = g_new0(UMLAttribute, 1);
140 
141   uml_attribute_copy_into(attr, newattr);
142 
143   return newattr;
144 }
145 
146 void
uml_attribute_destroy(UMLAttribute * attr)147 uml_attribute_destroy(UMLAttribute *attr)
148 {
149   g_free(attr->name);
150   g_free(attr->type);
151   if (attr->value != NULL)
152     g_free(attr->value);
153   if (attr->comment != NULL)
154     g_free(attr->comment);
155 #if 0 /* free'd elsewhere */
156   g_free(attr->left_connection);
157   g_free(attr->right_connection);
158 #endif
159   g_free(attr);
160 }
161 
162 void
uml_attribute_write(AttributeNode attr_node,UMLAttribute * attr)163 uml_attribute_write(AttributeNode attr_node, UMLAttribute *attr)
164 {
165   DataNode composite;
166 
167   composite = data_add_composite(attr_node, "umlattribute");
168 
169   data_add_string(composite_add_attribute(composite, "name"),
170 		  attr->name);
171   data_add_string(composite_add_attribute(composite, "type"),
172 		  attr->type);
173   data_add_string(composite_add_attribute(composite, "value"),
174 		  attr->value);
175   data_add_string(composite_add_attribute(composite, "comment"),
176 		  attr->comment);
177   data_add_enum(composite_add_attribute(composite, "visibility"),
178 		attr->visibility);
179   data_add_boolean(composite_add_attribute(composite, "abstract"),
180 		  attr->abstract);
181   data_add_boolean(composite_add_attribute(composite, "class_scope"),
182 		  attr->class_scope);
183 }
184 
185 /* Warning, the following *must* be strictly ASCII characters (or fix the
186    following code for UTF-8 cleanliness */
187 
188 char visible_char[] = { '+', '-', '#', ' ' };
189 
190 char *
uml_get_attribute_string(UMLAttribute * attribute)191 uml_get_attribute_string (UMLAttribute *attribute)
192 {
193   int len;
194   char *str;
195 
196   len = 1 + (attribute->name ? strlen (attribute->name) : 0)
197           + (attribute->type ? strlen (attribute->type) : 0);
198   if (attribute->name && attribute->name[0] && attribute->type && attribute->type[0]) {
199     len += 2;
200   }
201   if (attribute->value != NULL && attribute->value[0] != '\0') {
202     len += 3 + strlen (attribute->value);
203   }
204 
205   str = g_malloc (sizeof (char) * (len + 1));
206 
207   str[0] = visible_char[(int) attribute->visibility];
208   str[1] = 0;
209 
210   strcat (str, attribute->name ? attribute->name : "");
211   if (attribute->name && attribute->name[0] && attribute->type && attribute->type[0]) {
212     strcat (str, ": ");
213   }
214   strcat (str, attribute->type ? attribute->type : "");
215   if (attribute->value != NULL && attribute->value[0] != '\0') {
216     strcat (str, " = ");
217     strcat (str, attribute->value);
218   }
219 
220   g_assert (strlen (str) == len);
221 
222   return str;
223 }
224 
225 /*!
226  * The ownership of these connection points is quite complicated. Instead of being part of the UMLAttribute as one may expect
227   * at first, they are somewhat in between the DiaObject (see: DiaObject::connections and the concrete user, here UMLClass)
228   * and the UMLAttribute.
229   * But with taking undo state mangement into account it gets even worse. Deleted (to be restored connection points) live inside
230   * the UMLClassChange until they get reverted back to the object *or* get free'd by umlclass_change_free()
231   * Since the implementation of attributes/operations being settable via StdProps there are more places to keep this stuff
232   * consitent. So here comes a tolerant helper.
233   *
234   * NOTE: Same function as uml_operation_ensure_connection_points(), with C++ it would be a template function ;)
235  */
236 void
uml_attribute_ensure_connection_points(UMLAttribute * attr,DiaObject * obj)237 uml_attribute_ensure_connection_points (UMLAttribute* attr, DiaObject* obj)
238 {
239   if (!attr->left_connection)
240     attr->left_connection = g_new0(ConnectionPoint,1);
241   attr->left_connection->object = obj;
242   if (!attr->right_connection)
243     attr->right_connection = g_new0(ConnectionPoint,1);
244   attr->right_connection->object = obj;
245 }
246