KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > textarea > SelectionManager


1 /*
2  * SelectionManager.java
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2004 Slava Pestov
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */

22
23 package org.gjt.sp.jedit.textarea;
24
25 //{{{ Imports
26
import java.util.ArrayList JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.TreeSet JavaDoc;
31 import org.gjt.sp.jedit.buffer.*;
32 //}}}
33

34 class SelectionManager
35 {
36     // this is package-private so that the painter can use it without
37
// having to call getSelection() (which involves an array copy)
38
List JavaDoc<Selection> selection;
39
40     //{{{ SelectionManager constructor
41
SelectionManager(TextArea textArea)
42     {
43         this.textArea = textArea;
44         selection = new ArrayList JavaDoc<Selection>();
45     } //}}}
46

47     //{{{ getSelectionCount() method
48
/**
49      * Returns the number of selections. This can be used to test
50      * for the existence of selections.
51      */

52     int getSelectionCount()
53     {
54         return selection.size();
55     } //}}}
56

57     //{{{ getSelection() method
58
/**
59      * Returns the current selection.
60      * @since jEdit 3.2pre1
61      */

62     public Selection[] getSelection()
63     {
64         return selection.toArray(
65             new Selection[selection.size()]);
66     } //}}}
67

68     //{{{ setSelection() method
69
/**
70      * Sets the selection. Nested and overlapping selections are merged
71      * where possible.
72      */

73     void setSelection(Selection[] selection)
74     {
75         this.selection.clear();
76         addToSelection(selection);
77     } //}}}
78

79     //{{{ addToSelection() method
80
/**
81      * Adds to the selection. Nested and overlapping selections are merged
82      * where possible. Null elements of the array are ignored.
83      * @param selection The new selection
84      * since jEdit 3.2pre1
85      */

86     void addToSelection(Selection[] selection)
87     {
88         if(selection != null)
89         {
90             for(int i = 0; i < selection.length; i++)
91             {
92                 Selection s = selection[i];
93                 if(s != null)
94                     addToSelection(s);
95             }
96         }
97     } //}}}
98

99     //{{{ addToSelection() method
100
void addToSelection(Selection addMe)
101     {
102         if(addMe.start > addMe.end)
103         {
104             throw new IllegalArgumentException JavaDoc(addMe.start
105                 + " > " + addMe.end);
106         }
107         else if(addMe.start == addMe.end)
108         {
109             if(addMe instanceof Selection.Range)
110                 return;
111             else if(addMe instanceof Selection.Rect)
112             {
113                 if(((Selection.Rect)addMe).extraEndVirt == 0)
114                     return;
115             }
116         }
117
118         Iterator JavaDoc<Selection> iter = selection.iterator();
119         while(iter.hasNext())
120         {
121             // try and merge existing selections one by
122
// one with the new selection
123
Selection s = iter.next();
124             if(s.overlaps(addMe))
125             {
126                 addMe.start = Math.min(s.start,addMe.start);
127                 addMe.end = Math.max(s.end,addMe.end);
128                 iter.remove();
129             }
130         }
131
132         addMe.startLine = textArea.getLineOfOffset(addMe.start);
133         addMe.endLine = textArea.getLineOfOffset(addMe.end);
134
135         boolean added = false;
136
137         for(int i = 0; i < selection.size(); i++)
138         {
139             Selection s = selection.get(i);
140             if(addMe.start < s.start)
141             {
142                 selection.add(i,addMe);
143                 added = true;
144                 break;
145             }
146         }
147
148         if(!added)
149             selection.add(addMe);
150
151         textArea.invalidateLineRange(addMe.startLine,addMe.endLine);
152     } //}}}
153

154     //{{{ setSelection() method
155
/**
156      * Sets the selection. Nested and overlapping selections are merged
157      * where possible.
158      */

159     void setSelection(Selection selection)
160     {
161         this.selection.clear();
162
163         if(selection != null)
164             addToSelection(selection);
165     } //}}}
166

167     //{{{ getSelectionAtOffset() method
168
/**
169      * Returns the selection containing the specific offset, or <code>null</code>
170      * if there is no selection at that offset.
171      * @param offset The offset
172      * @since jEdit 3.2pre1
173      */

174     Selection getSelectionAtOffset(int offset)
175     {
176         if(selection != null)
177         {
178             for (Selection s : selection)
179             {
180                 if(offset >= s.start && offset <= s.end)
181                     return s;
182             }
183         }
184
185         return null;
186     } //}}}
187

188     //{{{ removeFromSelection() method
189
/**
190      * Deactivates the specified selection.
191      * @param sel The selection
192      */

193     void removeFromSelection(Selection sel)
194     {
195         selection.remove(sel);
196     } //}}}
197

198     //{{{ resizeSelection() method
199
/**
200      * Resizes the selection at the specified offset, or creates a new
201      * one if there is no selection at the specified offset. This is a
202      * utility method that is mainly useful in the mouse event handler
203      * because it handles the case of end being before offset gracefully
204      * (unlike the rest of the selection API).
205      * @param offset The offset
206      * @param end The new selection end
207      * @param extraEndVirt Only for rectangular selections - specifies how
208      * far it extends into virtual space.
209      * @param rect Make the selection rectangular?
210      */

211     void resizeSelection(int offset, int end, int extraEndVirt,
212         boolean rect)
213     {
214         boolean reversed = false;
215         if(end < offset)
216         {
217             int tmp = offset;
218             offset = end;
219             end = tmp;
220             reversed = true;
221         }
222
223         Selection newSel;
224         if(rect)
225         {
226             Selection.Rect rectSel = new Selection.Rect(offset,end);
227             if(reversed)
228                 rectSel.extraStartVirt = extraEndVirt;
229             else
230                 rectSel.extraEndVirt = extraEndVirt;
231             newSel = rectSel;
232         }
233         else
234             newSel = new Selection.Range(offset,end);
235
236         addToSelection(newSel);
237     } //}}}
238

239     //{{{ getSelectedLines() method
240
/**
241      * Returns a sorted array of line numbers on which a selection or
242      * selections are present.<p>
243      *
244      * This method is the most convenient way to iterate through selected
245      * lines in a buffer. The line numbers in the array returned by this
246      * method can be passed as a parameter to such methods as
247      * {@link org.gjt.sp.jedit.Buffer#getLineText(int)}.
248      */

249     int[] getSelectedLines()
250     {
251
252         Set JavaDoc<Integer JavaDoc> set = new TreeSet JavaDoc<Integer JavaDoc>();
253         for (Selection s : selection)
254         {
255             int endLine =
256                 s.end == textArea.getLineStartOffset(s.endLine)
257                 ? s.endLine - 1
258                 : s.endLine;
259
260             for(int j = s.startLine; j <= endLine; j++)
261             {
262                 set.add(j);
263             }
264         }
265
266
267         int[] returnValue = new int[set.size()];
268         int i = 0;
269         for (Integer JavaDoc line : set)
270             returnValue[i++] = line;
271
272         return returnValue;
273     } //}}}
274

275     //{{{ invertSelection() method
276
void invertSelection()
277     {
278         Selection[] newSelection = new Selection[selection.size() + 1];
279         int lastOffset = 0;
280         for(int i = 0; i < selection.size(); i++)
281         {
282             Selection s = selection.get(i);
283             newSelection[i] = new Selection.Range(lastOffset,
284                 s.getStart());
285             lastOffset = s.getEnd();
286         }
287         newSelection[selection.size()] = new Selection.Range(
288             lastOffset,textArea.getBufferLength());
289         setSelection(newSelection);
290     } //}}}
291

292     //{{{ getSelectionStartEndOnLine() method
293
/**
294      * Returns the x co-ordinates of the selection start and end on the
295      * given line. May return null.
296      */

297     int[] getSelectionStartAndEnd(int screenLine, int physicalLine,
298         Selection s)
299     {
300         int start = textArea.getScreenLineStartOffset(screenLine);
301         int end = textArea.getScreenLineEndOffset(screenLine);
302
303         if(end <= s.start || start > s.end)
304             return null;
305
306         int selStartScreenLine;
307         if(textArea.displayManager.isLineVisible(s.startLine))
308             selStartScreenLine = textArea.getScreenLineOfOffset(s.start);
309         else
310             selStartScreenLine = -1;
311
312         int selEndScreenLine;
313         if(textArea.displayManager.isLineVisible(s.endLine))
314             selEndScreenLine = textArea.getScreenLineOfOffset(s.end);
315         else
316             selEndScreenLine = -1;
317
318         JEditBuffer buffer = textArea.getBuffer();
319
320         int lineStart = buffer.getLineStartOffset(physicalLine);
321         int x1, x2;
322
323         if(s instanceof Selection.Rect)
324         {
325             start -= lineStart;
326             end -= lineStart;
327
328             Selection.Rect rect = (Selection.Rect)s;
329             int _start = rect.getStartColumn(buffer);
330             int _end = rect.getEndColumn(buffer);
331
332             int lineLen = buffer.getLineLength(physicalLine);
333
334             int[] total = new int[1];
335
336             int rectStart = buffer.getOffsetOfVirtualColumn(
337                 physicalLine,_start,total);
338             if(rectStart == -1)
339             {
340                 x1 = (_start - total[0]) * textArea.charWidth;
341                 rectStart = lineLen;
342             }
343             else
344                 x1 = 0;
345
346             int rectEnd = buffer.getOffsetOfVirtualColumn(
347                 physicalLine,_end,total);
348             if(rectEnd == -1)
349             {
350                 x2 = (_end - total[0]) * textArea.charWidth;
351                 rectEnd = lineLen;
352             }
353             else
354                 x2 = 0;
355
356             if(end <= rectStart || start > rectEnd)
357                 return null;
358
359             x1 = rectStart < start ? 0
360                 : x1 + textArea.offsetToXY(physicalLine,
361                 rectStart).x;
362             x2 = rectEnd > end ? textArea.getWidth()
363                 : x2 + textArea.offsetToXY(physicalLine,
364                 rectEnd).x;
365         }
366         else if(selStartScreenLine == selEndScreenLine
367             && selStartScreenLine != -1)
368         {
369             x1 = textArea.offsetToXY(physicalLine,
370                 s.start - lineStart).x;
371             x2 = textArea.offsetToXY(physicalLine,
372                 s.end - lineStart).x;
373         }
374         else if(screenLine == selStartScreenLine)
375         {
376             x1 = textArea.offsetToXY(physicalLine,
377                 s.start - lineStart).x;
378             x2 = textArea.getWidth();
379         }
380         else if(screenLine == selEndScreenLine)
381         {
382             x1 = 0;
383             x2 = textArea.offsetToXY(physicalLine,
384                 s.end - lineStart).x;
385         }
386         else
387         {
388             x1 = 0;
389             x2 = textArea.getWidth();
390         }
391
392         if(x1 < 0)
393             x1 = 0;
394         if(x2 < 0)
395             x2 = 0;
396
397         if(x1 == x2)
398             x2++;
399
400         return new int[] { x1, x2 };
401     } //}}}
402

403     //{{{ insideSelection() method
404
/**
405      * Returns if the given point is inside a selection.
406      * Used by drag and drop code in MouseHandler below.
407      */

408     boolean insideSelection(int x, int y)
409     {
410         int offset = textArea.xyToOffset(x,y);
411
412         Selection s = textArea.getSelectionAtOffset(offset);
413         if(s == null)
414             return false;
415
416         int screenLine = textArea.getScreenLineOfOffset(offset);
417         if(screenLine == -1)
418             return false;
419
420         int[] selectionStartAndEnd = getSelectionStartAndEnd(
421             screenLine,textArea.getLineOfOffset(offset),s);
422         if(selectionStartAndEnd == null)
423             return false;
424
425         return x >= selectionStartAndEnd[0]
426             && x <= selectionStartAndEnd[1];
427     } //}}}
428

429     private TextArea textArea;
430 }
431
Popular Tags