PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/textarea/Selection.java

#
Java | 715 lines | 494 code | 89 blank | 132 comment | 108 complexity | 6068652470c77bff00750530476a50fa 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. * Selection.java - Selected text
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2001, 2002 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 org.gjt.sp.jedit.Buffer;
  26. import org.gjt.sp.jedit.MiscUtilities;
  27. //}}}
  28. /**
  29. * An abstract class that holds data on a region of selected text.
  30. * As an abstract class, it cannot be used
  31. * directly, but instead serves as a parent class for two specific types
  32. * of selection structures:
  33. * <ul>
  34. * <li>{@link Selection.Range} - represents an ordinary range of selected text.</li>
  35. * <li>{@link Selection.Rect} - represents a rectangular selection.</li>
  36. * </ul>
  37. *
  38. * @author Slava Pestov
  39. * @author John Gellene (API documentation)
  40. * @version $Id: Selection.java 5012 2004-04-06 19:05:31Z spestov $
  41. * @since jEdit 3.2pre1
  42. */
  43. public abstract class Selection implements Cloneable
  44. {
  45. //{{{ getStart() method
  46. /**
  47. * Returns the start offset of this selection.
  48. */
  49. public int getStart()
  50. {
  51. return start;
  52. } //}}}
  53. //{{{ getEnd() method
  54. /**
  55. * Returns the end offset of this selection.
  56. */
  57. public int getEnd()
  58. {
  59. return end;
  60. } //}}}
  61. //{{{ getStart() method
  62. /**
  63. * Returns the beginning of the portion of the selection
  64. * falling on the specified line. Used to manipulate
  65. * selection text on a line-by-line basis.
  66. * @param buffer The buffer
  67. * @param line The line number
  68. * @since jEdit 4.1pre1
  69. */
  70. public abstract int getStart(Buffer buffer, int line);
  71. //}}}
  72. //{{{ getEnd() method
  73. /**
  74. * Returns the end of the portion of the selection
  75. * falling on the specified line. Used to manipulate
  76. * selection text on a line-by-line basis.
  77. * @param buffer The buffer
  78. * @param line The line number
  79. * @since jEdit 4.1pre1
  80. */
  81. public abstract int getEnd(Buffer buffer, int line);
  82. //}}}
  83. //{{{ getStartLine() method
  84. /**
  85. * Returns the starting line number of this selection.
  86. */
  87. public int getStartLine()
  88. {
  89. return startLine;
  90. } //}}}
  91. //{{{ getEndLine() method
  92. /**
  93. * Returns the ending line number of this selection.
  94. */
  95. public int getEndLine()
  96. {
  97. return endLine;
  98. } //}}}
  99. //{{{ overlaps() method
  100. /**
  101. * Returns if this selection and the specified selection overlap.
  102. * @param s The other selection
  103. * @since jEdit 4.1pre1
  104. */
  105. public boolean overlaps(Selection s)
  106. {
  107. if((start >= s.start && start <= s.end)
  108. || (end >= s.start && end <= s.end))
  109. return true;
  110. else
  111. return false;
  112. } //}}}
  113. //{{{ toString() method
  114. public String toString()
  115. {
  116. return getClass().getName() + "[start=" + start
  117. + ",end=" + end + ",startLine=" + startLine
  118. + ",endLine=" + endLine + "]";
  119. } //}}}
  120. //{{{ clone() method
  121. public Object clone()
  122. {
  123. try
  124. {
  125. return super.clone();
  126. }
  127. catch(CloneNotSupportedException e)
  128. {
  129. throw new InternalError("I just drank a whole "
  130. + "bottle of cough syrup and I feel "
  131. + "funny!");
  132. }
  133. } //}}}
  134. //{{{ Package-private members
  135. int start, end;
  136. int startLine, endLine;
  137. //{{{ Selection constructor
  138. Selection()
  139. {
  140. } //}}}
  141. //{{{ Selection constructor
  142. Selection(Selection sel)
  143. {
  144. this.start = sel.start;
  145. this.end = sel.end;
  146. } //}}}
  147. //{{{ Selection constructor
  148. Selection(int start, int end)
  149. {
  150. this.start = start;
  151. this.end = end;
  152. } //}}}
  153. // should the next two be public, maybe?
  154. abstract void getText(Buffer buffer, StringBuffer buf);
  155. abstract int setText(Buffer buffer, String text);
  156. abstract boolean contentInserted(Buffer buffer, int startLine, int start,
  157. int numLines, int length);
  158. abstract boolean contentRemoved(Buffer buffer, int startLine, int start,
  159. int numLines, int length);
  160. //}}}
  161. //{{{ Range class
  162. /**
  163. * An ordinary range selection.
  164. * @since jEdit 3.2pre1
  165. */
  166. public static class Range extends Selection
  167. {
  168. //{{{ Range constructor
  169. public Range()
  170. {
  171. } //}}}
  172. //{{{ Range constructor
  173. public Range(Selection sel)
  174. {
  175. super(sel);
  176. } //}}}
  177. //{{{ Range constructor
  178. public Range(int start, int end)
  179. {
  180. super(start,end);
  181. } //}}}
  182. //{{{ getStart() method
  183. public int getStart(Buffer buffer, int line)
  184. {
  185. if(line == startLine)
  186. return start;
  187. else
  188. return buffer.getLineStartOffset(line);
  189. } //}}}
  190. //{{{ getEnd() method
  191. public int getEnd(Buffer buffer, int line)
  192. {
  193. if(line == endLine)
  194. return end;
  195. else
  196. return buffer.getLineEndOffset(line) - 1;
  197. } //}}}
  198. //{{{ Package-private members
  199. //{{{ getText() method
  200. void getText(Buffer buffer, StringBuffer buf)
  201. {
  202. buf.append(buffer.getText(start,end - start));
  203. } //}}}
  204. //{{{ setText() method
  205. int setText(Buffer buffer, String text)
  206. {
  207. buffer.remove(start,end - start);
  208. if(text != null && text.length() != 0)
  209. {
  210. buffer.insert(start,text);
  211. return start + text.length();
  212. }
  213. else
  214. return start;
  215. } //}}}
  216. //{{{ contentInserted() method
  217. boolean contentInserted(Buffer buffer, int startLine, int start,
  218. int numLines, int length)
  219. {
  220. boolean changed = false;
  221. if(this.start >= start)
  222. {
  223. this.start += length;
  224. if(numLines != 0)
  225. this.startLine = buffer.getLineOfOffset(this.start);
  226. changed = true;
  227. }
  228. if(this.end >= start)
  229. {
  230. this.end += length;
  231. if(numLines != 0)
  232. this.endLine = buffer.getLineOfOffset(this.end);
  233. changed = true;
  234. }
  235. return changed;
  236. } //}}}
  237. //{{{ contentRemoved() method
  238. boolean contentRemoved(Buffer buffer, int startLine, int start,
  239. int numLines, int length)
  240. {
  241. int end = start + length;
  242. boolean changed = false;
  243. if(this.start > start && this.start <= end)
  244. {
  245. this.start = start;
  246. changed = true;
  247. }
  248. else if(this.start > end)
  249. {
  250. this.start -= length;
  251. changed = true;
  252. }
  253. if(this.end > start && this.end <= end)
  254. {
  255. this.end = start;
  256. changed = true;
  257. }
  258. else if(this.end > end)
  259. {
  260. this.end -= length;
  261. changed = true;
  262. }
  263. if(changed && numLines != 0)
  264. {
  265. this.startLine = buffer.getLineOfOffset(this.start);
  266. this.endLine = buffer.getLineOfOffset(this.end);
  267. }
  268. return changed;
  269. } //}}}
  270. //}}}
  271. } //}}}
  272. //{{{ Rect class
  273. /**
  274. * A rectangular selection.
  275. * @since jEdit 3.2pre1
  276. */
  277. // this class is not very fast...
  278. public static class Rect extends Selection
  279. {
  280. //{{{ Rect constructor
  281. public Rect()
  282. {
  283. super();
  284. } //}}}
  285. //{{{ Rect constructor
  286. public Rect(Selection sel)
  287. {
  288. super(sel);
  289. } //}}}
  290. //{{{ Rect constructor
  291. public Rect(int start, int end)
  292. {
  293. super(start,end);
  294. } //}}}
  295. //{{{ Rect constructor
  296. public Rect(int startLine, int start, int endLine, int end)
  297. {
  298. this.startLine = startLine;
  299. this.start = start;
  300. this.endLine = endLine;
  301. this.end = end;
  302. } //}}}
  303. //{{{ Rect constructor
  304. public Rect(Buffer buffer, int startLine, int startColumn,
  305. int endLine, int endColumn)
  306. {
  307. this.startLine = startLine;
  308. this.endLine = endLine;
  309. int[] width = new int[1];
  310. int startOffset = buffer.getOffsetOfVirtualColumn(startLine,
  311. startColumn,width);
  312. if(startOffset == -1)
  313. {
  314. extraStartVirt = startColumn - width[0];
  315. startOffset = buffer.getLineEndOffset(startLine) - 1;
  316. }
  317. else
  318. startOffset += buffer.getLineStartOffset(startLine);
  319. int endOffset = buffer.getOffsetOfVirtualColumn(endLine,
  320. endColumn,width);
  321. if(endOffset == -1)
  322. {
  323. extraEndVirt = endColumn - width[0];
  324. endOffset = buffer.getLineEndOffset(endLine) - 1;
  325. }
  326. else
  327. endOffset += buffer.getLineStartOffset(endLine);
  328. } //}}}
  329. //{{{ getStartColumn() method
  330. public int getStartColumn(Buffer buffer)
  331. {
  332. int virtColStart = buffer.getVirtualWidth(startLine,
  333. start - buffer.getLineStartOffset(startLine)) + extraStartVirt;
  334. int virtColEnd = buffer.getVirtualWidth(endLine,
  335. end - buffer.getLineStartOffset(endLine)) + extraEndVirt;
  336. return Math.min(virtColStart,virtColEnd);
  337. } //}}}
  338. //{{{ getEndColumn() method
  339. public int getEndColumn(Buffer buffer)
  340. {
  341. int virtColStart = buffer.getVirtualWidth(startLine,
  342. start - buffer.getLineStartOffset(startLine)) + extraStartVirt;
  343. int virtColEnd = buffer.getVirtualWidth(endLine,
  344. end - buffer.getLineStartOffset(endLine)) + extraEndVirt;
  345. return Math.max(virtColStart,virtColEnd);
  346. } //}}}
  347. //{{{ getStart() method
  348. public int getStart(Buffer buffer, int line)
  349. {
  350. return getColumnOnOtherLine(buffer,line,
  351. getStartColumn(buffer));
  352. } //}}}
  353. //{{{ getEnd() method
  354. public int getEnd(Buffer buffer, int line)
  355. {
  356. return getColumnOnOtherLine(buffer,line,
  357. getEndColumn(buffer));
  358. } //}}}
  359. //{{{ Package-private members
  360. int extraStartVirt;
  361. int extraEndVirt;
  362. //{{{ getText() method
  363. void getText(Buffer buffer, StringBuffer buf)
  364. {
  365. int start = getStartColumn(buffer);
  366. int end = getEndColumn(buffer);
  367. for(int i = startLine; i <= endLine; i++)
  368. {
  369. int lineStart = buffer.getLineStartOffset(i);
  370. int lineLen = buffer.getLineLength(i);
  371. int rectStart = buffer.getOffsetOfVirtualColumn(
  372. i,start,null);
  373. if(rectStart == -1)
  374. rectStart = lineLen;
  375. int rectEnd = buffer.getOffsetOfVirtualColumn(
  376. i,end,null);
  377. if(rectEnd == -1)
  378. rectEnd = lineLen;
  379. if(rectEnd < rectStart)
  380. System.err.println(i + ":::" + start + ":" + end
  381. + " ==> " + rectStart + ":" + rectEnd);
  382. buf.append(buffer.getText(lineStart + rectStart,
  383. rectEnd - rectStart));
  384. if(i != endLine)
  385. buf.append('\n');
  386. }
  387. } //}}}
  388. //{{{ setText() method
  389. int setText(Buffer buffer, String text)
  390. {
  391. int startColumn = getStartColumn(buffer);
  392. int endColumn = getEndColumn(buffer);
  393. int[] total = new int[1];
  394. int tabSize = buffer.getTabSize();
  395. int maxWidth = 0;
  396. int totalLines = 0;
  397. ArrayList lines = new ArrayList();
  398. //{{{ Split the text into lines
  399. if(text != null)
  400. {
  401. int lastNewline = 0;
  402. int currentWidth = startColumn;
  403. for(int i = 0; i < text.length(); i++)
  404. {
  405. char ch = text.charAt(i);
  406. if(ch == '\n')
  407. {
  408. totalLines++;
  409. lines.add(text.substring(
  410. lastNewline,i));
  411. lastNewline = i + 1;
  412. maxWidth = Math.max(maxWidth,currentWidth);
  413. lines.add(new Integer(currentWidth));
  414. currentWidth = startColumn;
  415. }
  416. else if(ch == '\t')
  417. currentWidth += tabSize - (currentWidth % tabSize);
  418. else
  419. currentWidth++;
  420. }
  421. if(lastNewline != text.length())
  422. {
  423. totalLines++;
  424. lines.add(text.substring(lastNewline));
  425. lines.add(new Integer(currentWidth));
  426. maxWidth = Math.max(maxWidth,currentWidth);
  427. }
  428. } //}}}
  429. //{{{ Insert the lines into the buffer
  430. int endOffset = 0;
  431. int lastLine = Math.max(startLine + totalLines - 1,endLine);
  432. for(int i = startLine; i <= lastLine; i++)
  433. {
  434. if(i == buffer.getLineCount())
  435. buffer.insert(buffer.getLength(),"\n");
  436. int lineStart = buffer.getLineStartOffset(i);
  437. int lineLen = buffer.getLineLength(i);
  438. int rectStart = buffer.getOffsetOfVirtualColumn(
  439. i,startColumn,total);
  440. int startWhitespace;
  441. if(rectStart == -1)
  442. {
  443. startWhitespace = (startColumn - total[0]);
  444. rectStart = lineLen;
  445. }
  446. else
  447. startWhitespace = 0;
  448. int rectEnd = buffer.getOffsetOfVirtualColumn(
  449. i,endColumn,null);
  450. if(rectEnd == -1)
  451. rectEnd = lineLen;
  452. buffer.remove(rectStart + lineStart,rectEnd - rectStart);
  453. if(startWhitespace != 0)
  454. {
  455. buffer.insert(rectStart + lineStart,
  456. MiscUtilities.createWhiteSpace(startWhitespace,0));
  457. }
  458. int endWhitespace;
  459. if(totalLines == 0)
  460. {
  461. if(rectEnd == lineLen)
  462. endWhitespace = 0;
  463. else
  464. endWhitespace = maxWidth - startColumn;
  465. }
  466. else
  467. {
  468. int index = 2 * ((i - startLine) % totalLines);
  469. String str = (String)lines.get(index);
  470. buffer.insert(rectStart + lineStart + startWhitespace,str);
  471. if(rectEnd == lineLen)
  472. endWhitespace = 0;
  473. else
  474. {
  475. endWhitespace = maxWidth
  476. - ((Integer)lines.get(index+1))
  477. .intValue();
  478. }
  479. startWhitespace += str.length();
  480. }
  481. if(endWhitespace != 0)
  482. {
  483. buffer.insert(rectStart + lineStart
  484. + startWhitespace,
  485. MiscUtilities.createWhiteSpace(endWhitespace,0));
  486. }
  487. endOffset = rectStart + lineStart
  488. + startWhitespace
  489. + endWhitespace;
  490. } //}}}
  491. //{{{ Move the caret down a line
  492. if(text == null || text.length() == 0)
  493. return end;
  494. else
  495. return endOffset;
  496. //}}}
  497. } //}}}
  498. //{{{ contentInserted() method
  499. boolean contentInserted(Buffer buffer, int startLine, int start,
  500. int numLines, int length)
  501. {
  502. if(this.end < start)
  503. return false;
  504. this.end += length;
  505. if(this.startLine > startLine)
  506. {
  507. this.start += length;
  508. if(numLines != 0)
  509. {
  510. this.startLine = buffer.getLineOfOffset(
  511. this.start);
  512. this.endLine = buffer.getLineOfOffset(
  513. this.end);
  514. }
  515. return true;
  516. }
  517. int endVirtualColumn = buffer.getVirtualWidth(
  518. this.endLine,end
  519. - buffer.getLineStartOffset(this.endLine));
  520. if(this.start == start)
  521. {
  522. int startVirtualColumn = buffer.getVirtualWidth(
  523. this.startLine,start
  524. - buffer.getLineStartOffset(
  525. this.startLine));
  526. this.start += length;
  527. int newStartVirtualColumn
  528. = buffer.getVirtualWidth(
  529. startLine,start -
  530. buffer.getLineStartOffset(
  531. this.startLine));
  532. int[] totalVirtualWidth = new int[1];
  533. int newEnd = buffer.getOffsetOfVirtualColumn(
  534. this.endLine,endVirtualColumn +
  535. newStartVirtualColumn -
  536. startVirtualColumn,
  537. totalVirtualWidth);
  538. if(newEnd != -1)
  539. {
  540. end = buffer.getLineStartOffset(
  541. this.endLine) + newEnd;
  542. }
  543. else
  544. {
  545. end = buffer.getLineEndOffset(
  546. this.endLine) - 1;
  547. extraEndVirt = totalVirtualWidth[0]
  548. - endVirtualColumn;
  549. }
  550. }
  551. else if(this.start > start)
  552. {
  553. this.start += length;
  554. if(numLines != 0)
  555. {
  556. this.startLine = buffer.getLineOfOffset(
  557. this.start);
  558. }
  559. }
  560. if(numLines != 0)
  561. this.endLine = buffer.getLineOfOffset(this.end);
  562. int newEndVirtualColumn = buffer.getVirtualWidth(
  563. endLine,
  564. end - buffer.getLineStartOffset(this.endLine));
  565. if(startLine == this.endLine && extraEndVirt != 0)
  566. {
  567. extraEndVirt += (endVirtualColumn
  568. - newEndVirtualColumn);
  569. }
  570. else if(startLine == this.startLine
  571. && extraStartVirt != 0)
  572. {
  573. extraStartVirt += (endVirtualColumn
  574. - newEndVirtualColumn);
  575. }
  576. return true;
  577. } //}}}
  578. //{{{ contentRemoved() method
  579. boolean contentRemoved(Buffer buffer, int startLine, int start,
  580. int numLines, int length)
  581. {
  582. int end = start + length;
  583. boolean changed = false;
  584. if(this.start > start && this.start <= end)
  585. {
  586. this.start = start;
  587. changed = true;
  588. }
  589. else if(this.start > end)
  590. {
  591. this.start -= length;
  592. changed = true;
  593. }
  594. if(this.end > start && this.end <= end)
  595. {
  596. this.end = start;
  597. changed = true;
  598. }
  599. else if(this.end > end)
  600. {
  601. this.end -= length;
  602. changed = true;
  603. }
  604. if(changed && numLines != 0)
  605. {
  606. this.startLine = buffer.getLineOfOffset(this.start);
  607. this.endLine = buffer.getLineOfOffset(this.end);
  608. }
  609. return changed;
  610. } //}}}
  611. //}}}
  612. //{{{ Private members
  613. //{{{ getColumnOnOtherLine() method
  614. private int getColumnOnOtherLine(Buffer buffer, int line,
  615. int col)
  616. {
  617. int returnValue = buffer.getOffsetOfVirtualColumn(
  618. line,col,null);
  619. if(returnValue == -1)
  620. return buffer.getLineEndOffset(line) - 1;
  621. else
  622. return buffer.getLineStartOffset(line) + returnValue;
  623. } //}}}
  624. //}}}
  625. } //}}}
  626. }