PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

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

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