Skip to main content
Inspiring
April 6, 2009
Answered

Undoing Paragraph Formatting

  • April 6, 2009
  • 2 replies
  • 1769 views

I may just be missing something simple here, but I'm not having any luck undoing (via FlowOperation.undo()) any paragraph formatting. This is using the TLF that comes with Flex SDK 4.0.0.5489.

I'm applying all my FlowOperations via the EditManager, for example using editManager.applyLeafFormat() to apply bold/italic/fonts etc, and calling undo() on these works fine.

However when I use applyFormat/applyFormatToElement() and specify not a leaf format, but a paragraph format (for example when applying a leftMargin to a ParagraphElement), I get a FlowOperationEvent dispatched, and an addition to the UndoManager's stack, but calling undo() has no effect on the TextFlow leaving me with the modified paragraph(s) but no way to undo.

Does anyone know why these Paragraph formatting operations would be one-way only?

I'm also thinking this could be something to do with the SelectionState, it's not very clear how/why you need to specify a SelectionState when calling applyFormatToElement() given you are providing the Element you would like to apply it to. Can anyone describe the role of the SelectionState in this case and perhaps whether this could be affecting the undo?

Just to provide some extra info, I am generally applying my ParagraphFormat-ing via CompositeOperations and I'm using a combination of element.getAbsoluteStart() and element.textLength to get my SelectionState when applying paragraph formats to certain elements that are *not* the current selectionState as defined by the EditManager.

This topic has been closed for replies.
Correct answer Abhi.G.

There is a bug in ApplyFormatToElementOperation which causes its undo state (the format it needs to restore to the target element on undo) to be overwritten by the format being applied. I have logged this bug.

For now, you could instead use ApplyFormatOperation which does not suffer from this bug.

Replace

compositeOp.addOperation( new ApplyFormatToElementOperation(getSelectionStateForElement(paragraph), paragraph, format) );

with

var op:ApplyFormatOperation = new ApplyFormatOperation (getSelectionStateForElement(paragraph), null /* leaf format */, format);

op.absoluteStart = op.absoluteEnd = paragraph.getAbsoluteStart();

compositeOp.addOperation(op);

- Abhishek

Adobe Systems Inc.

2 replies

Abhi.G.Correct answer
Participating Frequently
April 10, 2009

There is a bug in ApplyFormatToElementOperation which causes its undo state (the format it needs to restore to the target element on undo) to be overwritten by the format being applied. I have logged this bug.

For now, you could instead use ApplyFormatOperation which does not suffer from this bug.

Replace

compositeOp.addOperation( new ApplyFormatToElementOperation(getSelectionStateForElement(paragraph), paragraph, format) );

with

var op:ApplyFormatOperation = new ApplyFormatOperation (getSelectionStateForElement(paragraph), null /* leaf format */, format);

op.absoluteStart = op.absoluteEnd = paragraph.getAbsoluteStart();

compositeOp.addOperation(op);

- Abhishek

Adobe Systems Inc.

Inspiring
April 10, 2009

Thanks to both of you for your support. That did the trick! I'll try to revert it when a later build comes out, sticking a TODO for now.

I just want to add for those experiencing the same problem but for container formats, the same kind of solution works (e.g. use editManager.applyFormat(null, null, format, getSelectionStateForElement(editManager.textFlow)); for now).

Cheers,

Richard

Adobe Employee
April 7, 2009

If you are interpersing operations through the EditManager with direct calls to change the TextFlow, undo is disabled. This is because in order to undo we need to depend on the state of the TextFlow being the same as it was when the operation was originally completed. A textFlow has a generation number. The generation number it has after the operation is completed needs to match the number it has when the operation is undone. If you check and find that these are not matching, this explains your problem. The easiest solution if this is your problem is to find an operation that does what you are currently doing through direct calls on the FlowElements, and use that instead. Then that operation will be undone first, causing the generation number to roll back, and your susequent undo of the paragraph format should work as well. Can you check and see if this is what is causing you problem?

Thanks!

- robin

Inspiring
April 8, 2009

Hi Robin,

Thanks for your help on this... OK in my code I'm not using any direct calls to change the TextFlow so hopefully undo doesn't get disabled, I'm either using:

  EditManager.applyXXXXFormat(format...);

...or where I'm modifying several elements, e.g. "align the selected paragraphs"...

  EditManager.doOperation(aCompositeOperation);


I'm listening to FLOW_OPERATION_END and storing a reference to the operation that has been performed so that I can later undo it. This is either a format operation or a composite operation depending on what was done. In each case the "generation" increases by 1 after each operation as expected.

I've tried performing the undo via:

  1. EditManger.undo();

  2. theOperation.undo();   (followed by an updateAllContainers())

For method 1, I see another FLOW_OPERATION_END event, and the "generation" decreases by 1, returning back to what it was as you describe*.

For method 2 I don't see the complete event, and therefore I'm not sure what generation I'm looking at, but*...

*In both methods 1, and 2 I see no visual change after the undo, the alignment never reverts back to before the original operation.  

If it helps, here are my traces when applying a VerticalAlign.MIDDLE to the TextFlow via applyFormatToElement():

  Generation before: 46

  Calling editManager.applyFormatToElement(editManager.textFlow, format);
  FLOW_OPERATION_END: event.operation = [object ApplyFormatToElementOperation]
  Generation after: 107

  EditManager.undoManager.canUndo() = false
  FLOW_OPERATION_END: event.operation = [object UndoOperation]
  Generation after: 46

  EditManager.undoManager.canUndo() = false

I think the most striking thing here is clearly it says there is no undo available in the UndoManager. So somehow something is disabling it, but there's so little code I can't see where that happens.

I'm not totally sure I understand your advice to try the direct manipulation in order to get the undo working, should I do that as well as the EditManager approach, if so, before or after doing it via EditManager?

Thanks again,

Richard

Inspiring
April 9, 2009

I've just tested this with the weekly 409 build, but no luck I'm afraid.

So instead I've put together a little Flex project to illustrate the problem, hopefully this is boiled down enough to provide some insight, just the one class file:

http://richardleggett.co.uk/misc/TLFTest.zip


This is an AIR 1.5.1 project set to use the "Default Flex SDK", which for me was 4.0.0.5489, and I've replaced the textLayout.swc in that SDK with the latest 409 build.

If I've simply gone about something the wrong way that'd be great, but thanks anyway for taking the time to look.

Thanks,

Richard