KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > terminalemulator > Sel


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is Terminal Emulator.
16  * The Initial Developer of the Original Software is Sun Microsystems, Inc..
17  * Portions created by Sun Microsystems, Inc. are Copyright (C) 2001.
18  * All Rights Reserved.
19  *
20  * Contributor(s): Ivan Soleimanipour.
21  */

22
23 /*
24  * "Sel.java"
25  * Sel.java 1.22 01/07/26
26  */

27
28 package org.netbeans.lib.terminalemulator;
29
30 import java.awt.*;
31 import java.awt.datatransfer.*;
32
33 /**
34  * Selection expert:
35  * <ul>
36  * <li> Tracks gestures
37  * <li> Retrieves actual selected text
38  * <li> Paints the selection into a given Graphic
39  * </ul>
40  *
41  * The following actions are understood and dealt with:
42  * <dl>
43  * <dt> track()
44  * <dd> in general extends a selection.
45  * It is usually connecetd to a mouse drag event.
46  * <dt> track()
47  * <dd> will initiate a character-sized selection if no selection exists.
48  * <dt> select_word()
49  * <dd> selects a "word" after which track() extends the selection by words.
50  * It is usually connected to a left double-click.
51  * <dt> slect_line()
52  * <dd> selects a line after which track() extend the selection by lines.
53  * It is usually connected to a left triple-click.
54  * <dt> done()
55  * <dd> stops tracking. The current selection is stuffed into the clipboard.
56  * It is usually connected to a left release.
57  * <dt> extend()
58  * <dd> only extends an existing selection. (Doesn't start one like track)
59  * It is usually connected to a mouse right-press.
60  * <dt> cancel() nulls the selection.
61  * </dl>
62  * <p>
63  * A Selection has two components that need tracking, the visual feedback
64  * and the selected text. As the history scrolls out the visual feedback
65  * will be eliminated, but we (SHOULD but don't yet) retain the text so
66  * that copy actions still retreieve it properly. DtTerm actually
67  * suffers from this.
68  * <p>
69  * The selection has an origin and an extent. In general the origin and
70  * extent are not ordered (that is extent might be _before_ origin). they
71  * get ordered as needed.
72  */

73
74 class Sel implements ClipboardOwner {
75     // What granularity of selection are we working with
76
private static final int SEL_NONE = 0;
77     private static final int SEL_CHAR = 1;
78     private static final int SEL_WORD = 2;
79     private static final int SEL_LINE = 3;
80
81     // See intersection() for explanation.
82
public static final int INT_NONE = 0;
83     public static final int INT_ABOVE = 1;
84     public static final int INT_ON = 2;
85     public static final int INT_STRADDLES = 3;
86     public static final int INT_BELOW = 4;
87
88     private int sel_tracking;
89     private int old_sel_tracking;
90
91     // origin and extent are kept in absolute RowCol coordinates
92
private Coord sel_origin;
93     /* TMP private */ public Coord sel_extent;
94
95     // The word that was initially selected by select_word
96
// Used by 'track()'.
97
private Extent initial_word;
98
99     private Term term;
100     private State state;
101
102     // properties:
103
private Color color = new Color(204, 204, 255); // swing color
104
void setColor(Color color) { this.color = color; }
105     Color getColor() { return color; }
106     
107     private Color xor_color = Color.white;
108     void setXORColor(Color color) { xor_color = color; }
109     Color getXORColor() { return xor_color; }
110
111     Sel(Term term, State state) {
112     this.term = term;
113     this.state = state;
114     }
115
116     /**
117      * Adjust the selection against 'afirstline'.
118      * <p>
119      * As the selection reaches the top of the history buffer it will get
120      * trimmed until eventually all of it will go away.
121      *
122      * This form doesn't work if the selection is "split" by insertion of
123      * lines. Maybe we SHOULD have two arguments, adjust origin and adjust
124      * extent?
125      */

126     void adjust(int afirstline, int amount, int alastline) {
127
128     if (sel_origin == null)
129         return;
130
131     /* DEBUG
132     System.out.println("Sel.adjust origin " + sel_origin.row + " " + sel_origin.col); // NOI18N
133     System.out.println("Sel.adjust extent " + sel_extent.row + " " + sel_extent.col); // NOI18N
134     System.out.println("Sel.adjust afirstline " + afirstline + " amount " + amount + " alastline " + alastline); // NOI18N
135     */

136
137     if (sel_origin.compareTo(sel_extent) >= 0) {
138         // extent before origin
139
sel_extent.row += amount;
140         if (sel_extent.row < afirstline)
141         sel_extent.row = afirstline;
142
143         sel_origin.row += amount;
144         if (sel_origin.row >= alastline) {
145         sel_origin.row = alastline-1;
146         sel_origin.col = term.buf.totalCols();
147         }
148         if (sel_origin.row < afirstline || sel_extent.row > alastline) {
149         // it has completely vanished
150
sel_extent = null;
151         sel_origin = null;
152         }
153
154     } else {
155         // origin before extent
156
sel_origin.row += amount;
157         if (sel_origin.row < afirstline)
158         sel_origin.row = afirstline;
159
160         sel_extent.row += amount;
161         if (sel_extent.row >= alastline) {
162         sel_extent.row = alastline-1;
163         sel_extent.col = term.buf.totalCols();
164         }
165         if (sel_extent.row < afirstline || sel_origin.row > alastline) {
166         // it has completely vanished
167
sel_origin = null;
168         sel_extent = null;
169         }
170     }
171
172     term.fireSelectionExtentChanged();
173     }
174
175     void relocate(int from, int to) {
176     if (sel_origin == null)
177         return;
178     int delta = to - from;
179     sel_origin.row += delta;
180     sel_extent.row += delta;
181     }
182
183     Extent getExtent() {
184     if (sel_origin == null)
185         return null;
186     Extent x = new Extent(sel_origin, sel_extent);
187     x.order();
188     return x;
189     }
190
191     void setExtent(Extent extent) {
192     cancel(false);
193     extent.order();
194     sel_origin = (Coord) extent.begin.clone();
195     sel_extent = (Coord) extent.end.clone();
196     done(/* OLD false */); // so it makes it into clipboard
197
}
198
199     public void select_word(Extent range) {
200     sel_origin = new Coord(range.begin);
201     sel_extent = new Coord(range.end);
202     sel_tracking = Sel.SEL_WORD;
203     old_sel_tracking = Sel.SEL_NONE;
204     initial_word = range;
205     }
206
207     public void select_line(Coord coord) {
208
209     // LATER coord.clip(term.buf.nlines, term.buf.totalCols(), term.firsta);
210

211     sel_origin = Coord.make(coord.row, 0);
212     sel_extent = Coord.make(coord.row, term.buf.totalCols());
213     sel_tracking = Sel.SEL_LINE;
214     old_sel_tracking = Sel.SEL_NONE;
215     }
216
217     private boolean extend_work(Coord p, int tracking) {
218     /*
219      * return true if a screen refresh is needed
220      */

221     if (tracking == Sel.SEL_NONE) {
222         return false;
223
224     } else if (tracking == Sel.SEL_CHAR) {
225         sel_extent = p;
226
227     } else if (tracking == Sel.SEL_WORD) {
228         BExtent Bnew_range = term.buf.find_word(term.word_delineator, p.toBCoord(term.firsta));
229         Extent new_range = Bnew_range.toExtent(term.firsta);
230         if (p.compareTo(initial_word.begin) < 0) {
231         sel_origin = new Coord(new_range.begin);
232         sel_extent = initial_word.end;
233         } else if (p.compareTo(initial_word.end) > 0) {
234         sel_origin = initial_word.begin;
235         sel_extent = new Coord(new_range.end);
236         } else {
237         sel_origin = initial_word.begin;
238         sel_extent = initial_word.end;
239         }
240
241     } else if (tracking == Sel.SEL_LINE) {
242         if (p.compareTo(sel_origin) > 0) {
243         sel_origin = Coord.make(sel_origin.row, 0);
244         sel_extent = Coord.make(p.row, term.buf.totalCols());
245         } else {
246         sel_origin = Coord.make(sel_origin.row, term.buf.totalCols());
247         sel_extent = Coord.make(p.row, 0);
248         }
249     }
250     return true;
251     }
252
253     public void track(Coord p) {
254     if (sel_tracking == Sel.SEL_NONE) {
255         // initiate a selection
256
sel_origin = p;
257         sel_extent = p;
258         sel_tracking = Sel.SEL_CHAR;
259         old_sel_tracking = Sel.SEL_NONE;
260     }
261     extend_work(p, sel_tracking);
262     }
263
264     public boolean extend(Coord p) {
265     // return true if a screen refresh is needed
266
if (sel_origin == null)
267         return false;
268     else
269         return extend_work(p, old_sel_tracking);
270     }
271
272     /*
273      * Variation on cancel which doesn't update the Selection.
274      * Used by lostOwnership() in addition to plain cancel().
275      */

276     private boolean cancelHelp(boolean and_fire) {
277     if (sel_origin == null)
278         return false;
279     old_sel_tracking = Sel.SEL_NONE;
280     sel_tracking = Sel.SEL_NONE;
281     sel_origin = null;
282     sel_extent = null;
283     initial_word = null;
284
285     if (and_fire)
286         term.fireSelectionExtentChanged();
287
288     return true;
289     }
290
291     public boolean cancel(boolean and_fire) {
292     if (!cancelHelp(and_fire))
293         return false;
294     term.copyToSelection();
295     return true;
296     }
297
298     public void done(/* OLD boolean force_copy */) {
299     // don't track anymore
300
// but extend will still work
301
old_sel_tracking = sel_tracking;
302     sel_tracking = Sel.SEL_NONE;
303
304     term.copyToSelection();
305
306     term.fireSelectionExtentChanged();
307     }
308
309     public void lostOwnership(Clipboard cb, Transferable c) {
310     /*
311      * Part of the ClipboardOwner interface.
312      * The string created in sel_done should be retained until
313      * this function is called.
314      */

315     /* DEBUG
316     System.out.println("lostOwnership()"); // NOI18N
317     */

318     if (cancelHelp(true))
319         term.repaint(false);
320     }
321
322     public String JavaDoc getSelection() {
323
324     Extent x = getExtent();
325     if (x == null)
326         return null;
327
328         if (x.begin != null && x.end != null) {
329             final StringBuffer JavaDoc text = new StringBuffer JavaDoc();
330             term.visitLines(x.begin, x.end, true, new LineVisitor() {
331                 public boolean visit(Line l, int row, int bcol, int ecol) {
332                     text.append(l.text(bcol, ecol));
333                     return true;
334                 }
335             } );
336             return text.toString();
337         }
338
339     return ""; //NOI18N
340
}
341
342     /*
343      * Helps decide what to do with the selection when a line is
344      * added, removed or cleared.
345      */

346     int intersection(int line) {
347     /* DEBUG
348     if (sel_origin == null) {
349         System.out.println("Sel.intersection(" + line + ") no selection"); // NOI18N
350     } else {
351         System.out.println("Sel.intersection(" + line + ")" + // NOI18N
352         " sel_origin.row = " + sel_origin.row + // NOI18N
353         " sel_extent.row = " + sel_extent.row); // NOI18N
354     }
355     */

356
357     Extent x = getExtent();
358     if (x == null)
359         return INT_NONE;
360     x.order();
361
362     if (x.end.row < line)
363         return INT_ABOVE;
364     else if (x.end.row == line)
365         return INT_ON;
366     else if (x.begin.row > line)
367         return INT_BELOW;
368     else
369         return INT_STRADDLES;
370     }
371
372     /**
373      * Select inside one line
374      * Rows and columns are in absolute coords.
375      */

376     private void paint(Graphics g, int row, int bcol, int ecol) {
377
378     // Instead of doing this SHOULD clip the Extent to what's in view
379

380     // Row is outside the view
381
if (row < state.firstx)
382         return;
383     if (row > state.firstx + state.rows)
384         return;
385
386     // Construct the rectangle we're going to paint
387
BCoord begin = new BCoord(row, bcol);
388     BCoord end = new BCoord(row, ecol);
389
390     begin = term.toViewCoord(begin);
391     end = term.toViewCoord(end);
392         
393         //Hotfix for issue 40189
394
if (begin == null || end == null) {
395             return;
396         }
397
398     int lw; // width of last character in selection
399
Line l = term.buf.lineAt(row);
400     lw = l.width(term.metrics, ecol);
401
402     Point pbegin = term.toPixel(begin);
403     Point pend = term.toPixel(end);
404     pend.y += term.metrics.height;
405     pend.x += term.metrics.width * lw; // xterm actually doesn't do this
406

407     Dimension dim = new Dimension(pend.x - pbegin.x,
408                       pend.y - pbegin.y);
409     Rectangle rect = new Rectangle(pbegin, dim);
410
411
412     if (term.selection_xor)
413         g.setXORMode(xor_color);
414     else
415         g.setColor(color);
416
417     g.fillRect(rect.x, rect.y, rect.width, rect.height);
418     }
419
420     void paint(final Graphics g) {
421     /*
422      * Paint the selection.
423      */

424
425     Extent x = getExtent();
426     if (x == null)
427         return;
428     x.order();
429
430     // DEBUG System.out.println("Sel.paint extent: " + x); // NOI18N
431

432     term.visitLines(x.begin, x.end, true, new LineVisitor() {
433         public boolean visit(Line l, int row, int bcol, int ecol) {
434         paint(g, row, bcol, ecol);
435         return true;
436         }
437     } );
438     }
439 }
440
Popular Tags