On 15-10-2012 17:40, Krzysztof KosiĆski wrote:
2012/10/13 Johan Engelen <jbc.engelen@...2592...>:
Hi all, For backwards compatibility with old-style guides, we want to convert the old-style guides to new-style in sp_namedview_build. Removing the old-style guides from XML and adding new ones works fine, however, this is not represented at all in the SPObject tree. After removing the old-style guides, the SPObjects are still in memory and hooked up to namedview. Also, adding new guides to XML does not create SPObjects belonging to them. This all works fine outside sp_namedview_build (the mechanism is used in hundreds of places in the code), but for some reason does not work within sp_namedview_build. Is that expected behavior? Where should we move the conversion code to?
When the SP tree is initially created, the XML node observers, which are responsible for keeping the SP tree up to date, are not yet active. They are added by SPObject::invoke_build only once the build function for your SPObject finishes executing. The children of each object are created by its virtual build function, such as sp_namedview_build. For this document skeleton:
<svg> <g> <path> <path> </g> </svg>
The order of actions is:
call SPRoot::build call SPItemGroup::build call SPPath::build for the first path add first path observer call SPPath::build for the second path add second path observer add group observer add root observer
The XML observers do not send a notification when an object is destroyed. Deleting and creating SP nodes for children is the responsibility of the parent's listeners. This is the fundamental cause of some still unsolved crashes in the node tool (for example, undoing 2 or more stacked LPE applications through the undo history dialog). In particular, if you first create the child SPObject of the namedview, then remove their XML nodes and add some others, there will be no change in the SP tree because the listener for namedview will only activate once you return from sp_namedview_build. I hope this explains the problem.
A quick hack is to explicitly invoke the necessary listeners (SPObject::sp_object_repr_child_removed, SPObject::sp_object_repr_child_added, etc.) on SPNamedview in the build function, but this is rather ugly. A far better solution is to change the build function for the new SPObject for guides. First, check the XML element name. If you encounter the old guide XML, convert it to the new XML using a series of setAttribute() calls and finally call your XML node's setCodeUnsafe() function to change its element name to the one for new guides. After that, execute normally like for new guide XML. Once this is ready, modify sp-object-repr.cpp so that the new SPObject is created for both old and new guide elements. This way the compatibility code is kept in the element it's related to, rather than in its parent.
Thanks very much for describing the order of things. What is interesting that it did seem to work once for grids (which may have turned into a bug now), but that might be because grid objects are handled somewhat abnormally in SPNamedview.
I don't like adding the compatibility code to the classes themselves. Also, note that in this case the compatibility-fix is easy: simply change some values. But other compatibility patch-ups may involve more than one new objects or in another place in the SVG. For example, the old-style grid was not an SVG leaf and the patch-up required creating a new leaf.
What about adding a specific compatibility section in our file loading code? So after the XML is loaded, but before all objects are created. So the patch-ups involve modifying the XML. Then when all is well, the object tree is created. This way, all patch-ups are grouped together and don't clutter our codebase in different places.
Cheers, Johan