Author: rwhitcomb Date: Wed Jan 24 18:46:49 2018 New Revision: 1822149 URL: http://svn.apache.org/viewvc?rev=1822149&view=rev Log: PIVOT-1021: Complete rearrangement of how undo in TextPane works: * Save the removed characters all the time for undo purposes. * Use the TextPane.insert() method to undo a delete. * Reset the selection position after "undo". * Change what is saved during undo to basically be the characters and not the nodes themselves -- too much hassle to make that work. * Also add an accessor method to set the flag saying whether or not to save undo history. This is necessary so that node rearrangement that doesn't change the text won't have to get saved for undo.
Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/TextPane.java pivot/trunk/wtk/src/org/apache/pivot/wtk/text/Element.java pivot/trunk/wtk/src/org/apache/pivot/wtk/text/TextNode.java Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/TextPane.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/TextPane.java?rev=1822149&r1=1822148&r2=1822149&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/TextPane.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/TextPane.java Wed Jan 24 18:46:49 2018 @@ -44,6 +44,7 @@ import org.apache.pivot.wtk.text.NodeLis import org.apache.pivot.wtk.text.Paragraph; import org.apache.pivot.wtk.text.PlainTextSerializer; import org.apache.pivot.wtk.text.TextNode; +import org.apache.pivot.wtk.text.TextSpan; /** * Component that allows a user to enter and edit multiple lines of (optionally @@ -116,75 +117,42 @@ public class TextPane extends Container public void undo(); } - private static class NodesRemovedEdit implements Edit { - private final Node node; - private final int offset; - private final Sequence<Node> removed; - - public NodesRemovedEdit(Node node, Sequence<Node> removed, int offset) { - this.node = node; - this.offset = offset; - this.removed = removed; - } - - @Override - public void undo() { - int currentOffset = this.offset; - for (int i = 0; i < removed.getLength(); i++) { - Node removedNode = removed.get(i); - node.insertRange(removedNode, currentOffset); - currentOffset += removedNode.getCharacterCount(); - } - } - } - - private class RangeRemovedEdit implements Edit { + private class TextInsertedEdit implements Edit { private final Node node; private final int offset; private final int characterCount; - private final CharSequence removedChars; - public RangeRemovedEdit(Node node, int offset, int characterCount, CharSequence removedChars) { + public TextInsertedEdit(Node node, int offset, int characterCount) { this.node = node; this.offset = offset; this.characterCount = characterCount; - this.removedChars = removedChars; } @Override public void undo() { - if (!(node instanceof TextNode)) { - // TODO: can we / should we handle this? - throw new IllegalArgumentException("Undo of removed characters must be to a TextNode."); - } - TextNode textNode = (TextNode)node; - textNode.insertText(removedChars, offset - textNode.getDocumentOffset()); + node.removeRange(offset, characterCount); + setSelection(offset, 0); } } - private class RangeInsertedEdit implements Edit { + private class TextRemovedEdit implements Edit { private final Node node; private final int offset; - private final int characterCount; + private final CharSequence removedChars; - public RangeInsertedEdit(Node node, int offset, int characterCount) { + public TextRemovedEdit(Node node, int offset, CharSequence removedChars) { this.node = node; this.offset = offset; - this.characterCount = characterCount; + this.removedChars = removedChars; } @Override public void undo() { - node.removeRange(offset, characterCount); - int newSelectionStart = selectionStart; - int newSelectionLength = selectionLength; - if (newSelectionStart >= document.getCharacterCount()) { - newSelectionStart = document.getCharacterCount() - 1; - } - if (newSelectionStart + newSelectionLength > document.getCharacterCount()) { - newSelectionLength = document.getCharacterCount() - newSelectionStart; + if (offset != selectionStart) { + setSelection(offset, 0); } - setSelection(newSelectionStart, newSelectionLength); + insert(removedChars.toString()); + setSelection(offset + removedChars.length(), 0); } } @@ -224,7 +192,7 @@ public class TextPane extends Container } if (!undoingHistory) { - editHistory.push(new RangeInsertedEdit(node, offset, characterCount)); + editHistory.push(new TextInsertedEdit(node, offset, characterCount)); } if (!bulkOperation) { @@ -245,10 +213,6 @@ public class TextPane extends Container TextPane.super.remove(componentNode.getComponent()); } } - - if (!undoingHistory) { - editHistory.push(new NodesRemovedEdit(node, removed, offset)); - } } /** @@ -286,7 +250,7 @@ public class TextPane extends Container } if (!undoingHistory && removedChars != null) { - editHistory.push(new RangeRemovedEdit(node, offset, characterCount, removedChars)); + editHistory.push(new TextRemovedEdit(node, offset, removedChars)); } if (!bulkOperation) { @@ -388,6 +352,16 @@ public class TextPane extends Container } } + /** + * Some document rearrangements might not be suitable for undoing, + * so allow users to specify when to do so. + * + * @param save Whether or not to save history at this time. + */ + public void setSaveHistory(boolean save) { + this.undoingHistory = !save; + } + private Node getRightmostDescendant(Element element) { int n = element.getLength(); if (n > 0) { Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/Element.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/Element.java?rev=1822149&r1=1822148&r2=1822149&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/Element.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/Element.java Wed Jan 24 18:46:49 2018 @@ -370,6 +370,7 @@ public abstract class Element extends No // Remove the nodes Sequence<Node> removed = nodes.remove(index, count); count = removed.getLength(); + StringBuilder removedChars = new StringBuilder(); if (count > 0) { int removedCharacterCount = 0; @@ -377,6 +378,11 @@ public abstract class Element extends No Node node = removed.get(i); node.setParent(null); removedCharacterCount += node.getCharacterCount(); + if (node instanceof Element) { + removedChars.append(((Element)node).getText()); + } else if (node instanceof TextNode) { + removedChars.append(((TextNode)node).getText()); + } } // Update the character count @@ -399,7 +405,7 @@ public abstract class Element extends No } // Notify parent - super.rangeRemoved(this, offset, removedCharacterCount, null); + super.rangeRemoved(this, offset, removedCharacterCount, removedChars); super.nodesRemoved(this, removed, offset); // Fire event Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/text/TextNode.java URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/text/TextNode.java?rev=1822149&r1=1822148&r2=1822149&view=diff ============================================================================== --- pivot/trunk/wtk/src/org/apache/pivot/wtk/text/TextNode.java (original) +++ pivot/trunk/wtk/src/org/apache/pivot/wtk/text/TextNode.java Wed Jan 24 18:46:49 2018 @@ -129,7 +129,8 @@ public final class TextNode extends Node @Override public void insertRange(Node range, int offset) { if (!(range instanceof TextNode)) { - throw new IllegalArgumentException("range is not a text node."); + throw new IllegalArgumentException("Range node (" + + range.getClass().getSimpleName() + ") is not a text node."); } TextNode textNode = (TextNode) range;