Refactoring of Writer's usage of the Drawing layer
The refactoring of the Writer's usage of the Drawing Layer is to create and maintain different Draw models for the Writer's model of Drawing objects and for the Writer's view(s) of Drawing objects. The purpose of this refactoring is to
- improve the maintainability of the Writer's code regarding its usage of the Drawing layer,
- prepare the replacement of the Writer's implementation for graphic objects and embedded object by the corresponding implementation of the Drawing layer,
- get rid of special code in the Drawing layer, which only serves the Writer's needs for Drawing objects,
- solve certain issues regarding Drawing objects in repeated areas of a text document (Note: such repeated areas are page header, page footer and table headers), and
- "pre-prepare" the introduction of multiple different views on a certain text document.
- The information on this wiki page will be extended and adjusted during the implementation.
- 1 Roadmap
- 2 The Big picture of the refactoring
- 3 Drawing layer functionality and issues
- 4 Implementation constraints
- 5 Effect on other Drawing object functionalities
- 6 Issues fixed by the refactoring
- 7 Tests
- 8 Implementation details
- Develop general idea about the refactoring and its high-level implementation details – the big picture.
- Evaluate Drawing Layer functionality regarding the refactoring.
- Identify issues in Drawing Layer functionality, which needs to be solved in order to support the proposed refactoring.
- Identify certain implementation constraints which among other things
- simplify the refactoring and/or the new code,
- allow the removable of former inappropriate code/solutions, and
- assure a good performance of the new code.
- The load/save performance shall not be affected by the refactoring. The editing performance is affected by the refactoring, but its effect shall be as low as possible.
- Note: It is needed to find a balanced way between the above three goals – e.g. not everything, which simplifies the new code would be good for the performance.
- Evaluate consequences of the refactoring to other functionalities regarding Drawing objects in Writer.
- ODF import/export
- Writer's implementation of the Drawing objects' UNO-API
- Identify known issues, which shall be solved by the proposed refactoring.
- Define testing/QA issues
- test plan(s) for end user tests
- API tests
- UNIT tests
- Get overview of the implementation details.
- Design and implementation of the new/changed architecture of the Writer's usage of the Drawing Layer
- New Classes/Interfaces
- Classes/Interfaces, which are reused, but are adjusted
- Classes/Interfaces, which are removed
- Relationships between the Classes/Interfaces, which implement the new Writer's usage of the Drawing Layer
The Big picture of the refactoring
The general idea of the refactoring is to use the Drawing layer in such a way that the model and the views of Drawing objects from the perspective of the Writer are separated. This new usage shall be transparent for the Drawing layer - no special code should be included into the Drawing layer to reflect this separation.
The solution to make this idea happen is to create different Draw models for different purposes. One Draw model for the intrinsic model of Drawing objects - called simply Draw model in the following. One Draw model for each Writer view for the view of Drawing objects - called Draw view model in the following.
Current state of the art
Currently the Writer holds one Draw model with one Draw page for the model and the view of Drawing objects. This causes certain special code to reflect Writer's specifics regarding Drawing objects:
- As invisible marked layers in the Draw page.
- Certain Drawing objects are not visible in any view, because they are located inside a hidden area (hidden section, hidden paragraph) or inside a page header/footer of a page style, which is not applied to any visible text document page. But, these Drawing objects belong to the model. Thus, they have to be on a Draw page in the Draw model -> invisible marked layers.
- Virtual Drawing objects
- Drawing objects in repeated areas (page header/footer and table header) have to be shown more than once inside a certain view. Because each Drawing object shall be only once in the Draw model, virtual Drawing objects are introduced - class <SdrVirtObj>. These are referencing the intrinsic Drawing object. Drawing objects of type control are not working with this mechanism. There are also some effects (e.g. text animation), which does not work with this mechanism.
- Note: The current usage of class <SdrVirtObj> by inheriting certain classes causes a lot of implementation effort. It is error-prone and complicated. It lacks certain features (controls not supported, no support for certain effects). It is also hard to maintain.
- Special call back mechanism from Drawing layer to Writer on Drawing object changes
- Due to former needs a special call back mechanism from the Drawing layer to the Writer is implemented. In this call back mechanism further information - namely the bounding rectangle of the Drawing object before the change has been applied - is passed to the Writer. This special call back mechanism can be removed nowadays. But unfortunately during the implementation of changes and enhancements to Drawing objects in Writer made in the past (mostly done by myself - email@example.com) this call back mechanism was not put into question.
- Special treatment of Drawing object's position and related properties in UNO-API
- Due different layout directions in text documents, which are not supported by the Drawing layer, the Drawing object's position and related properties (Transformation, StartPosition, EndPosition and PolyPolygonBezier) have to be treated special in the Writer's UNO-API implementation of Drawing. The position directly after the ODF import equals the model position of the Drawing object. If the layout direction is not horizontal, left-to-right, the position of the Drawing object have to be adjusted for the layout. Because the Drawing layer only supports horizontal, left-to-right, the other layout direction have to simulated by the adjusted position. But at the UNO-API the model position have to be present and the actual position influences other properties - namely the ones mentioned above. That is the reason for the special treatment of the position and the related properties in Writer's implementation of the Drawing object's UNO-API. This special treatment costs performance on certain UNO-API calls, is error-prone and hard to maintain.
The current state of the art (especially the virtual Drawing objects) also causes some problems with Drawing objects in the preparation work for multiple different views and for probably new views of a text document - cws swrefactor071015.
Solution/Refactoring in detail
The details of the refactoring are:
- The Writer model holds a Draw model. This Draw model represents the model of the Drawing objects, which are contained in a text document. Thus, this Draw model is used for load/save and the UNO-API. The Drawing objects in this Draw model will be called Drawing model objects in the following.
- The Writer model is more or less represented by the <SwDoc> instance.
- Each Writer layout holds its own Draw model for the visualization of the Drawing objects. Such a Draw model will be called Draw view model in the following. The Drawing objects of a Draw view model are clones of the corresponding Drawing model objects. These clones will be called Drawing view objects in the following. For each visualization a new clone is created. For the Drawing layer these clones are independent from each other - there will be no functionality restrictions as they currently exist with virtual Drawing objects.
- A Writer layout is more or less represented by the tree of <SwFrm> instances with a <SwRootFrm> instance as its root.
- Note: Currently, only one Writer layout exists and it is shared between the existing Writer views (reason for the current restrictions between the existing views of a text document). Thus, after the refactoring there will be only one Draw view model. But, this solution will allow to continue the preparation work for multiple different views of a text document without having problems with Drawing objects (the goal of this preparation work is to give each Writer view its own Writer layout).
- The Writer will take care of the relationship between the Drawing model objects and its corresponding Drawing view objects.
- The Writer layout algorithm will create the Drawing view objects from the Drawing model objects for a certain Writer layout.
- A certain instance for each Writer layout will hold the relations to the corresponding Drawing view objects.
- A certain instance of the Writer model will listen to the Draw model for changes on Drawing model objects and will assure a propagation of the changes to existing Drawing view objects.
- A certain instance for each Writer layout will listen to the Draw view models for changes on Drawing view objects and will assure a propagation of the changes to the Drawing model object and the other existing Drawing view objects.
- No special handling for undo/redo actions seems to be necessary. A certain undo action is recorded for the Drawing object, at which the action has taken place. On undo/redo the reverse action is applied to this Drawing object and via the above listening mechanism the other Drawing objects are notified.
- The Writer will take care of the synchronization of the selection status between the Draw model and the existing Draw view models
Drawing layer functionality and issues
For the refactoring the following functions are needed:
- Clone Drawing objects
- Needed when a Drawing view object is created from the Drawing model object.
- Assignment of Drawing objects to each other
- Needed to propagate the changes on one Drawing object to the other related ones.
- Listening to Drawing object's changes
- Being notified, when changes are applied to a certain Drawing object in order to coordinate the propagation to the other related ones.
All functions are available at the Drawing layer. No serious issues regarding these functions are currently known.
- Treat every Drawing object type the same
- simplify code
- Try to avoid the introduction of code into the Drawing layer to support new Writer's usage of the Drawing layer
- special code in Drawing layer for Writer is one of the reasons for this refactoring
- Get rid of class <SdrVirtObj> - instead use "real" Drawing objects
- simplify code
- special Drawing object type of Drawing layer for Writer, not needed any more
- Get rid of class <SdrObjUserCall> - instead use implemented listener-concept
- simplify code
- special notification mechanism of Drawing layer for Writer, not needed any more
- Get rid of the special treatment of the Drawing model object's position and related properties (Transformation, StartPosition, EndPosition and PolyPolygonBezier) at Writer's UNO-API implementation.
- simplify code
- special treatment due to combined model and view data, not needed any more after separation of model and view
- Treatment of change of the Drawing object's position
- A change of the positioning attributes at the Drawing model object is not directly propagated to the existing Drawing view objects. Instead the Writer's layout process is triggered to adapt the Drawing view object's position accordingly.
- A change of the position at a Drawing view object is also not directly propagated to the Drawing model object and the other existing Drawing view objects. Instead the position change is converted to a change of the positioning attributes at the Drawing model object and afterwards the Writer's layout process is triggered to adapt the Drawing view object's position accordingly.
- Assure that on change of other attributes the Drawing model object's position and the Drawing view objects' positions are preserved.
- Evaluate, if special treatment of control objects regarding cloning is needed
- Special treatment of Draw embedded objects regarding cloning
- clone of embedded object for visualization should be a graphic object with the replacement graphic of the embedded object as its content.
- this approach is in use for the full drag support of embedded objects, because it reveals that cloning embedded objects is too expensive.
- causes special treatment of graphic objects as visualization objects for embedded objects
- propagation of changes
- context menu
- tool bars
- clipboard handling
- Important note - 8. not considered now, but...
Currently, Draw embedded objects are not possible in Writer, because Writer uses its own implementation. But, 8. has to be considered, when the Writer's implementation is replaced by Draw's implementation.
- 1. and 8. somehow contradicts each other. Thus, assure in the implementation that the special treatment of embedded objects is implemented via a wrapper in the Writer code or via a corresponding virtual method in the Draw code.
- Note: second solution (new virtual method) contradicts with 2. But, would support a similar Drawing layer usage from the other applications.
- 8. would probably cause a new class in the <SdrObject> class hierarchy in order to identify the graphic objects, which are visualizations of embedded objects.
- Note: this would contradict with 2. But, would support a similar Drawing layer usage from the other applications.
Effect on other Drawing object functionalities
- Writer's UNO-API implementation
- This functionality is directly touched - see implementation constraints
- No effect on its behavior and interface except a better performance on certain UNO-API calls
- ODF import/export
- Not touched, but affected by the change in the Writer's UNO-API implementation
- No effect except a better performance on retrieving certain properties via the UNO-API
- Not touched and not affected, as currently planned
- Cut, Copy and Paste
- Not touched and not affected - Cut, Copy and Paste have to be performed on the Draw model
- Not touched and not affected
Issues fixed by the refactoring
|firstname.lastname@example.org||support form controls in page header/footer||P3||OOo Later|
|email@example.com||Anchor control to header's paragraph, OpenOffice will crash||P2||OOo 3.x|
|firstname.lastname@example.org||Drawing object copied via CTRL+drag is not visible||P3||OOo 3.x|
|email@example.com||Pictures flicker on top of document when opening||P3||OOo 3.x|
|firstname.lastname@example.org||Invisible object after pasting during "edit group"||P3||OOo 3.x|
|email@example.com||animated text in drawing objects in page header/footer only in one page header/footer||P3||OOo Later|
|firstname.lastname@example.org||"edit group" for page header/footer anchored drawing object group only in one group possible||P3||OOo Later|
test plan(s) for end user tests
First thoughts by MRU and OD:
- Collect all known automatic tests for Drawing objects and Controls
- Probably extend automatic tests for Drawing objects and Controls
- Usage of standard and special ConvWatch test cases
- Check text documents in foreign file formats, especially in Microsoft Word's file formats (WW8, RTF and .docx)
MRU will continue the work on this topic and will take care of updating this content
- existing API tests for Drawing objects in Writer
- identify these API tests
- check, if still successful
- probably extend them
- new complex API test
- load of ODF text document containing Drawing objects of different types in different document areas (body text, page header, page footer, table header)
- check, if all Drawing objects are present and have the suggested positions
- insertion of new Drawing objects of different types in different document areas
- check, if all new inserted Drawing objects are present and have the suggested positions
- modification of the Drawing objects
- check, if all modification have taken place
[Work out during implementation]
- Model data of Drawing objects in text documents
- The model data of Drawing objects in text documents are spread over two instances
- <SwDrawFrmFmt> instance holding the text document specific model data about the Drawing object in its attribute set.
- <SdrObject> instance holding the intrinsic model data about the Drawing object.
- Position data are hold in both instances:
- <SwDrawFrmFmt> holds the complete set of position attributes needed to position the Drawing object in a certain view.
- <SdrObject> holds the relative position to its anchor, which is set during the import to adapt the position attributes of the <SwDrawFrmFmt> instance, when the Drawing object is laid out the first time, especially when the relative position of the <SdrObject> is in horizontal left-to-right layout in the stored text document file (OpenOffice.org file format). This relative position is also stored in ODF on export.
- Changes to <SwDrawFrmFmt>
- <SwDrawFrmFmt> will clearly take ownership of <SwDrawContact> - class member
- Redefine purpose of <SwDrawContact>
- Responsible for the connection of Writer model object for Drawing objects and the Drawing model object
- Responsible for the connection of Writer model object for Drawing objects and the Writer layout objects for Drawing objects
- Change of class name respectively new class?
- Changes to <SwAnchoredObject>
- <SwAnchoredObject> takes over ownership of <SdrObject> instance created for the corresponding Writer layout.
- Thus, <SwFlyFrm> instance takes over ownership of <SwFlyDrawViewObj> instance and <SwAnchoredDrawObject> instance takes over ownership of Drawing view object.
- The <SdrObject> instance representing the model in Writer model's Draw model is passed as a parameter to <SwAnchoredObject>'s constructor. A clone for the view of this <SdrObject> instance for the corresponding Writer layout is then created and owned. At this point the created <SdrObject> instance is not inserted in a Draw model and a Draw page.
- When the <SwAnchoredObject> instance is inserted into the Writer layout - method <SwAnchoredObject::ChgAnchorFrm(..)> the <SdrObject> is also inserted into the corresponding Draw view model and the corresponding Draw page of this Draw view model.
- Changes to <SwVirtFlyDrawObj>
- Replace by new class <SwFlyDrawViewObj> with the same responsibilities, but inherited from <SdrObject>
- Changes to <SwFlyFrmFmt>
- <SwFlyFrmFmt> takes over responsibility of <SwFlyDrawContact>
- Ownership of <SwFlyDrawObj> in Draw model
- New factory to create clones for the view from Drawing model objects and <SwFlyDrawObj> instances
- This factory functions as a wrapper in the Writer's code for cloning/copying/creation of <SdrObject> instances for the view out of certain <SdrObject> instances, which functions as model objects.
- <SwFlyDrawObj> --> <SwFlyDrawViewObj>
- Drawing model object --> clone
- Special clones for certain Drawing object type in the future are possible
- Drawing embedded objects
- Changes to <SwDoc>, probably implemented in a new aspect
- Listening to its Draw model for changes on its Drawing model objects
- Notification of Drawing model object changes to the corresponding Writer model object for this Drawing model object
- Changes to <SwRootFrm>, probably implemented in a new aspect
- Taking over responsibility of its Draw view model - class member
- Listening to its Draw view model for changes on its Drawing view objects
- Notification of Drawing view object changes to the Writer model. The notification has to contain the Drawing view object, on which the change has taken place in order to pass this change to the Drawing model object and the other Drawing view objects.
- Establish <SwModify>-<SwClient> relationship between <SwDrawContact> instance and <SwAnchoredDrawObject> instances
- As <SwFlyFrm> instances (Writer layout object for Writer text frames) are clients of a <SwFlyFrmFmt> instance (Writer model object for Writer text frames) <SwAnchoredDrawObject> instances (the Writer layout objects for Drawing objects) should be clients of <SwDrawContact> (helper class of the Writer model object for Drawing objects).
- As a result of this relationship the notification of changes to the Writer's model data about Drawing objects are simplified.
- Revise/Adjust/Correct handling of order number change
- method <SwDrawView::ObjOrderChanged(..)>
- Removal of no longer needed code/classes in Writer
- invisible marked layers in the Draw page and corresponding methods
- Removal of no longer needed code/classes in Drawing layer
- General code improvements to the code for Writer's usage of the Drawing layer
- One source file for each class definition
- One source file for each class implementation
- Base class of
- Drawing model objects
- Drawing view objects
- More or less representing together with its sub structures the intrinsic Writer model of a text document.
- Writer model object for a Drawing object.
- Part of the Writer model object for a Drawing object responsible for the relationship to the Drawing layer and the creation of Writer layout objects. Owned by <SwDrawFrmFmt>.
- Part of the Writer model object for a Writer text frame, a Writer graphic or a Writer embedded object holding the complete attribute set.
- Helper class of the Writer model object for a Writer text frame, a Writer graphic or a Writer embedded object to establish Drawing layer functionalities for such objects. I am not sure, if these are only functionalities for the View. If yes, may be this class can be removed.
- As far as I know it is also used in the ODF export - needs to be confirmed. If not, then may be this class can be removed.
- Root of the tree hierarchy of <SwFrm> instances representing the Writer layout - thus, in general called to be the Writer layout.
- Part of the Writer layout. Base class for <SwFlyFrm> and <SwAnchoredDrawObject> - Polymorphism.
- Writer layout object representing a Writer text frame, a Writer graphic or a Writer embedded object in the Writer layout.
- Part of Writer layout object representing a Writer text frame, a Writer graphic or a Writer embedded object in the Writer layout owned by <SwFlyFrm>. Responsible for the Drawing layer view functionalities of such an object.
- Writer layout object representing a Drawing object in the Writer layout.