proposed UML sequence diagram fixes



The changes have been implemented to ease the creation of
UML sequence diagrams. The storage format and geometric extents
remain unchanged such that all changes are compatible to dia 0.90
and 0.91.

The changes to UML-Object and UML-Lifeline can be seen as bugfixes, 
because the original versions could hardly be used together with grid 
alignment. The changes to UML-Message add in place editing and object 
menu to speed up drawing.

UML-Object
- object center is grid aligned instead of the upper left corner such
  that the attached lifeline will be on the grid.

UML-lifeline
- top handle moves box instead of resizing it to allow easy moving
  of the box.
- on move of bottom handle the number of connection points is set such 
  that they are located on the vertical grid. Due to the odd layout 
  actually twice as much connection points are assigned to keep 
  backwards compatibility and to allow odd vertical box sizes.
- the object menu has been kept, although there is not much use for it
  anymore. Removing it would reduce the code by about 20%.

UML-Message
- inplace text editing has been added. Replacing lots of character
  drawing code by lib/text methods actually reduced code size!
- added object menu to change arrow type

-------------
Code Changes:

diff -u objects/org-UML/lifeline.c objects/UML/lifeline.c
--- objects/org-UML/lifeline.c  Sun Jan 26 07:44:52 2003
+++ objects/UML/lifeline.c      Fri Mar 14 23:06:47 2003
@@ -205,7 +205,7 @@
 lifeline_move_handle(Lifeline *lifeline, Handle *handle,
                 Point *to, HandleMoveReason reason, ModifierKeys modifiers)
 {
-  real s, t;
+  real t, height;
   Connection *conn;
 
   assert(lifeline!=NULL);
@@ -213,60 +213,59 @@
   assert(to!=NULL);
 
   conn = &lifeline->connection;
-  if (handle->id == HANDLE_BOXBOT) {
-      t = to->y - conn->endpoints[0].y;
-      if (t > LIFELINE_BOXMINHEIGHT && 
-         t < conn->endpoints[1].y - conn->endpoints[0].y) {
+  height = conn->endpoints[1].y - conn->endpoints[0].y;
+  t = to->y - conn->endpoints[0].y;
+  switch(handle->id) {
+    case HANDLE_BOXTOP:
+      if (t > 0 && t < height - (lifeline->rbot - lifeline->rtop)) {
+         lifeline->rbot += t - lifeline->rtop; 
+         lifeline->rtop = t;   
+      }
+      break;
+    case HANDLE_BOXBOT: {
+      Layer *layer = dia_object_get_parent_layer(&conn->object);
+      DiagramData *dia_data = layer_get_parent_diagram(layer);
+
+      if (t > lifeline->rtop + LIFELINE_BOXMINHEIGHT && t < height) {
          lifeline->rbot = t;
-         if (t < lifeline->rtop + LIFELINE_BOXMINHEIGHT)
-             lifeline->rtop = t - LIFELINE_BOXMINHEIGHT;
       }
-  } else if (handle->id == HANDLE_BOXTOP) {
-      t = to->y - conn->endpoints[0].y;
-      if (t > 0 && 
-         t < conn->endpoints[1].y-conn->endpoints[0].y-LIFELINE_BOXMINHEIGHT) {
-         lifeline->rtop = t;   
-         if (t > lifeline->rbot - LIFELINE_BOXMINHEIGHT)
-             lifeline->rbot = t + LIFELINE_BOXMINHEIGHT;
+    /* update number of connections */
+      if (dia_data && dia_data->grid.width_y > 0) {
+       int count = (lifeline->rbot - lifeline->rtop) / 
+         (dia_data->grid.width_y) - 0.5;
+       if (count > 0) {
+         connpointline_adjust_count(lifeline->northwest, count, to);
+         connpointline_adjust_count(lifeline->northeast, count, to);
+         connpointline_adjust_count(lifeline->southwest, count, to);
+         connpointline_adjust_count(lifeline->southeast, count, to);
+       }
       }
-  } else {
-    /* move horizontally only if startpoint is moved */
-    if (handle->id==HANDLE_MOVE_STARTPOINT) {
-       conn->endpoints[0].x = conn->endpoints[1].x = to->x;
-    } else {
-       to->x = conn->endpoints[0].x;
+      break;
     }
-    /* If connected don't change size */  
-    t = (reason==HANDLE_MOVE_CONNECTED) ? 
-       conn->endpoints[1].y - conn->endpoints[0].y:
-       lifeline->rbot;
-    connection_move_handle(conn, handle->id, to, reason);
-    s = conn->endpoints[1].y - conn->endpoints[0].y;
-    if (handle->id==HANDLE_MOVE_ENDPOINT && s < t && s > lifeline->rtop +
LIFELINE_BOXMINHEIGHT)
-       lifeline->rbot = s;
-    else if (reason==HANDLE_MOVE_CONNECTED || s < t)
-       conn->endpoints[1].y = conn->endpoints[0].y + t;
+    case HANDLE_MOVE_STARTPOINT:
+      conn->endpoints[0] = conn->endpoints[1] = *to;
+      conn->endpoints[1].y = to->y + height;
+      break;
+    case HANDLE_MOVE_ENDPOINT:
+      if (t > lifeline->rbot)
+          conn->endpoints[1].y = to->y;
+      break;
+    default:
+      perror("illegal handle");
   }
-
   lifeline_update_data(lifeline);
 }
 
 static void
 lifeline_move(Lifeline *lifeline, Point *to)
 {
-  Point start_to_end;
-  Point delta;
+  Point delta = *to;
   Point *endpoints = &lifeline->connection.endpoints[0]; 
 
-  delta = *to;
-  point_sub(&delta, &endpoints[0]);
-  
-  start_to_end = endpoints[1];
-  point_sub(&start_to_end, &endpoints[0]);
+  point_sub(&delta, &lifeline->connection.object.position);
+  point_add(&endpoints[0], &delta);
+  point_add(&endpoints[1], &delta);
 
-  endpoints[1] = endpoints[0] = *to;
-  point_add(&endpoints[1], &start_to_end);
-  
   lifeline_update_data(lifeline);
 }
 
@@ -513,8 +512,6 @@
   LineBBExtras *extra = &conn->extra_spacing;
   Point p1, p2, pnw, psw, pne, pse, pmw,pme;
 
-  obj->position = conn->endpoints[0];
-
   /* box handles: */
   p1.x = conn->endpoints[0].x;
   p1.y = conn->endpoints[0].y + lifeline->rtop;
@@ -523,6 +520,8 @@
   p2.y = conn->endpoints[0].y + lifeline->rbot;
   lifeline->boxbot_handle.pos = p2;
 
+  obj->position = p1;          // this point should be on grid
+
   connection_update_handles(conn);
 
   /* Boundingbox: */
@@ -569,6 +568,7 @@
   connpointline_putonaline(lifeline->northeast,&pne,&pme);
   connpointline_update(lifeline->southeast);
   connpointline_putonaline(lifeline->southeast,&pme,&pse);
+
 }
 
 static Object *
@@ -577,12 +577,3 @@
   return object_load_using_properties(&lifeline_type,
                                       obj_node,version,filename);
 }
-
-
-
-
-
-
-
-
- 
diff -u objects/org-UML/message.c objects/UML/message.c
--- objects/org-UML/message.c   Sun Jan 26 07:44:52 2003
+++ objects/UML/message.c       Wed Mar 12 07:55:20 2003
@@ -34,6 +34,7 @@
 #include "handle.h"
 #include "arrows.h"
 #include "properties.h"
+#include "text.h"
 
 #include "pixmaps/message.xpm"
 
@@ -51,16 +52,24 @@
     MESSAGE_RECURSIVE
 } MessageType;
 
+typedef enum {
+  MESSAGE_SELECT_LINE,
+  MESSAGE_SELECT_TEXT
+} MessageSelectMode;
+ 
+
 struct _Message {
   Connection connection;
 
   Handle text_handle;
 
-  gchar *text;
+  Text *ttext;
+  gchar *text;         // used for backward compatible load/store only
   Point text_pos;
   real text_width;
     
   MessageType type;
+  MessageSelectMode select_mode;
 };
 
 #define MESSAGE_WIDTH 0.1
@@ -92,6 +101,8 @@
 static PropDescription *message_describe_props(Message *mes);
 static void message_get_props(Message * message, GPtrArray *props);
 static void message_set_props(Message *message, GPtrArray *props);
+static DiaMenu *message_get_object_menu(Message *message,
+                                       Point *clickedpoint);
 
 static ObjectTypeOps message_type_ops =
 {
@@ -120,7 +131,7 @@
   (MoveHandleFunc)      message_move_handle,
   (GetPropertiesFunc)   object_create_props_dialog,
   (ApplyPropertiesFunc) object_apply_props_from_dialog,
-  (ObjectMenuFunc)      NULL,
+  (ObjectMenuFunc)      message_get_object_menu,
   (DescribePropsFunc)   message_describe_props,
   (GetPropsFunc)        message_get_props,
   (SetPropsFunc)        message_set_props
@@ -168,6 +179,9 @@
 static void
 message_get_props(Message * message, GPtrArray *props)
 {
+  g_free(message->text);       // update string
+  message->text = text_get_string_copy(message->ttext);
+
   object_get_props_from_offsets(&message->connection.object, 
                                 message_offsets, props);
 }
@@ -177,6 +191,8 @@
 {
   object_set_props_from_offsets(&message->connection.object, 
                                 message_offsets, props);
+  text_set_string(message->ttext, message->text);
+
   message_update_data(message);
 }
 
@@ -185,12 +201,14 @@
 message_distance_from(Message *message, Point *point)
 {
   Point *endpoints;
-  real dist;
+  real dist, distText;
   
   endpoints = &message->connection.endpoints[0];
   
   dist = distance_line_point(&endpoints[0], &endpoints[1], MESSAGE_WIDTH,
point);
-  
+  distText = text_distance_from(message->ttext, point);
+  if (distText < dist)
+    dist = distText;
   return dist;
 }
 
@@ -198,6 +216,16 @@
 message_select(Message *message, Point *clicked_point,
            DiaRenderer *interactive_renderer)
 {
+  int no_text = text_is_empty(message->ttext);
+  Point *endpoints = &message->connection.endpoints[0];
+  message->select_mode = MESSAGE_SELECT_LINE;
+  if (no_text || text_distance_from(message->ttext, clicked_point) <
+      distance_line_point(&endpoints[0], &endpoints[1], 
+                         MESSAGE_WIDTH, clicked_point)) {
+    if (!no_text) message->select_mode = MESSAGE_SELECT_TEXT;
+    text_set_cursor(message->ttext, clicked_point, interactive_renderer);
+    text_grab_focus(message->ttext, &message->connection.object);
+  }
   connection_update_handles(&message->connection);
 }
 
@@ -235,18 +263,20 @@
   Point *endpoints = &message->connection.endpoints[0]; 
   Point delta;
 
-  delta = *to;
-  point_sub(&delta, &endpoints[0]);
+  if (message->select_mode != MESSAGE_SELECT_TEXT) {
+    delta = *to;
+    point_sub(&delta, &endpoints[0]);
  
-  start_to_end = endpoints[1];
-  point_sub(&start_to_end, &endpoints[0]);
+    start_to_end = endpoints[1];
+    point_sub(&start_to_end, &endpoints[0]);
 
-  endpoints[1] = endpoints[0] = *to;
-  point_add(&endpoints[1], &start_to_end);
+    endpoints[1] = endpoints[0] = *to;
+    point_add(&endpoints[1], &start_to_end);
 
-  point_add(&message->text_pos, &delta);
+    point_add(&message->text_pos, &delta);
   
-  message_update_data(message);
+    message_update_data(message);
+  }
 }
 
 static void
@@ -256,7 +286,6 @@
   Point *endpoints, p1, p2, px;
   Arrow arrow;
   int n1 = 1, n2 = 0;
-  gchar *mname = NULL;
 
   assert(message != NULL);
   assert(renderer != NULL);
@@ -313,24 +342,7 @@
 
   renderer_ops->set_font(renderer, message_font,
                          MESSAGE_FONTHEIGHT);
-
-  if (message->type==MESSAGE_CREATE)
-         mname = g_strdup_printf ("%s%s%s", UML_STEREOTYPE_START, "create",
UML_STEREOTYPE_END);
-  else if (message->type==MESSAGE_DESTROY)
-         mname = g_strdup_printf ("%s%s%s", UML_STEREOTYPE_START, "destroy",
UML_STEREOTYPE_END);
-  else
-         mname = message->text;
-
-  if (mname && strlen(mname) != 0) 
-      renderer_ops->draw_string(renderer,
-                                mname, /*message->text,*/
-                                &message->text_pos, ALIGN_CENTER,
-                                &color_black);
-  if (message->type == MESSAGE_CREATE || message->type == MESSAGE_DESTROY)
-  {
-         g_free(mname);
-  }
-         
+  text_draw(message->ttext, renderer);
 
 }
 
@@ -370,6 +382,9 @@
   message->text_pos.x = 0.5*(conn->endpoints[0].x + conn->endpoints[1].x);
   message->text_pos.y = 0.5*(conn->endpoints[0].y + conn->endpoints[1].y);
 
+  message->ttext = new_text("", message_font, 0.8, &message->text_pos, 
+                           &color_black, ALIGN_CENTER);
+
   message->text_handle.id = HANDLE_MOVE_TEXT;
   message->text_handle.type = HANDLE_MINOR_CONTROL;
   message->text_handle.connect_type = HANDLE_NONCONNECTABLE;
@@ -393,6 +408,7 @@
 {
   connection_destroy(&message->connection);
 
+  text_destroy(message->ttext);
   g_free(message->text);
 }
 
@@ -404,21 +420,14 @@
   Rectangle rect;
   
   obj->position = conn->endpoints[0];
-
+  
   message->text_handle.pos = message->text_pos;
-
+  text_set_position(message->ttext, &message->text_pos);
+  
   connection_update_handles(conn);
   connection_update_boundingbox(conn);
-
-  message->text_width =
-    dia_font_string_width(message->text, message_font, MESSAGE_FONTHEIGHT);
-
-  /* Add boundingbox for text: */
-  rect.left = message->text_pos.x-message->text_width/2;
-  rect.right = rect.left + message->text_width;
-  rect.top = message->text_pos.y -
-      dia_font_ascent(message->text, message_font, MESSAGE_FONTHEIGHT);
-  rect.bottom = rect.top + MESSAGE_FONTHEIGHT;
+  
+  text_calc_boundingbox(message->ttext, &rect);
   rectangle_union(&obj->bounding_box, &rect);
 }
 
@@ -430,4 +439,76 @@
                                       obj_node,version,filename);
 }
 
+/* Object menu handling */
+
+typedef struct {
+  ObjectChange obj_change;
+  MessageType oldType;
+  MessageType newType;
+} MessageChange;
+
+static void message_change_apply(MessageChange *change, Object *obj)
+{
+  ((Message*)obj)->type = change->newType;
+}
+
+static void message_change_revert(MessageChange *change, Object *obj)
+{
+  ((Message*)obj)->type = change->oldType;
+}
+
+static void message_change_free(MessageChange *change) 
+{
+}
+
+static ObjectChange *
+message_create_change(Message *message, int newType) 
+{
+  MessageChange *vc;
+ 
+  vc = g_new0(MessageChange,1);
+  vc->obj_change.apply = (ObjectChangeApplyFunc)message_change_apply;
+  vc->obj_change.revert = (ObjectChangeRevertFunc)message_change_revert;
+  vc->obj_change.free = (ObjectChangeFreeFunc)message_change_free;
+  vc->oldType = message->type;
+  message->type = vc->newType = newType;
+  message_update_data(message);
+  return (ObjectChange *)vc;
+}
+
 
+static ObjectChange *
+message_object_menu_callback(Object *obj, Point *clicked, gpointer data)
+{
+//  ((Message*)obj)->type = (int)data;
+  return message_create_change((Message *)obj, (MessageType)data);
+}
+
+static DiaMenuItem object_menu_items[] = {
+  { N_("Call"), message_object_menu_callback, (void*)MESSAGE_CALL, 1 },
+  { N_("Create"), message_object_menu_callback, (void*)MESSAGE_CREATE, 1 },
+  { N_("Destroy"), message_object_menu_callback, (void*)MESSAGE_DESTROY, 1
},
+  { N_("Simple"), message_object_menu_callback, (void*)MESSAGE_SIMPLE, 1 },
+  { N_("Return"), message_object_menu_callback, (void*)MESSAGE_RETURN, 1 },
+  { N_("Send"), message_object_menu_callback, (void*)MESSAGE_SEND, 1 },
+  { N_("Recursive"), message_object_menu_callback,     
+    (void*)MESSAGE_RECURSIVE, 1 },
+  { NULL, 0}
+};
+
+static DiaMenu object_menu = {
+  N_("UML Message"),
+  sizeof(object_menu_items)/sizeof(DiaMenuItem),
+  object_menu_items,
+  NULL
+};
+
+static DiaMenu *
+message_get_object_menu(Message *message, Point *clickedpoint)
+{
+  int i;
+  for(i = MESSAGE_CALL; i <= MESSAGE_RECURSIVE; i++) 
+    object_menu_items[i].active = message->type == i ? 0 : 1;
+
+  return &object_menu;
+}
diff -u objects/org-UML/object.c objects/UML/object.c
--- objects/org-UML/object.c    Sun Jan 26 07:44:52 2003
+++ objects/UML/object.c        Wed Mar 12 07:55:20 2003
@@ -226,7 +226,7 @@
 static void
 objet_move(Objet *ob, Point *to)
 {
-  ob->element.corner = *to;
+  ob->element.object.position = *to;
   objet_update_data(ob);
 }
 
@@ -345,7 +345,7 @@
   }
 
   font = ob->text->font;
-  h = elem->corner.y + OBJET_MARGIN_Y;
+  h = OBJET_MARGIN_Y;
 
   if (ob->is_multiple) {
     h += OBJET_MARGIN_M;
@@ -373,20 +373,13 @@
 
   if (ob->show_attributes) {
       h += OBJET_MARGIN_Y + ob->attributes->ascent;
-      p2.x = elem->corner.x + OBJET_MARGIN_X;
-      p2.y = h;      
-      text_set_position(ob->attributes, &p2);
-
+      p2.y = h;
       h += ob->attributes->height*ob->attributes->numlines; 
-
       w = MAX(w, ob->attributes->max_width);
   }
 
   w += 2*OBJET_MARGIN_X; 
 
-  p1.x = elem->corner.x + w/2.0;
-  text_set_position(ob->text, &p1);
-  
   ob->ex_pos.x = ob->st_pos.x = p1.x;
 
   
@@ -394,8 +387,20 @@
     w += OBJET_MARGIN_M;
   }
     
+  elem->corner.x = obj->position.x - w / 2.0;
+  elem->corner.y = obj->position.y - h / 2.0;
   elem->width = w;
-  elem->height = h - elem->corner.y;
+  elem->height = h;
+
+  p1.x = obj->position.x;
+  p1.y += elem->corner.y;
+  text_set_position(ob->text, &p1);
+
+  if (ob->show_attributes) {
+    p2.x = elem->corner.x + OBJET_MARGIN_X;
+    p2.y += elem->corner.y;
+    text_set_position(ob->attributes, &p2);
+  }  
 
   /* Update connections: */
   ob->connections[0].pos = elem->corner;
@@ -415,7 +420,6 @@
   ob->connections[7].pos.y = elem->corner.y + elem->height;
   
   element_update_boundingbox(elem);
-  obj->position = elem->corner;
   element_update_handles(elem);
 }
 
@@ -440,7 +444,7 @@
 
   obj->ops = &objet_ops;
 
-  elem->corner = *startpoint;
+  elem->object.position = *startpoint;
 
   font = dia_font_new_from_style(DIA_FONT_SANS, OBJET_FONTHEIGHT);
   

-- 
+++ GMX - Mail, Messaging & more  http://www.gmx.net +++
Bitte lächeln! Fotogalerie online mit GMX ohne eigene Homepage!




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]