1 /***
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions are
4 * met :
5 *
6 * . Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 *
9 * . Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * . The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $Id$
29 */
30
31 package palmed.edit.selection;
32
33 import java.io.ByteArrayInputStream;
34 import java.io.ByteArrayOutputStream;
35 import java.io.IOException;
36 import palmed.util.ChainedException;
37
38 /***
39 * This class factorizes behaviours common to all actions.
40 *
41 * @author Mathieu Champlon
42 * @version $Revision$ $Date$
43 */
44 public abstract class AbstractAction implements IAction
45 {
46 /***
47 * The selection.
48 */
49 private final ISelection selection_;
50 /***
51 * A backup of the initial selection state.
52 */
53 private byte[] initial_;
54 /***
55 * A backup of the final selection state.
56 */
57 private byte[] final_;
58 /***
59 * A backup of the removed data.
60 */
61 private byte[] data_;
62
63 /***
64 * Create an abstract action.
65 *
66 * @param selection the selection
67 */
68 protected AbstractAction( final ISelection selection )
69 {
70 if( selection == null )
71 throw new IllegalArgumentException( "parameter 'selection' is null" );
72 selection_ = selection;
73 }
74
75 /***
76 * {@inheritDoc}
77 */
78 public final void perform()
79 {
80 initial_ = backupState();
81 onPerform();
82 final_ = backupState();
83 }
84
85 /***
86 * {@inheritDoc}
87 */
88 public final void undo()
89 {
90 restoreState( final_ );
91 if( onUndo() )
92 restoreState( initial_ );
93 }
94
95 /***
96 * {@inheritDoc}
97 */
98 public final void redo()
99 {
100 restoreState( initial_ );
101 if( onRedo() )
102 restoreState( final_ );
103 }
104
105 /***
106 * Perform the action.
107 */
108 protected abstract void onPerform();
109
110 /***
111 * Undo the action.
112 *
113 * @return Whether the initial state must be restored or not
114 */
115 protected abstract boolean onUndo();
116
117 /***
118 * Redo the action.
119 *
120 * @return Whether the final state must be restored or not
121 */
122 protected abstract boolean onRedo();
123
124 /***
125 * Overwrite the current final state with the one of another action.
126 *
127 * @param action the action
128 */
129 protected final void overwriteFinalState( final AbstractAction action )
130 {
131 final_ = action.final_;
132 }
133
134 /***
135 * Prepend the current backup data with the data from another action.
136 *
137 * @param action the action
138 */
139 protected final void prependData( final AbstractAction action )
140 {
141 final byte[] data = new byte[data_.length + action.data_.length];
142 System.arraycopy( action.data_, 0, data, 0, action.data_.length );
143 System.arraycopy( data_, 0, data, action.data_.length, data_.length );
144 data_ = data;
145 }
146
147 private byte[] backupState()
148 {
149 final ByteArrayOutputStream stream = new ByteArrayOutputStream();
150 try
151 {
152 selection_.marshall( stream );
153 }
154 catch( IOException e )
155 {
156 throw new ChainedException( e );
157 }
158 return stream.toByteArray();
159 }
160
161 private void restoreState( final byte[] state )
162 {
163 try
164 {
165 selection_.unmarshall( new ByteArrayInputStream( state ) );
166 }
167 catch( IOException e )
168 {
169 throw new ChainedException( e );
170 }
171 }
172
173 /***
174 * Backup the selected text.
175 */
176 protected final void backupData()
177 {
178 final ByteArrayOutputStream stream = new ByteArrayOutputStream();
179 try
180 {
181 selection_.write( stream );
182 }
183 catch( IOException e )
184 {
185 throw new ChainedException( e );
186 }
187 data_ = stream.toByteArray();
188 }
189
190 /***
191 * Remove the selected text and restore backup.
192 */
193 protected final void restoreData()
194 {
195 try
196 {
197 selection_.read( new ByteArrayInputStream( data_ ) );
198 }
199 catch( IOException e )
200 {
201 throw new ChainedException( e );
202 }
203 }
204 }