1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
3 *
4 * umloperation.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 /*
25
26 classType = dia.get_object_type ("UML - Class")
27 operType = dia.get_object_type ("UML - Operation")
28 paramType = dia.get_object_type ("UML - Parameter")
29 for c in theClasses :
30 klass, h1, h2 = classType.create (0,0) # p.x, p.y
31 for f in theFunctions :
32 oper, _h1, _h2 = operType.create (0,0)
33 oper.properties["name"] = f.name
34 oper.properties["type"] = f.type
35
36 for p in f.parameters :
37 param, _h1, _h2 = paramType.create(0,0)
38 param.properties["name"] = p.name
39 param.properties["type"] = p.type
40
41 oper.insert(param, -1)
42 klass.insert(oper, -1)
43 layer.add_object(klass)
44
45 */
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50
51 #include <math.h>
52 #include <string.h>
53
54 #include "uml.h"
55 #include "properties.h"
56
57 extern PropEnumData _uml_visibilities[];
58 extern PropEnumData _uml_inheritances[];
59
60 static PropDescription umloperation_props[] = {
61 { "name", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
62 N_("Name"), NULL, NULL },
63 { "type", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
64 N_("Type"), NULL, NULL },
65 { "comment", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
66 N_("Comment"), NULL, NULL },
67 { "stereotype", PROP_TYPE_STRING, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
68 N_("Stereotype"), NULL, NULL },
69 /* visibility: public, protected, private (other languages?) */
70 { "visibility", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
71 N_("Visibility"), NULL, _uml_visibilities },
72 { "inheritance_type", PROP_TYPE_ENUM, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
73 N_("Inheritance type"), NULL, _uml_inheritances },
74 { "query", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
75 N_("Query (const)"), NULL, NULL },
76 { "class_scope", PROP_TYPE_BOOL, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
77 N_("Class scope (static)"), NULL, NULL },
78 { "parameters", PROP_TYPE_DARRAY, PROP_FLAG_VISIBLE | PROP_FLAG_OPTIONAL,
79 N_("Parameters"), NULL, NULL },
80
81 PROP_DESC_END
82 };
83
84 static PropOffset umloperation_offsets[] = {
85 { "name", PROP_TYPE_STRING, offsetof(UMLOperation, name) },
86 { "type", PROP_TYPE_STRING, offsetof(UMLOperation, type) },
87 { "comment", PROP_TYPE_STRING, offsetof(UMLOperation, comment) },
88 { "stereotype", PROP_TYPE_STRING, offsetof(UMLOperation, stereotype) },
89 { "visibility", PROP_TYPE_ENUM, offsetof(UMLOperation, visibility) },
90 { "inheritance_type", PROP_TYPE_ENUM, offsetof(UMLOperation, inheritance_type) },
91 { "query", PROP_TYPE_BOOL, offsetof(UMLOperation, query) },
92 { "class_scope", PROP_TYPE_BOOL, offsetof(UMLOperation, class_scope) },
93 { "parameters", PROP_TYPE_DARRAY, offsetof(UMLOperation, parameters) },
94 { NULL, 0, 0 },
95 };
96
97 PropDescDArrayExtra umloperation_extra = {
98 { umloperation_props, umloperation_offsets, "umloperation" },
99 (NewRecordFunc)uml_operation_new,
100 (FreeRecordFunc)uml_operation_destroy
101 };
102
103 UMLOperation *
uml_operation_new(void)104 uml_operation_new(void)
105 {
106 UMLOperation *op;
107 static gint next_id = 1;
108
109 op = g_new0(UMLOperation, 1);
110 op->internal_id = next_id++;
111 op->name = g_strdup("");
112 op->comment = g_strdup("");
113 op->visibility = UML_PUBLIC;
114 op->inheritance_type = UML_LEAF;
115
116 #if 0 /* setup elsewhere */
117 op->left_connection = g_new0(ConnectionPoint, 1);
118 op->right_connection = g_new0(ConnectionPoint, 1);
119 #endif
120 return op;
121 }
122
123 void
uml_operation_copy_into(UMLOperation * srcop,UMLOperation * destop)124 uml_operation_copy_into(UMLOperation *srcop, UMLOperation *destop)
125 {
126 UMLParameter *param;
127 UMLParameter *newparam;
128 GList *list;
129
130 destop->internal_id = srcop->internal_id;
131
132 if (destop->name != NULL) {
133 g_free(destop->name);
134 }
135 destop->name = g_strdup(srcop->name);
136
137 if (destop->type != NULL) {
138 g_free(destop->type);
139 }
140 if (srcop->type != NULL) {
141 destop->type = g_strdup(srcop->type);
142 } else {
143 destop->type = NULL;
144 }
145
146 if (destop->stereotype != NULL) {
147 g_free(destop->stereotype);
148 }
149 if(srcop->stereotype != NULL) {
150 destop->stereotype = g_strdup(srcop->stereotype);
151 } else {
152 destop->stereotype = NULL;
153 }
154
155 if (destop->comment != NULL) {
156 g_free(destop->comment);
157 }
158 if (srcop->comment != NULL) {
159 destop->comment = g_strdup(srcop->comment);
160 } else {
161 destop->comment = NULL;
162 }
163
164 destop->visibility = srcop->visibility;
165 destop->class_scope = srcop->class_scope;
166 destop->inheritance_type = srcop->inheritance_type;
167 destop->query = srcop->query;
168
169 list = destop->parameters;
170 while (list != NULL) {
171 param = (UMLParameter *)list->data;
172 uml_parameter_destroy(param);
173 list = g_list_next(list);
174 }
175 destop->parameters = NULL;
176 list = srcop->parameters;
177 while (list != NULL) {
178 param = (UMLParameter *)list->data;
179
180 newparam = g_new0(UMLParameter, 1);
181 newparam->name = g_strdup(param->name);
182 newparam->type = g_strdup(param->type);
183 newparam->comment = g_strdup(param->comment);
184
185 if (param->value != NULL)
186 newparam->value = g_strdup(param->value);
187 else
188 newparam->value = NULL;
189 newparam->kind = param->kind;
190
191 destop->parameters = g_list_append(destop->parameters, newparam);
192
193 list = g_list_next(list);
194 }
195 }
196
197 UMLOperation *
uml_operation_copy(UMLOperation * op)198 uml_operation_copy(UMLOperation *op)
199 {
200 UMLOperation *newop;
201
202 newop = g_new0(UMLOperation, 1);
203
204 uml_operation_copy_into(op, newop);
205 #if 0 /* setup elsewhere */
206 newop->left_connection = g_new0(ConnectionPoint,1);
207 *newop->left_connection = *op->left_connection;
208 newop->left_connection->object = NULL; /* must be setup later */
209
210 newop->right_connection = g_new0(ConnectionPoint,1);
211 *newop->right_connection = *op->right_connection;
212 newop->right_connection->object = NULL; /* must be setup later */
213 #endif
214 return newop;
215 }
216
217 void
uml_operation_destroy(UMLOperation * op)218 uml_operation_destroy(UMLOperation *op)
219 {
220 GList *list;
221 UMLParameter *param;
222
223 g_free(op->name);
224 if (op->type != NULL)
225 g_free(op->type);
226 if (op->stereotype != NULL)
227 g_free(op->stereotype);
228
229 g_free(op->comment);
230
231 list = op->parameters;
232 while (list != NULL) {
233 param = (UMLParameter *)list->data;
234 uml_parameter_destroy(param);
235 list = g_list_next(list);
236 }
237 if (op->wrappos) {
238 g_list_free(op->wrappos);
239 }
240
241 #if 0 /* freed elsewhere */
242 /* These are merely temporary reminders, don't need to unconnect */
243 g_free(op->left_connection);
244 g_free(op->right_connection);
245 #endif
246 g_free(op);
247 }
248
249 void
uml_operation_write(AttributeNode attr_node,UMLOperation * op)250 uml_operation_write(AttributeNode attr_node, UMLOperation *op)
251 {
252 GList *list;
253 UMLParameter *param;
254 DataNode composite;
255 DataNode composite2;
256 AttributeNode attr_node2;
257
258 composite = data_add_composite(attr_node, "umloperation");
259
260 data_add_string(composite_add_attribute(composite, "name"),
261 op->name);
262 data_add_string(composite_add_attribute(composite, "stereotype"),
263 op->stereotype);
264 data_add_string(composite_add_attribute(composite, "type"),
265 op->type);
266 data_add_enum(composite_add_attribute(composite, "visibility"),
267 op->visibility);
268 data_add_string(composite_add_attribute(composite, "comment"),
269 op->comment);
270 /* Backward compatibility */
271 data_add_boolean(composite_add_attribute(composite, "abstract"),
272 op->inheritance_type == UML_ABSTRACT);
273 data_add_enum(composite_add_attribute(composite, "inheritance_type"),
274 op->inheritance_type);
275 data_add_boolean(composite_add_attribute(composite, "query"),
276 op->query);
277 data_add_boolean(composite_add_attribute(composite, "class_scope"),
278 op->class_scope);
279
280 attr_node2 = composite_add_attribute(composite, "parameters");
281
282 list = op->parameters;
283 while (list != NULL) {
284 param = (UMLParameter *) list->data;
285
286 composite2 = data_add_composite(attr_node2, "umlparameter");
287
288 data_add_string(composite_add_attribute(composite2, "name"),
289 param->name);
290 data_add_string(composite_add_attribute(composite2, "type"),
291 param->type);
292 data_add_string(composite_add_attribute(composite2, "value"),
293 param->value);
294 data_add_string(composite_add_attribute(composite2, "comment"),
295 param->comment);
296 data_add_enum(composite_add_attribute(composite2, "kind"),
297 param->kind);
298 list = g_list_next(list);
299 }
300 }
301
302 extern char visible_char[];
303
304 char *
uml_get_operation_string(UMLOperation * operation)305 uml_get_operation_string (UMLOperation *operation)
306 {
307 int len;
308 char *str;
309 GList *list;
310 UMLParameter *param;
311
312 /* Calculate length: */
313 len = 1 + (operation->name ? strlen (operation->name) : 0) + 1;
314 if(operation->stereotype != NULL && operation->stereotype[0] != '\0') {
315 len += 5 + strlen (operation->stereotype);
316 }
317
318 list = operation->parameters;
319 while (list != NULL) {
320 param = (UMLParameter *) list->data;
321 list = g_list_next (list);
322
323 switch(param->kind)
324 {
325 case UML_UNDEF_KIND:
326 break;
327 case UML_IN:
328 len += 3;
329 break;
330 case UML_OUT:
331 len += 4;
332 break;
333 case UML_INOUT:
334 len += 6;
335 break;
336 }
337 len += (param->name ? strlen (param->name) : 0);
338 if (param->type != NULL) {
339 len += strlen (param->type);
340 if (param->type[0] && param->name[0]) {
341 len += 1;
342 }
343 }
344 if (param->value != NULL && param->value[0] != '\0') {
345 len += 1 + strlen (param->value);
346 }
347
348 if (list != NULL) {
349 len += 1; /* ',' */
350 }
351 }
352
353 len += 1; /* ')' */
354 if (operation->type != NULL && operation->type[0]) {
355 len += 2 + strlen (operation->type);
356 }
357 if(operation->query != 0) {
358 len += 6;
359 }
360
361 /* generate string: */
362 str = g_malloc (sizeof (char) * (len + 1));
363
364 str[0] = visible_char[(int) operation->visibility];
365 str[1] = 0;
366
367 if(operation->stereotype != NULL && operation->stereotype[0] != '\0') {
368 strcat(str, UML_STEREOTYPE_START);
369 strcat(str, operation->stereotype);
370 strcat(str, UML_STEREOTYPE_END);
371 strcat(str, " ");
372 }
373
374 strcat (str, operation->name ? operation->name : "");
375 strcat (str, "(");
376
377 list = operation->parameters;
378 while (list != NULL) {
379 param = (UMLParameter *) list->data;
380 list = g_list_next (list);
381
382 switch(param->kind)
383 {
384 case UML_UNDEF_KIND:
385 break;
386 case UML_IN:
387 strcat (str, "in ");
388 break;
389 case UML_OUT:
390 strcat (str, "out ");
391 break;
392 case UML_INOUT:
393 strcat (str, "inout ");
394 break;
395 }
396 strcat (str, param->name ? param->name : "");
397
398 if (param->type != NULL) {
399 if (param->type[0] && param->name[0]) {
400 strcat (str, ":");
401 }
402 strcat (str, param->type);
403 }
404
405 if (param->value != NULL && param->value[0] != '\0') {
406 strcat (str, "=");
407 strcat (str, param->value);
408 }
409
410 if (list != NULL) {
411 strcat (str, ",");
412 }
413 }
414 strcat (str, ")");
415
416 if (operation->type != NULL &&
417 operation->type[0]) {
418 strcat (str, ": ");
419 strcat (str, operation->type);
420 }
421
422 if (operation->query != 0) {
423 strcat(str, " const");
424 }
425
426 g_assert (strlen (str) == len);
427
428 return str;
429 }
430
431 /*!
432 * The ownership of these connection points is quite complicated. Instead of being part of the UMLOperation as one may expect
433 * at first, they are somewhat in between the DiaObject (see: DiaObject::connections and the concrete user, here UMLClass)
434 * and the UMLOperation.
435 * But with taking undo state mangement into account it gets even worse. Deleted (to be restored connection points) live inside
436 * the UMLClassChange until they get reverted back to the object *or* get free'd by umlclass_change_free()
437 * Since the implementation of attributes/operations being settable via StdProps there are more places to keep this stuff
438 * consitent. So here comes a tolerant helper.
439 *
440 * NOTE: Same function as uml_attribute_ensure_connection_points(), with C++ it would be a template function ;)
441 */
442 void
uml_operation_ensure_connection_points(UMLOperation * op,DiaObject * obj)443 uml_operation_ensure_connection_points (UMLOperation* op, DiaObject* obj)
444 {
445 if (!op->left_connection)
446 op->left_connection = g_new0(ConnectionPoint,1);
447 op->left_connection->object = obj;
448 if (!op->right_connection)
449 op->right_connection = g_new0(ConnectionPoint,1);
450 op->right_connection->object = obj;
451 }
452