PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/textarea/JEditTextArea.java

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