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 }