Package jpicedt.graphic
jPicEdt library core classes and packages. Package structure follows the model-view-controler paradigm. See documentation below for details about the VMC implementation in jPicEdt.
- Since:
- PicEdt 1.0
Table of contents
- The Model-View-Controler paradigm as implemented in jPicEdt
- The Drawing class and Element interface : a document model for vector-graphics
- The View interface : rendering the model
- The DrawingEvent's dispatching scheme : keeping things in touch
- The EditorKit class : processing UI events
- The FormaterFactory class : exporting documents to LaTeX format
- The ContentType interface : lumping things together
The Model-View-Controler paradigm as implemented in jPicEdt
[todo] a short introduction...The Drawing class and Element interface : a document model for vector-graphics
The document model mostly comprises classes in thejpicedt.graphic.model package. It is built on top of :- an
Elementinterface : this specifies the general contract for graphics primitives (see e.g. DefaultLeafElement and its subclasses) or composite elements (see e.g. BranchElement and PicGroup) which may be added to the model ; - a
Drawingclass : this is the document's model, designed as a tree-like container forElement's, the tree structure being inforced by the capability ofElement's to have a parent and -possibly- children. - an event-dispatching scheme based on the
jpicedt.graphic.event.DrawingEventclass : this allowsElement's to communicate with their hostingDrawing, and the latter to post events to registered listeners interested in change in the document's content (e.g. views, selection-handlers, UI components,...).
The root-element of the document is actually an instance of
Drawing.RootElementwhich inherits fromBranchElement: eachElementthat is directly added to theDrawingis actually added as a child ofDrawing.RootElement; yet this is rather internal machinery, and developpers may not have to bother withRootElement's methods, and might better use theDrawing's API to alter the document's content. In a way, the Drawing class may be simultaneously considered as the hosting document AND the document's root-element.Adding an
Elementto theDrawingthus effectively makes it a node a tree, where each node is able to communicate with its parent or -as it is- with its children. This makes it possible for anyElementbelonging to the model to postDrawingEvent's to the entire tree, so that e.g. the hostingDrawinggets eventually informed of changes that may have occured in the document's content. It is then up to the theDrawingto decide whether to post these event or not to registered listeners.The View interface : rendering the model
The document's view is aimed at rendering a
Drawing; most classes related to the rendering of the model are located in thejpicedt.graphic.viewpackage ; besides, some other classes of interest may be found in the various format-specific packages underjpicedt.format.Each
Drawingmay or may not have a view attached to it. Attaching a view to a model is required only as soon as the model has to be rendered on screen. For instance, parsers create and populate aDrawingwithout ever having to render it on screen. If a drawing has an associated view, then synchronization between the view and the model is based on an event-dispatching mechanism similar to the AWT's event-dispatching scheme (see DrawingEvent's documentation below).The view has a pseudo tree-like structure which mimics that of the associated Drawing, and is based on a cross-reference mechanism : every an
Elementmay have ajpicedt.graphic.view.Viewdirectly associated with it, in which case the View also holds a reference to theElementit is associated with. Hence this is a pseudo tree-like structure, in that anElement's View doesn't hold any direct reference to its parent's view ; instead, by holding a cross-reference to theElementit is associated with, it indirectly knows of its parent's view by relying on theDrawingtree structure. To sum up : let X and Y be twoElement's of aDrawing, where Y denotes X's child, and Xv, Yv the view attached to them ; then for Yv to reach its parent's view, it must rely on the following mechanism :Model View X -> : getView()Xv ^ : getParent()Y <- : getElement()Yv ViewFactory's
The view-tree is basically populated by calling
Drawing.setViewTree(ViewFactory f), as soon as one wants the model to be rendered. The givenjpicedt.graphic.view.ViewFactoryknows how to produceView's that are appropriate for eachElement; hence, there may be (and there are in effect) differentViewFactory's depending on the kind of content-type to be rendered (e.g. PsTricks, eepic/epic, SVG-XML,...). This approach allowsViewFactory's to be plugged on-the-fly byEditorKit's when the content-type of the model to be rendered changes.For the sake of clarity, the view-tree populating during
PECanvas's initialization is illustrated hereafter in sketchy outlines :- at some early point in
PECanvas's contructor,setContentType()is called with the kind of content-type given as argument to the constructor ; - this in turn calls
setEditorKitForContentType(): a newEditorKitapproriate for the given content-type is created, then linked to the hosting canvas (through a call toEditorKit.install(canvas), which allowsMouseEvent's to be properly dispatched to the editor-kit) ; - then a new
Drawingis created (usually by asking the editor-kit to create one that is appropriate for the given content-type, although jpicedt currently models all content-types with the same Drawing class) - the editor-kit is asked to create a
ViewFactoryappropriate for the given content-type (see documentation : EditorKit.ViewFactoryWrapper) - the view-tree associated with the model is then populated by this factory through a call to
Drawing.setViewTree(view-factory).: this actually callssetViewFromFactory(view-factory)onDrawing.RootElement, which populates the rest of the tree by callingsetViewFromFactory(view-factory) on all of its children.
(Re)painting things
Whenever the content of an Element changes, the View associated with the Element is asked to update itself by means of the changedUpdate() method : this usually means (as implemented in DefaultViewFactory) synchronizing some cached data with the Element (a Shape, a Stroke, ...). This however is not enough for the *real* screen to reflect the change : for that to happen, the hosting JComponent must be asked to repaint itself through the asynchronous AWT's repaint mechanism.
Now because any View belonging to the view-tree knows of its hosting container (= the Swing component that *really* paints things, usually an instance of PECanvas), it can easily - by means of the repaint() method in the View interface - ask the container to repaint itself (or a part of itself, see documentation in graphic.view.AbstractView.repaint()). This indirectly invokes, through the asynchronous AWT painting mechanism, paintComponent() on PECanvas, the latter being implemented so as to invoke the following paint() methods :- on the
Gridobject attached to the PECanvas; - on the
root-viewassociated with Drawing.RootElement (this view is implemented as an inner class of EditorKit, see documentation about EditorKit.RootView below) : this in turn invokes the paint() method on every child of this view ; - on the
EditorKitin which this PECanvas is installed : this will first invoke paint() on EditorKit.SelectionHandler, i.e. paint the highligher (small green/red squares for Element's control-points, tangents for Bezier curves, etc...), and then invoke paint() on the MouseTool that is currently active in EditorKit (this allows this MouseTool to do some specific rendering that makes sense with the operation being currently carried out, e.g. painting a selection rectangle, ...).
The DrawingEvent's dispatching scheme : keeping things in touch
A
Drawinghas the capability of postingDrawingEvent's to registered listeners to signal a change in the content of the model it holds. This may be used e.g. byView's, selection-handlers, or by any part of the UI to keep their state synchronized with the content of the model. Besides,DrawingEvent's contain enough information regarding the change in the document's content to allow receivers to efficiently optimize their re-synchronization with the model.As implemented in the
AbstractElementabstract class, any change in the content of an Element, e.g. by calling thesetPointmethod, eventually callsfireChangedUpdate: this in turn- forces the associated view (if any) to keep its state
synchronized with the model by calling
view.changedUpdate(hence in this abstract implementation of theElementinterface, the view/model synchronization is based on a direct peer-to-peer messaging, rather than by registering the entire view tree as a DrawingListener, and waiting for the event to reach the top of the Drawing's tree-model until the View can update ifself ; this is probably faster, yet this scheme doesn't make use of all the capacilities of the event-dispatching scheme). - forward the event to the parent of the element, by calling
parent.forwardChangedUpdate:- first, this give a chance to the parent to update some of its geometrical properties immediately (see e.g. PicGroup : there, the group's bounding-box must be kept up-to-date with the bounding-box of the group's children, and the group's view be updated immediately) ;
- then, this allows the event to propagate upward until it eventually reached
Drawing.RootElement, which then enables its hosting Drawing to dispatch the event to registered listeners.
This mechanism is illustrated in the figure below :
The EditorKit class : processing UI events
[todo]
How EditorKit creates ViewFactory's ...
There are two important inner classes in EditorKit for that matter : ViewFactoryWrapper and RootView. These classes currently have package access, hence documentation about them is mainly aimed at helping developpers to get some grasp of the machinery behind the EditorKit class.
An instance of
EditorKitis usually instanciated by aContentType, which thereby provides it with an approriateViewFactory. However, this ViewFactory may to all probabilities inherit fromDefaultViewFactory, since it is by far the easiest way for developpers to implement their own content-type classes. Yet if DefaultViewFactory can create View's for every Element in the graphic.model package, it doesn't provide any "root-view" to be associated withDrawing.RootElement: basically, such a view has to :- react to
DrawingEvent's posted byDrawing.RootElement(this is the case e.g. when a new Element is added to the drawing), by forcing the hosting Swing container (probably aPECanvas) to repaint itself ; - implement the
mouse-event-related
hitTest()method specified in the View interface so as to dispatch to all the Element's in the Drawing successively. - maintain a reference to the hosting container (=PECanvas), so that any view in the tree may retrieve its container by asking its root-element. Since RootView is an inner class of EditorKit, and EditorKit has a reference on the PECanvas it is installed in (see the install() method), this was pretty easy to implement.
Hence we have defined an inner class of EditorKit for that purpose : when asked to create a View for a Drawing.RootElement,
ViewFactoryWrapperreturns a specificRootView(also implemented as an inner class of EditorKit) ; otherwise it delegates to the ViewFactory provided as a constructor to EditorKit ; actually, ViewFactoryWrapper may even do better, since it first checks if theElementto create the View for does implement theViewFactoryinterface itself, in which case the given Element is asked FIRST to create a View for ... itself (this allows developpers to -lasily- design new Element's without having to extend the whole DefaultViewFactory machinery : they'd just have to make their new Element implement thecreateView()method ; of course this approach is valid as long as the rendering of the new Element doesn't depend on the current content-type being installed in PECanvas).SelectionHandler : selecting, copying, pasting.
[todo]
MouseTool's : pluggable behaviour for mouse-event handlers
[todo]
PEAction's : sharing action-handlers across jPicEdt
[todo]
The FormaterFactory class : exporting documents to LaTeX format
[todo]
The ContentType interface : lumping things together
Thejpicedt.graphic.ContentTypeclass "lumps" the three components of the VMC paradigm together, since it is able to create components appropriate for the kind of content-type it represents. In particular, this class knows how to create anEditorKit, which is enough to create the two remaining components by callingkit.createDefaultDrawingandkit.createDefaultViewFactory.Besides,
ContentTypeis able to create ajpicedt.graphic.io.FormaterFactorywhich knows how to format a Drawing to ASCII text.Concrete implementation of
ContentType's, together with there associated factories, are located in subpackages ofjpicedt.format. There currently exists content-types for PsTricks, LaTeX's picture environment, and the eepic package.Contributing a new content-type (e.g. PostScript, metapost, ...) therefore imposes :
- To write a new implementation of the
ContentTypeinterface ; - Possibly subclass
DefaultViewFactoryif specialized rendering behaviour is needed (e.g. no colour rendering) - Write a new
FormatterFactory; - Possibly write a new parser if one want jpicedt to be able to import files based on this content-type.
The easiest way to plug a new parser to the main parser tree is to add it to the
DefaultParserby calling theaddGrammarmethod. [todo:more documentation about implementing parsers].
Last-upd : January 20th 2003
-
Interface Summary Interface Description ContentType Specifies a content-type (aka mime-type) for a Drawing document created by an editor-kit.SelectionHandler a SelectionHandler allows to manage selection-related behaviours for a given instance ofDrawing. -
Class Summary Class Description AbstractSelectionHandler Provides some basic implementation of the SelectionHandler interface.DefaultContentType Default implementation of the ContentType interface suited for the JPIC-XML language.PageFormat Size and margins data for aPECanvas.PageFormat.Customizer a dialog box used to change a PageFormatPECanvas This is a JComponent on which graphic elements are drawn.PEScrollPane A scrollpane that is able to host aPECanvas.PEScrollPane.CenterViewportAction Move the view so that (0,0) is at the center of the viewportPEToolKit A collection of static -utilities- methods targetting number formatting, Swing's widget creation, computation of geometrical properties,...PicPoint Enhancement of Point2D.Double with convenient formatting methods and constructors.PicPoint.XComparator a comparator b/w PicPoint for X-axis orderingPicPoint.YComparator a comparator b/w PicPoint for Y-axis orderingPicVector This class encapsulates a geometrical vector (ie it has absolutely no relation with java.util.Vector !).