Skip to main content
June 27, 2011
Question

Managing undo operations across components

  • June 27, 2011
  • 1 reply
  • 1366 views

Hi,

I've been able to share an IUndoManager between various RichEditableText components using the interactionManager property of their text flows and the EditManager class. This works great for undoing and redoing -- except when a component is removed from the display list.

When a text field is re-added something odd seems to happen to its text flow generation property, which causes a mismatch when compared in the EditManager, thereby preventing the next operation to undo or redo.

Are operations being applied to the text flow simply by removing and re-adding it to the display list? Or what's affecting this count?

The failure is repeatable, and in each case the text flow's generation value is greater than the operation's endGeneration (in performUndo()) or beginGeneration (in performRedo()).

What can be done to freeze the text flow or its generation value, or is there a better way of keeping the EditManager operation validation happy?

Many thanks,

Waj

Flex 4.5.20967

This topic has been closed for replies.

1 reply

Adobe Employee
June 29, 2011

Can you provide your sample code? We need to debug to find what's happening, because spark.component.RichEditableText that is based on TLF is not a class in TLF but in Flex.

June 29, 2011

Sure, I just put together this simplified example, which comes in two parts.

Main application:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
               creationComplete="creationCompleteHandler(event)">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
   
    <fx:Script>
        <![CDATA[
            import flashx.undo.UndoManager;
            import mx.events.FlexEvent;

            protected var _textComp:TextComp;
           
            [Bindable]
            protected var _textOnDisplayList:Boolean = false;
           
            [Bindable]
            protected var _undoManager:UndoManager = new UndoManager();
           
            protected function creationCompleteHandler(event:FlexEvent):void
            {
                _textComp = new TextComp();
                _textComp.init(_undoManager);
                addText();
            }
           
            protected function addText():void
            {
                box.addElement(_textComp);
                _textOnDisplayList = true;
            }
           
            protected function removeText():void
            {
                if (box.contains(_textComp))
                    box.removeElement(_textComp);
                _textOnDisplayList = false;
            }
        ]]>
    </fx:Script>

    <s:Label text="Type some things (using flow operations such as insert, delete, cut & paste etc.), remove text from display, re-add it then try to undo or redo.{'\n'}This fails because of a mismatch in EditManager (line 923 or 1018 for undo or redo, respectively)." paddingTop="10" paddingLeft="10"/>
    <s:HGroup width="100%" paddingLeft="10">
        <s:Button label="Remove from display" click="removeText()" enabled="{_textOnDisplayList}"/>
        <s:Button label="Add to display" click="addText()" enabled="{!_textOnDisplayList}"/>
        <s:Button label="Undo" click="_undoManager.undo()"/>
        <s:Button label="Redo" click="_undoManager.redo()"/>
    </s:HGroup>
    <s:HGroup id="box" paddingLeft="10"/>
   
</s:Application>

Component:

<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
                   xmlns:s="library://ns.adobe.com/flex/spark"
                   xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
   
    <fx:Script>
        <![CDATA[
            import flashx.textLayout.edit.EditManager;
            import flashx.textLayout.elements.TextFlow;
            import flashx.undo.IUndoManager;
           
            [Bindable]
            /** Main text flow. */
            protected var _text:TextFlow;
           
            public function init(undoManager:IUndoManager):void
            {
                _text = new TextFlow();
                _text.interactionManager = new EditManager(undoManager);
            }

        ]]>
    </fx:Script>
   
    <s:RichEditableText id="textBox" editable="true" width="100%" height="100%" textFlow="{_text}"/>
   
</s:BorderContainer>

I'm not sure if the problem lies with the RichEditableText component but I hope this helps.

Thanks

Participating Frequently
June 30, 2011

Hi:

We studied your case. The operation num/count will increase when the container re-attached to the box. That's work as design. Seems you can only work around it. The following is my workaround for your special case. Hope it will be helpful:

Main application:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"

   creationComplete="creationCompleteHandler(event)">

<s:layout>

<s:VerticalLayout/>

</s:layout>

<fx:Script>

<![CDATA[

import flashx.undo.UndoManager;

import mx.events.FlexEvent;

protected var _textComp:TextComp;

[Bindable]

protected var _textOnDisplayList:Boolean = false;

[Bindable]

protected var _undoManager:UndoManager = new UndoManager();

protected function creationCompleteHandler(event:FlexEvent):void

{

_textComp = new TextComp();

_textComp.init(_undoManager);

addText();

}

protected function addText():void

{

_textComp.handleAddon();

box.addElement(_textComp);

_textOnDisplayList = true;

}

protected function removeText():void

{

if (box.contains(_textComp))

box.removeElement(_textComp);

_textOnDisplayList = false;

}

]]>

</fx:Script>

<s:Label text="Type some things (using flow operations such as insert, delete, cut & paste etc.), remove text from display, re-add it then try to undo or redo.{'\n'}This fails because of a mismatch in EditManager (line 923 or 1018 for undo or redo, respectively)." paddingTop="10" paddingLeft="10"/>

<s:HGroup width="100%" paddingLeft="10">

<s:Button label="Remove from display" click="removeText()" enabled="{_textOnDisplayList}"/>

<s:Button label="Add to display" click="addText()" enabled="{!_textOnDisplayList}"/>

<s:Button label="Undo" click="_undoManager.undo()"/>

<s:Button label="Redo" click="_undoManager.redo()"/>

</s:HGroup>

<s:HGroup id="box" paddingLeft="10"/>

</s:Application>

Component:
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Script>
<![CDATA[
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.events.DamageEvent;
import flashx.textLayout.tlf_internal;
import flashx.undo.IUndoManager;
use namespace tlf_internal;
[Bindable]
/** Main text flow. */
protected var _text:TextFlow;
public function init(undoManager:IUndoManager):void
{
_text = new TextFlow();
_text.interactionManager = new EditManager(undoManager);
}
public function handleAddon():void
{
_text.addEventListener(DamageEvent.DAMAGE, damageHandler);
}
private function damageHandler(event:DamageEvent):void
{
_text.setGeneration(_text.generation - 1);
_text.removeEventListener(DamageEvent.DAMAGE, damageHandler);
}
]]>
</fx:Script>
<s:RichEditableText id="textBox" editable="true" width="100%" height="100%" textFlow="{_text}"/>
</s:BorderContainer>