001 /*--------------------------------------------------------------------------+
002 $Id: StringUndoStackBase.java 26283 2010-02-18 11:18:57Z juergens $
003 | |
004 | Copyright 2005-2010 Technische Universitaet Muenchen |
005 | |
006 | Licensed under the Apache License, Version 2.0 (the "License"); |
007 | you may not use this file except in compliance with the License. |
008 | You may obtain a copy of the License at |
009 | |
010 | http://www.apache.org/licenses/LICENSE-2.0 |
011 | |
012 | Unless required by applicable law or agreed to in writing, software |
013 | distributed under the License is distributed on an "AS IS" BASIS, |
014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015 | See the License for the specific language governing permissions and |
016 | limitations under the License. |
017 +--------------------------------------------------------------------------*/
018 package edu.tum.cs.commons.string;
019
020 import java.util.ArrayList;
021 import java.util.List;
022
023 import edu.tum.cs.commons.algo.Diff;
024 import edu.tum.cs.commons.algo.Diff.Delta;
025 import edu.tum.cs.commons.assertion.CCSMPre;
026
027 /**
028 * Base class for an undo stack using a string as the underlying model.
029 *
030 * Please refer to the test case for a demonstration and further explanation of
031 * this class.
032 *
033 * @author hummelb
034 * @author $Author: juergens $
035 * @version $Rev: 26283 $
036 * @levd.rating GREEN Hash: 6C0282A04515FF5028992B67673ED9DD
037 */
038 public abstract class StringUndoStackBase {
039
040 /** The stack of versions. */
041 private final List<Delta<String>> deltas = new ArrayList<Delta<String>>();
042
043 /** The current string. */
044 private String currentVersion;
045
046 /** The index of the currently used version/delta. */
047 private int currentVersionIndex = -1;
048
049 /** The last position used for saving. */
050 private int savePosition = -1;
051
052 /** Constructor. */
053 protected StringUndoStackBase(String initialString) {
054 currentVersion = initialString;
055 }
056
057 /** Returns whether undo is possible. */
058 public boolean canUndo() {
059 return currentVersionIndex >= 0;
060 }
061
062 /** Performs one undo step. */
063 public void undo() {
064 CCSMPre.isTrue(canUndo(), "Must be allowed to undo!");
065 currentVersion = join(deltas.get(currentVersionIndex--).backwardPatch(
066 split(currentVersion)));
067 setModelFromString(currentVersion);
068 fireStackChanged();
069 }
070
071 /** Returns whether redo is possible. */
072 public boolean canRedo() {
073 return currentVersionIndex + 1 < deltas.size();
074 }
075
076 /** Performs one redo step. */
077 public void redo() {
078 CCSMPre.isTrue(canRedo(), "Must be allowed to redo!");
079 currentVersion = join(deltas.get(++currentVersionIndex).forwardPatch(
080 split(currentVersion)));
081 setModelFromString(currentVersion);
082 fireStackChanged();
083 }
084
085 /** Returns whether something changed compared to the last safe. */
086 public boolean isDirty() {
087 return currentVersionIndex != savePosition;
088 }
089
090 /** Mark the current position as saved (affects dirty calculation). */
091 public void doSave() {
092 savePosition = currentVersionIndex;
093 }
094
095 /** Inserts a new version of the model (as a string) into this stack. */
096 protected void insertNewVersion(String s) {
097 ++currentVersionIndex;
098 if (savePosition >= currentVersionIndex) {
099 savePosition = -1;
100 }
101
102 // discard later versions/deltas
103 while (deltas.size() > currentVersionIndex) {
104 deltas.remove(deltas.size() - 1);
105 }
106
107 deltas.add(Diff.computeDelta(split(currentVersion), split(s)));
108 currentVersion = s;
109 fireStackChanged();
110 }
111
112 /**
113 * Splits the given string (as reported from the implementing class) into
114 * suitable parts used for diffing (lines, words, tokens, etc.).
115 */
116 protected abstract List<String> split(String s);
117
118 /** Joins the parts created by {@link #split(String)}. */
119 protected abstract String join(List<String> parts);
120
121 /**
122 * This should write back the stack content to the model. This is called for
123 * every undo and redo operation.
124 */
125 protected abstract void setModelFromString(String s);
126
127 /** Something about this stack has changed. */
128 protected abstract void fireStackChanged();
129
130 /** Prints the amount of memory currently used by this stack. */
131 protected int debugGetSize() {
132 int size = 2 * currentVersion.length();
133 for (Delta<String> delta : deltas) {
134 for (int i = 0; i < delta.getSize(); ++i) {
135 size += 4 + 2 * delta.getT(i).length();
136 }
137 }
138 return 2 * size;
139 }
140 }