1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * Purpose: This file contains implementation of the "class" code.
34 #include "diarenderer.h"
35 #include "attributes.h"
36 #include "properties.h"
41 #include "pixmaps/umlclass.xpm"
45 #define UMLCLASS_BORDER 0.1
46 #define UMLCLASS_UNDERLINEWIDTH 0.05
48 static real
umlclass_distance_from(UMLClass
*umlclass
, Point
*point
);
49 static void umlclass_select(UMLClass
*umlclass
, Point
*clicked_point
,
50 DiaRenderer
*interactive_renderer
);
51 static ObjectChange
* umlclass_move_handle(UMLClass
*umlclass
, Handle
*handle
,
52 Point
*to
, ConnectionPoint
*cp
, HandleMoveReason reason
, ModifierKeys modifiers
);
53 static ObjectChange
* umlclass_move(UMLClass
*umlclass
, Point
*to
);
54 static void umlclass_draw(UMLClass
*umlclass
, DiaRenderer
*renderer
);
55 static DiaObject
*umlclass_create(Point
*startpoint
,
59 static void umlclass_destroy(UMLClass
*umlclass
);
60 static DiaObject
*umlclass_copy(UMLClass
*umlclass
);
62 static void umlclass_save(UMLClass
*umlclass
, ObjectNode obj_node
,
63 const char *filename
);
64 static DiaObject
*umlclass_load(ObjectNode obj_node
, int version
,
65 const char *filename
);
67 static DiaMenu
* umlclass_object_menu(DiaObject
*obj
, Point
*p
);
68 static ObjectChange
*umlclass_show_comments_callback(DiaObject
*obj
, Point
*pos
, gpointer data
);
70 static PropDescription
*umlclass_describe_props(UMLClass
*umlclass
);
71 static void umlclass_get_props(UMLClass
*umlclass
, GPtrArray
*props
);
72 static void umlclass_set_props(UMLClass
*umlclass
, GPtrArray
*props
);
74 static void fill_in_fontdata(UMLClass
*umlclass
);
75 static int umlclass_num_dynamic_connectionpoints(UMLClass
*class);
77 static ObjectTypeOps umlclass_type_ops
=
79 (CreateFunc
) umlclass_create
,
80 (LoadFunc
) umlclass_load
,
81 (SaveFunc
) umlclass_save
84 DiaObjectType umlclass_type
=
86 "UML - Class", /* name */
88 (char **) umlclass_xpm
, /* pixmap */
90 ¨class_type_ops
/* ops */
93 static ObjectOps umlclass_ops
= {
94 (DestroyFunc
) umlclass_destroy
,
95 (DrawFunc
) umlclass_draw
,
96 (DistanceFunc
) umlclass_distance_from
,
97 (SelectFunc
) umlclass_select
,
98 (CopyFunc
) umlclass_copy
,
99 (MoveFunc
) umlclass_move
,
100 (MoveHandleFunc
) umlclass_move_handle
,
101 (GetPropertiesFunc
) umlclass_get_properties
,
102 (ApplyPropertiesFunc
) umlclass_apply_props_from_dialog
,
103 (ObjectMenuFunc
) umlclass_object_menu
,
104 (DescribePropsFunc
) umlclass_describe_props
,
105 (GetPropsFunc
) umlclass_get_props
,
106 (SetPropsFunc
) umlclass_set_props
109 extern PropDescDArrayExtra umlattribute_extra
;
110 extern PropDescDArrayExtra umloperation_extra
;
111 extern PropDescDArrayExtra umlparameter_extra
;
112 extern PropDescDArrayExtra umlformalparameter_extra
;
114 static PropDescription umlclass_props
[] = {
115 ELEMENT_COMMON_PROPERTIES
,
116 PROP_STD_TEXT_COLOUR_OPTIONAL
,
117 PROP_STD_LINE_COLOUR_OPTIONAL
,
118 PROP_STD_FILL_COLOUR_OPTIONAL
,
120 PROP_STD_NOTEBOOK_BEGIN
,
121 PROP_NOTEBOOK_PAGE("class", PROP_FLAG_DONT_MERGE
, N_("Class")),
122 { "name", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
123 N_("Name"), NULL
, NULL
},
124 { "stereotype", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
125 N_("Stereotype"), NULL
, NULL
},
126 { "comment", PROP_TYPE_STRING
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
127 N_("Comment"), NULL
, NULL
},
128 { "abstract", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
129 N_("Abstract"), NULL
, NULL
},
130 { "template", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
| PROP_FLAG_NO_DEFAULTS
,
131 N_("Template"), NULL
, NULL
},
133 { "suppress_attributes", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
134 N_("Suppress Attributes"), NULL
, NULL
},
135 { "suppress_operations", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
136 N_("Suppress Operations"), NULL
, NULL
},
137 { "visible_attributes", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
138 N_("Visible Attributes"), NULL
, NULL
},
139 { "visible_operations", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
140 N_("Visible Operations"), NULL
, NULL
},
141 { "visible_comments", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
142 N_("Visible Comments"), NULL
, NULL
},
143 { "wrap_operations", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
144 N_("Wrap Operations"), NULL
, NULL
},
145 { "wrap_after_char", PROP_TYPE_INT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
146 N_("Wrap after char"), NULL
, NULL
},
147 { "Comment_line_length", PROP_TYPE_INT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
148 N_("Comment line length"), NULL
, NULL
},
150 /* all this just to make the defaults selectable ... */
151 PROP_NOTEBOOK_PAGE("font", PROP_FLAG_DONT_MERGE
, N_("Font")),
152 PROP_STD_MULTICOL_BEGIN
,
153 PROP_MULTICOL_COLUMN("font"),
154 /* FIXME: apparently multicol does not work correctly, this should be FIRST column */
155 { "normal_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
156 N_("Normal"), NULL
, NULL
},
157 { "polymorphic_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
158 N_("Polymorphic"), NULL
, NULL
},
159 { "abstract_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
160 N_("Abstract"), NULL
, NULL
},
161 { "classname_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
162 N_("Classname"), NULL
, NULL
},
163 { "abstract_classname_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
164 N_("Abstract Classname"), NULL
, NULL
},
165 { "comment_font", PROP_TYPE_FONT
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
166 N_("Comment"), NULL
, NULL
},
168 PROP_MULTICOL_COLUMN("height"),
169 { "normal_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
170 N_(" "), NULL
, NULL
},
171 { "polymorphic_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
172 N_(" "), NULL
, NULL
},
173 { "abstract_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
174 N_(" "), NULL
, NULL
},
175 { "classname_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
176 N_(" "), NULL
, NULL
},
177 { "abstract_classname_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
178 N_(" "), NULL
, NULL
},
179 { "comment_font_height", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
180 N_(" "), NULL
, NULL
},
181 PROP_STD_MULTICOL_END
,
182 PROP_STD_NOTEBOOK_END
,
184 /* these are used during load, but currently not during save */
185 { "attributes", PROP_TYPE_DARRAY
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
186 N_("Attributes"), NULL
, NULL
/* umlattribute_extra */ },
187 { "operations", PROP_TYPE_DARRAY
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
188 N_("Operations"), NULL
, NULL
/* umloperations_extra */ },
189 /* the naming is questionable, but kept for compatibility */
190 { "templates", PROP_TYPE_DARRAY
, PROP_FLAG_VISIBLE
| PROP_FLAG_OPTIONAL
,
191 N_("Template Parameters"), NULL
, NULL
/* umlformalparameters_extra */ },
196 static PropDescription
*
197 umlclass_describe_props(UMLClass
*umlclass
)
199 if (umlclass_props
[0].quark
== 0) {
202 prop_desc_list_calculate_quarks(umlclass_props
);
203 while (umlclass_props
[i
].name
!= NULL
) {
204 /* can't do this static, at least not on win32
205 * due to relocation (initializer not a constant)
207 if (0 == strcmp(umlclass_props
[i
].name
, "attributes"))
208 umlclass_props
[i
].extra_data
= ¨attribute_extra
;
209 else if (0 == strcmp(umlclass_props
[i
].name
, "operations")) {
210 PropDescription
*records
= umloperation_extra
.common
.record
;
213 umlclass_props
[i
].extra_data
= ¨operation_extra
;
214 while (records
[j
].name
!= NULL
) {
215 if (0 == strcmp(records
[j
].name
, "parameters"))
216 records
[j
].extra_data
= ¨parameter_extra
;
220 else if (0 == strcmp(umlclass_props
[i
].name
, "templates"))
221 umlclass_props
[i
].extra_data
= ¨formalparameter_extra
;
226 return umlclass_props
;
229 static PropOffset umlclass_offsets
[] = {
230 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
232 { "text_colour", PROP_TYPE_COLOUR
, offsetof(UMLClass
, text_color
) },
233 { "line_colour", PROP_TYPE_COLOUR
, offsetof(UMLClass
, line_color
) },
234 { "fill_colour", PROP_TYPE_COLOUR
, offsetof(UMLClass
, fill_color
) },
235 { "name", PROP_TYPE_STRING
, offsetof(UMLClass
, name
) },
236 { "stereotype", PROP_TYPE_STRING
, offsetof(UMLClass
, stereotype
) },
237 { "comment", PROP_TYPE_STRING
, offsetof(UMLClass
, comment
) },
238 { "abstract", PROP_TYPE_BOOL
, offsetof(UMLClass
, abstract
) },
239 { "template", PROP_TYPE_BOOL
, offsetof(UMLClass
, template) },
240 { "suppress_attributes", PROP_TYPE_BOOL
, offsetof(UMLClass
, suppress_attributes
) },
241 { "visible_attributes", PROP_TYPE_BOOL
, offsetof(UMLClass
, visible_attributes
) },
242 { "visible_comments", PROP_TYPE_BOOL
, offsetof(UMLClass
, visible_comments
) },
243 { "suppress_operations", PROP_TYPE_BOOL
, offsetof(UMLClass
, suppress_operations
) },
244 { "visible_operations", PROP_TYPE_BOOL
, offsetof(UMLClass
, visible_operations
) },
245 { "visible_comments", PROP_TYPE_BOOL
, offsetof(UMLClass
, visible_comments
) },
246 { "wrap_operations", PROP_TYPE_BOOL
, offsetof(UMLClass
, wrap_operations
) },
247 { "wrap_after_char", PROP_TYPE_INT
, offsetof(UMLClass
, wrap_after_char
) },
248 { "Comment_line_length", PROP_TYPE_INT
, offsetof(UMLClass
, Comment_line_length
) },
250 /* all this just to make the defaults selectable ... */
251 PROP_OFFSET_STD_MULTICOL_BEGIN
,
252 PROP_OFFSET_MULTICOL_COLUMN("font"),
253 { "normal_font", PROP_TYPE_FONT
, offsetof(UMLClass
, normal_font
) },
254 { "abstract_font", PROP_TYPE_FONT
, offsetof(UMLClass
, abstract_font
) },
255 { "polymorphic_font", PROP_TYPE_FONT
, offsetof(UMLClass
, polymorphic_font
) },
256 { "classname_font", PROP_TYPE_FONT
, offsetof(UMLClass
, classname_font
) },
257 { "abstract_classname_font", PROP_TYPE_FONT
, offsetof(UMLClass
, abstract_classname_font
) },
258 { "comment_font", PROP_TYPE_FONT
, offsetof(UMLClass
, comment_font
) },
260 PROP_OFFSET_MULTICOL_COLUMN("height"),
261 { "normal_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, font_height
) },
262 { "abstract_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, abstract_font_height
) },
263 { "polymorphic_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, polymorphic_font_height
) },
264 { "classname_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, classname_font_height
) },
265 { "abstract_classname_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, abstract_classname_font_height
) },
266 { "comment_font_height", PROP_TYPE_REAL
, offsetof(UMLClass
, comment_font_height
) },
267 PROP_OFFSET_STD_MULTICOL_END
,
269 { "operations", PROP_TYPE_DARRAY
, offsetof(UMLClass
, operations
) },
270 { "attributes", PROP_TYPE_DARRAY
, offsetof(UMLClass
, attributes
) } ,
271 { "templates", PROP_TYPE_DARRAY
, offsetof(UMLClass
, formal_params
) } ,
277 umlclass_get_props(UMLClass
* umlclass
, GPtrArray
*props
)
279 object_get_props_from_offsets(¨class
->element
.object
,
280 umlclass_offsets
, props
);
283 static DiaMenuItem umlclass_menu_items
[] = {
284 { N_("Show Comments"), umlclass_show_comments_callback
, NULL
,
285 DIAMENU_ACTIVE
|DIAMENU_TOGGLE
},
288 static DiaMenu umlclass_menu
= {
290 sizeof(umlclass_menu_items
)/sizeof(DiaMenuItem
),
296 umlclass_object_menu(DiaObject
*obj
, Point
*p
)
298 umlclass_menu_items
[0].active
= DIAMENU_ACTIVE
|DIAMENU_TOGGLE
|
299 (((UMLClass
*)obj
)->visible_comments
?DIAMENU_TOGGLE_ON
:0);
301 return ¨class_menu
;
304 ObjectChange
*umlclass_show_comments_callback(DiaObject
*obj
, Point
*pos
, gpointer data
)
306 ObjectChange
*change
= new_object_state_change(obj
, NULL
, NULL
, NULL
);
308 ((UMLClass
*)obj
)->visible_comments
= !((UMLClass
*)obj
)->visible_comments
;
309 umlclass_calculate_data((UMLClass
*)obj
);
310 umlclass_update_data((UMLClass
*)obj
);
315 umlclass_set_props(UMLClass
*umlclass
, GPtrArray
*props
)
317 /* now that operations/attributes can be set here as well we need to
318 * take for the number of connections update as well
319 * Note that due to a hack in umlclass_load, this is called before
320 * the normal connection points are set up.
322 DiaObject
*obj
= ¨class
->element
.object
;
326 object_set_props_from_offsets(¨class
->element
.object
, umlclass_offsets
,
329 num
= UMLCLASS_CONNECTIONPOINTS
+ umlclass_num_dynamic_connectionpoints(umlclass
);
332 obj
->num_connections
= num
+ 1;
334 obj
->num_connections
= num
;
337 obj
->connections
= g_realloc(obj
->connections
, obj
->num_connections
*sizeof(ConnectionPoint
*));
340 if (num
> UMLCLASS_CONNECTIONPOINTS
) {
342 /* this is just updating pointers to ConnectionPoint, the real connection handling is elsewhere.
343 * Note: Can't optimize here on number change cause the ops/attribs may have changed regardless of that.
345 i
= UMLCLASS_CONNECTIONPOINTS
;
346 list
= (!umlclass
->visible_attributes
|| umlclass
->suppress_attributes
) ? NULL
: umlclass
->attributes
;
347 while (list
!= NULL
) {
348 UMLAttribute
*attr
= (UMLAttribute
*)list
->data
;
350 printf("Setting obj conn %d to %p->left: %p\n", i
, attr
, attr
->left_connection
);
351 obj
->connections
[i
] = attr
->left_connection
;
352 obj
->connections
[i
]->object
= obj
;
354 printf("Setting obj conn %d to %p->right: %p\n", i
, attr
, attr
->right_connection
);
355 obj
->connections
[i
] = attr
->right_connection
;
356 obj
->connections
[i
]->object
= obj
;
358 list
= g_list_next(list
);
360 list
= (!umlclass
->visible_operations
|| umlclass
->suppress_operations
) ? NULL
: umlclass
->operations
;
361 while (list
!= NULL
) {
362 UMLOperation
*op
= (UMLOperation
*)list
->data
;
363 obj
->connections
[i
] = op
->left_connection
;
364 obj
->connections
[i
]->object
= obj
;
366 obj
->connections
[i
] = op
->right_connection
;
367 obj
->connections
[i
]->object
= obj
;
369 list
= g_list_next(list
);
373 obj
->connections
[num
] = ¨class
->connections
[UMLCLASS_CONNECTIONPOINTS
];
374 obj
->connections
[num
]->object
= obj
;
377 umlclass_calculate_data(umlclass
);
378 umlclass_update_data(umlclass
);
379 /* Would like to sanity check here, but the call to object_load_props
380 * in umlclass_load means we will be called with inconsistent data. */
381 umlclass_sanity_check(umlclass
, "After updating data");
385 umlclass_distance_from(UMLClass
*umlclass
, Point
*point
)
387 DiaObject
*obj
= ¨class
->element
.object
;
388 return distance_rectangle_point(&obj
->bounding_box
, point
);
392 umlclass_select(UMLClass
*umlclass
, Point
*clicked_point
,
393 DiaRenderer
*interactive_renderer
)
395 element_update_handles(¨class
->element
);
399 umlclass_move_handle(UMLClass
*umlclass
, Handle
*handle
,
400 Point
*to
, ConnectionPoint
*cp
,
401 HandleMoveReason reason
, ModifierKeys modifiers
)
403 assert(umlclass
!=NULL
);
404 assert(handle
!=NULL
);
407 assert(handle
->id
< UMLCLASS_CONNECTIONPOINTS
);
413 umlclass_move(UMLClass
*umlclass
, Point
*to
)
415 umlclass
->element
.corner
= *to
;
416 umlclass_update_data(umlclass
);
424 uml_underline_text(DiaRenderer
*renderer
,
431 real underline_width
)
433 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
434 Point UnderlineStartPoint
;
435 Point UnderlineEndPoint
;
437 UnderlineStartPoint
= StartPoint
;
438 UnderlineStartPoint
.y
+= font_height
* 0.1;
439 UnderlineEndPoint
= UnderlineStartPoint
;
440 UnderlineEndPoint
.x
+= dia_font_string_width(attstr
, font
, font_height
);
441 renderer_ops
->set_linewidth(renderer
, underline_width
);
442 renderer_ops
->draw_line(renderer
, &UnderlineStartPoint
, &UnderlineEndPoint
, color
);
443 renderer_ops
->set_linewidth(renderer
, line_width
);
447 ** uml_create_documentation_tag
449 * FILENAME: \dia\objects\UML\class.c
452 * comment - The comment to be wrapped to the line length limit
453 * WrapPoint - The maximum line length allowed for the line.
454 * NumberOfLines - The number of comment lines after the wrapping.
457 * This function takes a string of characters and creates a
458 * documentation tagged string which is also a wrapped string
459 * where no line is longer than the value of WrapPoint.
461 * First a string is created containing only the text
462 * "{documentation = ". Then the contents of the comment string
463 * are added but wrapped. This is done by first looking for any
464 * New Line characters. If the line segment is longer than the
465 * WrapPoint would allow, the line is broken at either the
466 * first whitespace before the WrapPoint or if there are no
467 * whitespaces in the segment, at the WrapPoint. This
468 * continues until the entire string has been processed and
469 * then the resulting new string is returned. No attempt is
470 * made to rejoin any of the segments, that is all New Lines
471 * are treated as hard newlines. No syllable matching is done
472 * either so breaks in words will sometimes not make real
475 * Finally, since this function returns newly created dynamic
476 * memory the caller must free the memory to prevent memory
480 * A pointer to the string containing the line breakpoints for
484 * This function should most likely be move to a source file for
485 * handling global UML functionallity at some point.
488 uml_create_documentation_tag(gchar
* comment
,gint WrapPoint
, gint
*NumberOfLines
)
490 gchar
*CommentTag
= "{documentation = ";
491 gint TagLength
= strlen(CommentTag
);
492 gchar
*WrappedComment
= g_malloc(TagLength
+1);
493 gint LengthOfComment
= strlen(comment
);
494 gint CommentIndex
= 0;
495 gint LengthOfWrappedComment
= 0;
496 gint LineLen
= WrapPoint
- TagLength
;
498 WrappedComment
[0] = '\0';
499 strcat(WrappedComment
, CommentTag
);
500 LengthOfWrappedComment
= strlen(WrappedComment
);
503 /* Remove leading whitespace */
504 while( isspace(comment
[CommentIndex
])){
509 while( CommentIndex
< LengthOfComment
) /* more of the comment to go? */
511 gchar
*Nl
= strchr(&comment
[CommentIndex
], '\n');
512 gint BytesToNextNewLine
= 0;
514 /* if this is the first line then we have to take into
515 * account the tag of the tagged value
518 LengthOfWrappedComment
= strlen(WrappedComment
);
520 * First handle the next new lines
523 BytesToNextNewLine
= (Nl
- &comment
[CommentIndex
]);
526 if ((Nl
!= NULL
) && (BytesToNextNewLine
< LineLen
)){
527 LineLen
= BytesToNextNewLine
;
530 if( (CommentIndex
+ LineLen
) > LengthOfComment
){
531 LineLen
= LengthOfComment
-CommentIndex
;
534 if ((LineLen
== strlen(&comment
[CommentIndex
])) ||
535 isspace(comment
[CommentIndex
+LineLen
])){
541 if ((*NumberOfLines
> 1) &&( LineLen
== 0)){
549 /* Grow the wrapped text to make room for the NL and the next chunk */
550 WrappedComment
= g_realloc(WrappedComment
,LengthOfWrappedComment
+LineLen
+2);
551 memset(&WrappedComment
[LengthOfWrappedComment
],0,LineLen
+2);
552 strncat(WrappedComment
, &comment
[CommentIndex
], LineLen
);
554 CommentIndex
+= LineLen
;
555 while( isspace(comment
[CommentIndex
])){
558 if (CommentIndex
< LengthOfComment
){
559 /* if this is not the last line add a new-line*/
560 strcat(WrappedComment
,"\n");
563 LengthOfWrappedComment
= strlen(WrappedComment
);
566 WrappedComment
= g_realloc(WrappedComment
,LengthOfWrappedComment
+2);
567 strcat(WrappedComment
, "}");
568 return WrappedComment
;
574 * FILENAME: \dia\objects\UML\class.c
577 * renderer - The Renderer on which the comment is being drawn.
578 * *font - The font to render the comment in.
579 * font_height - The Y size of the font used to render the comment
580 * *text_color - A pointer to the color to use to render the comment
581 * *comment - The comment string to render
582 * Comment_line_length-The maximum length of any one line in the comment
583 * *p - The point at which the comment is to start.
584 * alignment - The method to use for alignment of the font.
587 * Draw the comment at the point, p, using the comment font from the
588 * class defined by umlclass. When complete update the point to reflect
589 * the size of data drawn.
590 * The comment will have been word wrapped using the function
591 * uml_create_documentation_tag, so it may have more than one line on the
594 * RETURNS: void, No useful information is returned.
599 uml_draw_comments(DiaRenderer
*renderer
,
604 gint Comment_line_length
,
608 gint NumberOfLines
= 0;
610 gchar
*CommentString
= 0;
611 gchar
*NewLineP
= NULL
;
614 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
617 uml_create_documentation_tag(comment
, Comment_line_length
, &NumberOfLines
);
618 RenderP
= CommentString
;
619 renderer_ops
->set_font(renderer
, font
, font_height
);
620 for ( Index
=0; Index
< NumberOfLines
; Index
++)
622 p
->y
+= font_height
; /* Advance to the next line */
623 NewLineP
= strchr(RenderP
, '\n');
624 if ( NewLineP
!= NULL
)
628 renderer_ops
->draw_string(renderer
, RenderP
, p
, alignment
, text_color
);
630 if ( NewLineP
== NULL
){
634 g_free(CommentString
);
639 ** umlclass_draw_namebox
641 * FILENAME: \dia\objects\UML\class.c
644 * umlclass - The pointer to the class being drawn
645 * renderer - The pointer to the rendering object used to draw
646 * elem - The pointer to the element within the class to be drawn
651 * The offset from the start of the class to the bottom of the namebox
655 umlclass_draw_namebox(UMLClass
*umlclass
, DiaRenderer
*renderer
, Element
*elem
)
657 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
661 Point LowerRightPoint
;
663 Color
*text_color
= ¨class
->text_color
;
665 StartPoint
.x
= elem
->corner
.x
;
666 StartPoint
.y
= elem
->corner
.y
;
667 Yoffset
= elem
->corner
.y
+ umlclass
->namebox_height
;
669 LowerRightPoint
= StartPoint
;
670 LowerRightPoint
.x
+= elem
->width
;
671 LowerRightPoint
.y
= Yoffset
;
674 * First draw the outer box and fill color for the class name
677 renderer_ops
->fill_rect(renderer
, &StartPoint
, &LowerRightPoint
, ¨class
->fill_color
);
678 renderer_ops
->draw_rect(renderer
, &StartPoint
, &LowerRightPoint
, ¨class
->line_color
);
680 /* Start at the midpoint on the X axis */
681 StartPoint
.x
+= elem
->width
/ 2.0;
684 if (umlclass
->stereotype
!= NULL
&& umlclass
->stereotype
[0] != '\0') {
685 gchar
*String
= umlclass
->stereotype_string
;
687 StartPoint
.y
+= dia_font_ascent(String
, umlclass
->normal_font
, umlclass
->font_height
);
688 renderer_ops
->set_font(renderer
, umlclass
->normal_font
, umlclass
->font_height
);
689 renderer_ops
->draw_string(renderer
, String
, &StartPoint
, ALIGN_CENTER
, text_color
);
693 if (umlclass
->name
!= NULL
) {
694 if (umlclass
->abstract
) {
695 font
= umlclass
->abstract_classname_font
;
696 font_height
= umlclass
->abstract_classname_font_height
;
698 font
= umlclass
->classname_font
;
699 font_height
= umlclass
->classname_font_height
;
701 StartPoint
.y
+= font_height
;
703 renderer_ops
->set_font(renderer
, font
, font_height
);
704 renderer_ops
->draw_string(renderer
, umlclass
->name
, &StartPoint
, ALIGN_CENTER
, text_color
);
708 if (umlclass
->visible_comments
&& umlclass
->comment
!= NULL
&& umlclass
->comment
[0] != '\0'){
709 uml_draw_comments(renderer
, umlclass
->comment_font
,umlclass
->comment_font_height
,
710 ¨class
->text_color
, umlclass
->comment
,
711 umlclass
->Comment_line_length
, &StartPoint
, ALIGN_CENTER
);
717 ** umlclass_draw_attributebox
719 * FILENAME: \dia\objects\UML\class.c
722 * umlclass - The pointer to the class being drawn
723 * renderer - The pointer to the rendering object used to draw
724 * elem - The pointer to the element within the class to be drawn
725 * Yoffset - The Y offset from the start of the class at which to draw
731 * The offset from the start of the class to the bottom of the attributebox
734 umlclass_draw_attributebox(UMLClass
*umlclass
, DiaRenderer
*renderer
, Element
*elem
, real Yoffset
)
736 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
741 Color
*fill_color
= ¨class
->fill_color
;
742 Color
*line_color
= ¨class
->line_color
;
743 Color
*text_color
= ¨class
->text_color
;
746 StartPoint
.x
= elem
->corner
.x
;
747 StartPoint
.y
= Yoffset
;
748 Yoffset
+= umlclass
->attributesbox_height
;
750 LowerRight
= StartPoint
;
751 LowerRight
.x
+= elem
->width
;
752 LowerRight
.y
= Yoffset
;
754 renderer_ops
->fill_rect(renderer
, &StartPoint
, &LowerRight
, fill_color
);
755 renderer_ops
->draw_rect(renderer
, &StartPoint
, &LowerRight
, line_color
);
757 if (!umlclass
->suppress_attributes
) {
759 StartPoint
.x
+= (UMLCLASS_BORDER
/2.0 + 0.1);
762 list
= umlclass
->attributes
;
765 UMLAttribute
*attr
= (UMLAttribute
*)list
->data
;
766 gchar
*attstr
= g_list_nth(umlclass
->attributes_strings
, i
)->data
;
768 if (attr
->abstract
) {
769 font
= umlclass
->abstract_font
;
770 font_height
= umlclass
->abstract_font_height
;
773 font
= umlclass
->normal_font
;
774 font_height
= umlclass
->font_height
;
776 StartPoint
.y
+= font_height
;
777 renderer_ops
->set_font (renderer
, font
, font_height
);
778 renderer_ops
->draw_string(renderer
, attstr
, &StartPoint
, ALIGN_LEFT
, text_color
);
780 if (attr
->class_scope
) {
781 uml_underline_text(renderer
, StartPoint
, font
, font_height
, attstr
, line_color
,
782 UMLCLASS_BORDER
, UMLCLASS_UNDERLINEWIDTH
);
785 if (umlclass
->visible_comments
&& attr
->comment
!= NULL
&& attr
->comment
[0] != '\0') {
786 uml_draw_comments(renderer
, umlclass
->comment_font
,umlclass
->comment_font_height
,
787 ¨class
->text_color
, attr
->comment
,
788 umlclass
->Comment_line_length
, &StartPoint
, ALIGN_LEFT
);
789 StartPoint
.y
+= umlclass
->comment_font_height
/2;
791 list
= g_list_next(list
);
800 ** umlclass_draw_operationbox
802 * FILENAME: \dia\objects\UML\class.c
805 * umlclass - The pointer to the class being drawn
806 * renderer - The pointer to the rendering object used to draw
807 * elem - The pointer to the element within the class to be drawn
808 * Yoffset - The Y offset from the start of the class at which to draw
814 * The offset from the start of the class to the bottom of the operationbox
818 umlclass_draw_operationbox(UMLClass
*umlclass
, DiaRenderer
*renderer
, Element
*elem
, real Yoffset
)
820 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
826 Color
*fill_color
= ¨class
->fill_color
;
827 Color
*line_color
= ¨class
->line_color
;
828 Color
*text_color
= ¨class
->text_color
;
831 StartPoint
.x
= elem
->corner
.x
;
832 StartPoint
.y
= Yoffset
;
833 Yoffset
+= umlclass
->operationsbox_height
;
835 LowerRight
= StartPoint
;
836 LowerRight
.x
+= elem
->width
;
837 LowerRight
.y
= Yoffset
;
839 renderer_ops
->fill_rect(renderer
, &StartPoint
, &LowerRight
, fill_color
);
840 renderer_ops
->draw_rect(renderer
, &StartPoint
, &LowerRight
, line_color
);
842 if (!umlclass
->suppress_operations
) {
844 GList
*wrapsublist
= NULL
;
845 gchar
*part_opstr
= NULL
;
846 int wrap_pos
, last_wrap_pos
, ident
, wrapping_needed
;
847 int part_opstr_len
= 0, part_opstr_need
= 0;
849 StartPoint
.x
+= (UMLCLASS_BORDER
/2.0 + 0.1);
852 list
= umlclass
->operations
;
853 while (list
!= NULL
) {
854 UMLOperation
*op
= (UMLOperation
*)list
->data
;
858 switch (op
->inheritance_type
) {
860 font
= umlclass
->abstract_font
;
861 font_height
= umlclass
->abstract_font_height
;
863 case UML_POLYMORPHIC
:
864 font
= umlclass
->polymorphic_font
;
865 font_height
= umlclass
->polymorphic_font_height
;
869 font
= umlclass
->normal_font
;
870 font_height
= umlclass
->font_height
;
874 opstr
= (gchar
*) g_list_nth(umlclass
->operations_strings
, i
)->data
;
875 if( umlclass
->wrap_operations
) {
876 wrapsublist
= (GList
*)g_list_nth( umlclass
->operations_wrappos
, i
)->data
;
877 wrapping_needed
= GPOINTER_TO_INT( wrapsublist
->data
);
880 ascent
= dia_font_ascent(opstr
, font
, font_height
);
881 renderer_ops
->set_font(renderer
, font
, font_height
);
883 if( umlclass
->wrap_operations
&& wrapping_needed
) {
885 wrapsublist
= g_list_next( wrapsublist
);
886 ident
= GPOINTER_TO_INT( wrapsublist
->data
);
887 wrapsublist
= g_list_next( wrapsublist
);
888 wrap_pos
= last_wrap_pos
= 0;
890 while( wrapsublist
!= NULL
) {
891 wrap_pos
= GPOINTER_TO_INT( wrapsublist
->data
);
893 if( last_wrap_pos
== 0) {
894 part_opstr_need
= wrap_pos
+ 1;
895 if (part_opstr_len
< part_opstr_need
) {
896 part_opstr_len
= part_opstr_need
;
897 part_opstr
= g_realloc (part_opstr
, part_opstr_need
);
899 strncpy( part_opstr
, opstr
, wrap_pos
);
900 memset( part_opstr
+wrap_pos
, '\0', 1);
903 part_opstr_need
= ident
+ wrap_pos
- last_wrap_pos
+ 1;
904 if (part_opstr_len
< part_opstr_need
) {
905 part_opstr_len
= part_opstr_need
;
906 part_opstr
= g_realloc (part_opstr
, part_opstr_need
);
908 memset( part_opstr
, ' ', ident
);
909 memset( part_opstr
+ident
, '\0', 1);
910 strncat( part_opstr
, opstr
+last_wrap_pos
, wrap_pos
-last_wrap_pos
);
913 StartPoint
.y
+= ascent
;
914 renderer_ops
->draw_string(renderer
, part_opstr
, &StartPoint
, ALIGN_LEFT
, text_color
);
915 last_wrap_pos
= wrap_pos
;
916 wrapsublist
= g_list_next( wrapsublist
);
921 StartPoint
.y
+= ascent
;
922 renderer_ops
->draw_string(renderer
, opstr
, &StartPoint
, ALIGN_LEFT
, text_color
);
925 if (op
->class_scope
) {
926 uml_underline_text(renderer
, StartPoint
, font
, font_height
, opstr
, line_color
,
927 UMLCLASS_BORDER
, UMLCLASS_UNDERLINEWIDTH
);
930 StartPoint
.y
+= font_height
- ascent
;
932 if (umlclass
->visible_comments
&& op
->comment
!= NULL
&& op
->comment
[0] != '\0'){
933 uml_draw_comments(renderer
, umlclass
->comment_font
,umlclass
->comment_font_height
,
934 ¨class
->text_color
, op
->comment
,
935 umlclass
->Comment_line_length
, &StartPoint
, ALIGN_LEFT
);
938 list
= g_list_next(list
);
949 ** umlclass_draw_template_parameters_box
951 * FILENAME: \dia\objects\UML\class.c
954 * umlclass - The pointer to the class being drawn
955 * renderer - The pointer to the rendering object used to draw
956 * elem - The pointer to the element within the class to be drawn
960 * This function draws the template parameters box in the upper
961 * right hand corner of the class box for paramertize classes
962 * (aka template classes). It then fills in this box with the
963 * parameters for the class.
965 * At this time there is no provision for adding comments or
966 * documentation to the display.
973 umlclass_draw_template_parameters_box(UMLClass
*umlclass
, DiaRenderer
*renderer
, Element
*elem
)
975 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
981 DiaFont
*font
= umlclass
->normal_font
;
982 real font_height
= umlclass
->font_height
;
983 Color
*fill_color
= ¨class
->fill_color
;
984 Color
*line_color
= ¨class
->line_color
;
985 Color
*text_color
= ¨class
->text_color
;
987 UpperLeft
.x
= elem
->corner
.x
+ elem
->width
- 2.3;
988 UpperLeft
.y
= elem
->corner
.y
- umlclass
->templates_height
+ 0.3;
989 TextInsert
= UpperLeft
;
990 LowerRight
= UpperLeft
;
991 LowerRight
.x
+= umlclass
->templates_width
;
992 LowerRight
.y
+= umlclass
->templates_height
;
994 renderer_ops
->fill_rect(renderer
, &UpperLeft
, &LowerRight
, fill_color
);
995 renderer_ops
->set_linestyle(renderer
, LINESTYLE_DASHED
);
996 renderer_ops
->set_dashlength(renderer
, 0.3);
997 renderer_ops
->draw_rect(renderer
, &UpperLeft
, &LowerRight
, line_color
);
1000 renderer_ops
->set_font(renderer
, font
, font_height
);
1002 list
= umlclass
->formal_params
;
1003 while (list
!= NULL
)
1005 gchar
*ParameterString
= umlclass
->templates_strings
[i
];
1007 TextInsert
.y
+=(0.1 + dia_font_ascent(ParameterString
, font
, font_height
));
1008 renderer_ops
->draw_string(renderer
, ParameterString
, &TextInsert
, ALIGN_LEFT
, text_color
);
1010 list
= g_list_next(list
);
1018 * FILENAME: \dia\objects\UML\class.c
1024 * Important Note from earlier contributer:
1025 * Most of this crap could be rendered much more efficiently
1026 * (and probably much cleaner as well) using marked-up
1027 * Pango layout text.
1032 umlclass_draw(UMLClass
*umlclass
, DiaRenderer
*renderer
)
1034 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
1038 assert(umlclass
!= NULL
);
1039 assert(renderer
!= NULL
);
1041 renderer_ops
->set_fillstyle(renderer
, FILLSTYLE_SOLID
);
1042 renderer_ops
->set_linewidth(renderer
, UMLCLASS_BORDER
);
1043 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
1045 elem
= ¨class
->element
;
1047 y
= umlclass_draw_namebox(umlclass
, renderer
, elem
);
1048 if (umlclass
->visible_attributes
) {
1049 y
= umlclass_draw_attributebox(umlclass
, renderer
, elem
, y
);
1051 if (umlclass
->visible_operations
) {
1052 y
= umlclass_draw_operationbox(umlclass
, renderer
, elem
, y
);
1054 if (umlclass
->template) {
1055 umlclass_draw_template_parameters_box(umlclass
, renderer
, elem
);
1060 umlclass_update_data(UMLClass
*umlclass
)
1062 Element
*elem
= ¨class
->element
;
1063 DiaObject
*obj
= &elem
->object
;
1068 int lowerleftcorner
;
1074 /* Update connections: */
1075 umlclass
->connections
[0].pos
= elem
->corner
;
1076 umlclass
->connections
[0].directions
= DIR_NORTH
|DIR_WEST
;
1078 /* there are four corner points and two side points, thus all
1079 * remaining points are on the top/bottom width
1081 pointswide
= (UMLCLASS_CONNECTIONPOINTS
- 6) / 2;
1082 pointspacing
= elem
->width
/ (pointswide
+ 1.0);
1084 /* across the top connection points */
1085 for (i
=1;i
<=pointswide
;i
++) {
1086 umlclass
->connections
[i
].pos
.x
= x
+ (pointspacing
* i
);
1087 umlclass
->connections
[i
].pos
.y
= y
;
1088 umlclass
->connections
[i
].directions
= DIR_NORTH
;
1091 i
= (UMLCLASS_CONNECTIONPOINTS
/ 2) - 2;
1092 umlclass
->connections
[i
].pos
.x
= x
+ elem
->width
;
1093 umlclass
->connections
[i
].pos
.y
= y
;
1094 umlclass
->connections
[i
].directions
= DIR_NORTH
|DIR_EAST
;
1096 i
= (UMLCLASS_CONNECTIONPOINTS
/ 2) - 1;
1097 umlclass
->connections
[i
].pos
.x
= x
;
1098 umlclass
->connections
[i
].pos
.y
= y
+ umlclass
->namebox_height
/ 2.0;
1099 umlclass
->connections
[i
].directions
= DIR_WEST
;
1101 i
= (UMLCLASS_CONNECTIONPOINTS
/ 2);
1102 umlclass
->connections
[i
].pos
.x
= x
+ elem
->width
;
1103 umlclass
->connections
[i
].pos
.y
= y
+ umlclass
->namebox_height
/ 2.0;
1104 umlclass
->connections
[i
].directions
= DIR_EAST
;
1106 i
= (UMLCLASS_CONNECTIONPOINTS
/ 2) + 1;
1107 umlclass
->connections
[i
].pos
.x
= x
;
1108 umlclass
->connections
[i
].pos
.y
= y
+ elem
->height
;
1109 umlclass
->connections
[i
].directions
= DIR_WEST
|DIR_SOUTH
;
1111 /* across the bottom connection points */
1112 lowerleftcorner
= (UMLCLASS_CONNECTIONPOINTS
/ 2) + 1;
1113 for (i
=1;i
<=pointswide
;i
++) {
1114 umlclass
->connections
[lowerleftcorner
+ i
].pos
.x
= x
+ (pointspacing
* i
);
1115 umlclass
->connections
[lowerleftcorner
+ i
].pos
.y
= y
+ elem
->height
;
1116 umlclass
->connections
[lowerleftcorner
+ i
].directions
= DIR_SOUTH
;
1119 /* bottom-right corner */
1120 i
= (UMLCLASS_CONNECTIONPOINTS
) - 1;
1121 umlclass
->connections
[i
].pos
.x
= x
+ elem
->width
;
1122 umlclass
->connections
[i
].pos
.y
= y
+ elem
->height
;
1123 umlclass
->connections
[i
].directions
= DIR_EAST
|DIR_SOUTH
;
1125 #ifdef UML_MAINPOINT
1126 /* Main point -- lives just after fixed connpoints in umlclass array */
1127 i
= UMLCLASS_CONNECTIONPOINTS
;
1128 umlclass
->connections
[i
].pos
.x
= x
+ elem
->width
/ 2;
1129 umlclass
->connections
[i
].pos
.y
= y
+ elem
->height
/ 2;
1130 umlclass
->connections
[i
].directions
= DIR_ALL
;
1131 umlclass
->connections
[i
].flags
= CP_FLAGS_MAIN
;
1134 y
+= umlclass
->namebox_height
+ 0.1 + umlclass
->font_height
/2;
1136 list
= umlclass
->attributes
;
1137 while (list
!= NULL
) {
1138 UMLAttribute
*attr
= (UMLAttribute
*)list
->data
;
1140 attr
->left_connection
->pos
.x
= x
;
1141 attr
->left_connection
->pos
.y
= y
;
1142 attr
->left_connection
->directions
= DIR_WEST
;
1143 attr
->right_connection
->pos
.x
= x
+ elem
->width
;
1144 attr
->right_connection
->pos
.y
= y
;
1145 attr
->right_connection
->directions
= DIR_EAST
;
1147 y
+= umlclass
->font_height
;
1148 if (umlclass
->visible_comments
&& attr
->comment
!= NULL
&& attr
->comment
[0] != '\0')
1149 y
+= umlclass
->comment_font_height
;
1151 list
= g_list_next(list
);
1154 y
= elem
->corner
.y
+ umlclass
->namebox_height
+
1155 umlclass
->attributesbox_height
+ 0.1 + umlclass
->font_height
/2;
1157 list
= umlclass
->operations
;
1158 while (list
!= NULL
) {
1159 UMLOperation
*op
= (UMLOperation
*)list
->data
;
1161 op
->left_connection
->pos
.x
= x
;
1162 op
->left_connection
->pos
.y
= y
;
1163 op
->left_connection
->directions
= DIR_WEST
;
1164 op
->right_connection
->pos
.x
= x
+ elem
->width
;
1165 op
->right_connection
->pos
.y
= y
;
1166 op
->right_connection
->directions
= DIR_EAST
;
1168 y
+= umlclass
->font_height
;
1169 if (umlclass
->visible_comments
&& op
->comment
!= NULL
&& op
->comment
[0] != '\0')
1170 y
+= umlclass
->comment_font_height
;
1172 list
= g_list_next(list
);
1175 element_update_boundingbox(elem
);
1178 obj
->position
= elem
->corner
;
1180 element_update_handles(elem
);
1182 umlclass_sanity_check(umlclass
, "After updating data");
1188 * umlclass_calculate_name_data
1190 * FILENAME: \dia\objects\UML\class.c
1193 * umlclass - the class being rendered
1196 * This function calculates the height of the class bounding box for
1197 * the name and returns the width of that box. The height is stored
1198 * in the class structure.
1199 * When calculating the comment, if any, the comment is word wrapped
1200 * and the resulting number of lines is then used to calculate the
1201 * height of the bounding box.
1209 umlclass_calculate_name_data(UMLClass
*umlclass
)
1211 real maxwidth
= 0.0;
1215 if (umlclass
->name
!= NULL
&& umlclass
->name
[0] != '\0') {
1216 if (umlclass
->abstract
) {
1217 maxwidth
= dia_font_string_width(umlclass
->name
,
1218 umlclass
->abstract_classname_font
,
1219 umlclass
->abstract_classname_font_height
);
1221 maxwidth
= dia_font_string_width(umlclass
->name
,
1222 umlclass
->classname_font
,
1223 umlclass
->classname_font_height
);
1227 umlclass
->namebox_height
= umlclass
->classname_font_height
+ 4*0.1;
1228 if (umlclass
->stereotype_string
!= NULL
) {
1229 g_free(umlclass
->stereotype_string
);
1231 if (umlclass
->stereotype
!= NULL
&& umlclass
->stereotype
[0] != '\0') {
1232 umlclass
->namebox_height
+= umlclass
->font_height
;
1233 umlclass
->stereotype_string
= g_strconcat ( UML_STEREOTYPE_START
,
1234 umlclass
->stereotype
,
1238 width
= dia_font_string_width (umlclass
->stereotype_string
,
1239 umlclass
->normal_font
,
1240 umlclass
->font_height
);
1241 maxwidth
= MAX(width
, maxwidth
);
1243 umlclass
->stereotype_string
= NULL
;
1246 if (umlclass
->visible_comments
&& umlclass
->comment
!= NULL
&& umlclass
->comment
[0] != '\0')
1248 int NumberOfCommentLines
= 0;
1249 gchar
*wrapped_box
= uml_create_documentation_tag(umlclass
->comment
,
1250 umlclass
->Comment_line_length
,
1251 &NumberOfCommentLines
);
1253 width
= dia_font_string_width (wrapped_box
,
1254 umlclass
->comment_font
,
1255 umlclass
->comment_font_height
);
1257 g_free(wrapped_box
);
1258 umlclass
->namebox_height
+= umlclass
->comment_font_height
* NumberOfCommentLines
;
1259 maxwidth
= MAX(width
, maxwidth
);
1265 ** umlclass_calculate_attribute_data
1267 * FILENAME: \dia\objects\UML\class.c
1270 * umlclass - The class to be drawn.
1273 * Calculate the bounding box for the attributes. Include the
1274 * comments if enabled and present.
1277 * The real width of the attribute bounding box.
1282 umlclass_calculate_attribute_data(UMLClass
*umlclass
)
1291 real maxwidth
= 0.0;
1295 /* attributes box: */
1296 if (umlclass
->attributes_strings
!= NULL
)
1298 g_list_foreach(umlclass
->attributes_strings
, (GFunc
)g_free
, NULL
);
1299 g_list_free(umlclass
->attributes_strings
);
1301 umlclass
->attributesbox_height
= 2*0.1;
1303 umlclass
->attributes_strings
= NULL
;
1304 if (g_list_length(umlclass
->attributes
) != 0)
1307 list
= umlclass
->attributes
;
1308 while (list
!= NULL
)
1310 UMLAttribute
*attr
= (UMLAttribute
*) list
->data
;
1311 gchar
*attstr
= uml_get_attribute_string(attr
);
1313 umlclass
->attributes_strings
=
1314 g_list_append(umlclass
->attributes_strings
, attstr
);
1318 width
= dia_font_string_width(attstr
,
1319 umlclass
->abstract_font
,
1320 umlclass
->abstract_font_height
);
1321 umlclass
->attributesbox_height
+= umlclass
->abstract_font_height
;
1325 width
= dia_font_string_width(attstr
,
1326 umlclass
->normal_font
,
1327 umlclass
->font_height
);
1328 umlclass
->attributesbox_height
+= umlclass
->font_height
;
1330 maxwidth
= MAX(width
, maxwidth
);
1332 if (umlclass
->visible_comments
&& attr
->comment
!= NULL
&& attr
->comment
[0] != '\0')
1334 int NumberOfLines
= 0;
1335 gchar
*Wrapped
= uml_create_documentation_tag(attr
->comment
,
1336 umlclass
->Comment_line_length
,
1339 width
= dia_font_string_width(Wrapped
,
1340 umlclass
->comment_font
,
1341 umlclass
->comment_font_height
);
1344 umlclass
->attributesbox_height
+= (umlclass
->comment_font_height
* (NumberOfLines
));
1345 umlclass
->attributesbox_height
+= umlclass
->comment_font_height
/2;
1347 maxwidth
= MAX(width
, maxwidth
);
1351 list
= g_list_next(list
);
1355 if ((umlclass
->attributesbox_height
<0.4)|| umlclass
->suppress_attributes
)
1357 umlclass
->attributesbox_height
= 0.4;
1364 ** umlclass_calculate_operation_data
1366 * FILENAME: \dia\objects\UML\class.c
1369 * umlclass - The class to be drawn.
1372 * Calculate the bounding box for the operation. Include the
1373 * comments if enabled and present.
1376 * The real width of the attribute bounding box.
1380 umlclass_calculate_operation_data(UMLClass
*umlclass
)
1391 real maxwidth
= 0.0;
1397 /* operations box: */
1398 umlclass
->operationsbox_height
= 2*0.1;
1399 /* neither leak previously calculated strings ... */
1400 if (umlclass
->operations_strings
!= NULL
)
1402 g_list_foreach(umlclass
->operations_strings
, (GFunc
)g_free
, NULL
);
1403 g_list_free(umlclass
->operations_strings
);
1404 umlclass
->operations_strings
= NULL
;
1406 /* ... nor their wrappings */
1407 if (umlclass
->operations_wrappos
!= NULL
)
1409 g_list_foreach(umlclass
->operations_wrappos
, (GFunc
)g_list_free
, NULL
);
1410 g_list_free(umlclass
->operations_wrappos
);
1411 umlclass
->operations_wrappos
= NULL
;
1414 if (0 != g_list_length(umlclass
->operations
))
1417 list
= umlclass
->operations
;
1418 while (list
!= NULL
)
1420 UMLOperation
*op
= (UMLOperation
*) list
->data
;
1421 gchar
*opstr
= uml_get_operation_string(op
);
1423 umlclass
->operations_strings
=
1424 g_list_append(umlclass
->operations_strings
, opstr
);
1427 if( umlclass
->wrap_operations
)
1429 length
= strlen( (const gchar
*)opstr
);
1431 if( length
> umlclass
->wrap_after_char
)
1434 sublist
= g_list_append( sublist
, GINT_TO_POINTER( 1));
1436 /* count maximal line width to create a secure buffer (part_opstr)
1437 and build the sublist with the wrapping data for the current operation, which will be used by umlclass_draw(), too.
1438 The content of the sublist is:
1439 1st element: (bool) wrapping needed or not, 2nd: indentation in chars, 3rd-last: absolute wrapping positions */
1440 pos_next_comma
= pos_brace
= wrap_pos
= offset
= maxlinewidth
= umlclass
->max_wrapped_line_width
= 0;
1441 while( wrap_pos
+ offset
< length
)
1445 pos_next_comma
= strcspn( (const gchar
*)opstr
+ wrap_pos
+ offset
, ",");
1446 wrap_pos
+= pos_next_comma
+ 1;
1447 } while( wrap_pos
< umlclass
->wrap_after_char
- pos_brace
&& wrap_pos
+ offset
< length
);
1450 pos_brace
= strcspn( opstr
, "(");
1451 sublist
= g_list_append( sublist
, GINT_TO_POINTER( pos_brace
+1));
1453 sublist
= g_list_append( sublist
, GINT_TO_POINTER( wrap_pos
+ offset
));
1455 maxlinewidth
= MAX(maxlinewidth
, wrap_pos
);
1460 umlclass
->max_wrapped_line_width
= MAX( umlclass
->max_wrapped_line_width
, maxlinewidth
+1);
1462 wrapsublist
= g_list_next( sublist
);
1463 ident
= GPOINTER_TO_INT( wrapsublist
->data
);
1464 part_opstr
= g_alloca(umlclass
->max_wrapped_line_width
+ident
+1);
1465 pos_next_comma
= pos_brace
= wrap_pos
= offset
= 0;
1467 wrapsublist
= g_list_next( wrapsublist
);
1468 wrap_pos
= last_wrap_pos
= 0;
1470 while( wrapsublist
!= NULL
){
1473 wrap_pos
= GPOINTER_TO_INT( wrapsublist
->data
);
1474 if( last_wrap_pos
== 0){
1475 strncpy( part_opstr
, opstr
, wrap_pos
);
1476 memset( part_opstr
+wrap_pos
, '\0', 1);
1480 memset( part_opstr
, ' ', ident
);
1481 memset( part_opstr
+ident
, '\0', 1);
1482 strncat( part_opstr
, opstr
+last_wrap_pos
, wrap_pos
-last_wrap_pos
);
1485 switch(op
->inheritance_type
)
1488 Font
= umlclass
->abstract_font
;
1489 FontHeight
= umlclass
->abstract_font_height
;
1491 case UML_POLYMORPHIC
:
1492 Font
= umlclass
->polymorphic_font
;
1493 FontHeight
= umlclass
->polymorphic_font_height
;
1497 Font
= umlclass
->normal_font
;
1498 FontHeight
= umlclass
->font_height
;
1500 width
= dia_font_string_width(part_opstr
,Font
,FontHeight
);
1501 umlclass
->operationsbox_height
+= FontHeight
;
1503 maxwidth
= MAX(width
, maxwidth
);
1504 last_wrap_pos
= wrap_pos
;
1505 wrapsublist
= g_list_next( wrapsublist
);
1510 sublist
= g_list_append( sublist
, GINT_TO_POINTER( 0));
1512 umlclass
->operations_wrappos
= g_list_append( umlclass
->operations_wrappos
, sublist
);
1515 if( !umlclass
->wrap_operations
|| !(length
> umlclass
->wrap_after_char
)) {
1519 switch(op
->inheritance_type
)
1522 Font
= umlclass
->abstract_font
;
1523 FontHeight
= umlclass
->abstract_font_height
;
1525 case UML_POLYMORPHIC
:
1526 Font
= umlclass
->polymorphic_font
;
1527 FontHeight
= umlclass
->polymorphic_font_height
;
1531 Font
= umlclass
->normal_font
;
1532 FontHeight
= umlclass
->font_height
;
1534 width
= dia_font_string_width(opstr
,Font
,FontHeight
);
1535 umlclass
->operationsbox_height
+= FontHeight
;
1537 maxwidth
= MAX(width
, maxwidth
);
1540 if (umlclass
->visible_comments
&& op
->comment
!= NULL
&& op
->comment
[0] != '\0'){
1541 int NumberOfLines
= 0;
1542 gchar
*Wrapped
= uml_create_documentation_tag(op
->comment
,
1543 umlclass
->Comment_line_length
,
1546 width
= dia_font_string_width(Wrapped
,
1547 umlclass
->comment_font
,
1548 umlclass
->comment_font_height
);
1551 umlclass
->operationsbox_height
+= (umlclass
->comment_font_height
* (NumberOfLines
+1));
1553 maxwidth
= MAX(width
, maxwidth
);
1557 list
= g_list_next(list
);
1561 umlclass
->element
.width
= maxwidth
+ 2*0.3;
1563 if ((umlclass
->operationsbox_height
<0.4) || umlclass
->suppress_operations
) {
1564 umlclass
->operationsbox_height
= 0.4;
1572 ** umlclass_calculate_data
1574 * FILENAME: \dia\objects\UML\class.c
1577 * umlclass - The class to be drawn.
1580 * This function calculates the bounding box of the class image to be
1581 * displayed. It also calculates the three containing boxes. This is
1582 * done by calculating the size of the text to be displayed within
1583 * each of the contained bounding boxes, name, attributes and
1585 * Because the comments may require wrapping, each comment is wrapped
1586 * and the resulting number of lines is used to calculate the size of
1587 * the comment within the box.
1588 * The various font settings with in the class properties contribute
1589 * to the overall size of the resulting bounding box.
1595 umlclass_calculate_data(UMLClass
*umlclass
)
1606 real maxwidth
= 0.0;
1613 if (!umlclass
->destroyed
)
1615 maxwidth
= MAX(umlclass_calculate_name_data(umlclass
), maxwidth
);
1616 maxwidth
= MAX(umlclass_calculate_attribute_data(umlclass
), maxwidth
);
1617 maxwidth
= MAX(umlclass_calculate_operation_data(umlclass
), maxwidth
);
1619 umlclass
->element
.height
= umlclass
->namebox_height
;
1620 umlclass
->element
.width
= maxwidth
+0.5;
1622 if (umlclass
->visible_attributes
){
1623 umlclass
->element
.height
+= umlclass
->attributesbox_height
;
1625 if (umlclass
->visible_operations
){
1626 umlclass
->element
.height
+= umlclass
->operationsbox_height
;
1628 /* templates box: */
1629 if (umlclass
->templates_strings
!= NULL
)
1631 for (i
=0;i
<umlclass
->num_templates
;i
++)
1633 g_free(umlclass
->templates_strings
[i
]);
1635 g_free(umlclass
->templates_strings
);
1637 umlclass
->num_templates
= g_list_length(umlclass
->formal_params
);
1639 umlclass
->templates_height
=
1640 umlclass
->font_height
* umlclass
->num_templates
+ 2*0.1;
1641 umlclass
->templates_height
= MAX(umlclass
->templates_height
, 1.0);
1644 umlclass
->templates_strings
= NULL
;
1646 if (umlclass
->num_templates
!= 0)
1648 umlclass
->templates_strings
=
1649 g_malloc (sizeof (gchar
*) * umlclass
->num_templates
);
1651 list
= umlclass
->formal_params
;
1652 while (list
!= NULL
)
1654 UMLFormalParameter
*param
;
1656 param
= (UMLFormalParameter
*) list
->data
;
1657 umlclass
->templates_strings
[i
] = uml_get_formalparameter_string(param
);
1659 width
= dia_font_string_width(umlclass
->templates_strings
[i
],
1660 umlclass
->normal_font
,
1661 umlclass
->font_height
);
1662 maxwidth
= MAX(width
, maxwidth
);
1665 list
= g_list_next(list
);
1668 umlclass
->templates_width
= maxwidth
+ 2*0.2;
1673 fill_in_fontdata(UMLClass
*umlclass
)
1675 if (umlclass
->normal_font
== NULL
) {
1676 umlclass
->font_height
= 0.8;
1677 umlclass
->normal_font
= dia_font_new_from_style(DIA_FONT_MONOSPACE
, 0.8);
1679 if (umlclass
->abstract_font
== NULL
) {
1680 umlclass
->abstract_font_height
= 0.8;
1681 umlclass
->abstract_font
=
1682 dia_font_new_from_style(DIA_FONT_MONOSPACE
| DIA_FONT_ITALIC
| DIA_FONT_BOLD
, 0.8);
1684 if (umlclass
->polymorphic_font
== NULL
) {
1685 umlclass
->polymorphic_font_height
= 0.8;
1686 umlclass
->polymorphic_font
=
1687 dia_font_new_from_style(DIA_FONT_MONOSPACE
| DIA_FONT_ITALIC
, 0.8);
1689 if (umlclass
->classname_font
== NULL
) {
1690 umlclass
->classname_font_height
= 1.0;
1691 umlclass
->classname_font
=
1692 dia_font_new_from_style(DIA_FONT_SANS
| DIA_FONT_BOLD
, 1.0);
1694 if (umlclass
->abstract_classname_font
== NULL
) {
1695 umlclass
->abstract_classname_font_height
= 1.0;
1696 umlclass
->abstract_classname_font
=
1697 dia_font_new_from_style(DIA_FONT_SANS
| DIA_FONT_BOLD
| DIA_FONT_ITALIC
, 1.0);
1699 if (umlclass
->comment_font
== NULL
) {
1700 umlclass
->comment_font_height
= 0.7;
1701 umlclass
->comment_font
= dia_font_new_from_style(DIA_FONT_SANS
| DIA_FONT_ITALIC
, 0.7);
1706 umlclass_create(Point
*startpoint
,
1716 umlclass
= g_malloc0(sizeof(UMLClass
));
1717 elem
= ¨class
->element
;
1718 obj
= &elem
->object
;
1720 obj
->type
= ¨class_type
;
1722 obj
->ops
= ¨class_ops
;
1724 elem
->corner
= *startpoint
;
1726 #ifdef UML_MAINPOINT
1727 element_init(elem
, 8, UMLCLASS_CONNECTIONPOINTS
+ 1); /* No attribs or ops => 0 extra connectionpoints. */
1729 element_init(elem
, 8, UMLCLASS_CONNECTIONPOINTS
); /* No attribs or ops => 0 extra connectionpoints. */
1732 umlclass
->properties_dialog
= NULL
;
1733 fill_in_fontdata(umlclass
);
1735 umlclass
->name
= g_strdup (_("Class"));
1736 umlclass
->stereotype
= NULL
;
1737 umlclass
->comment
= NULL
;
1739 umlclass
->abstract
= FALSE
;
1741 umlclass
->suppress_attributes
= FALSE
;
1742 umlclass
->suppress_operations
= FALSE
;
1744 umlclass
->visible_attributes
= TRUE
;
1745 umlclass
->visible_operations
= TRUE
;
1746 umlclass
->visible_comments
= FALSE
;
1748 umlclass
->wrap_operations
= TRUE
;
1749 umlclass
->wrap_after_char
= UMLCLASS_WRAP_AFTER_CHAR
;
1751 umlclass
->attributes
= NULL
;
1753 umlclass
->operations
= NULL
;
1755 umlclass
->template = (GPOINTER_TO_INT(user_data
)==1);
1756 umlclass
->formal_params
= NULL
;
1758 umlclass
->stereotype_string
= NULL
;
1759 umlclass
->attributes_strings
= NULL
;
1760 umlclass
->operations_strings
= NULL
;
1761 umlclass
->operations_wrappos
= NULL
;
1762 umlclass
->templates_strings
= NULL
;
1764 umlclass
->text_color
= color_black
;
1765 umlclass
->line_color
= attributes_get_foreground();
1766 umlclass
->fill_color
= attributes_get_background();
1768 umlclass_calculate_data(umlclass
);
1770 for (i
=0;i
<UMLCLASS_CONNECTIONPOINTS
;i
++) {
1771 obj
->connections
[i
] = ¨class
->connections
[i
];
1772 umlclass
->connections
[i
].object
= obj
;
1773 umlclass
->connections
[i
].connected
= NULL
;
1775 #ifdef UML_MAINPOINT
1776 /* Put mainpoint at the end, after conditional attr/oprn points,
1777 * but store it in the local connectionpoint array. */
1778 i
+= umlclass_num_dynamic_connectionpoints(umlclass
);
1779 obj
->connections
[i
] = ¨class
->connections
[UMLCLASS_CONNECTIONPOINTS
];
1780 umlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].object
= obj
;
1781 umlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].connected
= NULL
;
1784 elem
->extra_spacing
.border_trans
= UMLCLASS_BORDER
/2.0;
1785 umlclass_update_data(umlclass
);
1788 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
1793 return ¨class
->element
.object
;
1797 umlclass_destroy(UMLClass
*umlclass
)
1803 UMLFormalParameter
*param
;
1805 umlclass_sanity_check(umlclass
, "Destroying");
1807 umlclass
->destroyed
= TRUE
;
1809 dia_font_unref(umlclass
->normal_font
);
1810 dia_font_unref(umlclass
->abstract_font
);
1811 dia_font_unref(umlclass
->polymorphic_font
);
1812 dia_font_unref(umlclass
->classname_font
);
1813 dia_font_unref(umlclass
->abstract_classname_font
);
1814 dia_font_unref(umlclass
->comment_font
);
1816 element_destroy(¨class
->element
);
1818 g_free(umlclass
->name
);
1819 g_free(umlclass
->stereotype
);
1820 g_free(umlclass
->comment
);
1822 list
= umlclass
->attributes
;
1823 while (list
!= NULL
) {
1824 attr
= (UMLAttribute
*)list
->data
;
1825 printf("Destroying attr %p\n", attr
);
1826 uml_attribute_destroy(attr
);
1827 list
= g_list_next(list
);
1829 printf("Freeing umlclass->attributes %p\n", umlclass
->attributes
);
1830 g_list_free(umlclass
->attributes
);
1832 list
= umlclass
->operations
;
1833 while (list
!= NULL
) {
1834 op
= (UMLOperation
*)list
->data
;
1835 uml_operation_destroy(op
);
1836 list
= g_list_next(list
);
1838 g_list_free(umlclass
->operations
);
1840 list
= umlclass
->formal_params
;
1841 while (list
!= NULL
) {
1842 param
= (UMLFormalParameter
*)list
->data
;
1843 uml_formalparameter_destroy(param
);
1844 list
= g_list_next(list
);
1846 g_list_free(umlclass
->formal_params
);
1848 if (umlclass
->stereotype_string
!= NULL
) {
1849 g_free(umlclass
->stereotype_string
);
1852 if (umlclass
->attributes_strings
!= NULL
) {
1853 g_list_foreach(umlclass
->attributes_strings
, (GFunc
)g_free
, NULL
);
1854 g_list_free(umlclass
->attributes_strings
);
1855 umlclass
->attributes_strings
= NULL
;
1858 if (umlclass
->operations_strings
!= NULL
) {
1859 g_list_foreach(umlclass
->operations_strings
, (GFunc
)g_free
, NULL
);
1860 g_list_free(umlclass
->operations_strings
);
1861 umlclass
->operations_strings
= NULL
;
1864 if (umlclass
->operations_wrappos
!= NULL
) {
1865 g_list_foreach(umlclass
->operations_wrappos
, (GFunc
)g_list_free
, NULL
);
1866 g_list_free(umlclass
->operations_wrappos
);
1867 umlclass
->operations_wrappos
= NULL
;
1870 if (umlclass
->templates_strings
!= NULL
) {
1871 for (i
=0;i
<umlclass
->num_templates
;i
++) {
1872 g_free(umlclass
->templates_strings
[i
]);
1874 g_free(umlclass
->templates_strings
);
1877 if (umlclass
->properties_dialog
!= NULL
) {
1878 g_list_free(umlclass
->properties_dialog
->deleted_connections
);
1879 gtk_widget_destroy(umlclass
->properties_dialog
->dialog
);
1880 g_free(umlclass
->properties_dialog
);
1885 umlclass_copy(UMLClass
*umlclass
)
1888 UMLClass
*newumlclass
;
1889 Element
*elem
, *newelem
;
1893 UMLAttribute
*newattr
;
1895 UMLOperation
*newop
;
1896 UMLFormalParameter
*param
;
1898 elem
= ¨class
->element
;
1900 newumlclass
= g_malloc0(sizeof(UMLClass
));
1901 newelem
= &newumlclass
->element
;
1902 newobj
= &newelem
->object
;
1904 element_copy(elem
, newelem
);
1906 newumlclass
->font_height
= umlclass
->font_height
;
1907 newumlclass
->abstract_font_height
= umlclass
->abstract_font_height
;
1908 newumlclass
->polymorphic_font_height
= umlclass
->polymorphic_font_height
;
1909 newumlclass
->classname_font_height
= umlclass
->classname_font_height
;
1910 newumlclass
->abstract_classname_font_height
=
1911 umlclass
->abstract_classname_font_height
;
1912 newumlclass
->comment_font_height
=
1913 umlclass
->comment_font_height
;
1915 newumlclass
->normal_font
=
1916 dia_font_ref(umlclass
->normal_font
);
1917 newumlclass
->abstract_font
=
1918 dia_font_ref(umlclass
->abstract_font
);
1919 newumlclass
->polymorphic_font
=
1920 dia_font_ref(umlclass
->polymorphic_font
);
1921 newumlclass
->classname_font
=
1922 dia_font_ref(umlclass
->classname_font
);
1923 newumlclass
->abstract_classname_font
=
1924 dia_font_ref(umlclass
->abstract_classname_font
);
1925 newumlclass
->comment_font
=
1926 dia_font_ref(umlclass
->comment_font
);
1928 newumlclass
->name
= g_strdup(umlclass
->name
);
1929 if (umlclass
->stereotype
!= NULL
&& umlclass
->stereotype
[0] != '\0')
1930 newumlclass
->stereotype
= g_strdup(umlclass
->stereotype
);
1932 newumlclass
->stereotype
= NULL
;
1934 if (umlclass
->comment
!= NULL
)
1935 newumlclass
->comment
= g_strdup(umlclass
->comment
);
1937 newumlclass
->comment
= NULL
;
1939 newumlclass
->abstract
= umlclass
->abstract
;
1940 newumlclass
->suppress_attributes
= umlclass
->suppress_attributes
;
1941 newumlclass
->suppress_operations
= umlclass
->suppress_operations
;
1942 newumlclass
->visible_attributes
= umlclass
->visible_attributes
;
1943 newumlclass
->visible_operations
= umlclass
->visible_operations
;
1944 newumlclass
->visible_comments
= umlclass
->visible_comments
;
1945 newumlclass
->wrap_operations
= umlclass
->wrap_operations
;
1946 newumlclass
->wrap_after_char
= umlclass
->wrap_after_char
;
1947 newumlclass
->Comment_line_length
= umlclass
->Comment_line_length
;
1948 newumlclass
->text_color
= umlclass
->text_color
;
1949 newumlclass
->line_color
= umlclass
->line_color
;
1950 newumlclass
->fill_color
= umlclass
->fill_color
;
1952 newumlclass
->attributes
= NULL
;
1953 list
= umlclass
->attributes
;
1954 while (list
!= NULL
) {
1955 attr
= (UMLAttribute
*)list
->data
;
1956 newattr
= uml_attribute_copy(attr
, newobj
);
1958 newumlclass
->attributes
= g_list_prepend(newumlclass
->attributes
,
1960 list
= g_list_next(list
);
1963 newumlclass
->operations
= NULL
;
1964 list
= umlclass
->operations
;
1965 while (list
!= NULL
) {
1966 op
= (UMLOperation
*)list
->data
;
1967 newop
= uml_operation_copy(op
);
1968 newop
->left_connection
->object
= newobj
;
1969 newop
->left_connection
->connected
= NULL
;
1971 newop
->right_connection
->object
= newobj
;
1972 newop
->right_connection
->connected
= NULL
;
1974 newumlclass
->operations
= g_list_prepend(newumlclass
->operations
,
1976 list
= g_list_next(list
);
1979 newumlclass
->template = umlclass
->template;
1981 newumlclass
->formal_params
= NULL
;
1982 list
= umlclass
->formal_params
;
1983 while (list
!= NULL
) {
1984 param
= (UMLFormalParameter
*)list
->data
;
1985 newumlclass
->formal_params
=
1986 g_list_prepend(newumlclass
->formal_params
,
1987 uml_formalparameter_copy(param
));
1988 list
= g_list_next(list
);
1991 newumlclass
->properties_dialog
= NULL
;
1993 newumlclass
->stereotype_string
= NULL
;
1994 newumlclass
->attributes_strings
= NULL
;
1995 newumlclass
->operations_strings
= NULL
;
1996 newumlclass
->operations_wrappos
= NULL
;
1997 newumlclass
->templates_strings
= NULL
;
1999 for (i
=0;i
<UMLCLASS_CONNECTIONPOINTS
;i
++) {
2000 newobj
->connections
[i
] = &newumlclass
->connections
[i
];
2001 newumlclass
->connections
[i
].object
= newobj
;
2002 newumlclass
->connections
[i
].connected
= NULL
;
2003 newumlclass
->connections
[i
].pos
= umlclass
->connections
[i
].pos
;
2004 newumlclass
->connections
[i
].last_pos
= umlclass
->connections
[i
].last_pos
;
2007 umlclass_calculate_data(newumlclass
);
2009 i
= UMLCLASS_CONNECTIONPOINTS
;
2010 if ( (newumlclass
->visible_attributes
) &&
2011 (!newumlclass
->suppress_attributes
)) {
2012 list
= newumlclass
->attributes
;
2013 while (list
!= NULL
) {
2014 attr
= (UMLAttribute
*)list
->data
;
2015 printf("Setting copy conn %d of %p to left %p\n", i
, newobj
, attr
->left_connection
);
2016 newobj
->connections
[i
++] = attr
->left_connection
;
2017 printf("Setting copy conn %d of %p to right %p\n", i
, newobj
, attr
->right_connection
);
2018 newobj
->connections
[i
++] = attr
->right_connection
;
2020 list
= g_list_next(list
);
2024 if ( (newumlclass
->visible_operations
) &&
2025 (!newumlclass
->suppress_operations
)) {
2026 list
= newumlclass
->operations
;
2027 while (list
!= NULL
) {
2028 op
= (UMLOperation
*)list
->data
;
2029 newobj
->connections
[i
++] = op
->left_connection
;
2030 newobj
->connections
[i
++] = op
->right_connection
;
2032 list
= g_list_next(list
);
2036 #ifdef UML_MAINPOINT
2037 newobj
->connections
[i
] = &newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
];
2038 newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].object
= newobj
;
2039 newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].connected
= NULL
;
2040 newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].pos
=
2041 umlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].pos
;
2042 newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].last_pos
=
2043 umlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].last_pos
;
2044 newumlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].flags
=
2045 umlclass
->connections
[UMLCLASS_CONNECTIONPOINTS
].flags
;
2049 umlclass_update_data(newumlclass
);
2051 umlclass_sanity_check(newumlclass
, "Copied");
2053 return &newumlclass
->element
.object
;
2058 umlclass_save(UMLClass
*umlclass
, ObjectNode obj_node
,
2059 const char *filename
)
2063 UMLFormalParameter
*formal_param
;
2065 AttributeNode attr_node
;
2067 umlclass_sanity_check(umlclass
, "Saving");
2069 element_save(¨class
->element
, obj_node
);
2072 data_add_string(new_attribute(obj_node
, "name"),
2074 data_add_string(new_attribute(obj_node
, "stereotype"),
2075 umlclass
->stereotype
);
2076 data_add_string(new_attribute(obj_node
, "comment"),
2078 data_add_boolean(new_attribute(obj_node
, "abstract"),
2079 umlclass
->abstract
);
2080 data_add_boolean(new_attribute(obj_node
, "suppress_attributes"),
2081 umlclass
->suppress_attributes
);
2082 data_add_boolean(new_attribute(obj_node
, "suppress_operations"),
2083 umlclass
->suppress_operations
);
2084 data_add_boolean(new_attribute(obj_node
, "visible_attributes"),
2085 umlclass
->visible_attributes
);
2086 data_add_boolean(new_attribute(obj_node
, "visible_operations"),
2087 umlclass
->visible_operations
);
2088 data_add_boolean(new_attribute(obj_node
, "visible_comments"),
2089 umlclass
->visible_comments
);
2090 data_add_boolean(new_attribute(obj_node
, "wrap_operations"),
2091 umlclass
->wrap_operations
);
2092 data_add_int(new_attribute(obj_node
, "wrap_after_char"),
2093 umlclass
->wrap_after_char
);
2094 data_add_int(new_attribute(obj_node
, "Comment_line_length"),
2095 umlclass
->Comment_line_length
);
2096 data_add_color(new_attribute(obj_node
, "line_color"),
2097 ¨class
->line_color
);
2098 data_add_color(new_attribute(obj_node
, "fill_color"),
2099 ¨class
->fill_color
);
2100 data_add_color(new_attribute(obj_node
, "text_color"),
2101 ¨class
->text_color
);
2102 data_add_font (new_attribute (obj_node
, "normal_font"),
2103 umlclass
->normal_font
);
2104 data_add_font (new_attribute (obj_node
, "abstract_font"),
2105 umlclass
->abstract_font
);
2106 data_add_font (new_attribute (obj_node
, "polymorphic_font"),
2107 umlclass
->polymorphic_font
);
2108 data_add_font (new_attribute (obj_node
, "classname_font"),
2109 umlclass
->classname_font
);
2110 data_add_font (new_attribute (obj_node
, "abstract_classname_font"),
2111 umlclass
->abstract_classname_font
);
2112 data_add_font (new_attribute (obj_node
, "comment_font"),
2113 umlclass
->comment_font
);
2114 data_add_real (new_attribute (obj_node
, "normal_font_height"),
2115 umlclass
->font_height
);
2116 data_add_real (new_attribute (obj_node
, "polymorphic_font_height"),
2117 umlclass
->polymorphic_font_height
);
2118 data_add_real (new_attribute (obj_node
, "abstract_font_height"),
2119 umlclass
->abstract_font_height
);
2120 data_add_real (new_attribute (obj_node
, "classname_font_height"),
2121 umlclass
->classname_font_height
);
2122 data_add_real (new_attribute (obj_node
, "abstract_classname_font_height"),
2123 umlclass
->abstract_classname_font_height
);
2124 data_add_real (new_attribute (obj_node
, "comment_font_height"),
2125 umlclass
->comment_font_height
);
2127 /* Attribute info: */
2128 attr_node
= new_attribute(obj_node
, "attributes");
2129 list
= umlclass
->attributes
;
2130 while (list
!= NULL
) {
2131 attr
= (UMLAttribute
*) list
->data
;
2132 printf("Writing attr %p\n", attr
);
2133 uml_attribute_write(attr_node
, attr
);
2134 list
= g_list_next(list
);
2137 /* Operations info: */
2138 attr_node
= new_attribute(obj_node
, "operations");
2139 list
= umlclass
->operations
;
2140 while (list
!= NULL
) {
2141 op
= (UMLOperation
*) list
->data
;
2142 uml_operation_write(attr_node
, op
);
2143 list
= g_list_next(list
);
2146 /* Template info: */
2147 data_add_boolean(new_attribute(obj_node
, "template"),
2148 umlclass
->template);
2150 attr_node
= new_attribute(obj_node
, "templates");
2151 list
= umlclass
->formal_params
;
2152 while (list
!= NULL
) {
2153 formal_param
= (UMLFormalParameter
*) list
->data
;
2154 uml_formalparameter_write(attr_node
, formal_param
);
2155 list
= g_list_next(list
);
2159 static DiaObject
*umlclass_load(ObjectNode obj_node
, int version
,
2160 const char *filename
)
2165 AttributeNode attr_node
;
2170 umlclass
= g_malloc0(sizeof(UMLClass
));
2171 elem
= ¨class
->element
;
2172 obj
= &elem
->object
;
2174 obj
->type
= ¨class_type
;
2175 obj
->ops
= ¨class_ops
;
2177 element_load(elem
, obj_node
);
2179 #ifdef UML_MAINPOINT
2180 element_init(elem
, 8, UMLCLASS_CONNECTIONPOINTS
+ 1);
2182 element_init(elem
, 8, UMLCLASS_CONNECTIONPOINTS
);
2185 umlclass
->properties_dialog
= NULL
;
2187 for (i
=0;i
<UMLCLASS_CONNECTIONPOINTS
;i
++) {
2188 obj
->connections
[i
] = ¨class
->connections
[i
];
2189 umlclass
->connections
[i
].object
= obj
;
2190 umlclass
->connections
[i
].connected
= NULL
;
2193 fill_in_fontdata(umlclass
);
2195 /* kind of dirty, object_load_props() may leave us in an inconsnected = NULL;
2198 fill_in_fontdata(umlclass);
2200 /* kind of dirty, object_load_props() may leave us in an inconsistent state --hb */
2201 object_load_props(obj
,obj_node
);
2202 /* a bunch of properties still need their own special handling */
2206 /* parameters loaded via StdProp dont belong here anymore. In case of strings they
2207 * will produce leaks. Otherwise the are just wasteing time (at runtime and while
2208 * reading the code). Except maybe for some compatibility stuff.
2209 * Although that *could* probably done via StdProp too. --hb
2212 /* new since 0.94, don't wrap by default to keep old diagrams intact */
2213 umlclass
->wrap_operations
= FALSE
;
2214 attr_node
= object_find_attribute(obj_node
, "wrap_operations");
2215 if (attr_node
!= NULL
)
2216 umlclass
->wrap_operations
= data_boolean(attribute_first_data(attr_node
));
2218 umlclass
->wrap_after_char
= UMLCLASS_WRAP_AFTER_CHAR
;
2219 attr_node
= object_find_attribute(obj_node
, "wrap_after_char");
2220 if (attr_node
!= NULL
)
2221 umlclass
->wrap_after_char
= data_int(attribute_first_data(attr_node
));
2223 umlclass
->Comment_line_length
= UMLCLASS_COMMENT_LINE_LENGTH
;
2224 attr_node
= object_find_attribute(obj_node
,"Comment_line_length");
2225 if (attr_node
!= NULL
)
2227 umlclass
->Comment_line_length
= data_int(attribute_first_data(attr_node
));
2229 umlclass
->line_color
= color_black
;
2230 /* support the old name ... */
2231 attr_node
= object_find_attribute(obj_node
, "foreground_color");
2232 if(attr_node
!= NULL
)
2233 data_color(attribute_first_data(attr_node
), ¨class
->line_color
);
2234 umlclass
->text_color
= umlclass
->line_color
;
2235 /* ... but prefer the new one */
2236 attr_node
= object_find_attribute(obj_node
, "line_color");
2237 if(attr_node
!= NULL
)
2238 data_color(attribute_first_data(attr_node
), ¨class
->line_color
);
2240 umlclass
->fill_color
= color_white
;
2241 /* support the old name ... */
2242 attr_node
= object_find_attribute(obj_node
, "background_color");
2243 if(attr_node
!= NULL
)
2244 data_color(attribute_first_data(attr_node
), ¨class
->fill_color
);
2245 /* ... but prefer the new one */
2246 attr_node
= object_find_attribute(obj_node
, "fill_color");
2247 if(attr_node
!= NULL
)
2248 data_color(attribute_first_data(attr_node
), ¨class
->fill_color
);
2250 /* Attribute info: */
2251 list
= umlclass
->attributes
;
2253 UMLAttribute
*attr
= list
->data
;
2256 attr
->left_connection
->object
= obj
;
2257 attr
->left_connection
->connected
= NULL
;
2258 attr
->right_connection
->object
= obj
;
2259 attr
->right_connection
->connected
= NULL
;
2260 list
= g_list_next(list
);
2263 /* Operations info: */
2264 list
= umlclass
->operations
;
2266 UMLOperation
*op
= (UMLOperation
*)list
->data
;
2269 op
->left_connection
->object
= obj
;
2270 op
->left_connection
->connected
= NULL
;
2272 op
->right_connection
->object
= obj
;
2273 op
->right_connection
->connected
= NULL
;
2274 list
= g_list_next(list
);
2277 /* Template info: */
2278 umlclass
->template = FALSE
;
2279 attr_node
= object_find_attribute(obj_node
, "template");
2280 if (attr_node
!= NULL
)
2281 umlclass
->template = data_boolean(attribute_first_data(attr_node
));
2283 fill_in_fontdata(umlclass
);
2285 umlclass
->stereotype_string
= NULL
;
2286 umlclass
->attributes_strings
= NULL
;
2287 umlclass
->operations_strings
= NULL
;
2288 umlclass
->operations_wrappos
= NULL
;
2289 umlclass
->templates_strings
= NULL
;
2291 umlclass_calculate_data(umlclass
);
2293 elem
->extra_spacing
.border_trans
= UMLCLASS_BORDER
/2.0;
2294 umlclass_update_data(umlclass
);
2297 obj
->handles
[i
]->type
= HANDLE_NON_MOVABLE
;
2300 umlclass_sanity_check(umlclass
, "Loaded class");
2302 return ¨class
->element
.object
;
2305 /** Returns the number of connection points used by the attributes and
2306 * connections in the current state of the object.
2309 umlclass_num_dynamic_connectionpoints(UMLClass
*umlclass
) {
2311 if ( (umlclass
->visible_attributes
) &&
2312 (!umlclass
->suppress_attributes
)) {
2313 GList
*list
= umlclass
->attributes
;
2314 num
+= 2 * g_list_length(list
);
2317 if ( (umlclass
->visible_operations
) &&
2318 (!umlclass
->suppress_operations
)) {
2319 GList
*list
= umlclass
->operations
;
2320 num
+= 2 * g_list_length(list
);
2326 umlclass_sanity_check(UMLClass
*c
, gchar
*msg
)
2328 #ifdef UML_MAINPOINT
2329 int num_fixed_connections
= UMLCLASS_CONNECTIONPOINTS
+ 1;
2331 int num_fixed_connections
= UMLCLASS_CONNECTIONPOINTS
;
2333 DiaObject
*obj
= (DiaObject
*)c
;
2337 dia_object_sanity_check((DiaObject
*)c
, msg
);
2339 /* Check that num_connections is correct */
2340 dia_assert_true(num_fixed_connections
+ umlclass_num_dynamic_connectionpoints(c
)
2341 == obj
->num_connections
,
2342 "%s: Class %p has %d connections, but %d fixed and %d dynamic\n",
2343 msg
, c
, obj
->num_connections
, num_fixed_connections
,
2344 umlclass_num_dynamic_connectionpoints(c
));
2346 for (i
= 0; i
< UMLCLASS_CONNECTIONPOINTS
; i
++) {
2347 dia_assert_true(&c
->connections
[i
] == obj
->connections
[i
],
2348 "%s: Class %p connection mismatch at %d: %p != %p\n",
2349 msg
, c
, i
, &c
->connections
[i
], obj
->connections
[i
]);
2352 #ifdef UML_MAINPOINT
2353 dia_assert_true(&c
->connections
[i
] ==
2354 obj
->connections
[i
+ umlclass_num_dynamic_connectionpoints(c
)],
2355 "%s: Class %p mainpoint mismatch: %p != %p (at %d)\n",
2356 msg
, c
, i
, &c
->connections
[i
],
2357 obj
->connections
[i
+ umlclass_num_dynamic_connectionpoints(c
)],
2358 i
+ umlclass_num_dynamic_connectionpoints(c
));
2361 /* Check that attributes are set up right. */
2363 for (attrs
= c
->attributes
; attrs
!= NULL
; attrs
= g_list_next(attrs
)) {
2364 UMLAttribute
*attr
= (UMLAttribute
*)attrs
->data
;
2365 int conn_offset
= UMLCLASS_CONNECTIONPOINTS
+ 2 * i
;
2366 dia_assert_true(attr
->name
!= NULL
,
2367 "%s: %p attr %d has null name\n",
2369 dia_assert_true(attr
->type
!= NULL
,
2370 "%s: %p attr %d has null type\n",
2372 dia_assert_true(attr
->comment
!= NULL
,
2373 "%s: %p attr %d has null comment\n",
2376 dia_assert_true(attr
->left_connection
!= NULL
,
2377 "%s: %p attr %d has null left connection\n",
2379 dia_assert_true(attr
->left_connection
== obj
->connections
[conn_offset
],
2380 "%s: %p attr %d left conn %p doesn't match obj conn %d: %p\n",
2381 msg
, c
, i
, attr
->left_connection
,
2382 conn_offset
, obj
->connections
[conn_offset
]);
2383 dia_assert_true(attr
->right_connection
== obj
->connections
[conn_offset
+ 1],
2384 "%s: %p attr %d right conn %p doesn't match obj conn %d: %p\n",
2385 msg
, c
, i
, attr
->right_connection
,
2386 conn_offset
+ 1, obj
->connections
[conn_offset
+ 1]);
2387 dia_assert_true(attr
->right_connection
!= NULL
,
2388 "%s: %p attr %d has null right connection\n",
2393 /* Check that operations are set up right. */