[Date Prev ][Date Next ] [Thread Prev ][Thread Next ]
[Thread Index ]
[Date Index ]
[Author Index ]
Patch providing line wrapping in class objects
From : Maurizio Tidei <tidei compal de>, (by way of Maurizio Tidei <tidei compal de>)
To : dia-list gnome org
Subject : Patch providing line wrapping in class objects
Date : Mon, 17 May 2004 09:53:03 +0200
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,
+ ¨class->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,
¨class->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"),
¨class->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