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

Patch providing line wrapping in class objects



Hi,

looking for a nice uml design tool for linux I encoutered dia, which is part
of the SuSE distribution.

I noticed that oparations with lots of parameters make class objects look far 
too wide, messing up the design of uml class diagrams. I needed to wrap long
lines of operations. It seemed that some other people drawing class diagrams
had the same problem, so I decided to write this patch.

The patch applies to the current CVS version without any problems.

I hope it will be useful.

Regards,
Maurizio Tidei
tidei compal de

P.S.: The patch is GPL, of course.
diff -urNbB dia-0.93_orig/objects/UML/class.c dia-0.93/objects/UML/class.c
--- dia-0.93_orig/objects/UML/class.c	2004-02-29 21:53:44.000000000 +0100
+++ dia-0.93/objects/UML/class.c	2004-05-13 11:58:21.000000000 +0200
@@ -121,6 +121,10 @@
   N_("Visible Operations"), NULL, NULL },
   { "visible_comments", PROP_TYPE_INT, PROP_FLAG_VISIBLE,
   N_("Visible Comments"), NULL, NULL },
+  { "wrap_operations", PROP_TYPE_INT, PROP_FLAG_VISIBLE,
+  N_("Wrap Operations"), NULL, NULL },
+  { "wrap_after_char", PROP_TYPE_INT, PROP_FLAG_VISIBLE,
+  N_("Wrap after char"), NULL, NULL },
   
   { "attributes", PROP_TYPE_STRINGLIST, PROP_FLAG_DONT_SAVE,
   N_("Attributes"), NULL, NULL }, 
@@ -157,6 +161,8 @@
   { "suppress_operations", PROP_TYPE_INT, offsetof(UMLClass , suppress_operations) },
   { "visible_operations", PROP_TYPE_INT, offsetof(UMLClass , visible_operations) },
   { "visible_comments", PROP_TYPE_INT, offsetof(UMLClass , visible_comments) },
+  { "wrap_operations", PROP_TYPE_INT, offsetof(UMLClass , wrap_operations) },
+  { "wrap_after_char", PROP_TYPE_INT, offsetof(UMLClass , wrap_after_char) },
 
   { "operations", PROP_TYPE_STRINGLIST, offsetof(UMLClass , operations_strings) },
   { "attributes", PROP_TYPE_STRINGLIST, offsetof(UMLClass , attributes_strings) },
@@ -436,6 +441,10 @@
       p.x = x + UMLCLASS_BORDER/2.0 + 0.1;
       p.y = p1.y + 0.1;
 
+      int wrap_pos, last_wrap_pos, ident, wrapping_needed;
+      GList *wrapsublist = NULL;
+      gchar part_opstr[umlclass->max_wrapped_line_width];
+
       i = 0;
       list = umlclass->operations;
       while (list != NULL) {
@@ -454,16 +463,56 @@
           font = umlclass->normal_font;
           font_height = umlclass->font_height;
         }
+
+        wrapping_needed = 0;
         opstr = (gchar*) g_list_nth(umlclass->operations_strings, i)->data;
-        ascent = dia_font_ascent(opstr,
-                                 font,font_height);     
-        p.y += ascent;
+        if( umlclass->wrap_operations == TRUE) {
+          wrapsublist = (GList*)g_list_nth( umlclass->operations_wrappos, i)->data;
+          wrapping_needed = GPOINTER_TO_INT( wrapsublist->data);
+        }
 
+        ascent = dia_font_ascent(opstr, font, font_height);
         renderer_ops->set_font(renderer, font, font_height);
+        
+        if( umlclass->wrap_operations == TRUE && wrapping_needed) {
+          
+          wrapsublist = g_list_next( wrapsublist);
+          ident = GPOINTER_TO_INT( wrapsublist->data);
+          wrapsublist = g_list_next( wrapsublist);
+          wrap_pos = last_wrap_pos = 0;
+          
+          while( wrapsublist != NULL) {
+            
+            wrap_pos = GPOINTER_TO_INT( wrapsublist->data);
+            
+            if( last_wrap_pos == 0) {
+              strncpy( part_opstr, opstr, wrap_pos);  
+              memset( part_opstr+wrap_pos, '\0', 1);
+            } else {  
+              memset( part_opstr, ' ', ident);
+              memset( part_opstr+ident, '\0', 1);
+              strncat( part_opstr, opstr+last_wrap_pos, wrap_pos-last_wrap_pos);                
+            }
+            
+            p.y += ascent;
+  
+            renderer_ops->draw_string(renderer,
+                                      part_opstr,
+                                      &p, ALIGN_LEFT, 
+                                      &umlclass->text_color);
+          
+            last_wrap_pos = wrap_pos;
+            wrapsublist = g_list_next( wrapsublist);
+          }
+        } else {
+
+          p.y += ascent;
+
         renderer_ops->draw_string(renderer,
                                    opstr,
                                    &p, ALIGN_LEFT, 
                                    &umlclass->text_color);
+        }
 
         if (op->class_scope) {
           p1 = p; 
@@ -787,7 +836,11 @@
 
   umlclass->operationsbox_height = 2*0.1;
 
+  int pos_next_comma, pos_brace, wrap_pos, last_wrap_pos, ident, offset, maxlinewidth, length;
+  GList *sublist, *wrapsublist;
+  
   umlclass->operations_strings = NULL;
+  umlclass->operations_wrappos = NULL;
   if (0 != g_list_length(umlclass->operations)) {
     i = 0;
     list = umlclass->operations;
@@ -798,6 +851,94 @@
       umlclass->operations_strings = 
         g_list_append(umlclass->operations_strings, opstr);
       
+      length = 0;
+      if( umlclass->wrap_operations == TRUE) {
+      
+        length = strlen( (const gchar*)opstr);
+        
+        sublist = NULL;
+        if( length > umlclass->wrap_after_char) {
+          
+          sublist = g_list_append( sublist, GINT_TO_POINTER( 1));
+          
+          /* count maximal line width to create a secure buffer (part_opstr)
+             and build the sublist with the wrapping data for the current operation, which will be used by umlclass_draw(), too. 
+             The content of the sublist is:
+             1st element: (bool) wrapping needed or not, 2nd: indentation in chars, 3rd-last: absolute wrapping positions */
+          pos_next_comma = pos_brace = wrap_pos = offset = maxlinewidth = umlclass->max_wrapped_line_width = 0;
+          while( wrap_pos + offset < length) {
+            
+            do {
+              pos_next_comma = strcspn( (const gchar*)opstr + wrap_pos + offset, ",");
+              wrap_pos += pos_next_comma + 1;
+            } 
+            while( wrap_pos < umlclass->wrap_after_char - pos_brace && wrap_pos + offset < length);
+            
+            if( offset == 0) {
+              pos_brace = strcspn( opstr, "(");
+              sublist = g_list_append( sublist, GINT_TO_POINTER( pos_brace+1));
+            }
+            sublist = g_list_append( sublist, GINT_TO_POINTER( wrap_pos + offset));
+            
+            maxlinewidth = MAX(maxlinewidth, wrap_pos);
+ 
+            offset += wrap_pos;
+            wrap_pos = 0;
+          }   
+          umlclass->max_wrapped_line_width = MAX( umlclass->max_wrapped_line_width, maxlinewidth+1);
+          
+          gchar part_opstr[umlclass->max_wrapped_line_width];
+          pos_next_comma = pos_brace = wrap_pos = offset = 0;
+          
+          wrapsublist = g_list_next( sublist);
+          ident = GPOINTER_TO_INT( wrapsublist->data);
+          wrapsublist = g_list_next( wrapsublist);
+          wrap_pos = last_wrap_pos = 0;
+          
+          while( wrapsublist != NULL) {
+            
+            wrap_pos = GPOINTER_TO_INT( wrapsublist->data);
+            
+            if( last_wrap_pos == 0) {
+              strncpy( part_opstr, opstr, wrap_pos);  
+              memset( part_opstr+wrap_pos, '\0', 1);
+            } else {  
+              memset( part_opstr, ' ', ident);
+              memset( part_opstr+ident, '\0', 1);
+              strncat( part_opstr, opstr+last_wrap_pos, wrap_pos-last_wrap_pos);                
+            }
+            
+            if (op->inheritance_type == UML_ABSTRACT) {
+              width = dia_font_string_width(part_opstr,
+                                            umlclass->abstract_font,
+                                            umlclass->abstract_font_height);
+              umlclass->operationsbox_height += umlclass->abstract_font_height;
+            } else if (op->inheritance_type == UML_POLYMORPHIC) {
+              width = dia_font_string_width(part_opstr,
+                                            umlclass->polymorphic_font,
+                                            umlclass->polymorphic_font_height);
+              umlclass->operationsbox_height += umlclass->polymorphic_font_height;        
+            } else {
+              width = dia_font_string_width(part_opstr,
+                                            umlclass->normal_font,
+                                            umlclass->font_height);
+              umlclass->operationsbox_height += umlclass->font_height;
+            }
+            
+            maxwidth = MAX(width, maxwidth);
+            last_wrap_pos = wrap_pos;
+            wrapsublist = g_list_next( wrapsublist);
+          }
+  
+        } else {
+          
+          sublist = g_list_append( sublist, GINT_TO_POINTER( 0));
+        }
+        umlclass->operations_wrappos = g_list_append( umlclass->operations_wrappos, sublist);
+      } 
+      
+      if( umlclass->wrap_operations == FALSE || !(length > umlclass->wrap_after_char)) {
+        
       if (op->inheritance_type == UML_ABSTRACT) {
         width = dia_font_string_width(opstr,
                                       umlclass->abstract_font,
@@ -814,8 +955,11 @@
                                       umlclass->font_height);
         umlclass->operationsbox_height += umlclass->font_height;
       }
+        
       maxwidth = MAX(width, maxwidth);
       
+      }
+                  
       if (umlclass->visible_comments && op->comment != NULL && op->comment[0] != '\0') {
         width = dia_font_string_width(op->comment,
                                       umlclass->comment_font,
@@ -953,6 +1097,9 @@
   umlclass->visible_operations = TRUE;
   umlclass->visible_comments = FALSE;
 
+  umlclass->wrap_operations = TRUE;
+  umlclass->wrap_after_char = UMLCLASS_WRAP_AFTER_CHAR;
+
   umlclass->attributes = NULL;
 
   umlclass->operations = NULL;
@@ -963,6 +1110,7 @@
   umlclass->stereotype_string = NULL;
   umlclass->attributes_strings = NULL;
   umlclass->operations_strings = NULL;
+  umlclass->operations_wrappos = NULL;
   umlclass->templates_strings = NULL;
   
   umlclass->text_color = color_black;
@@ -1059,6 +1207,12 @@
     umlclass->operations_strings = NULL;
   }
 
+  if (umlclass->operations_wrappos != NULL) {
+    g_list_foreach(umlclass->operations_wrappos, (GFunc)g_list_free, NULL);
+    g_list_free(umlclass->operations_wrappos);
+    umlclass->operations_wrappos = NULL;
+  }
+
   if (umlclass->templates_strings != NULL) {
     for (i=0;i<umlclass->num_templates;i++) {
       g_free(umlclass->templates_strings[i]);
@@ -1134,6 +1288,8 @@
   newumlclass->visible_attributes = umlclass->visible_attributes;
   newumlclass->visible_operations = umlclass->visible_operations;
   newumlclass->visible_comments = umlclass->visible_comments;
+  newumlclass->wrap_operations = umlclass->wrap_operations;
+  newumlclass->wrap_after_char = umlclass->wrap_after_char;
   newumlclass->text_color = umlclass->text_color;
   newumlclass->line_color = umlclass->line_color;
   newumlclass->fill_color = umlclass->fill_color;
@@ -1196,6 +1352,7 @@
   newumlclass->stereotype_string = NULL;
   newumlclass->attributes_strings = NULL;
   newumlclass->operations_strings = NULL;
+  newumlclass->operations_wrappos = NULL;
   newumlclass->templates_strings = NULL;
 
   for (i=0;i<UMLCLASS_CONNECTIONPOINTS;i++) {
@@ -1270,6 +1427,10 @@
 		   umlclass->visible_operations);
   data_add_boolean(new_attribute(obj_node, "visible_comments"),
 		   umlclass->visible_comments);
+  data_add_boolean(new_attribute(obj_node, "wrap_operations"),
+		   umlclass->wrap_operations);
+  data_add_int(new_attribute(obj_node, "wrap_after_char"),
+		   umlclass->wrap_after_char);
   data_add_color(new_attribute(obj_node, "line_color"), 
 		   &umlclass->line_color);
   data_add_color(new_attribute(obj_node, "fill_color"), 
@@ -1402,6 +1563,16 @@
   if (attr_node != NULL)
     umlclass->visible_comments = data_boolean(attribute_first_data(attr_node));
 
+  umlclass->wrap_operations = TRUE;
+  attr_node = object_find_attribute(obj_node, "wrap_operations");
+  if (attr_node != NULL)
+    umlclass->wrap_operations = data_boolean(attribute_first_data(attr_node));
+  
+  umlclass->wrap_after_char = UMLCLASS_WRAP_AFTER_CHAR;
+  attr_node = object_find_attribute(obj_node, "wrap_after_char");
+  if (attr_node != NULL)
+    umlclass->wrap_after_char = data_int(attribute_first_data(attr_node));
+
   umlclass->line_color = color_black;
   /* support the old name ... */
   attr_node = object_find_attribute(obj_node, "foreground_color");
@@ -1559,6 +1730,7 @@
   umlclass->stereotype_string = NULL;
   umlclass->attributes_strings = NULL;
   umlclass->operations_strings = NULL;
+  umlclass->operations_wrappos = NULL;
   umlclass->templates_strings = NULL;
 
   umlclass_calculate_data(umlclass);
diff -urNbB dia-0.93_orig/objects/UML/class.h dia-0.93/objects/UML/class.h
--- dia-0.93_orig/objects/UML/class.h	2004-02-29 21:55:14.000000000 +0100
+++ dia-0.93/objects/UML/class.h	2004-05-13 10:50:32.000000000 +0200
@@ -26,6 +26,7 @@
 #include "uml.h"
 
 #define UMLCLASS_CONNECTIONPOINTS 8
+#define UMLCLASS_WRAP_AFTER_CHAR 40
 
 typedef struct _UMLClass UMLClass;
 typedef struct _UMLClassDialog UMLClassDialog;
@@ -61,6 +62,9 @@
   int visible_operations;
   int visible_comments;
 
+  int wrap_operations; /* wrap operations with many parameters */
+  int wrap_after_char;
+
   Color line_color;
   Color fill_color;
   Color text_color;
@@ -85,6 +89,8 @@
   
   real operationsbox_height;
   GList *operations_strings;
+  GList **operations_wrappos;
+  int max_wrapped_line_width;
 
   real templates_height;
   real templates_width;
@@ -114,6 +120,7 @@
   GtkToggleButton *op_vis;
   GtkToggleButton *op_supp;
   GtkToggleButton *comments_vis;
+  GtkToggleButton *op_wrap;
   DiaFontSelector *normal_font;
   DiaFontSelector *abstract_font;
   DiaFontSelector *polymorphic_font;
@@ -126,9 +133,11 @@
   GtkSpinButton *classname_font_height;
   GtkSpinButton *abstract_classname_font_height;
   GtkSpinButton *comment_font_height;
+  GtkSpinButton *wrap_after_char;  
   DiaColorSelector *text_color;
   DiaColorSelector *line_color;
   DiaColorSelector *fill_color;
+  GtkLabel *max_length_label;
 
   GList *disconnected_connections;
   GList *added_connections; 
diff -urNbB dia-0.93_orig/objects/UML/class_dialog.c dia-0.93/objects/UML/class_dialog.c
--- dia-0.93_orig/objects/UML/class_dialog.c	2004-02-29 19:25:02.000000000 +0100
+++ dia-0.93/objects/UML/class_dialog.c	2004-05-13 11:50:59.000000000 +0200
@@ -149,6 +149,8 @@
   umlclass->abstract = prop_dialog->abstract_class->active;
   umlclass->visible_attributes = prop_dialog->attr_vis->active;
   umlclass->visible_operations = prop_dialog->op_vis->active;
+  umlclass->wrap_operations = prop_dialog->op_wrap->active;
+  umlclass->wrap_after_char = gtk_spin_button_get_value_as_int(prop_dialog->wrap_after_char);
   umlclass->visible_comments = prop_dialog->comments_vis->active;
   umlclass->suppress_attributes = prop_dialog->attr_supp->active;
   umlclass->suppress_operations = prop_dialog->op_supp->active;
@@ -193,6 +195,8 @@
   gtk_toggle_button_set_active(prop_dialog->abstract_class, umlclass->abstract);
   gtk_toggle_button_set_active(prop_dialog->attr_vis, umlclass->visible_attributes);
   gtk_toggle_button_set_active(prop_dialog->op_vis, umlclass->visible_operations);
+  gtk_toggle_button_set_active(prop_dialog->op_wrap, umlclass->wrap_operations);
+  gtk_spin_button_set_value (prop_dialog->wrap_after_char, umlclass->wrap_after_char);
   gtk_toggle_button_set_active(prop_dialog->comments_vis, umlclass->visible_comments);
   gtk_toggle_button_set_active(prop_dialog->attr_supp, umlclass->suppress_attributes);
   gtk_toggle_button_set_active(prop_dialog->op_supp, umlclass->suppress_operations);
@@ -245,6 +249,7 @@
   GtkWidget *page_label;
   GtkWidget *label;
   GtkWidget *hbox;
+  GtkWidget *hbox2;
   GtkWidget *vbox;
   GtkWidget *entry;
   GtkWidget *checkbox;
@@ -252,6 +257,7 @@
   GtkWidget *fill_color;
   GtkWidget *line_color;
   GtkWidget *table;
+  GtkObject *adj;
 
   prop_dialog = umlclass->properties_dialog;
 
@@ -310,6 +316,21 @@
   gtk_box_pack_start (GTK_BOX (hbox), checkbox, TRUE, TRUE, 0);
   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
 
+  hbox  = gtk_hbox_new(TRUE, 5);
+  hbox2 = gtk_hbox_new(FALSE, 5);
+  checkbox = gtk_check_button_new_with_label(_("Wrap Operations"));
+  prop_dialog->op_wrap = GTK_TOGGLE_BUTTON( checkbox );
+  gtk_box_pack_start (GTK_BOX (hbox), checkbox, TRUE, TRUE, 0);
+  adj = gtk_adjustment_new( umlclass->wrap_after_char, 0.0, 200.0, 1.0, 5.0, 1.0);
+  prop_dialog->wrap_after_char = GTK_SPIN_BUTTON(gtk_spin_button_new( GTK_ADJUSTMENT( adj), 0.1, 0));
+  gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( prop_dialog->wrap_after_char), TRUE);
+  gtk_spin_button_set_snap_to_ticks( GTK_SPIN_BUTTON( prop_dialog->wrap_after_char), TRUE);
+  prop_dialog->max_length_label = GTK_LABEL( gtk_label_new( "Wrap after this length: "));
+  gtk_box_pack_start (GTK_BOX (hbox2), GTK_WIDGET( prop_dialog->max_length_label), FALSE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox2), GTK_WIDGET( prop_dialog->wrap_after_char), TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET( hbox2), TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+
   hbox = gtk_hbox_new(FALSE, 5);
   checkbox = gtk_check_button_new_with_label(_("Comments visible"));
   prop_dialog->comments_vis = GTK_TOGGLE_BUTTON( checkbox );


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] Mail converted by Mofo Magic and the Flying D

 
All trademarks and copyrights are the property of their respective owners.

Other Directory Sites: SeekWonder | Directory Owners Forum

GuideSMACK