OnComplexGraphics(), cells, and ChildEditElemIter

If I read a cell from a cell library where the cell has some text or text nodes in it, I'd like to change the text in the cell. In the OnComplexGraphics() I make a call to my CreateElement() passing in an EditElemHandle. The cell library is searched, the cell found, then read into an elementDescr. Next I set the EditElemHandle with the elementDescr:

eeh.SetElemDescr(pCell, true,false);

Now I want to iterate through the cell, find text, and make changes, so I'm using a ChildEditElemIter:

for ( ChildEditElemIter child(eeh,EXPOSECHILDREN_FindText ); child.IsValid(); child=child.ToNext() )
{
 MSElement  *elP=child.GetElementP();
 if ( mdlElement_getType( child.GetElementP() ) == TEXT_ELM
 || mdlElement_getType( child.GetElementP() ) == TEXT_NODE_ELM )
 {
  // Found text - make the change(s)

MSElement   newText;
mdlText_create(&newText, elP, "NEW", NULL, NULL, NULL, NULL,NULL);
child.ReplaceElement(&newText);
}

return eeh.IsValid();

When the cell gets placed ( eeh.AddToModel(ACTIVEMODEL); ), I end up with two text elements (the cell only has a single text element) and both text strings are set to "NEW". There must be something else I need to do, but it's not obvious.

Bruce

Parents
  • I'm pleased to see you exploring the uncharted territory of the MicroStationAPI. I'm no expert on this (I view the uncharted territory more as a wilderness — and I'm lost in it), but how about using EXPOSECHILDREN_EditText rather than EXPOSECHILDREN_FindText?

    The Taint of MDL

    Unknown said:
    if ( mdlElement_getType( child.GetElementP() ) == TEXT_ELM

    You missed method ElemHandle.GetElementType. Your code would be more coherent if you were to do this …

    if (TEXT_ELM == child.GetElementType())

    Regards, Jon Summers
    LA Solutions

     
    Regards, Jon Summers
    LA Solutions

  • Unknown said:
    how about using EXPOSECHILDREN_EditText rather than EXPOSECHILDREN_FindText?

     

     

    Sounds like a reasonable question. I tried it, but got the same result. Then I went back to the model definition in the cell library. I made a "copy" of an existing model to play with as I am developing. My play model (and the original as well) actually DID have two text strings on top of each other. Corrected that issue and tried my app again - works as desired now. I'm curious as to how things would behave if the cell has a textNode with text elements. I'm guessing that the ChildEditElemIter would differenciate between the textNode and the text elements, and hopefully "adjust" the textNode properties if any changes to it's text strings would necessitate changes back in the textNode (would that ever need to happen?).

    Thanks for the suggestion and all the help you've provided regarding the MicroStationAPI.

    Bruce

  • A ChildElemIter doesn't recurse, it just iterates over top-level children. For stuff like nested cells you need to also iterate the children (if needed). As for text vs. text node, it's better to deal with a text node as a text node...and not try to change the component text elements directly.



  • And what's the difference, besides the apparent one, between EXPOSECHILDREN_EditText and EXPOSECHILDREN_FindText?  Do they invoke the iteration type that one infers from their name?

     
    Regards, Jon Summers
    LA Solutions

  • For V8i if you intend to modify the text using a ChildEditElemIter use EXPOSECHILDREN_EditText, if you only plan to extract it use a ChildElemIter and EXPOSECHILDREN_FindText. The idea would be if a *cell* contains text components that can be edited, vs. read only text that could only be queried...althought I don't think any complex element handler actually makes this distinction. HTH

    -B



  • Sorry for picking up that old thread, but I stumbled over this while searching for a solution, how to inspect an element at it's best.

    In some (really old) part of my code I used to create an (recursive) iterator by myself (using ElementDescriptors and the firstChild/next members). Actually I ran into problems with the recursion depth, which leads to an stack overflow (after some thousands of recursions at the ->next) level.

    I'm currently reworking this part and thought of using the API functions, but after reading this, from the 'stack' point of view, wouldn't  be a mdlElmdsr_operation the better solution, if i expect a valueable depth of nesting levels for the elements to be inspected ?

    To be clear: is the recursive call of ChildElemiter (by giving the ElementHandle into the recursive method call) or the usage of the 'old' mdlElmdsr_operation() with it's single instance callback the better solution (no changes, pure information retrival) ? I suppose that EXPOSECHILDREN_FindText is even not useable for this, as I would need to 'dive' deeper in the nesting levels of the given (cell) elements.

    Any thoughs are appreciated.



  • A big advantage to using a ChildElemIter to query element data is that it doesn't require you to read/allocate an MSElementDescr for a persistent element, it can be constructed from an ElementRef.

    EXPOSECHILDREN_QueryProperties is the most generic purpose, unless you are specifically only interested in finding text in cells, use that. As I mentioned previously, this will be greatly simplified in a future release.

    Only user defined cells and groups will expose public children to a ChildElemIter (unless you use EXPOSECHILDREN_Count...which you shouldn't ever use!). This means you won't waste time spelunking into complex types like feature solids/smart solids whose components should mean nothing to you. This is also a good thing as it limits the number of elements you will have to slog though and tells you what complex types (ex. smart solids) wish to be treated as a single element and not a collection of elements.

    void querySomething (ElemHandleCR eh)
        {
        checkSomething (eh)

        for (ChildElemIter childEh (eh, EXPOSECHILDREN_QueryProperties); childEh.IsValid (); childEh = childEh.ToNext ())
            querySomething (childEh);
        }

    What matters in terms of stack usage is nest depth. It would be the rare user defined cell that is nested even 10 deep. Feature Solids, one of the more deeply nested constructs don't often exceed a depth of 100.

    Don't declare any variables in the recurive function itself, call into another function to do any testing/modification of the current element. Stack for variables declared in the helper function are reclaimed when the function exits and isn't attributed to the recursion.

    This is effectively how mdlElmdscr_operation works, someone has to do the recursion...it's not doing anything you can't...

    -B



Reply
  • A big advantage to using a ChildElemIter to query element data is that it doesn't require you to read/allocate an MSElementDescr for a persistent element, it can be constructed from an ElementRef.

    EXPOSECHILDREN_QueryProperties is the most generic purpose, unless you are specifically only interested in finding text in cells, use that. As I mentioned previously, this will be greatly simplified in a future release.

    Only user defined cells and groups will expose public children to a ChildElemIter (unless you use EXPOSECHILDREN_Count...which you shouldn't ever use!). This means you won't waste time spelunking into complex types like feature solids/smart solids whose components should mean nothing to you. This is also a good thing as it limits the number of elements you will have to slog though and tells you what complex types (ex. smart solids) wish to be treated as a single element and not a collection of elements.

    void querySomething (ElemHandleCR eh)
        {
        checkSomething (eh)

        for (ChildElemIter childEh (eh, EXPOSECHILDREN_QueryProperties); childEh.IsValid (); childEh = childEh.ToNext ())
            querySomething (childEh);
        }

    What matters in terms of stack usage is nest depth. It would be the rare user defined cell that is nested even 10 deep. Feature Solids, one of the more deeply nested constructs don't often exceed a depth of 100.

    Don't declare any variables in the recurive function itself, call into another function to do any testing/modification of the current element. Stack for variables declared in the helper function are reclaimed when the function exits and isn't attributed to the recursion.

    This is effectively how mdlElmdscr_operation works, someone has to do the recursion...it's not doing anything you can't...

    -B



Children
  • That's the way I implemented it on Wednesday. :-)

    As I currently have an elementdescriptor from which the ElemHandle was build, there is no additional overhead, but I will check if I can get the caller changed, so it doesn't need to build the eh from an edp.

    I reduced the stack usage previously, but in opposite to all my other 'manual' traversals, the main problem was, that the -> next members even leads to a recursive call. Instead of changing it to the same (old) schema used elsewhere, I currently try to change to 'recommended' workflow, whereever I need to touch code.

    The only thing that is not described, is the meaning and influence of the  EXPOSECHILDREN_ enums. As far as I understood , the _findText and _editText variant do not return anything else than text components and are not valid if you like to 'dive' into the hierarchy of an nested cell (I almost have nested ones). But I think this could be a good subject for a blog entry.