2006-12-05 David Lodge <dave@cirt.net>
[dia.git] / objects / UML / umloperation.c
blobb07f42d5f83e2c788f40ac312b354c29974c203f
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
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
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.
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.
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.
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
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
41 oper.insert(param, -1)
42 klass.insert(oper, -1)
43 layer.add_object(klass)
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
51 #include <math.h>
52 #include <string.h>
54 #include "uml.h"
55 #include "properties.h"
57 extern PropEnumData _uml_visibilities[];
58 extern PropEnumData _uml_inheritances[];
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 },
81 PROP_DESC_END
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 { "class_scope", PROP_TYPE_BOOL, offsetof(UMLOperation, class_scope) },
92 { "parameters", PROP_TYPE_DARRAY, offsetof(UMLOperation, parameters) },
93 { NULL, 0, 0 },
96 PropDescDArrayExtra umloperation_extra = {
97 { umloperation_props, umloperation_offsets, "umloperation" },
98 (NewRecordFunc)uml_operation_new,
99 (FreeRecordFunc)uml_operation_destroy
102 UMLOperation *
103 uml_operation_new(void)
105 UMLOperation *op;
106 static gint next_id = 1;
108 op = g_new0(UMLOperation, 1);
109 op->internal_id = next_id++;
110 op->name = g_strdup("");
111 op->comment = g_strdup("");
112 op->visibility = UML_PUBLIC;
113 op->inheritance_type = UML_LEAF;
115 #if 0 /* setup elsewhere */
116 op->left_connection = g_new0(ConnectionPoint, 1);
117 op->right_connection = g_new0(ConnectionPoint, 1);
118 #endif
119 return op;
122 void
123 uml_operation_copy_into(UMLOperation *srcop, UMLOperation *destop)
125 UMLParameter *param;
126 UMLParameter *newparam;
127 GList *list;
129 destop->internal_id = srcop->internal_id;
131 if (destop->name != NULL) {
132 g_free(destop->name);
134 destop->name = g_strdup(srcop->name);
136 if (destop->type != NULL) {
137 g_free(destop->type);
139 if (srcop->type != NULL) {
140 destop->type = g_strdup(srcop->type);
141 } else {
142 destop->type = NULL;
145 if (destop->stereotype != NULL) {
146 g_free(destop->stereotype);
148 if(srcop->stereotype != NULL) {
149 destop->stereotype = g_strdup(srcop->stereotype);
150 } else {
151 destop->stereotype = NULL;
154 if (destop->comment != NULL) {
155 g_free(destop->comment);
157 if (srcop->comment != NULL) {
158 destop->comment = g_strdup(srcop->comment);
159 } else {
160 destop->comment = NULL;
163 destop->visibility = srcop->visibility;
164 destop->class_scope = srcop->class_scope;
165 destop->inheritance_type = srcop->inheritance_type;
166 destop->query = srcop->query;
168 list = destop->parameters;
169 while (list != NULL) {
170 param = (UMLParameter *)list->data;
171 uml_parameter_destroy(param);
172 list = g_list_next(list);
174 destop->parameters = NULL;
175 list = srcop->parameters;
176 while (list != NULL) {
177 param = (UMLParameter *)list->data;
179 newparam = g_new0(UMLParameter, 1);
180 newparam->name = g_strdup(param->name);
181 newparam->type = g_strdup(param->type);
182 newparam->comment = g_strdup(param->comment);
184 if (param->value != NULL)
185 newparam->value = g_strdup(param->value);
186 else
187 newparam->value = NULL;
188 newparam->kind = param->kind;
190 destop->parameters = g_list_append(destop->parameters, newparam);
192 list = g_list_next(list);
196 UMLOperation *
197 uml_operation_copy(UMLOperation *op)
199 UMLOperation *newop;
201 newop = g_new0(UMLOperation, 1);
203 uml_operation_copy_into(op, newop);
204 #if 0 /* setup elsewhere */
205 newop->left_connection = g_new0(ConnectionPoint,1);
206 *newop->left_connection = *op->left_connection;
207 newop->left_connection->object = NULL; /* must be setup later */
209 newop->right_connection = g_new0(ConnectionPoint,1);
210 *newop->right_connection = *op->right_connection;
211 newop->right_connection->object = NULL; /* must be setup later */
212 #endif
213 return newop;
216 void
217 uml_operation_destroy(UMLOperation *op)
219 GList *list;
220 UMLParameter *param;
222 g_free(op->name);
223 if (op->type != NULL)
224 g_free(op->type);
225 if (op->stereotype != NULL)
226 g_free(op->stereotype);
228 g_free(op->comment);
230 list = op->parameters;
231 while (list != NULL) {
232 param = (UMLParameter *)list->data;
233 uml_parameter_destroy(param);
234 list = g_list_next(list);
236 if (op->wrappos) {
237 g_list_free(op->wrappos);
240 #if 0 /* freed elsewhere */
241 /* These are merely temporary reminders, don't need to unconnect */
242 g_free(op->left_connection);
243 g_free(op->right_connection);
244 #endif
245 g_free(op);
248 void
249 uml_operation_write(AttributeNode attr_node, UMLOperation *op)
251 GList *list;
252 UMLParameter *param;
253 DataNode composite;
254 DataNode composite2;
255 AttributeNode attr_node2;
257 composite = data_add_composite(attr_node, "umloperation");
259 data_add_string(composite_add_attribute(composite, "name"),
260 op->name);
261 data_add_string(composite_add_attribute(composite, "stereotype"),
262 op->stereotype);
263 data_add_string(composite_add_attribute(composite, "type"),
264 op->type);
265 data_add_enum(composite_add_attribute(composite, "visibility"),
266 op->visibility);
267 data_add_string(composite_add_attribute(composite, "comment"),
268 op->comment);
269 /* Backward compatibility */
270 data_add_boolean(composite_add_attribute(composite, "abstract"),
271 op->inheritance_type == UML_ABSTRACT);
272 data_add_enum(composite_add_attribute(composite, "inheritance_type"),
273 op->inheritance_type);
274 data_add_boolean(composite_add_attribute(composite, "query"),
275 op->query);
276 data_add_boolean(composite_add_attribute(composite, "class_scope"),
277 op->class_scope);
279 attr_node2 = composite_add_attribute(composite, "parameters");
281 list = op->parameters;
282 while (list != NULL) {
283 param = (UMLParameter *) list->data;
285 composite2 = data_add_composite(attr_node2, "umlparameter");
287 data_add_string(composite_add_attribute(composite2, "name"),
288 param->name);
289 data_add_string(composite_add_attribute(composite2, "type"),
290 param->type);
291 data_add_string(composite_add_attribute(composite2, "value"),
292 param->value);
293 data_add_string(composite_add_attribute(composite2, "comment"),
294 param->comment);
295 data_add_enum(composite_add_attribute(composite2, "kind"),
296 param->kind);
297 list = g_list_next(list);
301 extern char visible_char[];
303 char *
304 uml_get_operation_string (UMLOperation *operation)
306 int len;
307 char *str;
308 GList *list;
309 UMLParameter *param;
311 /* Calculate length: */
312 len = 1 + strlen (operation->name) + 1;
313 if(operation->stereotype != NULL && operation->stereotype[0] != '\0') {
314 len += 5 + strlen (operation->stereotype);
317 list = operation->parameters;
318 while (list != NULL) {
319 param = (UMLParameter *) list->data;
320 list = g_list_next (list);
322 switch(param->kind)
324 case UML_UNDEF_KIND:
325 break;
326 case UML_IN:
327 len += 3;
328 break;
329 case UML_OUT:
330 len += 4;
331 break;
332 case UML_INOUT:
333 len += 6;
334 break;
336 len += strlen (param->name);
337 if (param->type != NULL) {
338 len += strlen (param->type);
339 if (param->type[0] && param->name[0]) {
340 len += 1;
343 if (param->value != NULL && param->value[0] != '\0') {
344 len += 1 + strlen (param->value);
347 if (list != NULL) {
348 len += 1; /* ',' */
352 len += 1; /* ')' */
353 if (operation->type != NULL && operation->type[0]) {
354 len += 2 + strlen (operation->type);
356 if(operation->query != 0) {
357 len += 6;
360 /* generate string: */
361 str = g_malloc (sizeof (char) * (len + 1));
363 str[0] = visible_char[(int) operation->visibility];
364 str[1] = 0;
366 if(operation->stereotype != NULL && operation->stereotype[0] != '\0') {
367 strcat(str, UML_STEREOTYPE_START);
368 strcat(str, operation->stereotype);
369 strcat(str, UML_STEREOTYPE_END);
370 strcat(str, " ");
373 strcat (str, operation->name);
374 strcat (str, "(");
376 list = operation->parameters;
377 while (list != NULL) {
378 param = (UMLParameter *) list->data;
379 list = g_list_next (list);
381 switch(param->kind)
383 case UML_UNDEF_KIND:
384 break;
385 case UML_IN:
386 strcat (str, "in ");
387 break;
388 case UML_OUT:
389 strcat (str, "out ");
390 break;
391 case UML_INOUT:
392 strcat (str, "inout ");
393 break;
395 strcat (str, param->name);
397 if (param->type != NULL) {
398 if (param->type[0] && param->name[0]) {
399 strcat (str, ":");
401 strcat (str, param->type);
404 if (param->value != NULL && param->value[0] != '\0') {
405 strcat (str, "=");
406 strcat (str, param->value);
409 if (list != NULL) {
410 strcat (str, ",");
413 strcat (str, ")");
415 if (operation->type != NULL &&
416 operation->type[0]) {
417 strcat (str, ": ");
418 strcat (str, operation->type);
421 if (operation->query != 0) {
422 strcat(str, " const");
425 g_assert (strlen (str) == len);
427 return str;
431 * The ownership of these connection points is quite complicated. Instead of being part of the UMLOperation as one may expect
432 * at first, they are somewhat in between the DiaObject (see: DiaObject::connections and the concrete user, here UMLClass)
433 * and the UMLOperation.
434 * But with taking undo state mangement into account it gets even worse. Deleted (to be restored connection points) live inside
435 * the UMLClassChange until they get reverted back to the object *or* get free'd by umlclass_change_free()
436 * Since the implementation of attributes/operations being settable via StdProps there are more places to keep this stuff
437 * consitent. So here comes a tolerant helper.
439 * NOTE: Same function as uml_attribute_ensure_connection_points(), with C++ it would be a template function ;)
441 void
442 uml_operation_ensure_connection_points (UMLOperation* op, DiaObject* obj)
444 if (!op->left_connection)
445 op->left_connection = g_new0(ConnectionPoint,1);
446 op->left_connection->object = obj;
447 if (!op->right_connection)
448 op->right_connection = g_new0(ConnectionPoint,1);
449 op->right_connection->object = obj;