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;
32
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import palmed.edit.selection.SelectionDeletion;
37 import palmed.edit.selection.Cut;
38 import palmed.edit.selection.CharacterDeletion;
39 import palmed.edit.selection.NewLineInsertion;
40 import palmed.edit.selection.IAction;
41 import palmed.edit.selection.ILineVisitor;
42 import palmed.edit.selection.ISelection;
43 import palmed.edit.selection.ISelectionView;
44 import palmed.edit.selection.Paste;
45 import palmed.edit.selection.Selection;
46 import palmed.edit.selection.CharacterInsertion;
47 import palmed.edit.selection.SelectionReplacement;
48 import palmed.edit.selection.UndoManager;
49 import palmed.edit.text.IText;
50 import palmed.edit.util.Coordinate;
51 import palmed.edit.view.IContent;
52 import palmed.edit.view.IView;
53
54 /***
55 * This class encapsulates text and selection manipulations.
56 *
57 * @author Mathieu Champlon
58 * @version $Revision$ $Date$
59 */
60 public final class Content implements IContent, ISelectionView
61 {
62 /***
63 * The code of the first valid characters.
64 */
65 private static final int FIRST_VALID_CHARACTER = 32;
66 /***
67 * the code of the last valid character.
68 */
69 private static final int LAST_VALID_CHARACTER = 0xFF;
70 /***
71 * The maximum number of actions to keep for undo.
72 */
73 private static final int UNDO_STACK_SIZE = 10;
74 /***
75 * The text.
76 */
77 private final IText text_;
78 /***
79 * The selection manager.
80 */
81 private final ISelection selection_;
82 /***
83 * The undo manager.
84 */
85 private final UndoManager manager_;
86 /***
87 * The current insertion point.
88 */
89 private Coordinate insertion_;
90
91 /***
92 * Create a content.
93 *
94 * @param text the text
95 */
96 public Content( final IText text )
97 {
98 if( text == null )
99 throw new IllegalArgumentException( "parameter 'text' is null" );
100 text_ = text;
101 selection_ = new Selection( text );
102 selection_.register( this );
103 manager_ = new UndoManager( UNDO_STACK_SIZE );
104 }
105
106 /***
107 * {@inheritDoc}
108 */
109 public void type( final int keyCode )
110 {
111 if( isValid( keyCode ) )
112 {
113 if( selection_.isEmpty() )
114 execute( new CharacterInsertion( selection_, text_, (char)keyCode, insertion_ ) );
115 else
116 execute( new SelectionReplacement( selection_, text_, (char)keyCode, insertion_ ) );
117 }
118 }
119
120 private boolean isValid( final int keyCode )
121 {
122 return keyCode >= FIRST_VALID_CHARACTER && keyCode <= LAST_VALID_CHARACTER;
123 }
124
125 /***
126 * {@inheritDoc}
127 */
128 public void enter()
129 {
130 execute( new NewLineInsertion( selection_, text_, insertion_ ) );
131 }
132
133 /***
134 * {@inheritDoc}
135 */
136 public void backspace()
137 {
138 if( selection_.isEmpty() )
139 execute( new CharacterDeletion( selection_ ) );
140 else
141 execute( new SelectionDeletion( selection_ ) );
142 }
143
144 /***
145 * {@inheritDoc}
146 */
147 public void drag( final int x, final int y )
148 {
149 selection_.extend( x, y );
150 manager_.skip();
151 }
152
153 /***
154 * {@inheritDoc}
155 */
156 public void click( final int x, final int y )
157 {
158 selection_.extend( x, y );
159 selection_.clear();
160 manager_.skip();
161 }
162
163 /***
164 * {@inheritDoc}
165 */
166 public void accept( final ILineVisitor visitor, final int y )
167 {
168 selection_.accept( visitor, y );
169 }
170
171 /***
172 * {@inheritDoc}
173 */
174 public void register( final IView view )
175 {
176 text_.register( view );
177 selection_.register( view );
178 }
179
180 /***
181 * {@inheritDoc}
182 */
183 public void marshall( final OutputStream stream ) throws IOException
184 {
185 selection_.marshall( stream );
186 text_.marshall( stream );
187 manager_.marshall( stream );
188 }
189
190 /***
191 * {@inheritDoc}
192 */
193 public void unmarshall( final InputStream stream ) throws IOException
194 {
195 selection_.unmarshall( stream );
196 text_.unmarshall( stream );
197 manager_.unmarshall( stream );
198 }
199
200 /***
201 * {@inheritDoc}
202 */
203 public void clear()
204 {
205 selection_.reset();
206 text_.clear();
207 manager_.clear();
208 }
209
210 /***
211 * {@inheritDoc}
212 */
213 public void update( final Coordinate position )
214 {
215 insertion_ = position;
216 }
217
218 /***
219 * {@inheritDoc}
220 */
221 public void copy( final OutputStream stream ) throws IOException
222 {
223 selection_.copy( stream );
224 }
225
226 /***
227 * {@inheritDoc}
228 */
229 public void cut( final OutputStream stream )
230 {
231 if( !selection_.isEmpty() )
232 execute( new Cut( selection_, stream ) );
233 }
234
235 /***
236 * {@inheritDoc}
237 */
238 public void paste( final InputStream stream )
239 {
240 execute( new Paste( selection_, stream ) );
241 }
242
243 private void execute( final IAction action )
244 {
245 action.perform();
246 manager_.add( action );
247 }
248
249 /***
250 * {@inheritDoc}
251 */
252 public void undo()
253 {
254 manager_.undo();
255 }
256
257 /***
258 * {@inheritDoc}
259 */
260 public void redo()
261 {
262 manager_.redo();
263 }
264 }