[Uml-devel] Re: karbon/umbrello

Luis De la Parra Blum lparrab at gmx.net
Tue May 13 13:45:11 UTC 2003


>I started a hopefully shared KCanvas class hierarchy in my kpainter project
>in KDE CVS.

>QPoint has only fixed point / integer coordinates
>KoPoint and KoRect provide floating point coordinates

yes, I know.
I also think it's better to use floats, but like I said, I did not feel like 
linking against libkoffice just to get a floating-point point class =)

> so easy integration/dependencies as QCanvas, etc, so I think it'd be great 
to 
> move those for now KOffice specifics which are not really KO speciffic to 
> some kdelib.

>This was my idea, to. Either that or put it into a separate library which
>is only dependent on qt and the render libs like libart.

I dont really care if you want to put it in a "libgvgraphics" which only 
depends on qt and libart, or if you want to put those classes into 
libkdebase.. the only thing I think it's important, is that it should be 
easyly available.  I would not care linking against libkdebase, because I do 
it anyways, but I would not want to link against libKOffice just for that.

> 
>Agreed. The pure path approach is fine for a general purpose graphics
>editor, but for application specific graphic objects the way is
>sub-optimal.

yeap.

>Do you have code available?

yop.
The "base"  diagram framework has been in umbrello's cvs for some days now, 
and last night I checked in the uml-shapes plugin.
you need to checkout/update kdesdk/umbrello
the relevant directories are:
dir:  umbrello/diagram   
   --> diagram, diagramview, diagramelement and all other "basic" classes. 
nothing that renders itself here,  just the basic "framework"
dir: umbrello/plugins/umlwidgets:
  --> implementation of uml-related shapes

>Could you please check if it would be possible to work with my code in
>kdenonbeta/painter/kcanvas (KDE CVS) instead?

to be honest I havent even looked at your code, but I'll try to give it a try 
as soon as I can.

> 
> Diagram : this is the "document" -- not really a document, but it contains / 
> manages the objects. in the case of Umbrello it's  a part of our Document. 

>Check. Its KCanvasModel in my class hierarchy
good. - I even think the name fits very nice... that's what it is after all, a 
canvas model!

>My KCanvasView is just a QScrollView which manages input events and
>document rendering.

my DiagramView is just a QCanvasView which manages input events... which is
not much more than a QScrollView which manages document rendering.. so it's 
pretty close to your's
Diagram is a QCanvas.

>I currently have a separate controller class (KCanvasController), which can
>convert view events to documentation specific "high level" events.
>I don't really like the current Karbon approach, because this approach
>doesn't really allow the use of the KDE xmlgui framework, which allow
>already for dynamic configuration of the GUI (menu, toolbar).
>I would like to use this xmlgui/kaction framework whenever possible.
>You get much better KDE integration by using existing frameworks instead of
>implementing your own.
 
I'm not sure if I understood you here...
the events in my DiagramView are all like this:
mousePressEvent( MouseEvent *e )
{
    // get the diagram coordinates -- ( zoom, other transformations )
	QPoint diagramPos = translateViewToDiagramCoords( e->pos() );
      bool accepted = false;
       if( m_tool )
        accepted =   m_tool->mouseEvent( MousePress, diagramPos );
      accepted ? e->accept() : e->reject () ;
}

and that's it. the tool takes care of processing the event


> it's DiagramElement.. 
>Check. A similar class at my class hierarchy is KCanvasElement.
yes. DiagramElement is a QCanvasPolygonalItem


> all other interaction is handled by the tools
> 
> DiagramElement: Base class for all elements in a diagram ( I guess this 
would 
> be your VObject) - offers basic functionality like move, setSelected and 
> "executeDefaultAction"
> 

>I haven't worked in this direction, my KCanvasElement is only able to
>render itself. I am, however fine, to use your definitions into
>KCanvasElement.

my DiagramElement can't render itself ( it's abstract ) but it provides the 
hook for sublcasses to draw themselves.

the basic mehtods of DiagramElement are

class DiagramElement {  //simplified!!
//draw -- needs implementation
void drawShape( QPainter ) = 0;

//move
void moveAbs( x,y);
void moveBy( dx, dy );

//exec default action.. this method is called, for example, at double-click 
//event. sublcasses decide what is their default action.. 
// in umbrello, most shapes just call editProperites( ) from this mehtod 
// ( show a dialog for editing the shape and uml object properites ), but some
// classes may choose to set a different action as default. 
// for example the Path::executeDefaultAction( ) breaks a segment in two, or 
// makes one segment out of two, and the Note::executeDefaultAction( ) sets it 
// in "edit mode"
void executeDefaultAction( );

//selection - most shapes draw themselves a bit different when selected.
// selection is also used for moving objects around via Diagram::moveSelected( 
//dx, dy)
setSelected(bool)

};  // end - class diagramelement

> Path: A collection of lines ( or a multi-segment line, if you will )
> 

>- is not really part of the framework, but rather some helper class
>- should consist of segments, where each segment may either be a line
>segment or a bezier curve segment. If you need other special segment types,
>line horizontal lines or arcs, you could check the KVectorPath class in
>kdenonbeta/kpainter/kpainter.

well... my Path is a DiagramElemnt which has a list of PathSegments.
the PathSegments are lines  ( I didnt think of beziers because I didnt need 
them, but of course a PathSegment could be that as well )
the things being drawn on the screen are really the PathSegments, the Path 
just manages them.. for example, when you move a "hotSpot"  ( point 
connecting two segments ), the Path moves the two segments start/end points 
accordingly.  when moving the path, the path just moves all segments by the 
same delta. whe you call Path::hide( ), the path just calls hide in all 
segments, and so on.


I'm not sure if it should be part of the framework or not, but it seemed to me 
such an important class, which will be used as base by a lot of plugins, so  
I built it in.
so there are two main subtrees in the hierarchy, DiagramWidgets, and Paths 
(the only two direct children of DiagramElement at the moment )


> DiagramWidget: A DiagramElement to which an association can attach itself.
> AssociatonWidget: A Path that can attach itself to two DiagramWidgets. 

>Application specific widgets. Should be e.g. part of Umbrello itself.
hmm... maybe you are right. but see my explanation above.

for example an AssociationWidget is just a line that updates itself when the 
widget  it's related to gets moved / modified. it knows nothing about UML 
objects or the such.
DiagramWidgets are elements which are "associable". 

a UMLClass is a DiagramWidget ( plugin umlshapes )
a Note is also a DiagramWidget ( plugin genericshapes ) ->so that you can 
associate a note to another element - since both need something in common, I 
put DiagramWidget in the built-in classes.


>How about UMLCanvasElement?

what about it?
I have no UMLCanvasElement in my code.

> 
> UMLWidget: a DiagramWidget which represents an UML::Element in a diagram. 
When 
> it detects that the UML::Element has changed, foreces a 
recalculation/refresh 
> of the widget

>This is real interesting. I know that Canvas like class libraries need back
>communication (i.e. from the model back to the view). However, I haven't
>seen until now a real implementtation / interface for that. I would be
>interested to look at your impl.

you are more than welcome to do so.
just 
$cvs up kdesdk/umbrello

my UMLWidget looks like this:

class UMLWidget : public DiagramWidget
{
	UMLWidget(diagram,name,obj) : DiagramWidget(diagram,name ),
                                                     m_umlObject(obj)
      {
            connect(m_umlObject,SIGNAL(modified()),
                       this,SLOT(umlObjModified());
	    recalculateWidget();
      }
public slots:
       void umlObjModified()
      {
          recalculateWidget();
          diagram()->update();
      }
private:
           UMLObject *m_umlObject;
};

and that's it.
it's nothing more than a DiagramWidget that has a "model object" which it 
represents. when the model obj is modified, the widget gets updated 
inmediatly.
the real work is done by (f.example) UMLClassWidget, which is a UMLWidget, but 
provides implementation for recalculateWidget ( ) and drawShape( )

>Do you already render the elements, if so, how?
yes. 
they are all QCanvasItems so they render themselves in 
drawShape( ) using a QPainter.
if the API of KPainter is similar to QPainter, it should be relativly easy to 
port my code. there are no rare/obscure dependencies on the QCanvas

> 
> ***********
> All shapes are created by the corresponding Tool, or they can be created by 
> the diagram through a WidgetFactory if they are droped into it ( for 
example, 
> if you want to create a new UML::Class, you use the ClassTool -> when you 
> click it creates a Class, and then a widget to represent it. But if you drag 
> an already exisitng UMLClass into the diagrm, the diagram calls 
> WidgetFactory::createWidget( object ), then the WidgetFactory quries all 
> loaded plugins to see if one of them can handle that kind of object, and if 
> yes, the plugin creates the widget and returns it.
> 

>Would it be possible to change this sequence so that the standard KAction
>framework can be used, instead of a custom framework?

I dont know if I understand you here....
the process is as follows:
the application calls
loadPlugin( string ), giving as parameter "umlshapes" and "cool_umlshapes"
the plugin framework calls
Plugin::initialize( )
and in the initialize implementation, both plugins call 
WidgetFactory::registerWidgetSet( this );
ToolFactory::registerWidgetSet( this );

then, the DiagramView calls toolBar->addTool( string ), which in turn queries 
all registered widgetsets (plugins) to see if they can create a tool named 
"string".

The same for the Diagram.. when
Diagram::dropEvent( ) is called, it does ( more or less):
myObject->getObject( dropEvent->decode( )->objectID () )
element = WidgetFactory::createWidget( myObject )
if( element )
	element->moveAbs( dropEvent->pos( ) )
        element->setVisible(true);

the plugin framework is at the moment andy's old plugin stuff ( I think he's 
switched to KPart::Plugin now ), but I would like to eventually use 
KParts::plugins as well

for the other part... of course I would like to use KActions, if I find a way 
to integrate them ( I'm not that familiar with KDE's plugin/xmlclient .. the 
only class I've used is KLibLoader and KLibFactory
 

regards,

luis




More information about the umbrello-devel mailing list