PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/textarea/SelectionManager.java

#
Java | 440 lines | 285 code | 53 blank | 102 comment | 63 complexity | 99a324127b87190fa7142f99ef37dabb MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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. package org.gjt.sp.jedit.textarea;
  23. //{{{ Imports
  24. import java.util.ArrayList;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Set;
  28. import java.util.TreeSet;
  29. import org.gjt.sp.jedit.buffer.*;
  30. //}}}
  31. class SelectionManager
  32. {
  33. // this is package-private so that the painter can use it without
  34. // having to call getSelection() (which involves an array copy)
  35. List selection;
  36. //{{{ SelectionManager constructor
  37. SelectionManager(JEditTextArea textArea)
  38. {
  39. this.textArea = textArea;
  40. selection = new ArrayList();
  41. } //}}}
  42. //{{{ getSelectionCount() method
  43. /**
  44. * Returns the number of selections. This can be used to test
  45. * for the existence of selections.
  46. */
  47. int getSelectionCount()
  48. {
  49. return selection.size();
  50. } //}}}
  51. //{{{ getSelection() method
  52. /**
  53. * Returns the current selection.
  54. * @since jEdit 3.2pre1
  55. */
  56. public Selection[] getSelection()
  57. {
  58. return (Selection[])selection.toArray(
  59. new Selection[selection.size()]);
  60. } //}}}
  61. //{{{ setSelection() method
  62. /**
  63. * Sets the selection. Nested and overlapping selections are merged
  64. * where possible.
  65. */
  66. void setSelection(Selection[] selection)
  67. {
  68. this.selection.clear();
  69. addToSelection(selection);
  70. } //}}}
  71. //{{{ addToSelection() method
  72. /**
  73. * Adds to the selection. Nested and overlapping selections are merged
  74. * where possible. Null elements of the array are ignored.
  75. * @param selection The new selection
  76. * since jEdit 3.2pre1
  77. */
  78. void addToSelection(Selection[] selection)
  79. {
  80. if(selection != null)
  81. {
  82. for(int i = 0; i < selection.length; i++)
  83. {
  84. Selection s = selection[i];
  85. if(s != null)
  86. addToSelection(s);
  87. }
  88. }
  89. } //}}}
  90. //{{{ addToSelection() method
  91. void addToSelection(Selection addMe)
  92. {
  93. if(addMe.start > addMe.end)
  94. {
  95. throw new IllegalArgumentException(addMe.start
  96. + " > " + addMe.end);
  97. }
  98. else if(addMe.start == addMe.end)
  99. {
  100. if(addMe instanceof Selection.Range)
  101. return;
  102. else if(addMe instanceof Selection.Rect)
  103. {
  104. if(((Selection.Rect)addMe).extraEndVirt == 0)
  105. return;
  106. }
  107. }
  108. Iterator iter = selection.iterator();
  109. while(iter.hasNext())
  110. {
  111. // try and merge existing selections one by
  112. // one with the new selection
  113. Selection s = (Selection)iter.next();
  114. if(s.overlaps(addMe))
  115. {
  116. addMe.start = Math.min(s.start,addMe.start);
  117. addMe.end = Math.max(s.end,addMe.end);
  118. iter.remove();
  119. }
  120. }
  121. addMe.startLine = textArea.getLineOfOffset(addMe.start);
  122. addMe.endLine = textArea.getLineOfOffset(addMe.end);
  123. boolean added = false;
  124. for(int i = 0; i < selection.size(); i++)
  125. {
  126. Selection s = (Selection)selection.get(i);
  127. if(addMe.start < s.start)
  128. {
  129. selection.add(i,addMe);
  130. added = true;
  131. break;
  132. }
  133. }
  134. if(!added)
  135. selection.add(addMe);
  136. textArea.invalidateLineRange(addMe.startLine,addMe.endLine);
  137. } //}}}
  138. //{{{ setSelection() method
  139. /**
  140. * Sets the selection. Nested and overlapping selections are merged
  141. * where possible.
  142. */
  143. void setSelection(Selection selection)
  144. {
  145. this.selection.clear();
  146. if(selection != null)
  147. addToSelection(selection);
  148. } //}}}
  149. //{{{ getSelectionAtOffset() method
  150. /**
  151. * Returns the selection containing the specific offset, or <code>null</code>
  152. * if there is no selection at that offset.
  153. * @param offset The offset
  154. * @since jEdit 3.2pre1
  155. */
  156. Selection getSelectionAtOffset(int offset)
  157. {
  158. if(selection != null)
  159. {
  160. Iterator iter = selection.iterator();
  161. while(iter.hasNext())
  162. {
  163. Selection s = (Selection)iter.next();
  164. if(offset >= s.start && offset <= s.end)
  165. return s;
  166. }
  167. }
  168. return null;
  169. } //}}}
  170. //{{{ removeFromSelection() method
  171. /**
  172. * Deactivates the specified selection.
  173. * @param sel The selection
  174. */
  175. void removeFromSelection(Selection sel)
  176. {
  177. selection.remove(sel);
  178. } //}}}
  179. //{{{ resizeSelection() method
  180. /**
  181. * Resizes the selection at the specified offset, or creates a new
  182. * one if there is no selection at the specified offset. This is a
  183. * utility method that is mainly useful in the mouse event handler
  184. * because it handles the case of end being before offset gracefully
  185. * (unlike the rest of the selection API).
  186. * @param offset The offset
  187. * @param end The new selection end
  188. * @param extraEndVirt Only for rectangular selections - specifies how
  189. * far it extends into virtual space.
  190. * @param rect Make the selection rectangular?
  191. */
  192. void resizeSelection(int offset, int end, int extraEndVirt,
  193. boolean rect)
  194. {
  195. boolean reversed = false;
  196. if(end < offset)
  197. {
  198. int tmp = offset;
  199. offset = end;
  200. end = tmp;
  201. reversed = true;
  202. }
  203. Selection newSel;
  204. if(rect)
  205. {
  206. Selection.Rect rectSel = new Selection.Rect(offset,end);
  207. if(reversed)
  208. rectSel.extraStartVirt = extraEndVirt;
  209. else
  210. rectSel.extraEndVirt = extraEndVirt;
  211. newSel = rectSel;
  212. }
  213. else
  214. newSel = new Selection.Range(offset,end);
  215. addToSelection(newSel);
  216. } //}}}
  217. //{{{ getSelectedLines() method
  218. /**
  219. * Returns a sorted array of line numbers on which a selection or
  220. * selections are present.<p>
  221. *
  222. * This method is the most convenient way to iterate through selected
  223. * lines in a buffer. The line numbers in the array returned by this
  224. * method can be passed as a parameter to such methods as
  225. * {@link org.gjt.sp.jedit.Buffer#getLineText(int)}.
  226. */
  227. int[] getSelectedLines()
  228. {
  229. Integer line;
  230. Set set = new TreeSet();
  231. Iterator iter = selection.iterator();
  232. while(iter.hasNext())
  233. {
  234. Selection s = (Selection)iter.next();
  235. int endLine =
  236. (s.end == textArea.getLineStartOffset(s.endLine)
  237. ? s.endLine - 1
  238. : s.endLine);
  239. for(int j = s.startLine; j <= endLine; j++)
  240. {
  241. line = new Integer(j);
  242. set.add(line);
  243. }
  244. }
  245. int[] returnValue = new int[set.size()];
  246. int i = 0;
  247. iter = set.iterator();
  248. while(iter.hasNext())
  249. {
  250. line = (Integer)iter.next();
  251. returnValue[i++] = line.intValue();
  252. }
  253. return returnValue;
  254. } //}}}
  255. //{{{ invertSelection() method
  256. void invertSelection()
  257. {
  258. Selection[] newSelection = new Selection[selection.size() + 1];
  259. int lastOffset = 0;
  260. for(int i = 0; i < selection.size(); i++)
  261. {
  262. Selection s = (Selection)selection.get(i);
  263. newSelection[i] = new Selection.Range(lastOffset,
  264. s.getStart());
  265. lastOffset = s.getEnd();
  266. }
  267. newSelection[selection.size()] = new Selection.Range(
  268. lastOffset,textArea.getBufferLength());
  269. setSelection(newSelection);
  270. } //}}}
  271. //{{{ getSelectionStartEndOnLine() method
  272. /**
  273. * Returns the x co-ordinates of the selection start and end on the
  274. * given line. May return null.
  275. */
  276. int[] getSelectionStartAndEnd(int screenLine, int physicalLine,
  277. Selection s)
  278. {
  279. int start = textArea.getScreenLineStartOffset(screenLine);
  280. int end = textArea.getScreenLineEndOffset(screenLine);
  281. if(end <= s.start || start > s.end)
  282. return null;
  283. int selStartScreenLine;
  284. if(textArea.displayManager.isLineVisible(s.startLine))
  285. selStartScreenLine = textArea.getScreenLineOfOffset(s.start);
  286. else
  287. selStartScreenLine = -1;
  288. int selEndScreenLine;
  289. if(textArea.displayManager.isLineVisible(s.endLine))
  290. selEndScreenLine = textArea.getScreenLineOfOffset(s.end);
  291. else
  292. selEndScreenLine = -1;
  293. JEditBuffer buffer = textArea.getBuffer();
  294. int lineStart = buffer.getLineStartOffset(physicalLine);
  295. int x1, x2;
  296. if(s instanceof Selection.Rect)
  297. {
  298. start -= lineStart;
  299. end -= lineStart;
  300. Selection.Rect rect = (Selection.Rect)s;
  301. int _start = rect.getStartColumn(buffer);
  302. int _end = rect.getEndColumn(buffer);
  303. int lineLen = buffer.getLineLength(physicalLine);
  304. int[] total = new int[1];
  305. int rectStart = buffer.getOffsetOfVirtualColumn(
  306. physicalLine,_start,total);
  307. if(rectStart == -1)
  308. {
  309. x1 = (_start - total[0]) * textArea.charWidth;
  310. rectStart = lineLen;
  311. }
  312. else
  313. x1 = 0;
  314. int rectEnd = buffer.getOffsetOfVirtualColumn(
  315. physicalLine,_end,total);
  316. if(rectEnd == -1)
  317. {
  318. x2 = (_end - total[0]) * textArea.charWidth;
  319. rectEnd = lineLen;
  320. }
  321. else
  322. x2 = 0;
  323. if(end <= rectStart || start > rectEnd)
  324. return null;
  325. x1 = (rectStart < start ? 0
  326. : x1 + textArea.offsetToXY(physicalLine,
  327. rectStart).x);
  328. x2 = (rectEnd > end ? textArea.getWidth()
  329. : x2 + textArea.offsetToXY(physicalLine,
  330. rectEnd).x);
  331. }
  332. else if(selStartScreenLine == selEndScreenLine
  333. && selStartScreenLine != -1)
  334. {
  335. x1 = textArea.offsetToXY(physicalLine,
  336. s.start - lineStart).x;
  337. x2 = textArea.offsetToXY(physicalLine,
  338. s.end - lineStart).x;
  339. }
  340. else if(screenLine == selStartScreenLine)
  341. {
  342. x1 = textArea.offsetToXY(physicalLine,
  343. s.start - lineStart).x;
  344. x2 = textArea.getWidth();
  345. }
  346. else if(screenLine == selEndScreenLine)
  347. {
  348. x1 = 0;
  349. x2 = textArea.offsetToXY(physicalLine,
  350. s.end - lineStart).x;
  351. }
  352. else
  353. {
  354. x1 = 0;
  355. x2 = textArea.getWidth();
  356. }
  357. if(x1 < 0)
  358. x1 = 0;
  359. if(x2 < 0)
  360. x2 = 0;
  361. if(x1 == x2)
  362. x2++;
  363. return new int[] { x1, x2 };
  364. } //}}}
  365. //{{{ insideSelection() method
  366. /**
  367. * Returns if the given point is inside a selection.
  368. * Used by drag and drop code in MouseHandler below.
  369. */
  370. boolean insideSelection(int x, int y)
  371. {
  372. int offset = textArea.xyToOffset(x,y);
  373. Selection s = textArea.getSelectionAtOffset(offset);
  374. if(s == null)
  375. return false;
  376. int screenLine = textArea.getScreenLineOfOffset(offset);
  377. if(screenLine == -1)
  378. return false;
  379. int[] selectionStartAndEnd = getSelectionStartAndEnd(
  380. screenLine,textArea.getLineOfOffset(offset),s);
  381. if(selectionStartAndEnd == null)
  382. return false;
  383. return x >= selectionStartAndEnd[0]
  384. && x <= selectionStartAndEnd[1];
  385. } //}}}
  386. private JEditTextArea textArea;
  387. }