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.DataInputStream;
34 import java.io.DataOutputStream;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.util.Enumeration;
39 import java.util.Vector;
40 import palmed.edit.text.IText;
41 import palmed.edit.util.Coordinate;
42
43 /***
44 * This class manages the text selection.
45 *
46 * @author Mathieu Champlon
47 * @version $Revision$ $Date$
48 */
49 public final class Selection implements ISelection
50 {
51 /***
52 * The text.
53 */
54 private final IText text_;
55 /***
56 * The current selection start.
57 */
58 private final Coordinate from_;
59 /***
60 * The current selection end.
61 */
62 private final Coordinate to_;
63 /***
64 * The current ordered selection start.
65 */
66 private Coordinate start_;
67 /***
68 * The current ordered selection end.
69 */
70 private Coordinate end_;
71 /***
72 * The views.
73 */
74 private final Vector views_;
75
76 /***
77 * Create a selection.
78 *
79 * @param text the text
80 */
81 public Selection( final IText text )
82 {
83 if( text == null )
84 throw new IllegalArgumentException( "parameter 'text' is null" );
85 text_ = text;
86 from_ = new Coordinate();
87 to_ = new Coordinate();
88 start_ = from_;
89 end_ = to_;
90 views_ = new Vector();
91 }
92
93 /***
94 * {@inheritDoc}
95 */
96 public boolean isEmpty()
97 {
98 return from_.equals( to_ );
99 }
100
101 /***
102 * {@inheritDoc}
103 */
104 public void forward()
105 {
106 final String line = text_.getLine( to_.y_ );
107 if( line != null && to_.x_ < line.length() )
108 {
109 to_.x_++;
110 reorder();
111 }
112 else if( to_.y_ < text_.getHeight() - 1 )
113 {
114 to_.x_ = 0;
115 to_.y_++;
116 reorder();
117 }
118 }
119
120 /***
121 * {@inheritDoc}
122 */
123 public void backward()
124 {
125 if( to_.x_ > 0 )
126 {
127 to_.x_--;
128 reorder();
129 }
130 else if( to_.y_ > 0 )
131 {
132 to_.y_--;
133 to_.x_ = text_.getLine( to_.y_ ).length();
134 reorder();
135 }
136 }
137
138 private void reorder()
139 {
140 if( from_.lessThan( to_ ) )
141 {
142 start_ = from_;
143 end_ = to_;
144 }
145 else
146 {
147 start_ = to_;
148 end_ = from_;
149 }
150 notify( to_ );
151 }
152
153 /***
154 * {@inheritDoc}
155 */
156 public void extend( final int x, final int y )
157 {
158 to_.y_ = Math.max( 0, Math.min( text_.getHeight() - 1, y ) );
159 to_.x_ = Math.max( 0, Math.min( text_.getLine( to_.y_ ).length(), x ) );
160 reorder();
161 }
162
163 /***
164 * {@inheritDoc}
165 */
166 public void clear()
167 {
168 from_.x_ = to_.x_;
169 from_.y_ = to_.y_;
170 notify( to_ );
171 }
172
173 /***
174 * {@inheritDoc}
175 */
176 public void delete()
177 {
178 if( !start_.equals( end_ ) )
179 {
180 text_.remove( start_, end_ );
181 end_.x_ = start_.x_;
182 end_.y_ = start_.y_;
183 clear();
184 }
185 }
186
187 /***
188 * {@inheritDoc}
189 */
190 public void accept( final ILineVisitor visitor, final int y )
191 {
192 final String line = text_.getLine( y );
193 if( line != null )
194 visitor.visit( line, getStart( y ), getEnd( y ), y >= start_.y_ && y < end_.y_ );
195 }
196
197 private int getStart( final int y )
198 {
199 if( start_.y_ == y )
200 return start_.x_;
201 return 0;
202 }
203
204 private int getEnd( final int y )
205 {
206 if( y >= start_.y_ && y < end_.y_ )
207 return text_.getLine( y ).length();
208 if( end_.y_ == y )
209 return end_.x_;
210 return 0;
211 }
212
213 /***
214 * {@inheritDoc}
215 */
216 public void unmarshall( final InputStream stream ) throws IOException
217 {
218 from_.unmarshall( stream );
219 to_.unmarshall( stream );
220 reorder();
221 }
222
223 /***
224 * {@inheritDoc}
225 */
226 public void marshall( final OutputStream stream ) throws IOException
227 {
228 from_.marshall( stream );
229 to_.marshall( stream );
230 }
231
232 /***
233 * {@inheritDoc}
234 */
235 public void reset()
236 {
237 from_.x_ = 0;
238 from_.y_ = 0;
239 to_.x_ = 0;
240 to_.y_ = 0;
241 notify( to_ );
242 }
243
244 /***
245 * {@inheritDoc}
246 */
247 public void register( final ISelectionView view )
248 {
249 view.update( to_ );
250 views_.addElement( view );
251 }
252
253 private void notify( final Coordinate position )
254 {
255 final Enumeration e = views_.elements();
256 while( e.hasMoreElements() )
257 ((ISelectionView)e.nextElement()).update( position );
258 }
259
260 /***
261 * {@inheritDoc}
262 */
263 public void copy( final OutputStream stream ) throws IOException
264 {
265 final DataOutputStream output = new DataOutputStream( stream );
266 output.writeInt( start_.x_ );
267 output.writeInt( start_.y_ );
268 output.writeInt( end_.x_ );
269 output.writeInt( end_.y_ );
270 text_.write( stream, start_, end_ );
271 }
272
273 /***
274 * {@inheritDoc}
275 */
276 public void cut( final OutputStream stream ) throws IOException
277 {
278 copy( stream );
279 delete();
280 }
281
282 /***
283 * {@inheritDoc}
284 */
285 public void paste( final InputStream stream ) throws IOException
286 {
287 final DataInputStream input = new DataInputStream( stream );
288 final int startX = input.readInt();
289 final int startY = input.readInt();
290 final int endX = input.readInt();
291 final int endY = input.readInt();
292 delete();
293 text_.read( stream, from_ );
294 if( startY == endY )
295 to_.x_ += endX - startX;
296 else
297 {
298 to_.x_ = endX;
299 to_.y_ += endY - startY;
300 }
301 reorder();
302 }
303
304 /***
305 * {@inheritDoc}
306 */
307 public void read( final InputStream stream ) throws IOException
308 {
309 delete();
310 text_.read( stream, from_ );
311 }
312
313 /***
314 * {@inheritDoc}
315 */
316 public void write( final OutputStream stream ) throws IOException
317 {
318 text_.write( stream, start_, end_ );
319 }
320 }