PageRenderTime 60ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/textarea/JEditTextArea.java

#
Java | 2902 lines | 1753 code | 373 blank | 776 comment | 375 complexity | f168b1ec86981a6abd53668ac1f63489 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

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * JEditTextArea.java - jEdit's text component
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000, 2001, 2002 Slava Pestov
  7. * Portions copyright (C) 2000 Ollie Rutherfurd
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.textarea;
  24. //{{{ Imports
  25. import javax.swing.border.*;
  26. import javax.swing.event.*;
  27. import javax.swing.plaf.metal.MetalLookAndFeel;
  28. import javax.swing.text.Segment;
  29. import javax.swing.undo.*;
  30. import javax.swing.*;
  31. import java.awt.event.*;
  32. import java.awt.font.*;
  33. import java.awt.geom.*;
  34. import java.awt.*;
  35. import java.util.Arrays;
  36. import java.util.ArrayList;
  37. import java.util.Enumeration;
  38. import java.util.Hashtable;
  39. import java.util.Vector;
  40. import org.gjt.sp.jedit.buffer.*;
  41. import org.gjt.sp.jedit.gui.*;
  42. import org.gjt.sp.jedit.syntax.*;
  43. import org.gjt.sp.jedit.*;
  44. import org.gjt.sp.util.Log;
  45. //}}}
  46. /**
  47. * jEdit's text component.
  48. *
  49. * @author Slava Pestov
  50. * @version $Id: JEditTextArea.java 4349 2002-10-02 20:51:18Z spestov $
  51. */
  52. public class JEditTextArea extends JComponent
  53. {
  54. //{{{ JEditTextArea constructor
  55. /**
  56. * Creates a new JEditTextArea.
  57. */
  58. public JEditTextArea(View view)
  59. {
  60. enableEvents(AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK);
  61. this.view = view;
  62. //{{{ Initialize some misc. stuff
  63. selection = new Vector();
  64. chunkCache = new ChunkCache(this);
  65. painter = new TextAreaPainter(this);
  66. gutter = new Gutter(view,this);
  67. bufferHandler = new BufferChangeHandler();
  68. listenerList = new EventListenerList();
  69. caretEvent = new MutableCaretEvent();
  70. bracketLine = bracketPosition = -1;
  71. blink = true;
  72. lineSegment = new Segment();
  73. returnValue = new Point();
  74. runnables = new ArrayList();
  75. //}}}
  76. //{{{ Initialize the GUI
  77. setLayout(new ScrollLayout());
  78. add(LEFT,gutter);
  79. add(CENTER,painter);
  80. add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL));
  81. add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
  82. horizontal.setValues(0,0,0,0);
  83. //}}}
  84. //{{{ this ensures that the text area's look is slightly
  85. // more consistent with the rest of the metal l&f.
  86. // while it depends on not-so-well-documented portions
  87. // of Swing, it only affects appearance, so future
  88. // breakage shouldn't matter
  89. if(UIManager.getLookAndFeel() instanceof MetalLookAndFeel)
  90. {
  91. setBorder(new TextAreaBorder());
  92. vertical.putClientProperty("JScrollBar.isFreeStanding",
  93. Boolean.FALSE);
  94. horizontal.putClientProperty("JScrollBar.isFreeStanding",
  95. Boolean.FALSE);
  96. //horizontal.setBorder(null);
  97. }
  98. //}}}
  99. //{{{ Add some event listeners
  100. vertical.addAdjustmentListener(new AdjustHandler());
  101. horizontal.addAdjustmentListener(new AdjustHandler());
  102. mouseHandler = new MouseHandler();
  103. painter.addMouseListener(mouseHandler);
  104. painter.addMouseMotionListener(mouseHandler);
  105. addFocusListener(new FocusHandler());
  106. //}}}
  107. // This doesn't seem very correct, but it fixes a problem
  108. // when setting the initial caret position for a buffer
  109. // (eg, from the recent file list)
  110. focusedComponent = this;
  111. } //}}}
  112. //{{{ Getters and setters
  113. //{{{ getPainter() method
  114. /**
  115. * Returns the object responsible for painting this text area.
  116. */
  117. public final TextAreaPainter getPainter()
  118. {
  119. return painter;
  120. } //}}}
  121. //{{{ getGutter() method
  122. /**
  123. * Returns the gutter to the left of the text area or null if the gutter
  124. * is disabled
  125. */
  126. public final Gutter getGutter()
  127. {
  128. return gutter;
  129. } //}}}
  130. //{{{ getFoldVisibilityManager() method
  131. /**
  132. * Returns the fold visibility manager used by this text area.
  133. * @since jEdit 4.0pre1
  134. */
  135. public FoldVisibilityManager getFoldVisibilityManager()
  136. {
  137. return foldVisibilityManager;
  138. } //}}}
  139. //{{{ isCaretBlinkEnabled() method
  140. /**
  141. * Returns true if the caret is blinking, false otherwise.
  142. */
  143. public final boolean isCaretBlinkEnabled()
  144. {
  145. return caretBlinks;
  146. } //}}}
  147. //{{{ setCaretBlinkEnabled() method
  148. /**
  149. * Toggles caret blinking.
  150. * @param caretBlinks True if the caret should blink, false otherwise
  151. */
  152. public void setCaretBlinkEnabled(boolean caretBlinks)
  153. {
  154. this.caretBlinks = caretBlinks;
  155. if(!caretBlinks)
  156. blink = false;
  157. if(buffer != null)
  158. invalidateLine(caretLine);
  159. } //}}}
  160. //{{{ getElectricScroll() method
  161. /**
  162. * Returns the number of lines from the top and button of the
  163. * text area that are always visible.
  164. */
  165. public final int getElectricScroll()
  166. {
  167. return electricScroll;
  168. } //}}}
  169. //{{{ setElectricScroll() method
  170. /**
  171. * Sets the number of lines from the top and bottom of the text
  172. * area that are always visible
  173. * @param electricScroll The number of lines always visible from
  174. * the top or bottom
  175. */
  176. public final void setElectricScroll(int electricScroll)
  177. {
  178. this.electricScroll = electricScroll;
  179. } //}}}
  180. //{{{ isQuickCopyEnabled() method
  181. /**
  182. * Returns if clicking the middle mouse button pastes the most
  183. * recent selection (% register), and if Control-dragging inserts
  184. * the selection at the caret.
  185. */
  186. public final boolean isQuickCopyEnabled()
  187. {
  188. return quickCopy;
  189. } //}}}
  190. //{{{ setQuickCopyEnabled() method
  191. /**
  192. * Sets if clicking the middle mouse button pastes the most
  193. * recent selection (% register), and if Control-dragging inserts
  194. * the selection at the caret.
  195. * @param quickCopy A boolean flag
  196. */
  197. public final void setQuickCopyEnabled(boolean quickCopy)
  198. {
  199. this.quickCopy = quickCopy;
  200. } //}}}
  201. //{{{ getBuffer() method
  202. /**
  203. * Returns the buffer this text area is editing.
  204. */
  205. public final Buffer getBuffer()
  206. {
  207. return buffer;
  208. } //}}}
  209. //{{{ setBuffer() method
  210. /**
  211. * Sets the buffer this text area is editing.
  212. * @param buffer The buffer
  213. */
  214. public void setBuffer(Buffer buffer)
  215. {
  216. if(this.buffer == buffer)
  217. return;
  218. try
  219. {
  220. bufferChanging = true;
  221. if(this.buffer != null)
  222. {
  223. setFirstLine(0);
  224. selectNone();
  225. caretLine = caret = caretScreenLine = 0;
  226. bracketLine = bracketPosition = -1;
  227. this.buffer._releaseFoldVisibilityManager(foldVisibilityManager);
  228. this.buffer.removeBufferChangeListener(bufferHandler);
  229. }
  230. this.buffer = buffer;
  231. buffer.addBufferChangeListener(bufferHandler);
  232. bufferHandlerInstalled = true;
  233. foldVisibilityManager = buffer._getFoldVisibilityManager(this);
  234. chunkCache.setFirstLine(0);
  235. physFirstLine = foldVisibilityManager.getFirstVisibleLine();
  236. propertiesChanged();
  237. recalculateLastPhysicalLine();
  238. }
  239. finally
  240. {
  241. bufferChanging = false;
  242. }
  243. } //}}}
  244. //{{{ isEditable() method
  245. /**
  246. * Returns true if this text area is editable, false otherwise.
  247. */
  248. public final boolean isEditable()
  249. {
  250. return buffer.isEditable();
  251. } //}}}
  252. //{{{ getRightClickPopup() method
  253. /**
  254. * Returns the right click popup menu.
  255. */
  256. public final JPopupMenu getRightClickPopup()
  257. {
  258. return popup;
  259. } //}}}
  260. //{{{ setRightClickPopup() method
  261. /**
  262. * Sets the right click popup menu.
  263. * @param popup The popup
  264. */
  265. public final void setRightClickPopup(JPopupMenu popup)
  266. {
  267. this.popup = popup;
  268. } //}}}
  269. //}}}
  270. //{{{ Scrolling
  271. //{{{ getFirstLine() method
  272. /**
  273. * Returns the line displayed at the text area's origin. This is
  274. * a virtual, not a physical, line number.
  275. */
  276. public final int getFirstLine()
  277. {
  278. return firstLine;
  279. } //}}}
  280. //{{{ setFirstLine() method
  281. /**
  282. * Sets the line displayed at the text area's origin. This is
  283. * a virtual, not a physical, line number.
  284. */
  285. public void setFirstLine(int firstLine)
  286. {
  287. if(firstLine == this.firstLine)
  288. return;
  289. _setFirstLine(firstLine);
  290. view.synchroScrollVertical(this,firstLine);
  291. } //}}}
  292. //{{{ _setFirstLine() method
  293. public void _setFirstLine(int firstLine)
  294. {
  295. firstLine = Math.max(0,Math.min(getVirtualLineCount() - 1,firstLine));
  296. this.firstLine = firstLine;
  297. physFirstLine = virtualToPhysical(firstLine);
  298. maxHorizontalScrollWidth = 0;
  299. chunkCache.setFirstLine(firstLine);
  300. recalculateLastPhysicalLine();
  301. if(this.firstLine != vertical.getValue())
  302. updateScrollBars();
  303. painter.repaint();
  304. gutter.repaint();
  305. fireScrollEvent(true);
  306. } //}}}
  307. //{{{ getVisibleLines() method
  308. /**
  309. * Returns the number of lines visible in this text area.
  310. */
  311. public final int getVisibleLines()
  312. {
  313. return visibleLines;
  314. } //}}}
  315. //{{{ getFirstPhysicalLine() method
  316. /**
  317. * Returns the first visible physical line index.
  318. * @since jEdit 4.0pre4
  319. */
  320. public final int getFirstPhysicalLine()
  321. {
  322. return physFirstLine;
  323. } //}}}
  324. //{{{ getLastPhysicalLine() method
  325. /**
  326. * Returns the last visible physical line index.
  327. * @since jEdit 4.0pre4
  328. */
  329. public final int getLastPhysicalLine()
  330. {
  331. return physLastLine;
  332. } //}}}
  333. //{{{ getHorizontalOffset() method
  334. /**
  335. * Returns the horizontal offset of drawn lines.
  336. */
  337. public final int getHorizontalOffset()
  338. {
  339. return horizontalOffset;
  340. } //}}}
  341. //{{{ setHorizontalOffset() method
  342. /**
  343. * Sets the horizontal offset of drawn lines. This can be used to
  344. * implement horizontal scrolling.
  345. * @param horizontalOffset offset The new horizontal offset
  346. */
  347. public void setHorizontalOffset(int horizontalOffset)
  348. {
  349. if(horizontalOffset == this.horizontalOffset)
  350. return;
  351. _setHorizontalOffset(horizontalOffset);
  352. view.synchroScrollHorizontal(this,horizontalOffset);
  353. } //}}}
  354. //{{{ _setHorizontalOffset() method
  355. public void _setHorizontalOffset(int horizontalOffset)
  356. {
  357. this.horizontalOffset = horizontalOffset;
  358. if(horizontalOffset != horizontal.getValue())
  359. updateScrollBars();
  360. painter.repaint();
  361. fireScrollEvent(false);
  362. } //}}}
  363. //{{{ updateScrollBars() method
  364. /**
  365. * Updates the state of the scroll bars. This should be called
  366. * if the number of lines in the buffer changes, or when the
  367. * size of the text are changes.
  368. */
  369. public void updateScrollBars()
  370. {
  371. if(vertical != null && visibleLines != 0)
  372. {
  373. // don't display stuff past the end of the buffer if
  374. // we can help it
  375. int lineCount = getVirtualLineCount();
  376. // very stupid but proper fix will go into 4.1
  377. if(softWrap)
  378. lineCount += visibleLines - 1;
  379. if(lineCount < firstLine + visibleLines)
  380. {
  381. // this will call updateScrollBars(), so
  382. // just return...
  383. int newFirstLine = Math.max(0,lineCount - visibleLines);
  384. if(newFirstLine != firstLine)
  385. {
  386. setFirstLine(newFirstLine);
  387. return;
  388. }
  389. }
  390. vertical.setValues(firstLine,visibleLines,0,lineCount);
  391. vertical.setUnitIncrement(2);
  392. vertical.setBlockIncrement(visibleLines);
  393. }
  394. int width = painter.getWidth();
  395. if(horizontal != null && width != 0)
  396. {
  397. maxHorizontalScrollWidth = 0;
  398. painter.repaint();
  399. horizontal.setUnitIncrement(painter.getFontMetrics()
  400. .charWidth('w'));
  401. horizontal.setBlockIncrement(width / 2);
  402. }
  403. } //}}}
  404. //{{{ scrollUpLine() method
  405. /**
  406. * Scrolls up by one line.
  407. * @since jEdit 2.7pre2
  408. */
  409. public void scrollUpLine()
  410. {
  411. if(firstLine > 0)
  412. setFirstLine(firstLine - 1);
  413. else
  414. getToolkit().beep();
  415. } //}}}
  416. //{{{ scrollUpPage() method
  417. /**
  418. * Scrolls up by one page.
  419. * @since jEdit 2.7pre2
  420. */
  421. public void scrollUpPage()
  422. {
  423. if(firstLine > 0)
  424. {
  425. int newFirstLine = firstLine - visibleLines;
  426. setFirstLine(newFirstLine);
  427. }
  428. else
  429. {
  430. getToolkit().beep();
  431. }
  432. } //}}}
  433. //{{{ scrollDownLine() method
  434. /**
  435. * Scrolls down by one line.
  436. * @since jEdit 2.7pre2
  437. */
  438. public void scrollDownLine()
  439. {
  440. int numLines = getVirtualLineCount();
  441. if((softWrap && firstLine < numLines) ||
  442. (firstLine + visibleLines < numLines))
  443. setFirstLine(firstLine + 1);
  444. else
  445. getToolkit().beep();
  446. } //}}}
  447. //{{{ scrollDownPage() method
  448. /**
  449. * Scrolls down by one page.
  450. * @since jEdit 2.7pre2
  451. */
  452. public void scrollDownPage()
  453. {
  454. int numLines = getVirtualLineCount();
  455. if(firstLine + visibleLines < numLines)
  456. {
  457. int newFirstLine = firstLine + visibleLines;
  458. setFirstLine(newFirstLine + visibleLines < numLines
  459. ? newFirstLine : numLines - visibleLines);
  460. }
  461. else
  462. {
  463. getToolkit().beep();
  464. }
  465. } //}}}
  466. //{{{ scrollToCaret() method
  467. /**
  468. * Ensures that the caret is visible by scrolling the text area if
  469. * necessary.
  470. * @param doElectricScroll If true, electric scrolling will be performed
  471. */
  472. public void scrollToCaret(boolean doElectricScroll)
  473. {
  474. scrollTo(caretLine,caret - buffer.getLineStartOffset(caretLine),
  475. doElectricScroll);
  476. } //}}}
  477. //{{{ scrollTo() method
  478. /**
  479. * Ensures that the specified location in the buffer is visible.
  480. * @param line The line number
  481. * @param offset The offset from the start of the line
  482. * @param doElectricScroll If true, electric scrolling will be performed
  483. * @since jEdit 4.0pre6
  484. */
  485. public void scrollTo(int line, int offset, boolean doElectricScroll)
  486. {
  487. int _electricScroll = (doElectricScroll && visibleLines > 6
  488. ? electricScroll : 0);
  489. // visibleLines == 0 before the component is realized
  490. // we can't do any proper scrolling then, so we have
  491. // this hack...
  492. if(visibleLines == 0)
  493. {
  494. setFirstLine(physicalToVirtual(
  495. Math.max(0,line - _electricScroll)));
  496. return;
  497. }
  498. //{{{ STAGE 1 -- determine if the caret is visible.
  499. int screenLine = getScreenLineOfOffset(buffer.getLineStartOffset(line) + offset);
  500. Point point;
  501. if(screenLine != -1)
  502. {
  503. // It's visible, but is it too close to the borders?
  504. int height = painter.getFontMetrics().getHeight();
  505. Rectangle rect = new Rectangle(0,height * _electricScroll,
  506. painter.getWidth() - 5,visibleLines * height
  507. - height * _electricScroll * 2);
  508. point = offsetToXY(line,offset,returnValue);
  509. if(rect.contains(point))
  510. return;
  511. }
  512. else
  513. point = null;
  514. //}}}
  515. //{{{ STAGE 2 -- scroll vertically
  516. if(line == physLastLine + 1)
  517. {
  518. int count = chunkCache.getLineInfosForPhysicalLine(physLastLine).length
  519. + chunkCache.getLineInfosForPhysicalLine(physLastLine + 1).length
  520. + _electricScroll;
  521. while(count > 0)
  522. {
  523. count -= chunkCache.getLineInfosForPhysicalLine(physFirstLine).length;
  524. firstLine++;
  525. physFirstLine = foldVisibilityManager.getNextVisibleLine(physFirstLine);
  526. }
  527. }
  528. else if(screenLine == -1)
  529. {
  530. if(line == physLastLine)
  531. {
  532. int count = chunkCache.getLineInfosForPhysicalLine(physLastLine).length
  533. + _electricScroll;
  534. while(count > 0)
  535. {
  536. count -= chunkCache.getLineInfosForPhysicalLine(physFirstLine).length;
  537. firstLine++;
  538. int nextLine = foldVisibilityManager.getNextVisibleLine(physFirstLine);
  539. if(nextLine == -1)
  540. break;
  541. else
  542. physFirstLine = nextLine;
  543. }
  544. }
  545. int virtualLine = foldVisibilityManager.physicalToVirtual(line);
  546. if(virtualLine == firstLine - 1)
  547. {
  548. firstLine = Math.max(0,firstLine - _electricScroll - 1);
  549. physFirstLine = foldVisibilityManager.virtualToPhysical(firstLine);
  550. }
  551. else
  552. {
  553. // keep chunking lines until we have visibleLines / 2
  554. if(!softWrap && virtualLine >= foldVisibilityManager.getVirtualLineCount()
  555. - visibleLines / 2)
  556. {
  557. firstLine = foldVisibilityManager.getVirtualLineCount()
  558. - visibleLines;
  559. physFirstLine = foldVisibilityManager
  560. .virtualToPhysical(firstLine);
  561. }
  562. else
  563. {
  564. physFirstLine = line;
  565. int count = 0;
  566. for(;;)
  567. {
  568. if(foldVisibilityManager.isLineVisible(physFirstLine))
  569. {
  570. int incr = chunkCache.getLineInfosForPhysicalLine(physFirstLine).length;
  571. if(count + incr > visibleLines / 2)
  572. break;
  573. else
  574. count += incr;
  575. }
  576. if(physFirstLine == 0)
  577. break;
  578. else
  579. {
  580. physFirstLine = foldVisibilityManager
  581. .getPrevVisibleLine(physFirstLine);
  582. }
  583. }
  584. firstLine = physicalToVirtual(physFirstLine);
  585. }
  586. }
  587. }
  588. else if(screenLine < _electricScroll && firstLine != 0)
  589. {
  590. int count = _electricScroll - screenLine;
  591. while(count > 0 && firstLine > 0)
  592. {
  593. count -= chunkCache.getLineInfosForPhysicalLine(physFirstLine).length;
  594. firstLine--;
  595. physFirstLine = foldVisibilityManager.getPrevVisibleLine(physFirstLine);
  596. }
  597. }
  598. else if(screenLine >= visibleLines - _electricScroll)
  599. {
  600. int count = _electricScroll - visibleLines + screenLine + 1;
  601. while(count > 0 && firstLine <= getVirtualLineCount())
  602. {
  603. count -= chunkCache.getLineInfosForPhysicalLine(physFirstLine).length;
  604. firstLine++;
  605. physFirstLine = foldVisibilityManager.getNextVisibleLine(physFirstLine);
  606. }
  607. }
  608. chunkCache.setFirstLine(firstLine);
  609. recalculateLastPhysicalLine();
  610. if(point == null)
  611. {
  612. point = offsetToXY(line,offset,returnValue);
  613. if(point == null)
  614. {
  615. // a soft wrapped line has more screen lines
  616. // than the number of visible lines
  617. return;
  618. }
  619. } //}}}
  620. //{{{ STAGE 3 -- scroll horizontally
  621. if(point.x < 0)
  622. {
  623. horizontalOffset = Math.min(0,horizontalOffset
  624. - point.x + charWidth + 5);
  625. }
  626. else if(point.x >= painter.getWidth() - charWidth - 5)
  627. {
  628. horizontalOffset = horizontalOffset +
  629. (painter.getWidth() - point.x)
  630. - charWidth - 5;
  631. } //}}}
  632. //{{{ STAGE 4 -- update some stuff
  633. updateScrollBars();
  634. painter.repaint();
  635. gutter.repaint();
  636. view.synchroScrollVertical(this,firstLine);
  637. view.synchroScrollHorizontal(this,horizontalOffset);
  638. // fire events for both a horizontal and vertical scroll
  639. fireScrollEvent(true);
  640. fireScrollEvent(false);
  641. //}}}
  642. } //}}}
  643. //{{{ addScrollListener() method
  644. /**
  645. * Adds a scroll listener to this text area.
  646. * @param listener The listener
  647. * @since jEdit 3.2pre2
  648. */
  649. public final void addScrollListener(ScrollListener listener)
  650. {
  651. listenerList.add(ScrollListener.class,listener);
  652. } //}}}
  653. //{{{ removeScrollListener() method
  654. /**
  655. * Removes a scroll listener from this text area.
  656. * @param listener The listener
  657. * @since jEdit 3.2pre2
  658. */
  659. public final void removeScrollListener(ScrollListener listener)
  660. {
  661. listenerList.remove(ScrollListener.class,listener);
  662. } //}}}
  663. //}}}
  664. //{{{ Screen line stuff
  665. //{{{ getPhysicalLineOfScreenLine() method
  666. /**
  667. * Returns the physical line number that contains the specified screen
  668. * line.
  669. * @param screenLine The screen line
  670. * @since jEdit 4.0pre6
  671. */
  672. public int getPhysicalLineOfScreenLine(int screenLine)
  673. {
  674. return chunkCache.getLineInfo(screenLine).physicalLine;
  675. } //}}}
  676. //{{{ getScreenLineOfOffset() method
  677. /**
  678. * Returns the screen (wrapped) line containing the specified offset.
  679. * @param offset The offset
  680. * @since jEdit 4.0pre4
  681. */
  682. public int getScreenLineOfOffset(int offset)
  683. {
  684. int line = buffer.getLineOfOffset(offset);
  685. offset -= buffer.getLineStartOffset(line);
  686. return chunkCache.getScreenLineOfOffset(line,offset);
  687. } //}}}
  688. //{{{ getScreenLineStartOffset() method
  689. /**
  690. * Returns the start offset of the specified screen (wrapped) line.
  691. * @param line The line
  692. * @since jEdit 4.0pre4
  693. */
  694. public int getScreenLineStartOffset(int line)
  695. {
  696. chunkCache.updateChunksUpTo(line);
  697. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
  698. if(lineInfo.physicalLine == -1)
  699. return -1;
  700. return buffer.getLineStartOffset(lineInfo.physicalLine)
  701. + lineInfo.offset;
  702. } //}}}
  703. //{{{ getScreenLineEndOffset() method
  704. /**
  705. * Returns the end offset of the specified screen (wrapped) line.
  706. * @param line The line
  707. * @since jEdit 4.0pre4
  708. */
  709. public int getScreenLineEndOffset(int line)
  710. {
  711. chunkCache.updateChunksUpTo(line);
  712. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
  713. if(lineInfo.physicalLine == -1)
  714. return -1;
  715. return buffer.getLineStartOffset(lineInfo.physicalLine)
  716. + lineInfo.offset + lineInfo.length;
  717. } //}}}
  718. //}}}
  719. //{{{ Offset conversion
  720. //{{{ xyToOffset() method
  721. /**
  722. * Converts a point to an offset.
  723. * Note that unlike in previous jEdit versions, this method now returns
  724. * -1 if the y co-ordinate is out of bounds.
  725. *
  726. * @param x The x co-ordinate of the point
  727. * @param y The y co-ordinate of the point
  728. */
  729. public int xyToOffset(int x, int y)
  730. {
  731. return xyToOffset(x,y,true);
  732. } //}}}
  733. //{{{ xyToOffset() method
  734. /**
  735. * Converts a point to an offset.
  736. * Note that unlike in previous jEdit versions, this method now returns
  737. * -1 if the y co-ordinate is out of bounds.
  738. *
  739. * @param x The x co-ordinate of the point
  740. * @param y The y co-ordinate of the point
  741. * @param round Round up to next letter if past the middle of a letter?
  742. * @since jEdit 3.2pre6
  743. */
  744. public int xyToOffset(int x, int y, boolean round)
  745. {
  746. FontMetrics fm = painter.getFontMetrics();
  747. int height = fm.getHeight();
  748. int line = y / height;
  749. if(line < 0 || line > visibleLines)
  750. return -1;
  751. chunkCache.updateChunksUpTo(line);
  752. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
  753. if(!lineInfo.chunksValid)
  754. System.err.println("xy to offset: not valid");
  755. if(lineInfo.physicalLine == -1)
  756. {
  757. return getLineEndOffset(foldVisibilityManager
  758. .getLastVisibleLine()) - 1;
  759. }
  760. else
  761. {
  762. int offset = Chunk.xToOffset(lineInfo.chunks,
  763. x - horizontalOffset,round);
  764. if(offset == -1 || offset == lineInfo.offset + lineInfo.length)
  765. offset = lineInfo.offset + lineInfo.length - 1;
  766. return getLineStartOffset(lineInfo.physicalLine) + offset;
  767. }
  768. } //}}}
  769. //{{{ offsetToXY() method
  770. /**
  771. * Converts an offset into a point in the text area painter's
  772. * co-ordinate space.
  773. * @param offset The offset
  774. * @return The location of the offset on screen, or <code>null</code>
  775. * if the specified offset is not visible
  776. */
  777. public Point offsetToXY(int offset)
  778. {
  779. int line = buffer.getLineOfOffset(offset);
  780. offset -= buffer.getLineStartOffset(line);
  781. Point retVal = new Point();
  782. return offsetToXY(line,offset,retVal);
  783. } //}}}
  784. //{{{ offsetToXY() method
  785. /**
  786. * Converts an offset into a point in the text area painter's
  787. * co-ordinate space.
  788. * @param line The physical line number
  789. * @param offset The offset, from the start of the line
  790. * @param retVal The point to store the return value in
  791. * @return <code>retVal</code> for convenience, or <code>null</code>
  792. * if the specified offset is not visible
  793. * @since jEdit 4.0pre4
  794. */
  795. public Point offsetToXY(int line, int offset, Point retVal)
  796. {
  797. int screenLine = chunkCache.getScreenLineOfOffset(line,offset);
  798. if(screenLine == -1)
  799. {
  800. if(line < physFirstLine)
  801. return null;
  802. // must have >= here because the last physical line
  803. // might only be partially visible (some offsets would
  804. // have a screen line, others would return -1 and hence
  805. // this code would be executed)
  806. else if(line >= physLastLine)
  807. return null;
  808. else
  809. {
  810. throw new InternalError("line=" + line
  811. + ",offset=" + offset
  812. + ",screenLine=" + screenLine
  813. + ",physFirstLine=" + physFirstLine
  814. + ",physLastLine=" + physLastLine);
  815. }
  816. }
  817. FontMetrics fm = painter.getFontMetrics();
  818. retVal.y = screenLine * fm.getHeight();
  819. ChunkCache.LineInfo info = chunkCache.getLineInfo(screenLine);
  820. if(!info.chunksValid)
  821. System.err.println("offset to xy: not valid");
  822. retVal.x = (int)(horizontalOffset + Chunk.offsetToX(
  823. info.chunks,offset));
  824. return retVal;
  825. } //}}}
  826. //}}}
  827. //{{{ Painting
  828. //{{{ invalidateScreenLineRange() method
  829. /**
  830. * Marks a range of screen lines as needing a repaint.
  831. * @param start The first line
  832. * @param end The last line
  833. * @since jEdit 4.0pre4
  834. */
  835. public void invalidateScreenLineRange(int start, int end)
  836. {
  837. if(chunkCache.needFullRepaint())
  838. {
  839. recalculateLastPhysicalLine();
  840. gutter.repaint();
  841. painter.repaint();
  842. return;
  843. }
  844. if(start > end)
  845. {
  846. int tmp = end;
  847. end = start;
  848. start = tmp;
  849. }
  850. FontMetrics fm = painter.getFontMetrics();
  851. int y = start * fm.getHeight();
  852. int height = (end - start + 1) * fm.getHeight();
  853. painter.repaint(0,y,painter.getWidth(),height);
  854. gutter.repaint(0,y,gutter.getWidth(),height);
  855. } //}}}
  856. //{{{ invalidateLine() method
  857. /**
  858. * Marks a line as needing a repaint.
  859. * @param line The physical line to invalidate
  860. */
  861. public void invalidateLine(int line)
  862. {
  863. if(line < physFirstLine || line > physLastLine
  864. || !foldVisibilityManager.isLineVisible(line))
  865. return;
  866. int startLine = -1;
  867. int endLine = -1;
  868. for(int i = 0; i <= visibleLines; i++)
  869. {
  870. chunkCache.updateChunksUpTo(i);
  871. ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
  872. if((info.physicalLine >= line || info.physicalLine == -1)
  873. && startLine == -1)
  874. {
  875. startLine = i;
  876. }
  877. if((info.physicalLine >= line && info.lastSubregion)
  878. || info.physicalLine == -1)
  879. {
  880. endLine = i;
  881. break;
  882. }
  883. }
  884. if(chunkCache.needFullRepaint())
  885. {
  886. recalculateLastPhysicalLine();
  887. endLine = visibleLines;
  888. }
  889. else if(endLine == -1)
  890. endLine = visibleLines;
  891. //if(startLine != endLine)
  892. // System.err.println(startLine + ":" + endLine);
  893. invalidateScreenLineRange(startLine,endLine);
  894. } //}}}
  895. //{{{ invalidateLineRange() method
  896. /**
  897. * Marks a range of physical lines as needing a repaint.
  898. * @param start The first line to invalidate
  899. * @param end The last line to invalidate
  900. */
  901. public void invalidateLineRange(int start, int end)
  902. {
  903. if(end < start)
  904. {
  905. int tmp = end;
  906. end = start;
  907. start = tmp;
  908. }
  909. if(end < physFirstLine || start > physLastLine)
  910. return;
  911. int startScreenLine = -1;
  912. int endScreenLine = -1;
  913. for(int i = 0; i <= visibleLines; i++)
  914. {
  915. chunkCache.updateChunksUpTo(i);
  916. ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
  917. if((info.physicalLine >= start || info.physicalLine == -1)
  918. && startScreenLine == -1)
  919. {
  920. startScreenLine = i;
  921. }
  922. if((info.physicalLine >= end && info.lastSubregion)
  923. || info.physicalLine == -1)
  924. {
  925. endScreenLine = i;
  926. break;
  927. }
  928. }
  929. if(startScreenLine == -1)
  930. startScreenLine = 0;
  931. if(chunkCache.needFullRepaint())
  932. {
  933. recalculateLastPhysicalLine();
  934. endScreenLine = visibleLines;
  935. }
  936. else if(endScreenLine == -1)
  937. endScreenLine = visibleLines;
  938. invalidateScreenLineRange(startScreenLine,endScreenLine);
  939. } //}}}
  940. //{{{ invalidateSelectedLines() method
  941. /**
  942. * Repaints the lines containing the selection.
  943. */
  944. public void invalidateSelectedLines()
  945. {
  946. // to hide line highlight if selections are being added later on
  947. invalidateLine(caretLine);
  948. for(int i = 0; i < selection.size(); i++)
  949. {
  950. Selection s = (Selection)selection.elementAt(i);
  951. invalidateLineRange(s.startLine,s.endLine);
  952. }
  953. } //}}}
  954. //}}}
  955. //{{{ Convenience methods
  956. //{{{ physicalToVirtual() method
  957. /**
  958. * Converts a physical line number to a virtual line number.
  959. * @param line A physical line index
  960. * @since jEdit 4.0pre1
  961. */
  962. public int physicalToVirtual(int line)
  963. {
  964. return foldVisibilityManager.physicalToVirtual(line);
  965. } //}}}
  966. //{{{ virtualToPhysical() method
  967. /**
  968. * Converts a virtual line number to a physical line number.
  969. * @param line A virtual line index
  970. * @since jEdit 4.0pre1
  971. */
  972. public int virtualToPhysical(int line)
  973. {
  974. return foldVisibilityManager.virtualToPhysical(line);
  975. } //}}}
  976. //{{{ getBufferLength() method
  977. /**
  978. * Returns the length of the buffer.
  979. */
  980. public final int getBufferLength()
  981. {
  982. return buffer.getLength();
  983. } //}}}
  984. //{{{ getLineCount() method
  985. /**
  986. * Returns the number of physical lines in the buffer.
  987. */
  988. public final int getLineCount()
  989. {
  990. return buffer.getLineCount();
  991. } //}}}
  992. //{{{ getVirtualLineCount() method
  993. /**
  994. * Returns the number of virtual lines in the buffer.
  995. */
  996. public final int getVirtualLineCount()
  997. {
  998. return foldVisibilityManager.getVirtualLineCount();
  999. } //}}}
  1000. //{{{ getLineOfOffset() method
  1001. /**
  1002. * Returns the line containing the specified offset.
  1003. * @param offset The offset
  1004. */
  1005. public final int getLineOfOffset(int offset)
  1006. {
  1007. return buffer.getLineOfOffset(offset);
  1008. } //}}}
  1009. //{{{ getLineStartOffset() method
  1010. /**
  1011. * Returns the start offset of the specified line.
  1012. * @param line The line
  1013. * @return The start offset of the specified line, or -1 if the line is
  1014. * invalid
  1015. */
  1016. public int getLineStartOffset(int line)
  1017. {
  1018. return buffer.getLineStartOffset(line);
  1019. } //}}}
  1020. //{{{ getLineEndOffset() method
  1021. /**
  1022. * Returns the end offset of the specified line.
  1023. * @param line The line
  1024. * @return The end offset of the specified line, or -1 if the line is
  1025. * invalid.
  1026. */
  1027. public int getLineEndOffset(int line)
  1028. {
  1029. return buffer.getLineEndOffset(line);
  1030. } //}}}
  1031. //{{{ getLineLength() method
  1032. /**
  1033. * Returns the length of the specified line.
  1034. * @param line The line
  1035. */
  1036. public int getLineLength(int line)
  1037. {
  1038. return buffer.getLineLength(line);
  1039. } //}}}
  1040. //{{{ getText() method
  1041. /**
  1042. * Returns the specified substring of the buffer.
  1043. * @param start The start offset
  1044. * @param len The length of the substring
  1045. * @return The substring
  1046. */
  1047. public final String getText(int start, int len)
  1048. {
  1049. return buffer.getText(start,len);
  1050. } //}}}
  1051. //{{{ getText() method
  1052. /**
  1053. * Copies the specified substring of the buffer into a segment.
  1054. * @param start The start offset
  1055. * @param len The length of the substring
  1056. * @param segment The segment
  1057. */
  1058. public final void getText(int start, int len, Segment segment)
  1059. {
  1060. buffer.getText(start,len,segment);
  1061. } //}}}
  1062. //{{{ getLineText() method
  1063. /**
  1064. * Returns the text on the specified line.
  1065. * @param lineIndex The line
  1066. * @return The text, or null if the line is invalid
  1067. */
  1068. public final String getLineText(int lineIndex)
  1069. {
  1070. return buffer.getLineText(lineIndex);
  1071. } //}}}
  1072. //{{{ getLineText() method
  1073. /**
  1074. * Copies the text on the specified line into a segment. If the line
  1075. * is invalid, the segment will contain a null string.
  1076. * @param lineIndex The line
  1077. */
  1078. public final void getLineText(int lineIndex, Segment segment)
  1079. {
  1080. buffer.getLineText(lineIndex,segment);
  1081. } //}}}
  1082. //{{{ getText() method
  1083. /**
  1084. * Returns the entire text of this text area.
  1085. */
  1086. public String getText()
  1087. {
  1088. return buffer.getText(0,buffer.getLength());
  1089. } //}}}
  1090. //{{{ setText() method
  1091. /**
  1092. * Sets the entire text of this text area.
  1093. */
  1094. public void setText(String text)
  1095. {
  1096. try
  1097. {
  1098. buffer.beginCompoundEdit();
  1099. buffer.remove(0,buffer.getLength());
  1100. buffer.insert(0,text);
  1101. }
  1102. finally
  1103. {
  1104. buffer.endCompoundEdit();
  1105. }
  1106. } //}}}
  1107. //}}}
  1108. //{{{ Selection
  1109. //{{{ selectAll() method
  1110. /**
  1111. * Selects all text in the buffer.
  1112. */
  1113. public final void selectAll()
  1114. {
  1115. setSelection(new Selection.Range(0,buffer.getLength()));
  1116. moveCaretPosition(buffer.getLength(),true);
  1117. } //}}}
  1118. //{{{ selectLine() method
  1119. /**
  1120. * Selects the current line.
  1121. * @since jEdit 2.7pre2
  1122. */
  1123. public void selectLine()
  1124. {
  1125. int caretLine = getCaretLine();
  1126. int start = getLineStartOffset(caretLine);
  1127. int end = getLineEndOffset(caretLine) - 1;
  1128. Selection s = new Selection.Range(start,end);
  1129. if(multi)
  1130. addToSelection(s);
  1131. else
  1132. setSelection(s);
  1133. moveCaretPosition(end);
  1134. } //}}}
  1135. //{{{ selectParagraph() method
  1136. /**
  1137. * Selects the paragraph at the caret position.
  1138. * @since jEdit 2.7pre2
  1139. */
  1140. public void selectParagraph()
  1141. {
  1142. int caretLine = getCaretLine();
  1143. if(getLineLength(caretLine) == 0)
  1144. {
  1145. view.getToolkit().beep();
  1146. return;
  1147. }
  1148. int start = caretLine;
  1149. int end = caretLine;
  1150. while(start >= 0)
  1151. {
  1152. if(getLineLength(start) == 0)
  1153. break;
  1154. else
  1155. start--;
  1156. }
  1157. while(end < getLineCount())
  1158. {
  1159. if(getLineLength(end) == 0)
  1160. break;
  1161. else
  1162. end++;
  1163. }
  1164. int selectionStart = getLineStartOffset(start + 1);
  1165. int selectionEnd = getLineEndOffset(end - 1) - 1;
  1166. Selection s = new Selection.Range(selectionStart,selectionEnd);
  1167. if(multi)
  1168. addToSelection(s);
  1169. else
  1170. setSelection(s);
  1171. moveCaretPosition(selectionEnd);
  1172. } //}}}
  1173. //{{{ selectWord() method
  1174. /**
  1175. * Selects the word at the caret position.
  1176. * @since jEdit 2.7pre2
  1177. */
  1178. public void selectWord()
  1179. {
  1180. int line = getCaretLine();
  1181. int lineStart = getLineStartOffset(line);
  1182. int offset = getCaretPosition() - lineStart;
  1183. if(getLineLength(line) == 0)
  1184. return;
  1185. String lineText = getLineText(line);
  1186. String noWordSep = buffer.getStringProperty("noWordSep");
  1187. if(offset == getLineLength(line))
  1188. offset--;
  1189. int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
  1190. int wordEnd = TextUtilities.findWordEnd(lineText,offset+1,noWordSep);
  1191. Selection s = new Selection.Range(lineStart + wordStart,
  1192. lineStart + wordEnd);
  1193. if(multi)
  1194. addToSelection(s);
  1195. else
  1196. setSelection(s);
  1197. moveCaretPosition(lineStart + wordEnd);
  1198. } //}}}
  1199. //{{{ selectToMatchingBracket() method
  1200. /**
  1201. * Selects from the bracket at the specified position to the
  1202. * corresponding bracket. Returns <code>true</code> if successful (i.e.
  1203. * there's a bracket at the specified position and there's a matching
  1204. * bracket for it), <code>false</code> otherwise.
  1205. * @since jEdit 4.1pre1
  1206. */
  1207. public boolean selectToMatchingBracket(int position)
  1208. {
  1209. int positionLine = buffer.getLineOfOffset(position);
  1210. int lineOffset = position - buffer.getLineStartOffset(positionLine);
  1211. int bracket = TextUtilities.findMatchingBracket(buffer,positionLine,lineOffset);
  1212. if(bracket != -1)
  1213. {
  1214. Selection s;
  1215. if(bracket < position)
  1216. {
  1217. moveCaretPosition(position,false);
  1218. s = new Selection.Range(++bracket,position);
  1219. }
  1220. else
  1221. {
  1222. moveCaretPosition(position + 1,false);
  1223. s = new Selection.Range(position + 1,bracket);
  1224. }
  1225. if(!multi)
  1226. selectNone();
  1227. addToSelection(s);
  1228. return true;
  1229. }
  1230. return false;
  1231. } //}}}
  1232. //{{{ selectToMatchingBracket() method
  1233. /**
  1234. * Selects from the bracket at the caret position to the corresponding
  1235. * bracket.
  1236. * @since jEdit 4.0pre2
  1237. */
  1238. public void selectToMatchingBracket()
  1239. {
  1240. // since we might change it below
  1241. int caret = this.caret;
  1242. int offset = caret - buffer.getLineStartOffset(caretLine);
  1243. if(buffer.getLineLength(caretLine) == 0)
  1244. return;
  1245. if(offset == buffer.getLineLength(caretLine))
  1246. caret--;
  1247. selectToMatchingBracket(caret);
  1248. } //}}}
  1249. //{{{ selectBlock() method
  1250. /**
  1251. * Selects the code block surrounding the caret.
  1252. * @since jEdit 2.7pre2
  1253. */
  1254. public void selectBlock()
  1255. {
  1256. String openBrackets = "([{";
  1257. String closeBrackets = ")]}";
  1258. Selection s = getSelectionAtOffset(caret);
  1259. int start, end;
  1260. if(s == null)
  1261. start = end = caret;
  1262. else
  1263. {
  1264. start = s.start;
  1265. end = s.end;
  1266. }
  1267. String text = getText(0,buffer.getLength());
  1268. // Scan backwards, trying to find a bracket
  1269. int count = 1;
  1270. char openBracket = '\0';
  1271. char closeBracket = '\0';
  1272. // We can't do the backward scan if start == 0
  1273. if(start == 0)
  1274. {
  1275. view.getToolkit().beep();
  1276. return;
  1277. }
  1278. backward_scan: while(--start > 0)
  1279. {
  1280. char c = text.charAt(start);
  1281. int index = openBrackets.indexOf(c);
  1282. if(index != -1)
  1283. {
  1284. if(--count == 0)
  1285. {
  1286. openBracket = c;
  1287. closeBracket = closeBrackets.charAt(index);
  1288. break backward_scan;
  1289. }
  1290. }
  1291. else if(closeBrackets.indexOf(c) != -1)
  1292. count++;
  1293. }
  1294. // Reset count
  1295. count = 1;
  1296. // Scan forward, matching that bracket
  1297. if(openBracket == '\0')
  1298. {
  1299. getToolkit().beep();
  1300. return;
  1301. }
  1302. else
  1303. {
  1304. forward_scan: do
  1305. {
  1306. char c = text.charAt(end);
  1307. if(c == closeBracket)
  1308. {
  1309. if(--count == 0)
  1310. {
  1311. end++;
  1312. break forward_scan;
  1313. }
  1314. }
  1315. else if(c == openBracket)
  1316. count++;
  1317. }
  1318. while(++end < buffer.getLength());
  1319. }
  1320. s = new Selection.Range(start,end);
  1321. if(multi)
  1322. addToSelection(s);
  1323. else
  1324. setSelection(s);
  1325. moveCaretPosition(end);
  1326. } //}}}
  1327. //{{{ invertSelection() method
  1328. /**
  1329. * Inverts the selection.
  1330. * @since jEdit 4.0pre1
  1331. */
  1332. public final void invertSelection()
  1333. {
  1334. Selection[] newSelection = new Selection[selection.size() + 1];
  1335. int lastOffset = 0;
  1336. for(int i = 0; i < selection.size(); i++)
  1337. {
  1338. Selection s = (Selection)selection.elementAt(i);
  1339. newSelection[i] = new Selection.Range(lastOffset,
  1340. s.getStart());
  1341. lastOffset = s.getEnd();
  1342. }
  1343. newSelection[selection.size()] = new Selection.Range(
  1344. lastOffset,buffer.getLength());
  1345. setSelection(newSelection);
  1346. } //}}}
  1347. //{{{ getSelectionCount() method
  1348. /**
  1349. * Returns the number of selections. This is primarily for use by the
  1350. * the status bar.
  1351. * @since jEdit 3.2pre2
  1352. */
  1353. public int getSelectionCount()
  1354. {
  1355. return selection.size();
  1356. } //}}}
  1357. //{{{ getSelection() method
  1358. /**
  1359. * Returns the current selection.
  1360. * @since jEdit 3.2pre1
  1361. */
  1362. public Selection[] getSelection()
  1363. {
  1364. Selection[] sel = new Selection[selection.size()];
  1365. selection.copyInto(sel);
  1366. return sel;
  1367. } //}}}
  1368. //{{{ selectNone() method
  1369. /**
  1370. * Deselects everything.
  1371. */
  1372. public void selectNone()
  1373. {
  1374. setSelection((Selection)null);
  1375. } //}}}
  1376. //{{{ setSelection() method
  1377. /**
  1378. * Sets the selection.
  1379. * @param selection The new selection
  1380. * since jEdit 3.2pre1
  1381. */
  1382. public void setSelection(Selection[] selection)
  1383. {
  1384. // invalidate the old selection
  1385. invalidateSelectedLines();
  1386. this.selection.removeAllElements();
  1387. if(selection != null)
  1388. {
  1389. for(int i = 0; i < selection.length; i++)
  1390. _addToSelection(selection[i]);
  1391. }
  1392. fireCaretEvent();
  1393. } //}}}
  1394. //{{{ setSelection() method
  1395. /**
  1396. * Sets the selection.
  1397. * @param selection The new selection
  1398. * since jEdit 3.2pre1
  1399. */
  1400. public void setSelection(Selection selection)
  1401. {
  1402. invalidateSelectedLines();
  1403. this.selection.removeAllElements();
  1404. if(selection != null)
  1405. _addToSelection(selection);
  1406. fireCaretEvent();
  1407. } //}}}
  1408. //{{{ addToSelection() method
  1409. /**
  1410. * Adds to the selection.
  1411. * @param selection The new selection
  1412. * since jEdit 3.2pre1
  1413. */
  1414. public void addToSelection(Selection[] selection)
  1415. {
  1416. if(selection != null)
  1417. {
  1418. for(int i = 0; i < selection.length; i++)
  1419. _addToSelection(selection[i]);
  1420. }
  1421. // to hide current line highlight
  1422. invalidateLine(caretLine);
  1423. fireCaretEvent();
  1424. } //}}}
  1425. //{{{ addToSelection() method
  1426. /**
  1427. * Adds to the selection.
  1428. * @param selection The new selection
  1429. * since jEdit 3.2pre1
  1430. */
  1431. public void addToSelection(Selection selection)
  1432. {
  1433. _addToSelection(selection);
  1434. // to hide current line highlight
  1435. invalidateLine(caretLine);
  1436. fireCaretEvent();
  1437. } //}}}
  1438. //{{{ getSelectionAtOffset() method
  1439. /**
  1440. * Returns the selection containing the specific offset, or null
  1441. * if there is no selection at that offset.
  1442. * @param offset The offset
  1443. * @since jEdit 3.2pre1
  1444. */
  1445. public Selection getSelectionAtOffset(int offset)
  1446. {
  1447. if(selection != null)
  1448. {
  1449. for(int i = 0; i < selection.size(); i++)
  1450. {
  1451. Selection s = (Selection)selection.elementAt(i);
  1452. if(offset >= s.start && offset <= s.end)
  1453. return s;
  1454. }
  1455. }
  1456. return null;
  1457. } //}}}
  1458. //{{{ removeFromSelection() method
  1459. /**
  1460. * Deactivates the specified selection.
  1461. * @param s The selection
  1462. * @since jEdit 3.2pre1
  1463. */
  1464. public void removeFromSelection(Selection sel)
  1465. {
  1466. selection.removeElement(sel);
  1467. invalidateLineRange(sel.startLine,sel.endLine);
  1468. // to hide current line highlight
  1469. invalidateLine(caretLine);
  1470. fireCaretEvent();
  1471. } //}}}
  1472. //{{{ removeFromSelection() method
  1473. /**
  1474. * Deactivates the selection at the specified offset. If there is
  1475. * no selection at that offset, does nothing.
  1476. * @param offset The offset
  1477. * @since jEdit 3.2pre1
  1478. */
  1479. public void removeFromSelection(int offset)
  1480. {
  1481. Selection sel = getSelectionAtOffset(offset);
  1482. if(sel == null)
  1483. return;
  1484. selection.removeElement(sel);
  1485. invalidateLineRange(sel.startLine,sel.endLine);
  1486. // to hide current line highlight
  1487. invalidateLine(caretLine);
  1488. fireCaretEvent();
  1489. } //}}}
  1490. //{{{ resizeSelection() method
  1491. /**
  1492. * Resizes the selection at the specified offset, or creates a new
  1493. * one if there is no selection at the specified offset. This is a
  1494. * utility method that is mainly useful in the mouse event handler
  1495. * because it handles the case of end being before offset gracefully
  1496. * (unlike the rest of the selection API).
  1497. * @param offset The offset
  1498. * @param end The new selection end
  1499. * @param extraEndVirt Only for rectangular selections - specifies how
  1500. * far it extends into virtual space.
  1501. * @param rect Make the selection rectangular?
  1502. * @since jEdit 3.2pre1
  1503. */
  1504. public void resizeSelection(int offset, int end, int extraEndVirt,
  1505. boolean rect)
  1506. {
  1507. Selection s = getSelectionAtOffset(offset);
  1508. if(s != null)
  1509. {
  1510. invalidateLineRange(s.startLine,s.endLine);
  1511. selection.removeElement(s);
  1512. }
  1513. boolean reversed = false;
  1514. if(end < offset)
  1515. {
  1516. int tmp = offset;
  1517. offset = end;
  1518. end = tmp;
  1519. reversed = true;
  1520. }
  1521. Selection newSel;
  1522. if(rect)
  1523. {
  1524. Selection.Rect rectSel = new Selection.Rect(offset,end);
  1525. if(reversed)
  1526. rectSel.extraStartVirt = extraEndVirt;
  1527. else
  1528. rectSel.extraEndVirt = extraEndVirt;
  1529. newSel = rectSel;
  1530. }
  1531. else
  1532. newSel = new Selection.Range(offset,end);
  1533. _addToSelection(newSel);
  1534. fireCaretEvent();
  1535. } //}}}
  1536. //{{{ extendSelection() method
  1537. /**
  1538. * Extends the selection at the specified offset, or creates a new
  1539. * one if there is no selection at the specified offset. This is
  1540. * different from resizing in that the new chunk is added to the
  1541. * selection in question, instead of replacing it.
  1542. * @param offset The offset
  1543. * @param end The new selection end
  1544. * @param rect Make the selection rectangular?
  1545. * @since jEdit 3.2pre1
  1546. */
  1547. public void extendSelection(int offset, int end)
  1548. {
  1549. Selection s = getSelectionAtOffset(offset);
  1550. if(s != null)
  1551. {
  1552. invalidateLineRange(s.startLine,s.endLine);
  1553. selection.removeElement(s);
  1554. if(offset == s.start)
  1555. {
  1556. offset = end;
  1557. end = s.end;
  1558. }
  1559. else if(offset == s.end)
  1560. {
  1561. offset = s.start;
  1562. }
  1563. }
  1564. if(end < offset)
  1565. {
  1566. int tmp = end;
  1567. end = offset;
  1568. offset = tmp;
  1569. }
  1570. _addToSelection(new Selection.Range(offset,end));
  1571. fireCaretEvent();
  1572. } //}}}
  1573. //{{{ getSelectedText() method
  1574. /**
  1575. * Returns the text in the specified selection.
  1576. * @param s The selection
  1577. * @since jEdit 3.2pre1
  1578. */
  1579. public String getSelectedText(Selection s)
  1580. {
  1581. StringBuffer buf = new StringBuffer();
  1582. s.getText(buffer,buf);
  1583. return buf.toString();
  1584. } //}}}
  1585. //{{{ getSelectedText() method
  1586. /**
  1587. * Returns the text in all active selections.
  1588. * @param separator The string to insert between each text chunk
  1589. * (for example, a newline)
  1590. * @since jEdit 3.2pre1
  1591. */
  1592. public String getSelectedText(String separator)
  1593. {
  1594. if(selection.size() == 0)
  1595. return null;
  1596. StringBuffer buf = new StringBuffer();
  1597. for(int i = 0; i < selection.size(); i++)
  1598. {
  1599. if(i != 0)
  1600. buf.append(separator);
  1601. ((Selection)selection.elementAt(i)).getText(buffer,buf);
  1602. }
  1603. return buf.toString();
  1604. } //}}}
  1605. //{{{ getSelectedText() method
  1606. /**
  1607. * Returns the text in all active selections, with a newline
  1608. * between each text chunk.
  1609. */
  1610. public String getSelectedText()
  1611. {
  1612. return getSelectedText("\n");
  1613. } //}}}
  1614. //{{{ setSelectedText() method
  1615. /**
  1616. * Replaces the selection with the specified text.
  1617. * @param s The selection
  1618. * @param selectedText The new text
  1619. * @since jEdit 3.2pre1
  1620. */
  1621. public void setSelectedText(Selection s, String selectedText)
  1622. {
  1623. if(!isEditable())
  1624. {
  1625. throw new InternalError("Text component"
  1626. + " read only");
  1627. }
  1628. try
  1629. {
  1630. buffer.beginCompoundEdit();
  1631. moveCaretPosition(s.setText(buffer,selectedText));
  1632. }
  1633. // No matter what happends... stops us from leaving buffer
  1634. // in a bad state
  1635. finally
  1636. {
  1637. buffer.endCompoundEdit();
  1638. }
  1639. // no no no!!!!
  1640. //selectNone();
  1641. } //}}}
  1642. //{{{ setSelectedText() method
  1643. /**
  1644. * Replaces the selection at the caret with the specified text.
  1645. * If there is no selection at the caret, the text is inserted at
  1646. * the caret position.
  1647. */
  1648. public void setSelectedText(String selectedText)
  1649. {
  1650. if(!isEditable())
  1651. {
  1652. throw new InternalError("Text component"
  1653. + " read only");
  1654. }
  1655. Selection[] selection = getSelection();
  1656. if(selection.length == 0)
  1657. {
  1658. // for compatibility with older jEdit versions
  1659. buffer.insert(caret,selectedText);
  1660. }
  1661. else
  1662. {
  1663. try
  1664. {
  1665. int newCaret = -1;
  1666. buffer.beginCompoundEdit();
  1667. for(int i = 0; i < selection.length; i++)
  1668. {
  1669. newCaret = selection[i].setText(buffer,selectedText);
  1670. }
  1671. moveCaretPosition(newCaret);
  1672. }
  1673. finally
  1674. {
  1675. buffer.endCompoundEdit();
  1676. }
  1677. }
  1678. selectNone();
  1679. } //}}}
  1680. //{{{ getSelectedLines() method
  1681. /**
  1682. * Returns an array of all line numbers that contain a selection.
  1683. * This array will also include the line number containing the
  1684. * caret, for convinience.
  1685. * @since jEdit 3.2pre1
  1686. */
  1687. public int[] getSelectedLines()
  1688. {
  1689. if(selection.size() == 0)
  1690. return new int[] { caretLine };
  1691. Integer line;
  1692. Hashtable hash = new Hashtable();
  1693. for(int i = 0; i < selection.size(); i++)
  1694. {
  1695. Selection s = (Selection)selection.elementAt(i);
  1696. int endLine = (s.end == getLineStartOffset(s.endLine)
  1697. ? s.endLine - 1
  1698. : s.endLine);
  1699. for(int j = s.startLine; j <= endLine; j++)
  1700. {
  1701. line = new Integer(j);
  1702. hash.put(line,line);
  1703. }
  1704. }
  1705. int[] returnValue = new int[hash.size()];
  1706. int i = 0;
  1707. Enumeration keys = hash.keys();
  1708. while(keys.hasMoreElements())
  1709. {
  1710. line = (Integer)keys.nextElement();
  1711. returnValue[i++] = line.intValue();
  1712. }
  1713. Arrays.sort(returnValue);
  1714. return returnValue;
  1715. } //}}}
  1716. //{{{ showSelectLineRangeDialog() method
  1717. /**
  1718. * Displays the 'select line range' dialog box, and selects the
  1719. * specified range of lines.
  1720. * @since jEdit 2.7pre2
  1721. */
  1722. public void showSelectLineRangeDialog()
  1723. {
  1724. new SelectLineRange(view);
  1725. } //}}}
  1726. //}}}
  1727. //{{{ Caret
  1728. //{{{ blinkCaret() method
  1729. /**
  1730. * Blinks the caret.
  1731. */
  1732. public final void blinkCaret()
  1733. {
  1734. if(caretBlinks)
  1735. {
  1736. blink = !blink;
  1737. invalidateLine(caretLine);
  1738. }
  1739. else
  1740. blink = true;
  1741. } //}}}
  1742. //{{{ centerCaret() method
  1743. /**
  1744. * Centers the caret on the screen.
  1745. * @since jEdit 2.7pre2
  1746. */
  1747. public void centerCaret()
  1748. {
  1749. int offset = getScreenLineStartOffset(visibleLines / 2);
  1750. if(offset == -1)
  1751. getToolkit().beep();
  1752. else
  1753. setCaretPosition(offset);
  1754. } //}}}
  1755. //{{{ setCaretPosition() method
  1756. /**
  1757. * Sets the caret position and deactivates the selection.
  1758. * @param caret The caret position
  1759. */
  1760. public void setCaretPosition(int newCaret)
  1761. {
  1762. invalidateSelectedLines();
  1763. selection.removeAllElements();
  1764. moveCaretPosition(newCaret,true);
  1765. } //}}}
  1766. //{{{ setCaretPosition() method
  1767. /**
  1768. * Sets the caret position and deactivates the selection.
  1769. * @param caret The caret position
  1770. * @param doElectricScroll Do electric scrolling?
  1771. */
  1772. public void setCaretPosition(int newCaret, boolean doElectricScroll)
  1773. {
  1774. invalidateSelectedLines();
  1775. selection.removeAllElements();
  1776. moveCaretPosition(newCaret,doElectricScroll);
  1777. } //}}}
  1778. //{{{ moveCaretPosition() method
  1779. /**
  1780. * Sets the caret position without deactivating the selection.
  1781. * @param caret The caret position
  1782. */
  1783. public void moveCaretPosition(int newCaret)
  1784. {
  1785. moveCaretPosition(newCaret,true);
  1786. } //}}}
  1787. //{{{ moveCaretPosition() method
  1788. /**
  1789. * Sets the caret position without deactivating the selection.
  1790. * @param caret The caret position
  1791. * @param doElectricScroll Do electric scrolling?
  1792. */
  1793. public void moveCaretPosition(int newCaret, boolean doElectricScroll)
  1794. {
  1795. if(newCaret < 0 || newCaret > buffer.getLength())
  1796. {
  1797. throw new IllegalArgumentException("caret out of bounds: "
  1798. + newCaret);
  1799. }
  1800. // When the user is typing, etc, we don't want the caret
  1801. // to blink
  1802. blink = true;
  1803. caretTimer.restart();
  1804. if(caret == newCaret)
  1805. {
  1806. if(view.getTextArea() == this)
  1807. finishCaretUpdate(doElectricScroll,false);
  1808. return;
  1809. }
  1810. int newCaretLine = getLineOfOffset(newCaret);
  1811. magicCaret = -1;
  1812. if(!foldVisibilityManager.isLineVisible(newCaretLine))
  1813. {
  1814. if(foldVisibilityManager.isNarrowed())
  1815. {
  1816. int collapseFolds = buffer.getIntegerProperty(
  1817. "collapseFolds",0);
  1818. if(collapseFolds != 0)
  1819. foldVisibilityManager.expandFolds(collapseFolds);
  1820. else
  1821. foldVisibilityManager.expandAllFolds();
  1822. }
  1823. else
  1824. foldVisibilityManager.expandFold(newCaretLine,false);
  1825. }
  1826. if(caretLine == newCaretLine)
  1827. {
  1828. if(caretScreenLine != -1)
  1829. invalidateScreenLineRange(caretScreenLine,caretScreenLine);
  1830. }
  1831. else
  1832. {
  1833. caretScreenLine = chunkCache.getScreenLineOfOffset(newCaretLine,
  1834. newCaret - buffer.getLineStartOffset(newCaretLine));
  1835. invalidateLineRange(caretLine,newCaretLine);
  1836. }
  1837. caret = newCaret;
  1838. caretLine = newCaretLine;
  1839. if(view.getTextArea() == this)
  1840. finishCaretUpdate(doElectricScroll,true);
  1841. } //}}}
  1842. //{{{ getCaretPosition() method
  1843. /**
  1844. * Returns the caret position.
  1845. */
  1846. public int getCaretPosition()
  1847. {
  1848. return caret;
  1849. } //}}}
  1850. //{{{ getCaretLine() method
  1851. /**
  1852. * Returns the line number containing the caret.
  1853. */
  1854. public int getCaretLine()
  1855. {
  1856. return caretLine;
  1857. } //}}}
  1858. //{{{ getMagicCaretPosition() method
  1859. /**
  1860. * @deprecated Do not call this method.
  1861. */
  1862. public final int getMagicCaretPosition()
  1863. {
  1864. if(magicCaret == -1)
  1865. {
  1866. magicCaret = offsetToX(caretLine,caret
  1867. - getLineStartOffset(caretLine));
  1868. }
  1869. return magicCaret;
  1870. } //}}}
  1871. //{{{ setMagicCaretPosition() method
  1872. /**
  1873. * Sets the `magic' caret position. This can be used to preserve
  1874. * the column position when moving up and down lines.
  1875. * @param magicCaret The magic caret position
  1876. */
  1877. public final void setMagicCaretPosition(int magicCaret)
  1878. {
  1879. this.magicCaret = magicCaret;
  1880. } //}}}
  1881. //{{{ addCaretListener() method
  1882. /**
  1883. * Adds a caret change listener to this text area.
  1884. * @param listener The listener
  1885. */
  1886. public final void addCaretListener(CaretListener listener)
  1887. {
  1888. listenerList.add(CaretListener.class,listener);
  1889. } //}}}
  1890. //{{{ remo…

Large files files are truncated, but you can click here to view the full file