/* Dia -- an diagram creation/manipulation program * Copyright (C) 1998 Alexander Larsson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "config.h" #include "intl.h" #include "render.h" #include "attributes.h" #include "class.h" #include "pixmaps/umlclass.xpm" #define UMLCLASS_BORDER 0.1 #define UMLCLASS_UNDERLINEWIDTH 0.05 static real umlclass_distance_from(UMLClass *umlclass, Point *point); static void umlclass_select(UMLClass *umlclass, Point *clicked_point, Renderer *interactive_renderer); static void umlclass_move_handle(UMLClass *umlclass, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers); static void umlclass_move(UMLClass *umlclass, Point *to); static void umlclass_draw(UMLClass *umlclass, Renderer *renderer); static Object *umlclass_create(Point *startpoint, void *user_data, Handle **handle1, Handle **handle2); static void umlclass_destroy(UMLClass *umlclass); static Object *umlclass_copy(UMLClass *umlclass); static void umlclass_save(UMLClass *umlclass, ObjectNode obj_node, const char *filename); static Object *umlclass_load(ObjectNode obj_node, int version, const char *filename); static ObjectTypeOps umlclass_type_ops = { (CreateFunc) umlclass_create, (LoadFunc) umlclass_load, (SaveFunc) umlclass_save }; ObjectType umlclass_type = { "UML - Class", /* name */ 0, /* version */ (char **) umlclass_xpm, /* pixmap */ ¨class_type_ops /* ops */ }; static ObjectOps umlclass_ops = { (DestroyFunc) umlclass_destroy, (DrawFunc) umlclass_draw, (DistanceFunc) umlclass_distance_from, (SelectFunc) umlclass_select, (CopyFunc) umlclass_copy, (MoveFunc) umlclass_move, (MoveHandleFunc) umlclass_move_handle, (GetPropertiesFunc) umlclass_get_properties, (ApplyPropertiesFunc) umlclass_apply_properties, (ObjectMenuFunc) NULL }; static real umlclass_distance_from(UMLClass *umlclass, Point *point) { Object *obj = ¨class->element.object; return distance_rectangle_point(&obj->bounding_box, point); } static void umlclass_select(UMLClass *umlclass, Point *clicked_point, Renderer *interactive_renderer) { element_update_handles(¨class->element); } static void umlclass_move_handle(UMLClass *umlclass, Handle *handle, Point *to, HandleMoveReason reason, ModifierKeys modifiers) { assert(umlclass!=NULL); assert(handle!=NULL); assert(to!=NULL); assert(handle->id < 8); } static void umlclass_move(UMLClass *umlclass, Point *to) { umlclass->element.corner = *to; umlclass_update_data(umlclass); } static void umlclass_draw(UMLClass *umlclass, Renderer *renderer) { Element *elem; real x,y; Point p, p1, p2, p3; Font *font; int i; GList *list; assert(umlclass != NULL); assert(renderer != NULL); elem = ¨class->element; x = elem->corner.x; y = elem->corner.y; renderer->ops->set_fillstyle(renderer, FILLSTYLE_SOLID); renderer->ops->set_linewidth(renderer, UMLCLASS_BORDER); renderer->ops->set_linestyle(renderer, LINESTYLE_SOLID); p1.x = x; p2.x = x + elem->width; p1.y = y; y += umlclass->namebox_height; p2.y = y; renderer->ops->fill_rect(renderer, &p1, &p2, &color_white); renderer->ops->draw_rect(renderer, &p1, &p2, &color_black); /* stereotype: */ font = umlclass->normal_font; p.x = x + elem->width / 2.0; p.y = p1.y; if (umlclass->stereotype != NULL) { p.y += 0.1 + umlclass->font_ascent; renderer->ops->set_font(renderer, font, umlclass->font_height); renderer->ops->draw_string(renderer, umlclass->stereotype_string, &p, ALIGN_CENTER, &color_black); } /* name: */ if (umlclass->abstract) font = umlclass->abstract_classname_font; else font = umlclass->classname_font; p.y += umlclass->classname_font_height; renderer->ops->set_font(renderer, font, umlclass->classname_font_height); renderer->ops->draw_string(renderer, umlclass->name, &p, ALIGN_CENTER, &color_black); if (umlclass->visible_attributes) { p1.x = x; p1.y = y; y += umlclass->attributesbox_height; p2.y = y; renderer->ops->fill_rect(renderer, &p1, &p2, &color_white); renderer->ops->draw_rect(renderer, &p1, &p2, &color_black); if (!umlclass->suppress_attributes) { p.x = x + UMLCLASS_BORDER/2.0 + 0.1; p.y = p1.y + 0.1 + umlclass->font_ascent; i = 0; list = umlclass->attributes; while (list != NULL) { UMLAttribute *attr = (UMLAttribute *)list->data; if (attr->abstract) font = umlclass->abstract_font; else font = umlclass->normal_font; renderer->ops->set_font(renderer, font, umlclass->font_height); renderer->ops->draw_string(renderer, umlclass->attributes_strings[i], &p, ALIGN_LEFT, &color_black); if (attr->class_scope) { p1 = p; p1.y += umlclass->font_height*0.1; p3 = p1; p3.x += font_string_width(umlclass->attributes_strings[i], font, umlclass->font_height); renderer->ops->set_linewidth(renderer, UMLCLASS_UNDERLINEWIDTH); renderer->ops->draw_line(renderer, &p1, &p3, &color_black); renderer->ops->set_linewidth(renderer, UMLCLASS_BORDER); } p.y += umlclass->font_height; list = g_list_next(list); i++; } } } if (umlclass->visible_operations) { p1.x = x; p1.y = y; y += umlclass->operationsbox_height; p2.y = y; renderer->ops->fill_rect(renderer, &p1, &p2, &color_white); renderer->ops->draw_rect(renderer, &p1, &p2, &color_black); if (!umlclass->suppress_operations) { p.x = x + UMLCLASS_BORDER/2.0 + 0.1; p.y = p1.y + 0.1 + umlclass->font_ascent; i = 0; list = umlclass->operations; while (list != NULL) { UMLOperation *op = (UMLOperation *)list->data; if (op->abstract) font = umlclass->abstract_font; else font = umlclass->normal_font; renderer->ops->set_font(renderer, font, umlclass->font_height); renderer->ops->draw_string(renderer, umlclass->operations_strings[i], &p, ALIGN_LEFT, &color_black); if (op->class_scope) { p1 = p; p1.y += umlclass->font_height*0.1; p3 = p1; p3.x += font_string_width(umlclass->operations_strings[i], font, umlclass->font_height); renderer->ops->set_linewidth(renderer, UMLCLASS_UNDERLINEWIDTH); renderer->ops->draw_line(renderer, &p1, &p3, &color_black); renderer->ops->set_linewidth(renderer, UMLCLASS_BORDER); } p.y += umlclass->font_height; list = g_list_next(list); i++; } } } if (umlclass->template) { x = elem->corner.x + elem->width - 2.3; y = elem->corner.y - umlclass->templates_height + 0.3; p1.x = x; p1.y = y; p2.x = x + umlclass->templates_width; p2.y = y + umlclass->templates_height; renderer->ops->fill_rect(renderer, &p1, &p2, &color_white); renderer->ops->set_linestyle(renderer, LINESTYLE_DASHED); renderer->ops->set_dashlength(renderer, 0.3); renderer->ops->draw_rect(renderer, &p1, &p2, &color_black); p.x = x + 0.3; p.y = y + 0.1 + font_ascent(umlclass->normal_font, umlclass->font_height); renderer->ops->set_font(renderer, umlclass->normal_font, umlclass->font_height); i = 0; list = umlclass->formal_params; while (list != NULL) { /*UMLFormalParameter *param = (UMLFormalParameter *)list->data;*/ renderer->ops->draw_string(renderer, umlclass->templates_strings[i], &p, ALIGN_LEFT, &color_black); p.y += umlclass->font_height; list = g_list_next(list); i++; } } } void umlclass_update_data(UMLClass *umlclass) { Element *elem = ¨class->element; Object *obj = (Object *)umlclass; real x,y; GList *list; x = elem->corner.x; y = elem->corner.y; /* Update connections: */ umlclass->connections[0].pos = elem->corner; umlclass->connections[1].pos.x = x + elem->width / 2.0; umlclass->connections[1].pos.y = y; umlclass->connections[2].pos.x = x + elem->width; umlclass->connections[2].pos.y = y; umlclass->connections[3].pos.x = x; umlclass->connections[3].pos.y = y + umlclass->namebox_height/2.0; umlclass->connections[4].pos.x = x + elem->width; umlclass->connections[4].pos.y = y + umlclass->namebox_height/2.0; umlclass->connections[5].pos.x = x; umlclass->connections[5].pos.y = y + elem->height; umlclass->connections[6].pos.x = x + elem->width / 2.0; umlclass->connections[6].pos.y = y + elem->height; umlclass->connections[7].pos.x = x + elem->width; umlclass->connections[7].pos.y = y + elem->height; y += umlclass->namebox_height + 0.1 + umlclass->font_height/2; list = umlclass->attributes; while (list != NULL) { UMLAttribute *attr = (UMLAttribute *)list->data; attr->left_connection->pos.x = x; attr->left_connection->pos.y = y; attr->right_connection->pos.x = x + elem->width; attr->right_connection->pos.y = y; y += umlclass->font_height; list = g_list_next(list); } y = elem->corner.y + umlclass->namebox_height + umlclass->attributesbox_height + 0.1 + umlclass->font_height/2; list = umlclass->operations; while (list != NULL) { UMLOperation *op = (UMLOperation *)list->data; op->left_connection->pos.x = x; op->left_connection->pos.y = y; op->right_connection->pos.x = x + elem->width; op->right_connection->pos.y = y; y += umlclass->font_height; list = g_list_next(list); } element_update_boundingbox(elem); /* fix boundingumlclass for line_width: */ obj->bounding_box.top -= UMLCLASS_BORDER/2.0; obj->bounding_box.left -= UMLCLASS_BORDER/2.0; obj->bounding_box.bottom += UMLCLASS_BORDER/2.0; obj->bounding_box.right += UMLCLASS_BORDER/2.0; if (umlclass->template) { /* fix boundingumlclass for templates: */ obj->bounding_box.top -= (umlclass->templates_height - 0.3) ; obj->bounding_box.right += (umlclass->templates_width - 2.3); } obj->position = elem->corner; element_update_handles(elem); } void umlclass_calculate_data(UMLClass *umlclass) { real font_height; int i; GList *list; real maxwidth; real width; font_height = umlclass->font_height; umlclass->font_ascent = font_ascent(umlclass->normal_font, font_height); /* name box: */ if (umlclass->abstract) maxwidth = font_string_width(umlclass->name, umlclass->abstract_classname_font, umlclass->classname_font_height); else maxwidth = font_string_width(umlclass->name, umlclass->classname_font, umlclass->classname_font_height); umlclass->namebox_height = umlclass->classname_font_height + 4*0.1; if (umlclass->stereotype_string != NULL) { g_free(umlclass->stereotype_string); } if (umlclass->stereotype != NULL) { umlclass->namebox_height += font_height; umlclass->stereotype_string = g_malloc(sizeof(char)*(strlen(umlclass->stereotype)+2+1)); umlclass->stereotype_string[0] = UML_STEREOTYPE_START; umlclass->stereotype_string[1] = 0; strcat(umlclass->stereotype_string, umlclass->stereotype); i = strlen(umlclass->stereotype_string); umlclass->stereotype_string[i] = UML_STEREOTYPE_END; umlclass->stereotype_string[i+1] = 0; width = font_string_width(umlclass->stereotype_string, umlclass->normal_font, font_height); maxwidth = MAX(width, maxwidth); } else { umlclass->stereotype_string = NULL; } /* attributes box: */ if (umlclass->attributes_strings != NULL) { for (i=0;inum_attributes;i++) { g_free(umlclass->attributes_strings[i]); } g_free(umlclass->attributes_strings); } umlclass->num_attributes = g_list_length(umlclass->attributes); umlclass->attributesbox_height = font_height * umlclass->num_attributes + 2*0.1; if ((umlclass->attributesbox_height<0.4) || umlclass->suppress_attributes ) umlclass->attributesbox_height = 0.4; if (!umlclass->visible_attributes ) umlclass->attributesbox_height = 0.0; umlclass->attributes_strings = NULL; if (umlclass->num_attributes != 0) { umlclass->attributes_strings = g_malloc(sizeof(char *)*umlclass->num_attributes); i = 0; list = umlclass->attributes; while (list != NULL) { UMLAttribute *attr; attr = (UMLAttribute *) list->data; umlclass->attributes_strings[i] = uml_get_attribute_string(attr); if (attr->abstract) width = font_string_width(umlclass->attributes_strings[i], umlclass->abstract_font, font_height); else width = font_string_width(umlclass->attributes_strings[i], umlclass->normal_font, font_height); maxwidth = MAX(width, maxwidth); i++; list = g_list_next(list); } } /* operations box: */ if (umlclass->operations_strings != NULL) { for (i=0;inum_operations;i++) { g_free(umlclass->operations_strings[i]); } g_free(umlclass->operations_strings); } umlclass->num_operations = g_list_length(umlclass->operations); umlclass->operationsbox_height = font_height * umlclass->num_operations + 2*0.1; if ((umlclass->operationsbox_height<0.4) || umlclass->suppress_operations ) umlclass->operationsbox_height = 0.4; umlclass->operations_strings = NULL; if (umlclass->num_operations != 0) { umlclass->operations_strings = g_malloc(sizeof(char *)*umlclass->num_operations); i = 0; list = umlclass->operations; while (list != NULL) { UMLOperation *op; op = (UMLOperation *) list->data; umlclass->operations_strings[i] = uml_get_operation_string(op); if (op->abstract) width = font_string_width(umlclass->operations_strings[i], umlclass->abstract_font, font_height); else width = font_string_width(umlclass->operations_strings[i], umlclass->normal_font, font_height); maxwidth = MAX(width, maxwidth); i++; list = g_list_next(list); } } umlclass->element.width = maxwidth + 2*0.3; umlclass->element.height = umlclass->namebox_height; if (umlclass->visible_attributes) umlclass->element.height += umlclass->attributesbox_height; if (umlclass->visible_operations) umlclass->element.height += umlclass->operationsbox_height; /* templates box: */ if (umlclass->templates_strings != NULL) { for (i=0;inum_templates;i++) { g_free(umlclass->templates_strings[i]); } g_free(umlclass->templates_strings); } umlclass->num_templates = g_list_length(umlclass->formal_params); umlclass->templates_height = font_height * umlclass->num_templates + 2*0.1; umlclass->templates_height = MAX(umlclass->templates_height, 1.0); umlclass->templates_strings = NULL; maxwidth = 2.3; if (umlclass->num_templates != 0) { umlclass->templates_strings = g_malloc(sizeof(char *)*umlclass->num_templates); i = 0; list = umlclass->formal_params; while (list != NULL) { UMLFormalParameter *param; param = (UMLFormalParameter *) list->data; umlclass->templates_strings[i] = uml_get_formalparameter_string(param); width = font_string_width(umlclass->templates_strings[i], umlclass->normal_font, font_height); maxwidth = MAX(width, maxwidth); i++; list = g_list_next(list); } } umlclass->templates_width = maxwidth + 2*0.2; } static void fill_in_fontdata(UMLClass *umlclass) { umlclass->font_height = 0.8; umlclass->classname_font_height = 1.0; umlclass->normal_font = font_getfont("Courier"); umlclass->abstract_font = font_getfont("Courier-Oblique"); umlclass->classname_font = font_getfont("Helvetica-Bold"); umlclass->abstract_classname_font = font_getfont("Helvetica-BoldOblique"); } static Object * umlclass_create(Point *startpoint, void *user_data, Handle **handle1, Handle **handle2) { UMLClass *umlclass; Element *elem; Object *obj; int i; umlclass = g_malloc(sizeof(UMLClass)); elem = ¨class->element; obj = (Object *) umlclass; obj->type = ¨class_type; obj->ops = ¨class_ops; elem->corner = *startpoint; element_init(elem, 8, 8); /* No attribs or ops => 0 extra connectionpoints. */ umlclass->properties_dialog = NULL; fill_in_fontdata(umlclass); umlclass->name = strdup(_("Class")); umlclass->stereotype = NULL; umlclass->abstract = FALSE; umlclass->suppress_attributes = FALSE; umlclass->suppress_operations = FALSE; umlclass->visible_attributes = TRUE; umlclass->visible_operations = TRUE; umlclass->attributes = NULL; umlclass->operations = NULL; umlclass->template = (GPOINTER_TO_INT(user_data)==1); umlclass->formal_params = NULL; umlclass->stereotype_string = NULL; umlclass->attributes_strings = NULL; umlclass->operations_strings = NULL; umlclass->templates_strings = NULL; umlclass_calculate_data(umlclass); for (i=0;i<8;i++) { obj->connections[i] = ¨class->connections[i]; umlclass->connections[i].object = obj; umlclass->connections[i].connected = NULL; } umlclass_update_data(umlclass); for (i=0;i<8;i++) { obj->handles[i]->type = HANDLE_NON_MOVABLE; } *handle1 = NULL; *handle2 = NULL; return (Object *)umlclass; } static void umlclass_destroy(UMLClass *umlclass) { int i; GList *list; UMLAttribute *attr; UMLOperation *op; UMLFormalParameter *param; element_destroy(¨class->element); g_free(umlclass->name); if (umlclass->stereotype != NULL) g_free(umlclass->stereotype); list = umlclass->attributes; while (list != NULL) { attr = (UMLAttribute *)list->data; g_free(attr->left_connection); g_free(attr->right_connection); uml_attribute_destroy(attr); list = g_list_next(list); } g_list_free(umlclass->attributes); list = umlclass->operations; while (list != NULL) { op = (UMLOperation *)list->data; g_free(op->left_connection); g_free(op->right_connection); uml_operation_destroy(op); list = g_list_next(list); } g_list_free(umlclass->operations); list = umlclass->formal_params; while (list != NULL) { param = (UMLFormalParameter *)list->data; uml_formalparameter_destroy(param); list = g_list_next(list); } g_list_free(umlclass->formal_params); if (umlclass->stereotype_string != NULL) { g_free(umlclass->stereotype_string); } if (umlclass->attributes_strings != NULL) { for (i=0;inum_attributes;i++) { g_free(umlclass->attributes_strings[i]); } g_free(umlclass->attributes_strings); } if (umlclass->operations_strings != NULL) { for (i=0;inum_operations;i++) { g_free(umlclass->operations_strings[i]); } g_free(umlclass->operations_strings); } if (umlclass->templates_strings != NULL) { for (i=0;inum_templates;i++) { g_free(umlclass->templates_strings[i]); } g_free(umlclass->templates_strings); } if (umlclass->properties_dialog != NULL) { gtk_widget_destroy(umlclass->properties_dialog->dialog); g_list_free(umlclass->properties_dialog->deleted_connections); g_free(umlclass->properties_dialog); } } static Object * umlclass_copy(UMLClass *umlclass) { int i; UMLClass *newumlclass; Element *elem, *newelem; Object *newobj; GList *list; UMLAttribute *attr; UMLAttribute *newattr; UMLOperation *op; UMLOperation *newop; UMLFormalParameter *param; elem = ¨class->element; newumlclass = g_malloc(sizeof(UMLClass)); newelem = &newumlclass->element; newobj = (Object *) newumlclass; element_copy(elem, newelem); newumlclass->font_height = umlclass->font_height; newumlclass->classname_font_height = umlclass->classname_font_height; newumlclass->normal_font = umlclass->normal_font; newumlclass->abstract_font = umlclass->abstract_font; newumlclass->classname_font = umlclass->classname_font; newumlclass->abstract_classname_font = umlclass->abstract_classname_font; newumlclass->name = strdup(umlclass->name); if (umlclass->stereotype != NULL) newumlclass->stereotype = strdup(umlclass->stereotype); else newumlclass->stereotype = NULL; newumlclass->abstract = umlclass->abstract; newumlclass->suppress_attributes = umlclass->suppress_attributes; newumlclass->suppress_operations = umlclass->suppress_operations; newumlclass->visible_attributes = umlclass->visible_attributes; newumlclass->visible_operations = umlclass->visible_operations; newumlclass->attributes = NULL; list = umlclass->attributes; while (list != NULL) { attr = (UMLAttribute *)list->data; newattr = uml_attribute_copy(attr); newattr->left_connection = g_new(ConnectionPoint,1); *newattr->left_connection = *attr->left_connection; newattr->left_connection->object = newobj; newattr->left_connection->connected = NULL; newattr->right_connection = g_new(ConnectionPoint,1); *newattr->right_connection = *attr->right_connection; newattr->right_connection->object = newobj; newattr->right_connection->connected = NULL; newumlclass->attributes = g_list_prepend(newumlclass->attributes, newattr); list = g_list_next(list); } newumlclass->operations = NULL; list = umlclass->operations; while (list != NULL) { op = (UMLOperation *)list->data; newop = uml_operation_copy(op); newop->left_connection = g_new(ConnectionPoint,1); *newop->left_connection = *op->left_connection; newop->left_connection->object = newobj; newop->left_connection->connected = NULL; newop->right_connection = g_new(ConnectionPoint,1); *newop->right_connection = *op->right_connection; newop->right_connection->object = newobj; newop->right_connection->connected = NULL; newumlclass->operations = g_list_prepend(newumlclass->operations, newop); list = g_list_next(list); } newumlclass->template = umlclass->template; newumlclass->formal_params = NULL; list = umlclass->formal_params; while (list != NULL) { param = (UMLFormalParameter *)list->data; newumlclass->formal_params = g_list_prepend(newumlclass->formal_params, uml_formalparameter_copy(param)); list = g_list_next(list); } newumlclass->properties_dialog = NULL; newumlclass->stereotype_string = NULL; newumlclass->attributes_strings = NULL; newumlclass->operations_strings = NULL; newumlclass->templates_strings = NULL; for (i=0;i<8;i++) { newobj->connections[i] = &newumlclass->connections[i]; newumlclass->connections[i].object = newobj; newumlclass->connections[i].connected = NULL; newumlclass->connections[i].pos = umlclass->connections[i].pos; newumlclass->connections[i].last_pos = umlclass->connections[i].last_pos; } umlclass_calculate_data(newumlclass); i = 8; if ( (newumlclass->visible_attributes) && (!newumlclass->suppress_attributes)) { list = newumlclass->attributes; while (list != NULL) { attr = (UMLAttribute *)list->data; newobj->connections[i++] = attr->left_connection; newobj->connections[i++] = attr->right_connection; list = g_list_next(list); } } if ( (newumlclass->visible_operations) && (!newumlclass->suppress_operations)) { list = newumlclass->operations; while (list != NULL) { op = (UMLOperation *)list->data; newobj->connections[i++] = op->left_connection; newobj->connections[i++] = op->right_connection; list = g_list_next(list); } } umlclass_update_data(newumlclass); return (Object *)newumlclass; } static void umlclass_save(UMLClass *umlclass, ObjectNode obj_node, const char *filename) { UMLAttribute *attr; UMLOperation *op; UMLFormalParameter *formal_param; GList *list; AttributeNode attr_node; element_save(¨class->element, obj_node); /* Class info: */ data_add_string(new_attribute(obj_node, "name"), umlclass->name); data_add_string(new_attribute(obj_node, "stereotype"), umlclass->stereotype); data_add_boolean(new_attribute(obj_node, "abstract"), umlclass->abstract); data_add_boolean(new_attribute(obj_node, "suppress_attributes"), umlclass->suppress_attributes); data_add_boolean(new_attribute(obj_node, "suppress_operations"), umlclass->suppress_operations); data_add_boolean(new_attribute(obj_node, "visible_attributes"), umlclass->visible_attributes); data_add_boolean(new_attribute(obj_node, "visible_operations"), umlclass->visible_operations); /* Attribute info: */ attr_node = new_attribute(obj_node, "attributes"); list = umlclass->attributes; while (list != NULL) { attr = (UMLAttribute *) list->data; uml_attribute_write(attr_node, attr); list = g_list_next(list); } /* Operations info: */ attr_node = new_attribute(obj_node, "operations"); list = umlclass->operations; while (list != NULL) { op = (UMLOperation *) list->data; uml_operation_write(attr_node, op); list = g_list_next(list); } /* Template info: */ data_add_boolean(new_attribute(obj_node, "template"), umlclass->template); attr_node = new_attribute(obj_node, "templates"); list = umlclass->formal_params; while (list != NULL) { formal_param = (UMLFormalParameter *) list->data; uml_formalparameter_write(attr_node, formal_param); list = g_list_next(list); } } static Object *umlclass_load(ObjectNode obj_node, int version, const char *filename) { UMLClass *umlclass; Element *elem; Object *obj; UMLAttribute *attr; UMLOperation *op; UMLFormalParameter *formal_param; AttributeNode attr_node; DataNode composite; int i; int num, num_attr, num_ops; GList *list; umlclass = g_malloc(sizeof(UMLClass)); elem = ¨class->element; obj = (Object *) umlclass; obj->type = ¨class_type; obj->ops = ¨class_ops; element_load(elem, obj_node); /* Class info: */ umlclass->name = NULL; attr_node = object_find_attribute(obj_node, "name"); if (attr_node != NULL) umlclass->name = data_string(attribute_first_data(attr_node)); umlclass->stereotype = NULL; attr_node = object_find_attribute(obj_node, "stereotype"); if (attr_node != NULL) umlclass->stereotype = data_string(attribute_first_data(attr_node)); umlclass->abstract = FALSE; attr_node = object_find_attribute(obj_node, "abstract"); if (attr_node != NULL) umlclass->abstract = data_boolean(attribute_first_data(attr_node)); umlclass->suppress_attributes = FALSE; attr_node = object_find_attribute(obj_node, "suppress_attributes"); if (attr_node != NULL) umlclass->suppress_attributes = data_boolean(attribute_first_data(attr_node)); umlclass->suppress_operations = FALSE; attr_node = object_find_attribute(obj_node, "suppress_operations"); if (attr_node != NULL) umlclass->suppress_operations = data_boolean(attribute_first_data(attr_node)); umlclass->visible_attributes = FALSE; attr_node = object_find_attribute(obj_node, "visible_attributes"); if (attr_node != NULL) umlclass->visible_attributes = data_boolean(attribute_first_data(attr_node)); umlclass->visible_operations = FALSE; attr_node = object_find_attribute(obj_node, "visible_operations"); if (attr_node != NULL) umlclass->visible_operations = data_boolean(attribute_first_data(attr_node)); /* Attribute info: */ attr_node = object_find_attribute(obj_node, "attributes"); num_attr = num = attribute_num_data(attr_node); composite = attribute_first_data(attr_node); umlclass->attributes = NULL; for (i=0;ileft_connection = g_new(ConnectionPoint,1); attr->left_connection->object = obj; attr->left_connection->connected = NULL; attr->right_connection = g_new(ConnectionPoint,1); attr->right_connection->object = obj; attr->right_connection->connected = NULL; umlclass->attributes = g_list_append(umlclass->attributes, attr); composite = data_next(composite); } /* Operations info: */ attr_node = object_find_attribute(obj_node, "operations"); num_ops = num = attribute_num_data(attr_node); composite = attribute_first_data(attr_node); umlclass->operations = NULL; for (i=0;ileft_connection = g_new(ConnectionPoint,1); op->left_connection->object = obj; op->left_connection->connected = NULL; op->right_connection = g_new(ConnectionPoint,1); op->right_connection->object = obj; op->right_connection->connected = NULL; umlclass->operations = g_list_append(umlclass->operations, op); composite = data_next(composite); } /* Template info: */ umlclass->template = FALSE; attr_node = object_find_attribute(obj_node, "template"); if (attr_node != NULL) umlclass->template = data_boolean(attribute_first_data(attr_node)); attr_node = object_find_attribute(obj_node, "templates"); num = attribute_num_data(attr_node); composite = attribute_first_data(attr_node); umlclass->formal_params = NULL; for (i=0;iformal_params = g_list_append(umlclass->formal_params, formal_param); composite = data_next(composite); } if ( (!umlclass->visible_attributes) || (umlclass->suppress_attributes)) num_attr = 0; if ( (!umlclass->visible_operations) || (umlclass->suppress_operations)) num_ops = 0; element_init(elem, 8, 8 + num_attr*2 + num_ops*2); umlclass->properties_dialog = NULL; fill_in_fontdata(umlclass); umlclass->stereotype_string = NULL; umlclass->attributes_strings = NULL; umlclass->operations_strings = NULL; umlclass->templates_strings = NULL; umlclass_calculate_data(umlclass); for (i=0;i<8;i++) { obj->connections[i] = ¨class->connections[i]; umlclass->connections[i].object = obj; umlclass->connections[i].connected = NULL; } i = 8; if ( (umlclass->visible_attributes) && (!umlclass->suppress_attributes)) { list = umlclass->attributes; while (list != NULL) { attr = (UMLAttribute *)list->data; obj->connections[i++] = attr->left_connection; obj->connections[i++] = attr->right_connection; list = g_list_next(list); } } if ( (umlclass->visible_operations) && (!umlclass->suppress_operations)) { list = umlclass->operations; while (list != NULL) { op = (UMLOperation *)list->data; obj->connections[i++] = op->left_connection; obj->connections[i++] = op->right_connection; list = g_list_next(list); } } umlclass_update_data(umlclass); for (i=0;i<8;i++) { obj->handles[i]->type = HANDLE_NON_MOVABLE; } return (Object *)umlclass; }