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.view;
32
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.util.Enumeration;
37 import java.util.Vector;
38 import palmed.edit.selection.ILineVisitor;
39 import palmed.edit.util.Coordinate;
40
41 /***
42 * This class implements a viewport on a content.
43 *
44 * @author Mathieu Champlon
45 * @version $Revision$ $Date$
46 */
47 public final class Viewport implements IViewport, IContent, IView
48 {
49 /***
50 * The current upper-left character coordinate.
51 */
52 private final Coordinate scroll_;
53 /***
54 * Visible text size in characters.
55 */
56 private int visibleColumns_, visibleLines_;
57 /***
58 * Current text size in characters.
59 */
60 private int maxColumns_, maxLines_;
61 /***
62 * The current cursor position.
63 */
64 private final Coordinate cursorPosition_;
65 /***
66 * The content.
67 */
68 private final IContent content_;
69 /***
70 * The view.
71 */
72 private IView view_;
73 /***
74 * The scroll views.
75 */
76 private final Vector views_;
77
78 /***
79 * Create a content viewport.
80 *
81 * @param content the content to manage
82 */
83 public Viewport( final IContent content )
84 {
85 if( content == null )
86 throw new IllegalArgumentException( "parameter 'content' is null" );
87 content_ = content;
88 scroll_ = new Coordinate();
89 view_ = new NullView();
90 cursorPosition_ = new Coordinate();
91 views_ = new Vector();
92 content_.register( this );
93 }
94
95 /***
96 * {@inheritDoc}
97 */
98 public void type( final int keyCode )
99 {
100 content_.type( keyCode );
101 showCursor();
102 }
103
104 /***
105 * {@inheritDoc}
106 */
107 public void drag( final int x, final int y )
108 {
109 content_.drag( x + scroll_.x_, y + scroll_.y_ );
110 showCursor();
111 }
112
113 /***
114 * {@inheritDoc}
115 */
116 public void click( final int x, final int y )
117 {
118 content_.click( x + scroll_.x_, y + scroll_.y_ );
119 showCursor();
120 }
121
122 /***
123 * {@inheritDoc}
124 */
125 public void enter()
126 {
127 content_.enter();
128 showCursor();
129 }
130
131 /***
132 * {@inheritDoc}
133 */
134 public void backspace()
135 {
136 content_.backspace();
137 showCursor();
138 }
139
140 /***
141 * {@inheritDoc}
142 */
143 public void accept( final ILineVisitor visitor, final int y )
144 {
145 content_.accept( new TranslatedLineVisitor( visitor, scroll_.x_ ), y + scroll_.y_ );
146 }
147
148 /***
149 * {@inheritDoc}
150 */
151 public void register( final IView view )
152 {
153 if( view == null )
154 throw new IllegalArgumentException( "parameter 'view' is null" );
155 view_ = view;
156 }
157
158 /***
159 * {@inheritDoc}
160 */
161 public void scroll( final int columns, final int lines )
162 {
163 scroll_.x_ += columns;
164 scroll_.y_ += lines;
165 center();
166 }
167
168 /***
169 * {@inheritDoc}
170 */
171 public void update( final Coordinate position )
172 {
173 cursorPosition_.x_ = position.x_;
174 cursorPosition_.y_ = position.y_;
175 view_.update( new Coordinate( cursorPosition_.x_ - scroll_.x_, cursorPosition_.y_ - scroll_.y_ ) );
176 }
177
178 /***
179 * {@inheritDoc}
180 */
181 public void update( final int columns, final int lines )
182 {
183 maxColumns_ = columns;
184 maxLines_ = lines;
185 center();
186 }
187
188 /***
189 * {@inheritDoc}
190 */
191 public void modified( final boolean status )
192 {
193 view_.modified( status );
194 }
195
196 /***
197 * {@inheritDoc}
198 */
199 public void resize( final int columns, final int lines )
200 {
201 visibleColumns_ = columns;
202 visibleLines_ = lines;
203 center();
204 }
205
206 private void center()
207 {
208 scroll_.x_ = Math.max( 0, Math.min( scroll_.x_, maxColumns_ - visibleColumns_ ) );
209 scroll_.y_ = Math.max( 0, Math.min( scroll_.y_, maxLines_ - visibleLines_ ) );
210 view_.update( new Coordinate( cursorPosition_.x_ - scroll_.x_, cursorPosition_.y_ - scroll_.y_ ) );
211 view_.update( maxColumns_, maxLines_ );
212 final Enumeration e = views_.elements();
213 while( e.hasMoreElements() )
214 ((IScrollView)e.nextElement()).scrolled( scroll_ );
215 }
216
217 /***
218 * {@inheritDoc}
219 */
220 public void register( final IScrollView view )
221 {
222 if( view == null )
223 throw new IllegalArgumentException( "parameter 'view' is null" );
224 views_.addElement( view );
225 view.scrolled( scroll_ );
226 }
227
228 /***
229 * {@inheritDoc}
230 */
231 public void unmarshall( final InputStream stream ) throws IOException
232 {
233 scroll_.unmarshall( stream );
234 content_.unmarshall( stream );
235 }
236
237 /***
238 * {@inheritDoc}
239 */
240 public void marshall( final OutputStream stream ) throws IOException
241 {
242 scroll_.marshall( stream );
243 content_.marshall( stream );
244 }
245
246 /***
247 * {@inheritDoc}
248 */
249 public void clear()
250 {
251 content_.clear();
252 }
253
254 private void showCursor()
255 {
256 scroll( nearestColumn( cursorPosition_.x_ - scroll_.x_ ), nearestLine( cursorPosition_.y_ - scroll_.y_ ) );
257 }
258
259 private int nearestLine( final int y )
260 {
261 if( visibleLines_ > 0 )
262 {
263 if( y >= visibleLines_ )
264 return y - visibleLines_ + 1;
265 else if( y < 0 )
266 return y;
267 }
268 return 0;
269 }
270
271 private int nearestColumn( final int x )
272 {
273 if( visibleColumns_ > 0 )
274 {
275 if( x > visibleColumns_ )
276 return x - visibleColumns_;
277 else if( x <= 0 )
278 return x - 1;
279 }
280 return 0;
281 }
282
283 /***
284 * {@inheritDoc}
285 */
286 public void copy( final OutputStream stream ) throws IOException
287 {
288 content_.copy( stream );
289 }
290
291 /***
292 * {@inheritDoc}
293 */
294 public void cut( final OutputStream stream ) throws IOException
295 {
296 content_.cut( stream );
297 showCursor();
298 }
299
300 /***
301 * {@inheritDoc}
302 */
303 public void paste( final InputStream stream ) throws IOException
304 {
305 content_.paste( stream );
306 showCursor();
307 }
308
309 /***
310 * {@inheritDoc}
311 */
312 public void undo()
313 {
314 content_.undo();
315 showCursor();
316 }
317
318 /***
319 * {@inheritDoc}
320 */
321 public void redo()
322 {
323 content_.redo();
324 showCursor();
325 }
326 }