PageRenderTime 68ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/textarea/JEditTextArea.java

#
Java | 2867 lines | 1682 code | 348 blank | 837 comment | 379 complexity | ca5078213baa152f7ee737459a1769ba 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. * JEditTextArea.java - jEdit's text component
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2003 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 java.awt.*;
  26. import java.awt.event.*;
  27. import java.util.Enumeration;
  28. import java.util.Iterator;
  29. import java.util.LinkedList;
  30. import java.util.List;
  31. import java.util.Set;
  32. import java.util.TreeSet;
  33. import java.util.Vector;
  34. import javax.swing.*;
  35. import javax.swing.border.*;
  36. import javax.swing.event.*;
  37. import javax.swing.plaf.metal.MetalLookAndFeel;
  38. import javax.swing.text.Position;
  39. import javax.swing.text.Segment;
  40. import org.gjt.sp.jedit.*;
  41. import org.gjt.sp.jedit.buffer.*;
  42. import org.gjt.sp.jedit.gui.*;
  43. import org.gjt.sp.jedit.syntax.*;
  44. import org.gjt.sp.util.Log;
  45. //}}}
  46. /**
  47. * jEdit's text component.<p>
  48. *
  49. * Unlike most other text editors, the selection API permits selection and
  50. * concurrent manipulation of multiple, non-contiguous regions of text.
  51. * Methods in this class that deal with selecting text rely upon classes derived
  52. * the {@link Selection} class.
  53. *
  54. * @author Slava Pestov
  55. * @author John Gellene (API documentation)
  56. * @version $Id: JEditTextArea.java 4841 2003-07-28 21:08:04Z spestov $
  57. */
  58. public class JEditTextArea extends JComponent
  59. {
  60. //{{{ JEditTextArea constructor
  61. /**
  62. * Creates a new JEditTextArea.
  63. */
  64. public JEditTextArea(View view)
  65. {
  66. enableEvents(AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK);
  67. this.view = view;
  68. //{{{ Initialize some misc. stuff
  69. selection = new Vector();
  70. chunkCache = new ChunkCache(this);
  71. painter = new TextAreaPainter(this);
  72. gutter = new Gutter(view,this);
  73. bufferHandler = new BufferChangeHandler();
  74. listenerList = new EventListenerList();
  75. caretEvent = new MutableCaretEvent();
  76. blink = true;
  77. lineSegment = new Segment();
  78. returnValue = new Point();
  79. runnables = new LinkedList();
  80. structureMatchers = new LinkedList();
  81. structureMatchers.add(new StructureMatcher.BracketMatcher());
  82. //}}}
  83. //{{{ Initialize the GUI
  84. setLayout(new ScrollLayout());
  85. add(CENTER,painter);
  86. add(LEFT,gutter);
  87. // some plugins add stuff in a "right-hand" gutter
  88. verticalBox = new Box(BoxLayout.X_AXIS);
  89. verticalBox.add(vertical = new JScrollBar(JScrollBar.VERTICAL));
  90. vertical.setRequestFocusEnabled(false);
  91. add(RIGHT,verticalBox);
  92. add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
  93. horizontal.setRequestFocusEnabled(false);
  94. horizontal.setValues(0,0,0,0);
  95. //}}}
  96. //{{{ this ensures that the text area's look is slightly
  97. // more consistent with the rest of the metal l&f.
  98. // while it depends on not-so-well-documented portions
  99. // of Swing, it only affects appearance, so future
  100. // breakage shouldn't matter
  101. if(UIManager.getLookAndFeel() instanceof MetalLookAndFeel)
  102. {
  103. setBorder(new TextAreaBorder());
  104. vertical.putClientProperty("JScrollBar.isFreeStanding",
  105. Boolean.FALSE);
  106. horizontal.putClientProperty("JScrollBar.isFreeStanding",
  107. Boolean.FALSE);
  108. //horizontal.setBorder(null);
  109. }
  110. //}}}
  111. //{{{ Add some event listeners
  112. vertical.addAdjustmentListener(new AdjustHandler());
  113. horizontal.addAdjustmentListener(new AdjustHandler());
  114. mouseHandler = new MouseHandler();
  115. painter.addMouseListener(mouseHandler);
  116. painter.addMouseMotionListener(mouseHandler);
  117. addFocusListener(new FocusHandler());
  118. //}}}
  119. // This doesn't seem very correct, but it fixes a problem
  120. // when setting the initial caret position for a buffer
  121. // (eg, from the recent file list)
  122. focusedComponent = this;
  123. } //}}}
  124. //{{{ dispose() method
  125. /**
  126. * Plugins and macros should not call this method.
  127. * @since jEdit 4.2pre1
  128. */
  129. public void dispose()
  130. {
  131. DisplayManager.textAreaDisposed(this);
  132. } //}}}
  133. //{{{ Getters and setters
  134. //{{{ getPainter() method
  135. /**
  136. * Returns the object responsible for painting this text area.
  137. */
  138. public final TextAreaPainter getPainter()
  139. {
  140. return painter;
  141. } //}}}
  142. //{{{ getGutter() method
  143. /**
  144. * Returns the gutter to the left of the text area or null if the gutter
  145. * is disabled
  146. */
  147. public final Gutter getGutter()
  148. {
  149. return gutter;
  150. } //}}}
  151. //{{{ getDisplayManager() method
  152. /**
  153. * Returns the display manager used by this text area.
  154. * @since jEdit 4.2pre1
  155. */
  156. public DisplayManager getDisplayManager()
  157. {
  158. return displayManager;
  159. } //}}}
  160. //{{{ isCaretBlinkEnabled() method
  161. /**
  162. * Returns true if the caret is blinking, false otherwise.
  163. */
  164. public final boolean isCaretBlinkEnabled()
  165. {
  166. return caretBlinks;
  167. } //}}}
  168. //{{{ setCaretBlinkEnabled() method
  169. /**
  170. * Toggles caret blinking.
  171. * @param caretBlinks True if the caret should blink, false otherwise
  172. */
  173. public void setCaretBlinkEnabled(boolean caretBlinks)
  174. {
  175. this.caretBlinks = caretBlinks;
  176. if(!caretBlinks)
  177. blink = false;
  178. if(buffer != null)
  179. invalidateLine(caretLine);
  180. } //}}}
  181. //{{{ getElectricScroll() method
  182. /**
  183. * Returns the number of lines from the top and button of the
  184. * text area that are always visible.
  185. */
  186. public final int getElectricScroll()
  187. {
  188. return electricScroll;
  189. } //}}}
  190. //{{{ setElectricScroll() method
  191. /**
  192. * Sets the number of lines from the top and bottom of the text
  193. * area that are always visible
  194. * @param electricScroll The number of lines always visible from
  195. * the top or bottom
  196. */
  197. public final void setElectricScroll(int electricScroll)
  198. {
  199. this.electricScroll = electricScroll;
  200. } //}}}
  201. //{{{ isQuickCopyEnabled() method
  202. /**
  203. * Returns if clicking the middle mouse button pastes the most
  204. * recent selection (% register), and if Control-dragging inserts
  205. * the selection at the caret.
  206. */
  207. public final boolean isQuickCopyEnabled()
  208. {
  209. return quickCopy;
  210. } //}}}
  211. //{{{ setQuickCopyEnabled() method
  212. /**
  213. * Sets if clicking the middle mouse button pastes the most
  214. * recent selection (% register), and if Control-dragging inserts
  215. * the selection at the caret.
  216. * @param quickCopy A boolean flag
  217. */
  218. public final void setQuickCopyEnabled(boolean quickCopy)
  219. {
  220. this.quickCopy = quickCopy;
  221. } //}}}
  222. //{{{ getBuffer() method
  223. /**
  224. * Returns the buffer this text area is editing.
  225. */
  226. public final Buffer getBuffer()
  227. {
  228. return buffer;
  229. } //}}}
  230. //{{{ setBuffer() method
  231. /**
  232. * Sets the buffer this text area is editing. Do not call this method -
  233. * use {@link org.gjt.sp.jedit.EditPane#setBuffer(Buffer)} instead.
  234. * @param buffer The buffer
  235. */
  236. public void setBuffer(Buffer buffer)
  237. {
  238. if(this.buffer == buffer)
  239. return;
  240. try
  241. {
  242. bufferChanging = true;
  243. if(this.buffer != null)
  244. {
  245. // dubious?
  246. //setFirstLine(0);
  247. selectNone();
  248. caretLine = caret = caretScreenLine = 0;
  249. match = null;
  250. this.buffer.removeBufferChangeListener(bufferHandler);
  251. }
  252. this.buffer = buffer;
  253. buffer.addBufferChangeListener(bufferHandler);
  254. bufferHandlerInstalled = true;
  255. chunkCache.setBuffer(buffer);
  256. propertiesChanged();
  257. if(displayManager != null)
  258. {
  259. DisplayManager.releaseDisplayManager(
  260. displayManager);
  261. }
  262. displayManager = DisplayManager.getDisplayManager(
  263. buffer,this);
  264. displayManager.init();
  265. maxHorizontalScrollWidth = 0;
  266. repaint();
  267. fireScrollEvent(true);
  268. }
  269. finally
  270. {
  271. bufferChanging = false;
  272. }
  273. } //}}}
  274. //{{{ isEditable() method
  275. /**
  276. * Returns true if this text area is editable, false otherwise.
  277. */
  278. public final boolean isEditable()
  279. {
  280. return buffer.isEditable();
  281. } //}}}
  282. //{{{ getRightClickPopup() method
  283. /**
  284. * Returns the right click popup menu.
  285. */
  286. public final JPopupMenu getRightClickPopup()
  287. {
  288. return popup;
  289. } //}}}
  290. //{{{ setRightClickPopup() method
  291. /**
  292. * Sets the right click popup menu.
  293. * @param popup The popup
  294. */
  295. public final void setRightClickPopup(JPopupMenu popup)
  296. {
  297. this.popup = popup;
  298. } //}}}
  299. //}}}
  300. //{{{ Scrolling
  301. //{{{ Debugging code
  302. /* public void scrollTest(boolean paint)
  303. {
  304. Image im = painter.createImage(painter.getWidth(),painter.getHeight());
  305. Graphics gfx = im.getGraphics();
  306. gfx.setFont(painter.getFont());
  307. gfx.setColor(painter.getForeground());
  308. gfx.clipRect(0,0,painter.getWidth(),painter.getHeight());
  309. long start = System.currentTimeMillis();
  310. for(int i = 0; i < displayManager.getScrollLineCount(); i++)
  311. {
  312. setFirstLine(i);
  313. if(!paint)
  314. chunkCache.getLineInfo(visibleLines - 1);
  315. else
  316. painter.paintComponent(gfx);
  317. }
  318. System.err.println(System.currentTimeMillis() - start);
  319. } */ //}}}
  320. //{{{ getFirstLine() method
  321. /**
  322. * Returns the vertical scroll bar position.
  323. * @since jEdit 4.2pre1
  324. */
  325. public final int getFirstLine()
  326. {
  327. return displayManager.firstLine.scrollLine
  328. + displayManager.firstLine.skew;
  329. } //}}}
  330. //{{{ setFirstLine() method
  331. public Exception trace;
  332. /**
  333. * Sets the vertical scroll bar position
  334. *
  335. * @param firstLine The scroll bar position
  336. */
  337. public void setFirstLine(int firstLine)
  338. {
  339. if(Debug.SCROLL_DEBUG)
  340. {
  341. Log.log(Log.DEBUG,this,"setFirstLine() from "
  342. + getFirstLine() + " to " + firstLine);
  343. }
  344. //{{{ ensure we don't have empty space at the bottom or top, etc
  345. int max = displayManager.getScrollLineCount() - visibleLines
  346. + (lastLinePartial ? 1 : 0);
  347. if(firstLine > max)
  348. firstLine = max;
  349. if(firstLine < 0)
  350. firstLine = 0;
  351. //}}}
  352. int oldFirstLine = getFirstLine();
  353. if(firstLine == oldFirstLine)
  354. return;
  355. trace = new Exception();
  356. if(firstLine >= oldFirstLine + visibleLines)
  357. {
  358. displayManager.firstLine.scrollDown(firstLine - oldFirstLine);
  359. chunkCache.invalidateAll();
  360. }
  361. else if(firstLine <= oldFirstLine - visibleLines)
  362. {
  363. displayManager.firstLine.scrollUp(oldFirstLine - firstLine);
  364. chunkCache.invalidateAll();
  365. }
  366. else if(firstLine > oldFirstLine)
  367. {
  368. displayManager.firstLine.scrollDown(firstLine - oldFirstLine);
  369. chunkCache.scrollDown(firstLine - oldFirstLine);
  370. }
  371. else if(firstLine < oldFirstLine)
  372. {
  373. displayManager.firstLine.scrollUp(oldFirstLine - firstLine);
  374. chunkCache.scrollUp(oldFirstLine - firstLine);
  375. }
  376. displayManager.firstLine.changed();
  377. maxHorizontalScrollWidth = 0;
  378. //if(buffer.isLoaded())
  379. // recalculateLastPhysicalLine();
  380. repaint();
  381. fireScrollEvent(true);
  382. } //}}}
  383. //{{{ getFirstPhysicalLine() method
  384. /**
  385. * Returns the first visible physical line index.
  386. * @since jEdit 4.0pre4
  387. */
  388. public final int getFirstPhysicalLine()
  389. {
  390. return displayManager.firstLine.physicalLine;
  391. } //}}}
  392. //{{{ setFirstPhysicalLine() method
  393. /**
  394. * Sets the vertical scroll bar position.
  395. * @param physFirstLine The first physical line to display
  396. * @param skew A local screen line delta
  397. * @since jEdit 4.2pre1
  398. */
  399. public void setFirstPhysicalLine(int physFirstLine)
  400. {
  401. setFirstPhysicalLine(physFirstLine,0);
  402. } //}}}
  403. //{{{ setFirstPhysicalLine() method
  404. /**
  405. * Sets the vertical scroll bar position.
  406. * @param physFirstLine The first physical line to display
  407. * @param skew A local screen line delta
  408. * @since jEdit 4.2pre1
  409. */
  410. public void setFirstPhysicalLine(int physFirstLine, int skew)
  411. {
  412. if(Debug.SCROLL_DEBUG)
  413. {
  414. Log.log(Log.DEBUG,this,"setFirstPhysicalLine("
  415. + physFirstLine + "," + skew + ")");
  416. }
  417. //{{{ ensure we don't have empty space at the bottom or top, etc
  418. /* int screenLineCount = 0;
  419. int physicalLine = displayManager.getLastVisibleLine();
  420. int visibleLines = this.visibleLines - (lastLinePartial ? 1 : 0);
  421. for(;;)
  422. {
  423. screenLineCount += displayManager.getScreenLineCount(physicalLine);
  424. if(screenLineCount >= visibleLines)
  425. break;
  426. int prevLine = displayManager.getPrevVisibleLine(physicalLine);
  427. if(prevLine == -1)
  428. break;
  429. physicalLine = prevLine;
  430. }
  431. if(physFirstLine > physicalLine)
  432. physFirstLine = physicalLine; */
  433. //}}}
  434. int amount = (physFirstLine - displayManager.firstLine.physicalLine);
  435. int oldFirstLine = getFirstLine();
  436. if(amount == 0)
  437. {
  438. skew -= displayManager.firstLine.skew;
  439. // JEditTextArea.scrollTo() needs this to simplify
  440. // its code
  441. if(skew < 0)
  442. displayManager.firstLine.scrollUp(-skew);
  443. else if(skew > 0)
  444. displayManager.firstLine.scrollDown(skew);
  445. else
  446. {
  447. // nothing to do
  448. return;
  449. }
  450. }
  451. else if(amount > 0)
  452. displayManager.firstLine.physDown(amount,skew);
  453. else if(amount < 0)
  454. displayManager.firstLine.physUp(-amount,skew);
  455. int firstLine = getFirstLine();
  456. if(firstLine == oldFirstLine)
  457. /* do nothing */;
  458. else if(firstLine >= oldFirstLine + visibleLines
  459. || firstLine <= oldFirstLine - visibleLines)
  460. {
  461. chunkCache.invalidateAll();
  462. }
  463. else if(firstLine > oldFirstLine)
  464. {
  465. chunkCache.scrollDown(firstLine - oldFirstLine);
  466. }
  467. else if(firstLine < oldFirstLine)
  468. {
  469. chunkCache.scrollUp(oldFirstLine - firstLine);
  470. }
  471. displayManager.firstLine.changed();
  472. maxHorizontalScrollWidth = 0;
  473. //if(buffer.isLoaded())
  474. // recalculateLastPhysicalLine();
  475. repaint();
  476. fireScrollEvent(true);
  477. } //}}}
  478. //{{{ getLastPhysicalLine() method
  479. /**
  480. * Returns the last visible physical line index.
  481. * @since jEdit 4.0pre4
  482. */
  483. public final int getLastPhysicalLine()
  484. {
  485. return physLastLine;
  486. } //}}}
  487. //{{{ getVisibleLines() method
  488. /**
  489. * Returns the number of lines visible in this text area.
  490. */
  491. public final int getVisibleLines()
  492. {
  493. return visibleLines;
  494. } //}}}
  495. //{{{ getHorizontalOffset() method
  496. /**
  497. * Returns the horizontal offset of drawn lines.
  498. */
  499. public final int getHorizontalOffset()
  500. {
  501. return horizontalOffset;
  502. } //}}}
  503. //{{{ setHorizontalOffset() method
  504. /**
  505. * Sets the horizontal offset of drawn lines. This can be used to
  506. * implement horizontal scrolling.
  507. * @param horizontalOffset offset The new horizontal offset
  508. */
  509. public void setHorizontalOffset(int horizontalOffset)
  510. {
  511. if(horizontalOffset > 0)
  512. horizontalOffset = 0;
  513. if(horizontalOffset == this.horizontalOffset)
  514. return;
  515. this.horizontalOffset = horizontalOffset;
  516. if(horizontalOffset != horizontal.getValue())
  517. updateScrollBars();
  518. painter.repaint();
  519. fireScrollEvent(false);
  520. } //}}}
  521. //{{{ scrollUpLine() method
  522. /**
  523. * Scrolls up by one line.
  524. * @since jEdit 2.7pre2
  525. */
  526. public void scrollUpLine()
  527. {
  528. setFirstLine(getFirstLine() - 1);
  529. } //}}}
  530. //{{{ scrollUpPage() method
  531. /**
  532. * Scrolls up by one page.
  533. * @since jEdit 2.7pre2
  534. */
  535. public void scrollUpPage()
  536. {
  537. setFirstLine(getFirstLine() - getVisibleLines()
  538. + (lastLinePartial ? 1 : 0));
  539. } //}}}
  540. //{{{ scrollDownLine() method
  541. /**
  542. * Scrolls down by one line.
  543. * @since jEdit 2.7pre2
  544. */
  545. public void scrollDownLine()
  546. {
  547. setFirstLine(getFirstLine() + 1);
  548. } //}}}
  549. //{{{ scrollDownPage() method
  550. /**
  551. * Scrolls down by one page.
  552. * @since jEdit 2.7pre2
  553. */
  554. public void scrollDownPage()
  555. {
  556. setFirstLine(getFirstLine() + getVisibleLines()
  557. - (lastLinePartial ? 1 : 0));
  558. } //}}}
  559. //{{{ scrollToCaret() method
  560. /**
  561. * Ensures that the caret is visible by scrolling the text area if
  562. * necessary.
  563. * @param doElectricScroll If true, electric scrolling will be performed
  564. */
  565. public void scrollToCaret(boolean doElectricScroll)
  566. {
  567. scrollTo(caretLine,caret - buffer.getLineStartOffset(caretLine),
  568. doElectricScroll);
  569. } //}}}
  570. //{{{ scrollTo() method
  571. /**
  572. * Ensures that the specified location in the buffer is visible.
  573. * @param offset The offset from the start of the buffer
  574. * @param doElectricScroll If true, electric scrolling will be performed
  575. * @since jEdit 4.2pre3
  576. */
  577. public void scrollTo(int offset, boolean doElectricScroll)
  578. {
  579. int line = buffer.getLineOfOffset(offset);
  580. scrollTo(line,offset - buffer.getLineStartOffset(line),
  581. doElectricScroll);
  582. } //}}}
  583. //{{{ scrollTo() method
  584. /**
  585. * Ensures that the specified location in the buffer is visible.
  586. * @param line The line number
  587. * @param offset The offset from the start of the line
  588. * @param doElectricScroll If true, electric scrolling will be performed
  589. * @since jEdit 4.0pre6
  590. */
  591. public void scrollTo(int line, int offset, boolean doElectricScroll)
  592. {
  593. if(Debug.SCROLL_DEBUG)
  594. Log.log(Log.DEBUG,this,"scrollTo(), lineCount="
  595. + getLineCount());
  596. //{{{ Get ready
  597. int extraEndVirt;
  598. int lineLength = buffer.getLineLength(line);
  599. if(offset > lineLength)
  600. {
  601. extraEndVirt = charWidth * (offset - lineLength);
  602. offset = lineLength;
  603. }
  604. else
  605. extraEndVirt = 0;
  606. int _electricScroll = (doElectricScroll
  607. && visibleLines - 1 > electricScroll * 2
  608. ? electricScroll : 0); //}}}
  609. if(visibleLines == 0)
  610. {
  611. setFirstPhysicalLine(line,_electricScroll);
  612. // it will figure itself out after being added...
  613. return;
  614. }
  615. //{{{ Scroll vertically
  616. int firstLine = getFirstLine();
  617. int screenLine = chunkCache.getScreenLineOfOffset(line,offset);
  618. int visibleLines = getVisibleLines();
  619. if(screenLine == -1)
  620. {
  621. ChunkCache.LineInfo[] infos = chunkCache
  622. .getLineInfosForPhysicalLine(line);
  623. int subregion = chunkCache.getSubregionOfOffset(
  624. offset,infos);
  625. int prevLine = displayManager.getPrevVisibleLine(getFirstPhysicalLine());
  626. int nextLine = displayManager.getNextVisibleLine(getLastPhysicalLine());
  627. if(line == prevLine)
  628. {
  629. setFirstPhysicalLine(prevLine,subregion
  630. - _electricScroll);
  631. }
  632. else if(line == nextLine)
  633. {
  634. setFirstPhysicalLine(nextLine,
  635. subregion + electricScroll
  636. - visibleLines - 1);
  637. }
  638. else
  639. {
  640. setFirstPhysicalLine(line,subregion
  641. - visibleLines / 2);
  642. }
  643. }
  644. else if(screenLine < _electricScroll)
  645. {
  646. setFirstLine(getFirstLine() - _electricScroll + screenLine);
  647. }
  648. else if(screenLine > visibleLines - _electricScroll
  649. - (lastLinePartial ? 2 : 1))
  650. {
  651. setFirstLine(getFirstLine() + _electricScroll - visibleLines + screenLine + (lastLinePartial ? 2 : 1));
  652. } //}}}
  653. //{{{ Scroll horizontally
  654. if(!displayManager.isLineVisible(line))
  655. return;
  656. Point point = offsetToXY(line,offset,returnValue);
  657. if(point == null)
  658. Log.log(Log.ERROR,this,"BUG: screenLine=" + screenLine
  659. + ",visibleLines=" + visibleLines
  660. + ",physicalLine=" + line
  661. + ",firstPhysicalLine=" + getFirstPhysicalLine()
  662. + ",lastPhysicalLine=" + getLastPhysicalLine());
  663. point.x += extraEndVirt;
  664. if(point.x < 0)
  665. {
  666. setHorizontalOffset(horizontalOffset
  667. - point.x + charWidth + 5);
  668. }
  669. else if(point.x >= painter.getWidth() - charWidth - 5)
  670. {
  671. setHorizontalOffset(horizontalOffset +
  672. (painter.getWidth() - point.x)
  673. - charWidth - 5);
  674. } //}}}
  675. } //}}}
  676. //{{{ addScrollListener() method
  677. /**
  678. * Adds a scroll listener to this text area.
  679. * @param listener The listener
  680. * @since jEdit 3.2pre2
  681. */
  682. public final void addScrollListener(ScrollListener listener)
  683. {
  684. listenerList.add(ScrollListener.class,listener);
  685. } //}}}
  686. //{{{ removeScrollListener() method
  687. /**
  688. * Removes a scroll listener from this text area.
  689. * @param listener The listener
  690. * @since jEdit 3.2pre2
  691. */
  692. public final void removeScrollListener(ScrollListener listener)
  693. {
  694. listenerList.remove(ScrollListener.class,listener);
  695. } //}}}
  696. //}}}
  697. //{{{ Screen line stuff
  698. //{{{ getPhysicalLineOfScreenLine() method
  699. /**
  700. * Returns the physical line number that contains the specified screen
  701. * line.
  702. * @param screenLine The screen line
  703. * @since jEdit 4.0pre6
  704. */
  705. public int getPhysicalLineOfScreenLine(int screenLine)
  706. {
  707. return chunkCache.getLineInfo(screenLine).physicalLine;
  708. } //}}}
  709. //{{{ getScreenLineOfOffset() method
  710. /**
  711. * Returns the screen (wrapped) line containing the specified offset.
  712. * @param offset The offset
  713. * @since jEdit 4.0pre4
  714. */
  715. public int getScreenLineOfOffset(int offset)
  716. {
  717. int line = buffer.getLineOfOffset(offset);
  718. offset -= buffer.getLineStartOffset(line);
  719. return chunkCache.getScreenLineOfOffset(line,offset);
  720. } //}}}
  721. //{{{ getScreenLineStartOffset() method
  722. /**
  723. * Returns the start offset of the specified screen (wrapped) line.
  724. * @param line The line
  725. * @since jEdit 4.0pre4
  726. */
  727. public int getScreenLineStartOffset(int line)
  728. {
  729. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
  730. if(lineInfo.physicalLine == -1)
  731. return -1;
  732. return buffer.getLineStartOffset(lineInfo.physicalLine)
  733. + lineInfo.offset;
  734. } //}}}
  735. //{{{ getScreenLineEndOffset() method
  736. /**
  737. * Returns the end offset of the specified screen (wrapped) line.
  738. * @param line The line
  739. * @since jEdit 4.0pre4
  740. */
  741. public int getScreenLineEndOffset(int line)
  742. {
  743. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(line);
  744. if(lineInfo.physicalLine == -1)
  745. return -1;
  746. return buffer.getLineStartOffset(lineInfo.physicalLine)
  747. + lineInfo.offset + lineInfo.length;
  748. } //}}}
  749. //}}}
  750. //{{{ Offset conversion
  751. //{{{ xyToOffset() method
  752. /**
  753. * Converts a point to an offset.
  754. * Note that unlike in previous jEdit versions, this method now returns
  755. * -1 if the y co-ordinate is out of bounds.
  756. *
  757. * @param x The x co-ordinate of the point
  758. * @param y The y co-ordinate of the point
  759. */
  760. public int xyToOffset(int x, int y)
  761. {
  762. return xyToOffset(x,y,true);
  763. } //}}}
  764. //{{{ xyToOffset() method
  765. /**
  766. * Converts a point to an offset.
  767. * Note that unlike in previous jEdit versions, this method now returns
  768. * -1 if the y co-ordinate is out of bounds.
  769. *
  770. * @param x The x co-ordinate of the point
  771. * @param y The y co-ordinate of the point
  772. * @param round Round up to next letter if past the middle of a letter?
  773. * @since jEdit 3.2pre6
  774. */
  775. public int xyToOffset(int x, int y, boolean round)
  776. {
  777. FontMetrics fm = painter.getFontMetrics();
  778. int height = fm.getHeight();
  779. int line = y / height;
  780. if(line < 0 || line >= visibleLines)
  781. return -1;
  782. return xToScreenLineOffset(line,x,round);
  783. } //}}}
  784. //{{{ xToScreenLineOffset() method
  785. /**
  786. * Converts a point in a given screen line to an offset.
  787. * Note that unlike in previous jEdit versions, this method now returns
  788. * -1 if the y co-ordinate is out of bounds.
  789. *
  790. * @param x The x co-ordinate of the point
  791. * @param screenLine The screen line
  792. * @param round Round up to next letter if past the middle of a letter?
  793. * @since jEdit 3.2pre6
  794. */
  795. public int xToScreenLineOffset(int screenLine, int x, boolean round)
  796. {
  797. ChunkCache.LineInfo lineInfo = chunkCache.getLineInfo(screenLine);
  798. if(lineInfo.physicalLine == -1)
  799. {
  800. return getLineEndOffset(displayManager
  801. .getLastVisibleLine()) - 1;
  802. }
  803. else
  804. {
  805. int offset = Chunk.xToOffset(lineInfo.chunks,
  806. x - horizontalOffset,round);
  807. if(offset == -1 || offset == lineInfo.offset + lineInfo.length)
  808. offset = lineInfo.offset + lineInfo.length - 1;
  809. return getLineStartOffset(lineInfo.physicalLine) + offset;
  810. }
  811. } //}}}
  812. //{{{ offsetToXY() method
  813. /**
  814. * Converts an offset into a point in the text area painter's
  815. * co-ordinate space.
  816. * @param offset The offset
  817. * @return The location of the offset on screen, or <code>null</code>
  818. * if the specified offset is not visible
  819. */
  820. public Point offsetToXY(int offset)
  821. {
  822. int line = buffer.getLineOfOffset(offset);
  823. offset -= buffer.getLineStartOffset(line);
  824. Point retVal = new Point();
  825. return offsetToXY(line,offset,retVal);
  826. } //}}}
  827. //{{{ offsetToXY() method
  828. /**
  829. * Converts an offset into a point in the text area painter's
  830. * co-ordinate space.
  831. * @param line The physical line number
  832. * @param offset The offset, from the start of the line
  833. * @param retVal The point to store the return value in
  834. * @return <code>retVal</code> for convenience, or <code>null</code>
  835. * if the specified offset is not visible
  836. * @since jEdit 4.0pre4
  837. */
  838. public Point offsetToXY(int line, int offset, Point retVal)
  839. {
  840. int screenLine = chunkCache.getScreenLineOfOffset(line,offset);
  841. if(screenLine == -1)
  842. return null;
  843. FontMetrics fm = painter.getFontMetrics();
  844. retVal.y = screenLine * fm.getHeight();
  845. ChunkCache.LineInfo info = chunkCache.getLineInfo(screenLine);
  846. retVal.x = (int)(horizontalOffset + Chunk.offsetToX(
  847. info.chunks,offset));
  848. return retVal;
  849. } //}}}
  850. //}}}
  851. //{{{ Painting
  852. //{{{ invalidateScreenLineRange() method
  853. /**
  854. * Marks a range of screen lines as needing a repaint.
  855. * @param start The first line
  856. * @param end The last line
  857. * @since jEdit 4.0pre4
  858. */
  859. public void invalidateScreenLineRange(int start, int end)
  860. {
  861. if(!buffer.isLoaded())
  862. return;
  863. //if(start != end)
  864. // System.err.println(start + ":" + end + ":" + chunkCache.needFullRepaint());
  865. if(start > end)
  866. {
  867. int tmp = end;
  868. end = start;
  869. start = tmp;
  870. }
  871. if(chunkCache.needFullRepaint())
  872. end = visibleLines;
  873. FontMetrics fm = painter.getFontMetrics();
  874. int y = start * fm.getHeight();
  875. int height = (end - start + 1) * fm.getHeight();
  876. painter.repaint(0,y,painter.getWidth(),height);
  877. gutter.repaint(0,y,gutter.getWidth(),height);
  878. } //}}}
  879. //{{{ invalidateLine() method
  880. /**
  881. * Marks a line as needing a repaint.
  882. * @param line The physical line to invalidate
  883. */
  884. public void invalidateLine(int line)
  885. {
  886. if(!isShowing()
  887. || !buffer.isLoaded()
  888. || line < getFirstPhysicalLine()
  889. || line > physLastLine
  890. || !displayManager.isLineVisible(line))
  891. return;
  892. int startLine = -1;
  893. int endLine = -1;
  894. for(int i = 0; i < visibleLines; i++)
  895. {
  896. ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
  897. if((info.physicalLine >= line || info.physicalLine == -1)
  898. && startLine == -1)
  899. {
  900. startLine = i;
  901. }
  902. if((info.physicalLine >= line && info.lastSubregion)
  903. || info.physicalLine == -1)
  904. {
  905. endLine = i;
  906. break;
  907. }
  908. }
  909. if(chunkCache.needFullRepaint() || endLine == -1)
  910. endLine = visibleLines;
  911. //if(startLine != endLine)
  912. // System.err.println(startLine + ":" + endLine);
  913. invalidateScreenLineRange(startLine,endLine);
  914. } //}}}
  915. //{{{ invalidateLineRange() method
  916. /**
  917. * Marks a range of physical lines as needing a repaint.
  918. * @param start The first line to invalidate
  919. * @param end The last line to invalidate
  920. */
  921. public void invalidateLineRange(int start, int end)
  922. {
  923. if(!isShowing() || !buffer.isLoaded())
  924. return;
  925. if(end < start)
  926. {
  927. int tmp = end;
  928. end = start;
  929. start = tmp;
  930. }
  931. if(end < getFirstPhysicalLine() || start > getLastPhysicalLine())
  932. return;
  933. int startScreenLine = -1;
  934. int endScreenLine = -1;
  935. for(int i = 0; i < visibleLines; i++)
  936. {
  937. ChunkCache.LineInfo info = chunkCache.getLineInfo(i);
  938. if((info.physicalLine >= start || info.physicalLine == -1)
  939. && startScreenLine == -1)
  940. {
  941. startScreenLine = i;
  942. }
  943. if((info.physicalLine >= end && info.lastSubregion)
  944. || info.physicalLine == -1)
  945. {
  946. endScreenLine = i;
  947. break;
  948. }
  949. }
  950. if(startScreenLine == -1)
  951. startScreenLine = 0;
  952. if(chunkCache.needFullRepaint() || endScreenLine == -1)
  953. endScreenLine = visibleLines;
  954. invalidateScreenLineRange(startScreenLine,endScreenLine);
  955. } //}}}
  956. //{{{ invalidateSelectedLines() method
  957. /**
  958. * Repaints the lines containing the selection.
  959. */
  960. public void invalidateSelectedLines()
  961. {
  962. // to hide line highlight if selections are being added later on
  963. invalidateLine(caretLine);
  964. for(int i = 0; i < selection.size(); i++)
  965. {
  966. Selection s = (Selection)selection.elementAt(i);
  967. invalidateLineRange(s.startLine,s.endLine);
  968. }
  969. } //}}}
  970. //}}}
  971. //{{{ Convenience methods
  972. //{{{ getBufferLength() method
  973. /**
  974. * Returns the length of the buffer.
  975. */
  976. public final int getBufferLength()
  977. {
  978. return buffer.getLength();
  979. } //}}}
  980. //{{{ getLineCount() method
  981. /**
  982. * Returns the number of physical lines in the buffer.
  983. */
  984. public final int getLineCount()
  985. {
  986. return buffer.getLineCount();
  987. } //}}}
  988. //{{{ getLineOfOffset() method
  989. /**
  990. * Returns the line containing the specified offset.
  991. * @param offset The offset
  992. */
  993. public final int getLineOfOffset(int offset)
  994. {
  995. return buffer.getLineOfOffset(offset);
  996. } //}}}
  997. //{{{ getLineStartOffset() method
  998. /**
  999. * Returns the start offset of the specified line.
  1000. * @param line The line
  1001. * @return The start offset of the specified line, or -1 if the line is
  1002. * invalid
  1003. */
  1004. public int getLineStartOffset(int line)
  1005. {
  1006. return buffer.getLineStartOffset(line);
  1007. } //}}}
  1008. //{{{ getLineEndOffset() method
  1009. /**
  1010. * Returns the end offset of the specified line.
  1011. * @param line The line
  1012. * @return The end offset of the specified line, or -1 if the line is
  1013. * invalid.
  1014. */
  1015. public int getLineEndOffset(int line)
  1016. {
  1017. return buffer.getLineEndOffset(line);
  1018. } //}}}
  1019. //{{{ getLineLength() method
  1020. /**
  1021. * Returns the length of the specified line.
  1022. * @param line The line
  1023. */
  1024. public int getLineLength(int line)
  1025. {
  1026. return buffer.getLineLength(line);
  1027. } //}}}
  1028. //{{{ getText() method
  1029. /**
  1030. * Returns the specified substring of the buffer.
  1031. * @param start The start offset
  1032. * @param len The length of the substring
  1033. * @return The substring
  1034. */
  1035. public final String getText(int start, int len)
  1036. {
  1037. return buffer.getText(start,len);
  1038. } //}}}
  1039. //{{{ getText() method
  1040. /**
  1041. * Copies the specified substring of the buffer into a segment.
  1042. * @param start The start offset
  1043. * @param len The length of the substring
  1044. * @param segment The segment
  1045. */
  1046. public final void getText(int start, int len, Segment segment)
  1047. {
  1048. buffer.getText(start,len,segment);
  1049. } //}}}
  1050. //{{{ getLineText() method
  1051. /**
  1052. * Returns the text on the specified line.
  1053. * @param lineIndex The line
  1054. * @return The text, or null if the line is invalid
  1055. */
  1056. public final String getLineText(int lineIndex)
  1057. {
  1058. return buffer.getLineText(lineIndex);
  1059. } //}}}
  1060. //{{{ getLineText() method
  1061. /**
  1062. * Copies the text on the specified line into a segment. If the line
  1063. * is invalid, the segment will contain a null string.
  1064. * @param lineIndex The line
  1065. */
  1066. public final void getLineText(int lineIndex, Segment segment)
  1067. {
  1068. buffer.getLineText(lineIndex,segment);
  1069. } //}}}
  1070. //{{{ getText() method
  1071. /**
  1072. * Returns the entire text of this text area.
  1073. */
  1074. public String getText()
  1075. {
  1076. return buffer.getText(0,buffer.getLength());
  1077. } //}}}
  1078. //{{{ setText() method
  1079. /**
  1080. * Sets the entire text of this text area.
  1081. */
  1082. public void setText(String text)
  1083. {
  1084. try
  1085. {
  1086. buffer.beginCompoundEdit();
  1087. buffer.remove(0,buffer.getLength());
  1088. buffer.insert(0,text);
  1089. }
  1090. finally
  1091. {
  1092. buffer.endCompoundEdit();
  1093. }
  1094. } //}}}
  1095. //}}}
  1096. //{{{ Selection
  1097. //{{{ selectAll() method
  1098. /**
  1099. * Selects all text in the buffer.
  1100. */
  1101. public final void selectAll()
  1102. {
  1103. setSelection(new Selection.Range(0,buffer.getLength()));
  1104. moveCaretPosition(buffer.getLength(),true);
  1105. } //}}}
  1106. //{{{ selectLine() method
  1107. /**
  1108. * Selects the current line.
  1109. * @since jEdit 2.7pre2
  1110. */
  1111. public void selectLine()
  1112. {
  1113. int caretLine = getCaretLine();
  1114. int start = getLineStartOffset(caretLine);
  1115. int end = getLineEndOffset(caretLine) - 1;
  1116. Selection s = new Selection.Range(start,end);
  1117. if(multi)
  1118. addToSelection(s);
  1119. else
  1120. setSelection(s);
  1121. moveCaretPosition(end);
  1122. } //}}}
  1123. //{{{ selectParagraph() method
  1124. /**
  1125. * Selects the paragraph at the caret position.
  1126. * @since jEdit 2.7pre2
  1127. */
  1128. public void selectParagraph()
  1129. {
  1130. int caretLine = getCaretLine();
  1131. if(getLineLength(caretLine) == 0)
  1132. {
  1133. getToolkit().beep();
  1134. return;
  1135. }
  1136. int start = caretLine;
  1137. int end = caretLine;
  1138. while(start >= 0)
  1139. {
  1140. if(getLineLength(start) == 0)
  1141. break;
  1142. else
  1143. start--;
  1144. }
  1145. while(end < getLineCount())
  1146. {
  1147. if(getLineLength(end) == 0)
  1148. break;
  1149. else
  1150. end++;
  1151. }
  1152. int selectionStart = getLineStartOffset(start + 1);
  1153. int selectionEnd = getLineEndOffset(end - 1) - 1;
  1154. Selection s = new Selection.Range(selectionStart,selectionEnd);
  1155. if(multi)
  1156. addToSelection(s);
  1157. else
  1158. setSelection(s);
  1159. moveCaretPosition(selectionEnd);
  1160. } //}}}
  1161. //{{{ selectWord() method
  1162. /**
  1163. * Selects the word at the caret position.
  1164. * @since jEdit 2.7pre2
  1165. */
  1166. public void selectWord()
  1167. {
  1168. int line = getCaretLine();
  1169. int lineStart = getLineStartOffset(line);
  1170. int offset = getCaretPosition() - lineStart;
  1171. if(getLineLength(line) == 0)
  1172. return;
  1173. String lineText = getLineText(line);
  1174. String noWordSep = buffer.getStringProperty("noWordSep");
  1175. if(offset == getLineLength(line))
  1176. offset--;
  1177. int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
  1178. int wordEnd = TextUtilities.findWordEnd(lineText,offset+1,noWordSep);
  1179. Selection s = new Selection.Range(lineStart + wordStart,
  1180. lineStart + wordEnd);
  1181. if(multi)
  1182. addToSelection(s);
  1183. else
  1184. setSelection(s);
  1185. moveCaretPosition(lineStart + wordEnd);
  1186. } //}}}
  1187. //{{{ selectToMatchingBracket() method
  1188. /**
  1189. * Selects from the bracket at the specified position to the
  1190. * corresponding bracket.
  1191. * @since jEdit 4.2pre1
  1192. */
  1193. public Selection selectToMatchingBracket(int position,
  1194. boolean quickCopy)
  1195. {
  1196. int positionLine = buffer.getLineOfOffset(position);
  1197. int lineOffset = position - buffer.getLineStartOffset(positionLine);
  1198. if(getLineLength(positionLine) != 0)
  1199. {
  1200. int bracket = TextUtilities.findMatchingBracket(buffer,
  1201. positionLine,Math.max(0,lineOffset - 1));
  1202. if(bracket != -1)
  1203. {
  1204. Selection s;
  1205. if(bracket < position)
  1206. {
  1207. if(!quickCopy)
  1208. moveCaretPosition(position,false);
  1209. s = new Selection.Range(bracket,position);
  1210. }
  1211. else
  1212. {
  1213. if(!quickCopy)
  1214. moveCaretPosition(bracket + 1,false);
  1215. s = new Selection.Range(position - 1,bracket + 1);
  1216. }
  1217. if(!multi && !quickCopy)
  1218. selectNone();
  1219. addToSelection(s);
  1220. return s;
  1221. }
  1222. }
  1223. return null;
  1224. } //}}}
  1225. //{{{ selectToMatchingBracket() method
  1226. /**
  1227. * Selects from the bracket at the caret position to the corresponding
  1228. * bracket.
  1229. * @since jEdit 4.0pre2
  1230. */
  1231. public void selectToMatchingBracket()
  1232. {
  1233. selectToMatchingBracket(caret,false);
  1234. } //}}}
  1235. //{{{ selectBlock() method
  1236. /**
  1237. * Selects the code block surrounding the caret.
  1238. * @since jEdit 2.7pre2
  1239. */
  1240. public void selectBlock()
  1241. {
  1242. String openBrackets = "([{";
  1243. String closeBrackets = ")]}";
  1244. Selection s = getSelectionAtOffset(caret);
  1245. int start, end;
  1246. if(s == null)
  1247. start = end = caret;
  1248. else
  1249. {
  1250. start = s.start;
  1251. end = s.end;
  1252. }
  1253. String text = getText(0,buffer.getLength());
  1254. // Scan backwards, trying to find a bracket
  1255. int count = 1;
  1256. char openBracket = '\0';
  1257. char closeBracket = '\0';
  1258. // We can't do the backward scan if start == 0
  1259. if(start == 0)
  1260. {
  1261. getToolkit().beep();
  1262. return;
  1263. }
  1264. backward_scan: while(--start > 0)
  1265. {
  1266. char c = text.charAt(start);
  1267. int index = openBrackets.indexOf(c);
  1268. if(index != -1)
  1269. {
  1270. if(--count == 0)
  1271. {
  1272. openBracket = c;
  1273. closeBracket = closeBrackets.charAt(index);
  1274. break backward_scan;
  1275. }
  1276. }
  1277. else if(closeBrackets.indexOf(c) != -1)
  1278. count++;
  1279. }
  1280. // Reset count
  1281. count = 1;
  1282. // Scan forward, matching that bracket
  1283. if(openBracket == '\0')
  1284. {
  1285. getToolkit().beep();
  1286. return;
  1287. }
  1288. else
  1289. {
  1290. forward_scan: do
  1291. {
  1292. char c = text.charAt(end);
  1293. if(c == closeBracket)
  1294. {
  1295. if(--count == 0)
  1296. {
  1297. end++;
  1298. break forward_scan;
  1299. }
  1300. }
  1301. else if(c == openBracket)
  1302. count++;
  1303. }
  1304. while(++end < buffer.getLength());
  1305. }
  1306. s = new Selection.Range(start,end);
  1307. if(multi)
  1308. addToSelection(s);
  1309. else
  1310. setSelection(s);
  1311. moveCaretPosition(end);
  1312. } //}}}
  1313. //{{{ lineInStructureScope() method
  1314. /**
  1315. * Returns if the specified line is contained in the currently
  1316. * matched structure's scope.
  1317. * @since jEdit 4.2pre3
  1318. */
  1319. public boolean lineInStructureScope(int line)
  1320. {
  1321. if(match == null)
  1322. return false;
  1323. if(match.startLine < caretLine)
  1324. return (line >= match.startLine && line <= caretLine);
  1325. else
  1326. return (line <= match.endLine && line >= caretLine);
  1327. } //}}}
  1328. //{{{ invertSelection() method
  1329. /**
  1330. * Inverts the selection.
  1331. * @since jEdit 4.0pre1
  1332. */
  1333. public final void invertSelection()
  1334. {
  1335. Selection[] newSelection = new Selection[selection.size() + 1];
  1336. int lastOffset = 0;
  1337. for(int i = 0; i < selection.size(); i++)
  1338. {
  1339. Selection s = (Selection)selection.elementAt(i);
  1340. newSelection[i] = new Selection.Range(lastOffset,
  1341. s.getStart());
  1342. lastOffset = s.getEnd();
  1343. }
  1344. newSelection[selection.size()] = new Selection.Range(
  1345. lastOffset,buffer.getLength());
  1346. setSelection(newSelection);
  1347. } //}}}
  1348. //{{{ getSelectionCount() method
  1349. /**
  1350. * Returns the number of selections. This can be used to test
  1351. * for the existence of selections.
  1352. * @since jEdit 3.2pre2
  1353. */
  1354. public int getSelectionCount()
  1355. {
  1356. return selection.size();
  1357. } //}}}
  1358. //{{{ getSelection() method
  1359. /**
  1360. * Returns the current selection.
  1361. * @since jEdit 3.2pre1
  1362. */
  1363. public Selection[] getSelection()
  1364. {
  1365. Selection[] sel = new Selection[selection.size()];
  1366. selection.copyInto(sel);
  1367. return sel;
  1368. } //}}}
  1369. //{{{ selectNone() method
  1370. /**
  1371. * Deselects everything.
  1372. */
  1373. public void selectNone()
  1374. {
  1375. setSelection((Selection)null);
  1376. } //}}}
  1377. //{{{ setSelection() method
  1378. /**
  1379. * Sets the selection. Nested and overlapping selections are merged
  1380. * where possible.
  1381. * @param selection The new selection
  1382. * since jEdit 3.2pre1
  1383. */
  1384. public void setSelection(Selection[] selection)
  1385. {
  1386. // invalidate the old selection
  1387. invalidateSelectedLines();
  1388. this.selection.removeAllElements();
  1389. if(selection != null)
  1390. {
  1391. for(int i = 0; i < selection.length; i++)
  1392. _addToSelection(selection[i]);
  1393. }
  1394. fireCaretEvent();
  1395. } //}}}
  1396. //{{{ setSelection() method
  1397. /**
  1398. * Sets the selection. Nested and overlapping selections are merged
  1399. * where possible.
  1400. * @param selection The new selection
  1401. * since jEdit 3.2pre1
  1402. */
  1403. public void setSelection(Selection selection)
  1404. {
  1405. invalidateSelectedLines();
  1406. this.selection.removeAllElements();
  1407. if(selection != null)
  1408. _addToSelection(selection);
  1409. fireCaretEvent();
  1410. } //}}}
  1411. //{{{ addToSelection() method
  1412. /**
  1413. * Adds to the selection. Nested and overlapping selections are merged
  1414. * where possible.
  1415. * @param selection The new selection
  1416. * since jEdit 3.2pre1
  1417. */
  1418. public void addToSelection(Selection[] selection)
  1419. {
  1420. if(selection != null)
  1421. {
  1422. for(int i = 0; i < selection.length; i++)
  1423. _addToSelection(selection[i]);
  1424. }
  1425. // to hide current line highlight
  1426. invalidateLine(caretLine);
  1427. fireCaretEvent();
  1428. } //}}}
  1429. //{{{ addToSelection() method
  1430. /**
  1431. * Adds to the selection. Nested and overlapping selections are merged
  1432. * where possible.
  1433. * @param selection The new selection
  1434. * since jEdit 3.2pre1
  1435. */
  1436. public void addToSelection(Selection selection)
  1437. {
  1438. _addToSelection(selection);
  1439. // to hide current line highlight
  1440. invalidateLine(caretLine);
  1441. fireCaretEvent();
  1442. } //}}}
  1443. //{{{ getSelectionAtOffset() method
  1444. /**
  1445. * Returns the selection containing the specific offset, or <code>null</code>
  1446. * if there is no selection at that offset.
  1447. * @param offset The offset
  1448. * @since jEdit 3.2pre1
  1449. */
  1450. public Selection getSelectionAtOffset(int offset)
  1451. {
  1452. if(selection != null)
  1453. {
  1454. for(int i = 0; i < selection.size(); i++)
  1455. {
  1456. Selection s = (Selection)selection.elementAt(i);
  1457. if(offset >= s.start && offset <= s.end)
  1458. return s;
  1459. }
  1460. }
  1461. return null;
  1462. } //}}}
  1463. //{{{ removeFromSelection() method
  1464. /**
  1465. * Deactivates the specified selection.
  1466. * @param s The selection
  1467. * @since jEdit 3.2pre1
  1468. */
  1469. public void removeFromSelection(Selection sel)
  1470. {
  1471. selection.removeElement(sel);
  1472. invalidateLineRange(sel.startLine,sel.endLine);
  1473. // to hide current line highlight
  1474. invalidateLine(caretLine);
  1475. fireCaretEvent();
  1476. } //}}}
  1477. //{{{ removeFromSelection() method
  1478. /**
  1479. * Deactivates the selection at the specified offset. If there is
  1480. * no selection at that offset, does nothing.
  1481. * @param offset The offset
  1482. * @since jEdit 3.2pre1
  1483. */
  1484. public void removeFromSelection(int offset)
  1485. {
  1486. Selection sel = getSelectionAtOffset(offset);
  1487. if(sel == null)
  1488. return;
  1489. selection.removeElement(sel);
  1490. invalidateLineRange(sel.startLine,sel.endLine);
  1491. // to hide current line highlight
  1492. invalidateLine(caretLine);
  1493. fireCaretEvent();
  1494. } //}}}
  1495. //{{{ resizeSelection() method
  1496. /**
  1497. * Resizes the selection at the specified offset, or creates a new
  1498. * one if there is no selection at the specified offset. This is a
  1499. * utility method that is mainly useful in the mouse event handler
  1500. * because it handles the case of end being before offset gracefully
  1501. * (unlike the rest of the selection API).
  1502. * @param offset The offset
  1503. * @param end The new selection end
  1504. * @param extraEndVirt Only for rectangular selections - specifies how
  1505. * far it extends into virtual space.
  1506. * @param rect Make the selection rectangular?
  1507. * @since jEdit 3.2pre1
  1508. */
  1509. public void resizeSelection(int offset, int end, int extraEndVirt,
  1510. boolean rect)
  1511. {
  1512. Selection s = getSelectionAtOffset(offset);
  1513. if(s != null)
  1514. {
  1515. invalidateLineRange(s.startLine,s.endLine);
  1516. selection.removeElement(s);
  1517. }
  1518. boolean reversed = false;
  1519. if(end < offset)
  1520. {
  1521. int tmp = offset;
  1522. offset = end;
  1523. end = tmp;
  1524. reversed = true;
  1525. }
  1526. Selection newSel;
  1527. if(rect)
  1528. {
  1529. Selection.Rect rectSel = new Selection.Rect(offset,end);
  1530. if(reversed)
  1531. rectSel.extraStartVirt = extraEndVirt;
  1532. else
  1533. rectSel.extraEndVirt = extraEndVirt;
  1534. newSel = rectSel;
  1535. }
  1536. else
  1537. newSel = new Selection.Range(offset,end);
  1538. _addToSelection(newSel);
  1539. fireCaretEvent();
  1540. } //}}}
  1541. //{{{ extendSelection() method
  1542. /**
  1543. * Extends the selection at the specified offset, or creates a new
  1544. * one if there is no selection at the specified offset. This is
  1545. * different from resizing in that the new chunk is added to the
  1546. * selection in question, instead of replacing it.
  1547. * @param offset The offset
  1548. * @param end The new selection end
  1549. * @since jEdit 3.2pre1
  1550. */
  1551. public void extendSelection(int offset, int end)
  1552. {
  1553. extendSelection(offset,end,0,0);
  1554. } //}}}
  1555. //{{{ extendSelection() method
  1556. /**
  1557. * Extends the selection at the specified offset, or creates a new
  1558. * one if there is no selection at the specified offset. This is
  1559. * different from resizing in that the new chunk is added to the
  1560. * selection in question, instead of replacing it.
  1561. * @param offset The offset
  1562. * @param end The new selection end
  1563. * @param extraStartVirt Extra virtual space at the start
  1564. * @param extraEndVirt Extra virtual space at the end
  1565. * @since jEdit 4.2pre1
  1566. */
  1567. public void extendSelection(int offset, int end,
  1568. int extraStartVirt, int extraEndVirt)
  1569. {
  1570. Selection s = getSelectionAtOffset(offset);
  1571. if(s != null)
  1572. {
  1573. invalidateLineRange(s.startLine,s.endLine);
  1574. selection.removeElement(s);
  1575. if(offset == s.start)
  1576. {
  1577. offset = end;
  1578. end = s.end;
  1579. }
  1580. else if(offset == s.end)
  1581. {
  1582. offset = s.start;
  1583. }
  1584. }
  1585. if(end < offset)
  1586. {
  1587. int tmp = end;
  1588. end = offset;
  1589. offset = tmp;
  1590. }
  1591. if(rectangularSelectionMode)
  1592. {
  1593. s = new Selection.Rect(offset,end);
  1594. ((Selection.Rect)s).extraStartVirt = extraStartVirt;
  1595. ((Selection.Rect)s).extraEndVirt = extraEndVirt;
  1596. }
  1597. else
  1598. s = new Selection.Range(offset,end);
  1599. _addToSelection(s);
  1600. fireCaretEvent();
  1601. if(rectangularSelectionMode && extraEndVirt != 0)
  1602. {
  1603. int line = getLineOfOffset(end);
  1604. scrollTo(line,getLineLength(line) + extraEndVirt,false);
  1605. }
  1606. } //}}}
  1607. //{{{ getSelectedText() method
  1608. /**
  1609. * Returns the text in the specified selection.
  1610. * @param s The selection
  1611. * @since jEdit 3.2pre1
  1612. */
  1613. public String getSelectedText(Selection s)
  1614. {
  1615. StringBuffer buf = new StringBuffer();
  1616. s.getText(buffer,buf);
  1617. return buf.toString();
  1618. } //}}}
  1619. //{{{ getSelectedText() method
  1620. /**
  1621. * Returns the text in all active selections.
  1622. * @param separator The string to insert between each text chunk
  1623. * (for example, a newline)
  1624. * @since jEdit 3.2pre1
  1625. */
  1626. public String getSelectedText(String separator)
  1627. {
  1628. if(selection.size() == 0)
  1629. return null;
  1630. StringBuffer buf = new StringBuffer();
  1631. for(int i = 0; i < selection.size(); i++)
  1632. {
  1633. if(i != 0)
  1634. buf.append(separator);
  1635. ((Selection)selection.elementAt(i)).getText(buffer,buf);
  1636. }
  1637. return buf.toString();
  1638. } //}}}
  1639. //{{{ getSelectedText() method
  1640. /**
  1641. * Returns the text in all active selections, with a newline
  1642. * between each text chunk.
  1643. */
  1644. public String getSelectedText()
  1645. {
  1646. return getSelectedText("\n");
  1647. } //}}}
  1648. //{{{ setSelectedText() method
  1649. /**
  1650. * Replaces the selection with the specified text.
  1651. * @param s The selection
  1652. * @param selectedText The new text
  1653. * @since jEdit 3.2pre1
  1654. */
  1655. public void setSelectedText(Selection s, String selectedText)
  1656. {
  1657. if(!isEditable())
  1658. {
  1659. throw new InternalError("Text component"
  1660. + " read only");
  1661. }
  1662. try
  1663. {
  1664. buffer.beginCompoundEdit();
  1665. moveCaretPosition(s.setText(buffer,selectedText));
  1666. }
  1667. // No matter what happends... stops us from leaving buffer
  1668. // in a bad state
  1669. finally
  1670. {
  1671. buffer.endCompoundEdit();
  1672. }
  1673. // no no no!!!!
  1674. //selectNone();
  1675. } //}}}
  1676. //{{{ setSelectedText() method
  1677. /**
  1678. * Replaces the selection at the caret with the specified text.
  1679. * If there is no selection at the caret, the text is inserted at
  1680. * the caret position.
  1681. */
  1682. public void setSelectedText(String selectedText)
  1683. {
  1684. if(!isEditable())
  1685. {
  1686. throw new InternalError("Text component"
  1687. + " read only");
  1688. }
  1689. Selection[] selection = getSelection();
  1690. if(selection.length == 0)
  1691. {
  1692. // for compatibility with older jEdit versions
  1693. buffer.insert(caret,selectedText);
  1694. }
  1695. else
  1696. {
  1697. try
  1698. {
  1699. int newCaret = -1;
  1700. buffer.beginCompoundEdit();
  1701. for(int i = 0; i < selection.length; i++)
  1702. {
  1703. newCaret = selection[i].setText(buffer,selectedText);
  1704. }
  1705. moveCaretPosition(newCaret);
  1706. }
  1707. finally
  1708. {
  1709. buffer.endCompoundEdit();
  1710. }
  1711. }
  1712. selectNone();
  1713. } //}}}
  1714. //{{{ getSelectedLines() method
  1715. /**
  1716. * Returns a sorted array of line numbers on which a selection or
  1717. * selections are present.<p>
  1718. *
  1719. * This method is the most convenient way to iterate through selected
  1720. * lines in a buffer. The line numbers in the array returned by this
  1721. * method can be passed as a parameter to such methods as
  1722. * {@link org.gjt.sp.jedit.Buffer#getLineText(int)}.
  1723. *
  1724. * @since jEdit 3.2pre1
  1725. */
  1726. public int[] getSelectedLines()
  1727. {
  1728. if(selection.size() == 0)
  1729. return new int[] { caretLine };
  1730. Integer line;
  1731. Set set = new TreeSet();
  1732. for(int i = 0; i < selection.size(); i++)
  1733. {
  1734. Selection s = (Selection)selection.elementAt(i);
  1735. int endLine = (s.end == getLineStartOffset(s.endLine)
  1736. ? s.endLine - 1
  1737. : s.endLine);
  1738. for(int j = s.startLine; j <= endLine; j++)
  1739. {
  1740. line = new Integer(j);
  1741. set.add(line);
  1742. }
  1743. }
  1744. int[] returnValue = new int[set.size()];
  1745. int i = 0;
  1746. Iterator iter = set.iterator();
  1747. while(iter.hasNext())
  1748. {
  1749. line = (Integer)iter.next();
  1750. returnValue[i++] = line.intValue();
  1751. }
  1752. return returnValue;
  1753. } //}}}
  1754. //{{{ showSelectLineRangeDialog() method
  1755. /**
  1756. * Displays the 'select line range' dialog box, and selects the
  1757. * specified range of lines.
  1758. * @since jEdit 2.7pre2
  1759. */
  1760. public void showSelectLineRangeDialog()
  1761. {
  1762. new SelectLineRange(view);
  1763. } //}}}
  1764. //}}}
  1765. //{{{ Caret
  1766. //{{{ addStructureMatcher() method
  1767. /**
  1768. * Adds a structure matcher.
  1769. * @since jEdit 4.2pre3
  1770. */
  1771. public void addStructureMatcher(StructureMatcher matcher)
  1772. {
  1773. structureMatchers.add(matcher);
  1774. } //}}}
  1775. //{{{ removeStructureMatcher() method
  1776. /**
  1777. * Removes a structure matcher.
  1778. * @since jEdit 4.2pre3
  1779. */
  1780. public void removeStructureMatcher(StructureMatcher matcher)
  1781. {
  1782. structureMatchers.remove(matcher);
  1783. } //}}}
  1784. //{{{ getStructureMatch() method
  1785. /**
  1786. * Returns the structure element (bracket, or XML tag, etc) matching the
  1787. * one before the caret.
  1788. * @since jEdit 4.2pre3
  1789. */
  1790. public StructureMatcher.Match getStructureMatch()
  1791. {
  1792. return match;
  1793. } //}}}
  1794. //{{{ blinkCaret() method
  1795. /**
  1796. * Blinks the caret.
  1797. */
  1798. public final void blinkCaret()
  1799. {
  1800. if(caretBlinks)
  1801. {
  1802. blink = !blink;
  1803. invalidateLine(caretLine);
  1804. }
  1805. else
  1806. blink = true;
  1807. } //}}}
  1808. //{{{ centerCaret() method
  1809. /**
  1810. * Centers the caret on the screen.
  1811. * @since jEdit 2.7pre2
  1812. */
  1813. public void centerCaret()
  1814. {
  1815. int offset = getScreenLineStartOffset(visibleLines / 2);
  1816. if(offset == -1)
  1817. getToolkit().beep();
  1818. else
  1819. setCaretPosition(offset);
  1820. } //}}}
  1821. //{{{ setCaretPosition() method
  1822. /**
  1823. * Sets the caret position and deactivates the selection.
  1824. * @param caret The caret position
  1825. */
  1826. public void setCaretPosition(int newCaret)
  1827. {
  1828. invalidateSelectedLines();
  1829. selection.removeAllElements();
  1830. moveCaretPosition(newCaret,true);
  1831. } //}}}
  1832. //{{{ setCaretPosition() method
  1833. /**
  1834. * Sets the caret position and deactivates the selection.
  1835. * @param caret The caret position
  1836. * @param doElectricScroll Do electric scrolling?
  1837. */
  1838. public void setCaretPosition(int newCaret, boolean doElectricScroll)
  1839. {
  1840. invalidateSelectedLines();
  1841. selection.removeAllElements();
  1842. moveCaretPosition(newCaret,doElectricScroll);
  1843. } //}}}
  1844. //{{{ moveCaretPosition() method
  1845. /**
  1846. * Sets the caret position without deactivating the selection.
  1847. * @param caret The caret position
  1848. */
  1849. public void moveCaretPosition(int newCaret)
  1850. {
  1851. moveCaretPosition(newCaret,true);
  1852. } //}}}
  1853. //{{{ moveCaretPosition() method
  1854. /**
  1855. * Sets the caret position without deactivating the selection.
  1856. * @param caret The caret position
  1857. * @param doElectricScroll Do electric scrolling?
  1858. */
  1859. public void moveCaretPosition(int newCaret, boolean doElectricScroll)
  1860. {
  1861. moveCaretPosition(newCaret,doElectricScroll ? ELECTRIC_SCROLL
  1862. : NORMAL_SCROLL);
  1863. } //}}}
  1864. //{{{ moveCaretPosition() method
  1865. public int NO_SCROLL = 0;
  1866. public int NORMAL_SCROLL = 1;
  1867. public int ELECTRIC_SCROLL = 2;
  1868. /**
  1869. * Sets the caret position without deactivating the selection.
  1870. * @param caret The caret position
  1871. * @param scrollMode The scroll mode (NO_SCROLL, NORMAL_SCROLL, or
  1872. * ELECTRIC_SCROLL).
  1873. * @since jEdit 4.2pre1
  1874. */
  1875. public void moveCaretPosition(int newCaret, int scrollMode)
  1876. {
  1877. if(newCaret < 0 || newCaret > buffer.getLength())
  1878. {
  1879. throw new IllegalArgumentException("caret out of bounds: "
  1880. + newCaret);
  1881. }
  1882. if(match != null)
  1883. {
  1884. if(caretLine < match.startLine)
  1885. invalidateLineRange(caretLine,match.endLine);
  1886. else
  1887. invalidateLineRange(match.startLine,caretLine);
  1888. match = null;
  1889. }
  1890. if(caret == newCaret)
  1891. {
  1892. if(scrollMode == NORMAL_SCROLL)
  1893. finishCaretUpdate(false,false);
  1894. else if(scrollMode == ELECTRIC_SCROLL)
  1895. finishCaretUpdate(true,false);
  1896. }
  1897. else
  1898. {
  1899. int newCaretLine = getLineOfOffset(newCaret);
  1900. magicCaret = -1;
  1901. if(!displayManager.isLineVisible(newCaretLine))
  1902. {
  1903. if(newCaretLine < displayManager.getFirstVisibleLine()
  1904. || newCaretLine > displayManager.getLastVisibleLine())
  1905. {
  1906. int collapseFolds = buffer.getIntegerProperty(
  1907. "collapseFolds",0);
  1908. if(collapseFolds != 0)
  1909. {
  1910. displayManager.expandFolds(collapseFolds);
  1911. displayManager.expandFold(newCaretLine,false);
  1912. }
  1913. else
  1914. displayManager.expandAllFolds();
  1915. }
  1916. else
  1917. displayManager.expandFold(newCaretLine,false);
  1918. }
  1919. if(caretLine == newCaretLine)
  1920. {
  1921. if(caretScreenLine != -1)
  1922. invalidateScreenLineRange(caretScreenLine,caretScreenLine);
  1923. }
  1924. else
  1925. {
  1926. int newCaretScreenLine = chunkCache.getScreenLineOfOffset(newCaretLine,
  1927. newCaret - buffer.getLineStartOffset(newCaretLine));
  1928. if(caretScreenLine == -1)
  1929. invalidateScreenLineRange(newCaretScreenLine,newCaretScreenLine);
  1930. else
  1931. invalidateScreenLineRange(caretScreenLine,newCaretScreenLine);
  1932. caretScreenLine = newCaretScreenLine;
  1933. }
  1934. caret = newCaret;
  1935. caretLine = newCaretLine;
  1936. if(scrollMode == NORMAL_SCROLL)
  1937. finishCaretUpdate(false,true);
  1938. else if(scrollMode == ELECTRIC_SCROLL)
  1939. finishCaretUpdate(true,true);
  1940. }
  1941. } //}}}
  1942. //{{{ getCaretPosition() method
  1943. /**
  1944. * Returns a zero-based index of the caret position.
  1945. */
  1946. public int getCaretPosition()
  1947. {
  1948. return caret;
  1949. } //}}}
  1950. //{{{ getCaretLine() method
  1951. /**
  1952. * Returns the line number containing the caret.
  1953. */
  1954. public int getCaretLine()
  1955. {
  1956. return caretLine;
  1957. } //}}}
  1958. //{{{ getMagicCaretPosition() method
  1959. /**
  1960. * Returns an internal position used to keep the caret in one
  1961. * column while moving around lines of varying lengths.
  1962. * @since jEdit 4.2pre1
  1963. */
  1964. public int getMagicCaretPosition()
  1965. {
  1966. if(magicCaret == -1)
  1967. {
  1968. magicCaret = chunkCache.subregionOffsetToX(
  1969. caretLine,caret - getLineStartOffset(caretLine));
  1970. }
  1971. return magicCaret;
  1972. } //}}}
  1973. //{{{ setMagicCaretPosition() method
  1974. /**
  1975. * Sets the `magic' caret position. This can be used to preserve
  1976. * the column position when moving up and down lines.
  1977. * @param magicCaret The magic caret position
  1978. * @since jEdit 4.2pre1
  1979. */
  1980. public void setMagicCaretPosition(int magicCaret)
  1981. {
  1982. this.magicCaret = magicCaret;
  1983. } //}}}
  1984. //{{{ addCaretListener() method
  1985. /**
  1986. * Adds a caret change listener to this text area.
  1987. * @param listener The listener
  1988. */
  1989. public final void addCaretListener(CaretListener listener)
  1990. {
  1991. listenerList.add(CaretListener.class,listener);
  1992. } //}}}
  1993. //{{{ removeCaretListener() method
  1994. /**
  1995. * Removes a caret change listener from this text area.
  1996. * @param listener The listener
  1997. */
  1998. public final void removeCaretListener(CaretListener listener)
  1999. {
  2000. listenerList.remove(CaretListener.class,listener);
  2001. } //}}}
  2002. //{{{ goToNextBracket() method
  2003. /**
  2004. * Moves the caret to the next closing bracket.
  2005. * @since jEdit 2.7pre2.
  2006. */
  2007. public void goToNextBracket(boolean select)
  2008. {
  2009. String text = getText(caret,buffer.getLength() - caret - 1);
  2010. int newCaret = -1;
  2011. loop: for(int i = 0; i < text.length(); i++)
  2012. {
  2013. switch(text.charAt(i))
  2014. {
  2015. case ')': case ']': case '}':
  2016. newCaret = caret + i + 1;
  2017. break loop;
  2018. }
  2019. }
  2020. if(newCaret == -1)
  2021. getToolkit().beep();
  2022. else
  2023. {
  2024. if(select)
  2025. extendSelection(caret,newCaret);
  2026. else if(!multi)
  2027. selectNone();
  2028. moveCaretPosition(newCaret);
  2029. }
  2030. } //}}}
  2031. //{{{ goToNextCharacter() method
  2032. /**
  2033. * Moves the caret to the next character.
  2034. * @since jEdit 2.7pre2.
  2035. */
  2036. public void goToNextCharacter(boolean select)
  2037. {
  2038. Selection s = getSelectionAtOffset(caret);
  2039. if(!select && s instanceof Selection.Range)
  2040. {
  2041. if(multi)
  2042. {
  2043. if(caret != s.end)
  2044. {
  2045. moveCaretPosition(s.end);
  2046. return;
  2047. }
  2048. }
  2049. else
  2050. {
  2051. setCaretPosition(s.end);
  2052. return;
  2053. }
  2054. }
  2055. int extraStartVirt, extraEndVirt;
  2056. if(s instanceof Selection.Rect)
  2057. {
  2058. extraStartVirt = ((Selection.Rect)s).extraStartVirt;
  2059. extraEndVirt = ((Selection.Rect)s).extraEndVirt;
  2060. }
  2061. else
  2062. {
  2063. extraStartVirt = 0;
  2064. extraEndVirt = 0;
  2065. }
  2066. int newCaret = caret;
  2067. if(select && caret == buffer.getLength())
  2068. {
  2069. if(rectangularSelectionMode || s instanceof Selection.Rect)
  2070. {
  2071. if(caret == s.start)
  2072. extraStartVirt++;
  2073. else
  2074. extraEndVirt++;
  2075. }
  2076. else
  2077. {
  2078. getToolkit().beep();
  2079. return;
  2080. }
  2081. }
  2082. else if(caret == getLineEndOffset(caretLine) - 1)
  2083. {
  2084. if(rectangularSelectionMode || s instanceof Selection.Rect)
  2085. {
  2086. if(caret == s.start)
  2087. extraStartVirt++;
  2088. else
  2089. extraEndVirt++;
  2090. }
  2091. else
  2092. {
  2093. int line = displayManager.getNextVisibleLine(caretLine);
  2094. if(line == -1)
  2095. {
  2096. getToolkit().beep();
  2097. return;
  2098. }
  2099. else
  2100. newCaret = getLineStartOffset(line);
  2101. }
  2102. }
  2103. else
  2104. newCaret = caret + 1;
  2105. if(select)
  2106. extendSelection(caret,newCaret,extraStartVirt,extraEndVirt);
  2107. else if(!multi)
  2108. selectNone();
  2109. moveCaretPosition(newCaret);
  2110. } //}}}
  2111. //{{{ goToNextLine() method
  2112. /**
  2113. * Move the caret to the next line.
  2114. * @since jEdit 2.7pre2
  2115. */
  2116. public void goToNextLine(boolean select)
  2117. {
  2118. Selection s = getSelectionAtOffset(caret);
  2119. boolean rectSelect = (s == null ? rectangularSelectionMode
  2120. : s instanceof Selection.Rect);
  2121. int magic = getMagicCaretPosition();
  2122. int newCaret = chunkCache.getBelowPosition(caretLine,
  2123. caret - buffer.getLineStartOffset(caretLine),magic + 1,
  2124. rectSelect && select);
  2125. if(newCaret == -1)
  2126. {
  2127. int end = getLineEndOffset(caretLine) - 1;
  2128. if(caret == end)
  2129. {
  2130. getToolkit().beep();
  2131. return;
  2132. }
  2133. else
  2134. newCaret = end;
  2135. }
  2136. if(select)
  2137. {
  2138. RectParams params = getRectParams(caret,newCaret);
  2139. int extraStartVirt;
  2140. int extraEndVirt;
  2141. if(params == null)
  2142. {
  2143. extraStartVirt = 0;
  2144. extraEndVirt = 0;
  2145. }
  2146. else
  2147. {
  2148. extraStartVirt = params.extraStartVirt;
  2149. extraEndVirt = params.extraEndVirt;
  2150. newCaret = params.newCaret;
  2151. }
  2152. extendSelection(caret,newCaret,extraStartVirt,extraEndVirt);
  2153. }
  2154. else if(!multi)
  2155. selectNone();
  2156. moveCaretPosition(newCaret);
  2157. setMagicCaretPosition(magic);
  2158. } //}}}
  2159. //{{{ goToNextMarker() method
  2160. /**
  2161. * Moves the caret to the next marker.
  2162. * @since jEdit 2.7pre2
  2163. */
  2164. public void goToNextMarker(boolean select)
  2165. {
  2166. Vector markers = buffer.getMarkers();
  2167. if(markers.size() == 0)
  2168. {
  2169. getToolkit().beep();
  2170. return;
  2171. }
  2172. Marker marker = null;
  2173. for(int i = 0; i < markers.size(); i++)
  2174. {
  2175. Marker _marker = (Marker)markers.get(i);
  2176. if(_marker.getPosition() > caret)
  2177. {
  2178. marker = _marker;
  2179. break;
  2180. }
  2181. }
  2182. if(marker == null)
  2183. marker = (Marker)markers.get(0);
  2184. if(select)
  2185. extendSelection(caret,marker.getPosition());
  2186. else if(!multi)
  2187. selectNone();
  2188. moveCaretPosition(marker.getPosition());
  2189. } //}}}
  2190. //{{{ goToNextPage() method
  2191. /**
  2192. * Moves the caret to the next screenful.
  2193. * @since jEdit 2.7pre2.
  2194. */
  2195. public void goToNextPage(boolean select)
  2196. {
  2197. scrollToCaret(false);
  2198. int magic = getMagicCaretPosition();
  2199. int caretScreenLine = getScreenLineOfOffset(caret);
  2200. scrollDownPage();
  2201. int newCaret = xToScreenLineOffset(caretScreenLine,magic,true);
  2202. if(select)
  2203. extendSelection(caret,newCaret);
  2204. else if(!multi)
  2205. selectNone();
  2206. moveCaretPosition(newCaret,false);
  2207. setMagicCaretPosition(magic);
  2208. } //}}}
  2209. //{{{ goToNextParagraph() method
  2210. /**
  2211. * Moves the caret to the start of the next paragraph.
  2212. * @since jEdit 2.7pre2
  2213. */
  2214. public void goToNextParagraph(boolean select)
  2215. {
  2216. int lineNo = getCaretLine();
  2217. int newCaret = getBufferLength();
  2218. boolean foundBlank = false;
  2219. loop: for(int i = lineNo + 1; i < getLineCount(); i++)
  2220. {
  2221. if(!displayManager.isLineVisible(i))
  2222. continue;
  2223. getLineText(i,lineSegment);
  2224. for(int j = 0; j < lineSegment.count; j++)
  2225. {
  2226. switch(lineSegment.array[lineSegment.offset + j])
  2227. {
  2228. case ' ':
  2229. case '\t':
  2230. break;
  2231. default:
  2232. if(foundBlank)
  2233. {
  2234. newCaret = getLineStartOffset(i);
  2235. break loop;
  2236. }
  2237. else
  2238. continue loop;
  2239. }
  2240. }
  2241. foundBlank = true;
  2242. }
  2243. if(select)
  2244. extendSelection(caret,newCaret);
  2245. else if(!multi)
  2246. selectNone();
  2247. moveCaretPosition(newCaret);
  2248. } //}}}
  2249. //{{{ goToNextWord() method
  2250. /**
  2251. * Moves the caret to the start of the next word.
  2252. * Note that if the "view.stdNextPrevWord" boolean propery is false,
  2253. * this method moves the caret to the end of the current word instead.
  2254. * @since jEdit 2.7pre2
  2255. */
  2256. public void goToNextWord(boolean select)
  2257. {
  2258. goToNextWord(select,false);
  2259. } //}}}
  2260. //{{{ goToNextWord() method
  2261. /**
  2262. * Moves the caret to the start of the next word.
  2263. * @since jEdit 4.1pre5
  2264. */
  2265. public void goToNextWord(boolean select, boolean stdNextPrevWord)
  2266. {
  2267. int lineStart = getLineStartOffset(caretLine);
  2268. int newCaret = caret - lineStart;
  2269. String lineText = getLineText(caretLine);
  2270. if(newCaret == lineText.length())
  2271. {
  2272. int nextLine = displayManager.getNextVisibleLine(caretLine);
  2273. if(nextLine == -1)
  2274. {
  2275. getToolkit().beep();
  2276. return;
  2277. }
  2278. newCaret = getLineStartOffset(nextLine);
  2279. }
  2280. else
  2281. {
  2282. String noWordSep = buffer.getStringProperty("noWordSep");
  2283. newCaret = TextUtilities.findWordEnd(lineText,newCaret + 1,
  2284. noWordSep);
  2285. if(stdNextPrevWord)
  2286. {
  2287. while((newCaret < lineText.length()) && Character.isWhitespace(lineText.charAt(newCaret)))
  2288. newCaret = TextUtilities.findWordEnd(lineText,newCaret + 1,
  2289. noWordSep);
  2290. }
  2291. newCaret += lineStart;
  2292. }
  2293. if(select)
  2294. extendSelection(caret,newCaret);
  2295. else if(!multi)
  2296. selectNone();
  2297. moveCaretPosition(newCaret);
  2298. } //}}}
  2299. //{{{ goToPrevBracket() method
  2300. /**
  2301. * Moves the caret to the previous bracket.
  2302. * @since jEdit 2.7pre2
  2303. */
  2304. public void goToPrevBracket(boolean select)
  2305. {
  2306. String text = getText(0,caret);
  2307. int newCaret = -1;
  2308. loop: for(int i = getCaretPosition() - 1; i >= 0; i--)
  2309. {
  2310. switch(text.charAt(i))
  2311. {
  2312. case '(': case '[': case '{':
  2313. newCaret = i;
  2314. break loop;
  2315. }
  2316. }
  2317. if(newCaret == -1)
  2318. getToolkit().beep();
  2319. else
  2320. {
  2321. if(select)
  2322. extendSelection(caret,newCaret);
  2323. else if(!multi)
  2324. selectNone();
  2325. moveCaretPosition(newCaret);
  2326. }
  2327. } //}}}
  2328. //{{{ goToPrevCharacter() method
  2329. /**
  2330. * Moves the caret to the previous character.
  2331. * @since jEdit 2.7pre2.
  2332. */
  2333. public void goToPrevCharacter(boolean select)
  2334. {
  2335. Selection s = getSelectionAtOffset(caret);
  2336. if(!select && s instanceof Selection.Range)
  2337. {
  2338. if(multi)
  2339. {
  2340. if(caret != s.start)
  2341. {
  2342. moveCaretPosition(s.start);
  2343. return;
  2344. }
  2345. }
  2346. else
  2347. {
  2348. setCaretPosition(s.start);
  2349. return;
  2350. }
  2351. }
  2352. int extraStartVirt = 0;
  2353. int extraEndVirt = 0;
  2354. int newCaret = caret;
  2355. if(select && caret == getLineEndOffset(caretLine) - 1)
  2356. {
  2357. if(s instanceof Selection.Rect)
  2358. {
  2359. extraStartVirt = ((Selection.Rect)s).extraStartVirt;
  2360. extraEndVirt = ((Selection.Rect)s).extraEndVirt;
  2361. if(caret == s.start)
  2362. {
  2363. if(extraStartVirt == 0)
  2364. newCaret = caret - 1;
  2365. else
  2366. extraStartVirt--;
  2367. }
  2368. else
  2369. {
  2370. if(extraEndVirt == 0)
  2371. newCaret = caret - 1;
  2372. else
  2373. extraEndVirt--;
  2374. }
  2375. }
  2376. else
  2377. newCaret = caret - 1;
  2378. }
  2379. else if(caret == getLineStartOffset(caretLine))
  2380. {
  2381. int line = displayManager.getPrevVisibleLine(caretLine);
  2382. if(line == -1)
  2383. {
  2384. getToolkit().beep();
  2385. return;
  2386. }
  2387. newCaret = getLineEndOffset(line) - 1;
  2388. }
  2389. else
  2390. newCaret = caret - 1;
  2391. if(select)
  2392. extendSelection(caret,newCaret,extraStartVirt,extraEndVirt);
  2393. else if(!multi)
  2394. selectNone();
  2395. moveCaretPosition(newCaret);
  2396. } //}}}
  2397. //{{{ goToPrevLine() method
  2398. /**
  2399. * Moves the caret to the previous line.
  2400. * @since jEdit 2.7pre2
  2401. */
  2402. public void goToPrevLine(boolean select)
  2403. {
  2404. Selection s = getSelectionAtOffset(caret);
  2405. boolean rectSelect = (s == null ? rectangularSelectionMode
  2406. : s instanceof Selection.Rect);
  2407. int magic = getMagicCaretPosition();
  2408. int newCaret = chunkCache.getAbovePosition(caretLine,
  2409. caret - buffer.getLineStartOffset(caretLine),magic + 1,
  2410. rectSelect && select);
  2411. if(newCaret == -1)
  2412. {
  2413. int start = getLineStartOffset(caretLine);
  2414. if(caret == start)
  2415. {
  2416. getToolkit().beep();
  2417. return;
  2418. }
  2419. else
  2420. newCaret = start;
  2421. }
  2422. if(select)
  2423. {
  2424. RectParams params = getRectParams(caret,newCaret);
  2425. int extraStartVirt;
  2426. int extraEndVirt;
  2427. if(params == null)
  2428. {
  2429. extraStartVirt = 0;
  2430. extraEndVirt = 0;
  2431. }
  2432. else
  2433. {
  2434. extraStartVirt = params.extraStartVirt;
  2435. extraEndVirt = params.extraEndVirt;
  2436. newCaret = params.newCaret;
  2437. }
  2438. extendSelection(caret,newCaret,extraStartVirt,extraEndVirt);
  2439. }
  2440. else if(!multi)
  2441. selectNone();
  2442. moveCaretPosition(newCaret);
  2443. setMagicCaretPosition(magic);
  2444. } //}}}
  2445. //{{{ goToPrevMarker() method
  2446. /**
  2447. * Moves the caret to the previous marker.
  2448. * @since jEdit 2.7pre2
  2449. */
  2450. public void goToPrevMarker(boolean select)
  2451. {
  2452. Vector markers = buffer.getMarkers();
  2453. if(markers.size() == 0)
  2454. {
  2455. getToolkit().beep();
  2456. return;
  2457. }
  2458. Marker marker = null;
  2459. for(int i = markers.size() - 1; i >= 0; i--)
  2460. {
  2461. Marker _marker = (Marker)markers.elementAt(i);
  2462. if(_marker.getPosition() < caret)
  2463. {
  2464. marker = _marker;
  2465. break;
  2466. }
  2467. }
  2468. if(marker == null)
  2469. marker = (Marker)markers.get(markers.size() - 1);
  2470. if(select)
  2471. extendSelection(caret,marker.getPosition());
  2472. else if(!multi)
  2473. selectNone();
  2474. moveCaretPosition(marker.getPosition());
  2475. } //}}}
  2476. //{{{ goToPrevPage() method
  2477. /**
  2478. * Moves the caret to the previous screenful.
  2479. * @since jEdit 2.7pre2
  2480. */
  2481. public void goToPrevPage(boolean select)
  2482. {
  2483. scrollToCaret(false);
  2484. int magic = getMagicCaretPosition();
  2485. int caretScreenLine = getScreenLineOfOffset(caret);
  2486. scrollUpPage();
  2487. int newCaret = xToScreenLineOffset(caretScreenLine,magic,true);
  2488. if(select)
  2489. extendSelection(caret,newCaret);
  2490. else if(!multi)
  2491. selectNone();
  2492. moveCaretPosition(newCaret,false);
  2493. setMagicCaretPosition(magic);
  2494. } //}}}
  2495. //{{{ goToPrevParagraph() method
  2496. /**
  2497. * Moves the caret to the start of the previous paragraph.
  2498. * @since jEdit 2.7pre2
  2499. */
  2500. public void goToPrevParagraph(boolean select)
  2501. {
  2502. int lineNo = caretLine;
  2503. int newCaret = 0;
  2504. boolean foundBlank = false;
  2505. loop: for(int i = lineNo - 1; i >= 0; i--)
  2506. {
  2507. if(!displayManager.isLineVisible(i))
  2508. continue;
  2509. getLineText(i,lineSegment);
  2510. for(int j = 0; j < lineSegment.count; j++)
  2511. {
  2512. switch(lineSegment.array[lineSegment.offset + j])
  2513. {
  2514. case ' ':
  2515. case '\t':
  2516. break;
  2517. default:
  2518. if(foundBl