PageRenderTime 46ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 930 lines | 584 code | 116 blank | 230 comment | 98 complexity | 8a3303bcd2ff7792f7276b47c4e16005 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. * Gutter.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000 mike dillon
  7. * Portions copyright (C) 2001, 2002 Slava Pestov
  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 javax.swing.*;
  29. import javax.swing.border.*;
  30. import javax.swing.event.*;
  31. import org.gjt.sp.jedit.*;
  32. import org.gjt.sp.util.Log;
  33. //}}}
  34. /**
  35. * The gutter is the component that displays folding triangles and line
  36. * numbers to the left of the text area. The only methods in this class
  37. * that should be called by plugins are those for adding and removing
  38. * text area extensions.
  39. *
  40. * @see #addExtension(TextAreaExtension)
  41. * @see #addExtension(int,TextAreaExtension)
  42. * @see #removeExtension(TextAreaExtension)
  43. * @see TextAreaExtension
  44. * @see JEditTextArea
  45. *
  46. * @author Mike Dillon and Slava Pestov
  47. * @version $Id: Gutter.java 4328 2002-08-27 22:31:39Z spestov $
  48. */
  49. public class Gutter extends JComponent implements SwingConstants
  50. {
  51. //{{{ Layers
  52. /**
  53. * The lowest possible layer.
  54. * @see #addExtension(int,TextAreaExtension)
  55. * @since jEdit 4.0pre4
  56. */
  57. public static final int LOWEST_LAYER = Integer.MIN_VALUE;
  58. /**
  59. * Default extension layer. This is above the wrap guide but below the
  60. * bracket highlight.
  61. * @since jEdit 4.0pre4
  62. */
  63. public static final int DEFAULT_LAYER = 0;
  64. /**
  65. * Highest possible layer.
  66. * @since jEdit 4.0pre4
  67. */
  68. public static final int HIGHEST_LAYER = Integer.MAX_VALUE;
  69. //}}}
  70. //{{{ Gutter constructor
  71. public Gutter(View view, JEditTextArea textArea)
  72. {
  73. this.view = view;
  74. this.textArea = textArea;
  75. setAutoscrolls(true);
  76. setOpaque(true);
  77. extensionMgr = new ExtensionManager();
  78. MouseHandler ml = new MouseHandler();
  79. addMouseListener(ml);
  80. addMouseMotionListener(ml);
  81. addExtension(new MarkerHighlight());
  82. } //}}}
  83. //{{{ paintComponent() method
  84. public void paintComponent(Graphics _gfx)
  85. {
  86. Graphics2D gfx = (Graphics2D)_gfx;
  87. // fill the background
  88. Rectangle clip = gfx.getClipBounds();
  89. gfx.setColor(getBackground());
  90. gfx.fillRect(clip.x, clip.y, clip.width, clip.height);
  91. // if buffer is loading, don't paint anything
  92. if (!textArea.getBuffer().isLoaded())
  93. return;
  94. // paint highlights and line numbers
  95. int lineHeight = textArea.getPainter().getFontMetrics()
  96. .getHeight();
  97. int firstLine = clip.y / lineHeight;
  98. int lastLine = (clip.y + clip.height - 1) / lineHeight;
  99. FontMetrics pfm = textArea.getPainter().getFontMetrics();
  100. Color fg = getForeground();
  101. int baseline = (int)((this.baseline + lineHeight
  102. - pfm.getDescent()) / 2.0);
  103. boolean highlightCurrentLine = currentLineHighlightEnabled
  104. && textArea.selection.size() == 0;
  105. int y = (clip.y - clip.y % lineHeight);
  106. Buffer buffer = textArea.getBuffer();
  107. textArea.chunkCache.updateChunksUpTo(lastLine);
  108. for (int line = firstLine; line <= lastLine;
  109. line++, y += lineHeight)
  110. {
  111. ChunkCache.LineInfo info = textArea.chunkCache.getLineInfo(line);
  112. if(!info.chunksValid)
  113. System.err.println("gutter paint: not valid");
  114. int physicalLine = info.physicalLine;
  115. //{{{ Paint text area extensions
  116. if(physicalLine != -1)
  117. {
  118. int start = textArea.getScreenLineStartOffset(line);
  119. int end = textArea.getScreenLineEndOffset(line);
  120. extensionMgr.paintValidLine(gfx,line,physicalLine,start,end,y);
  121. }
  122. else
  123. extensionMgr.paintInvalidLine(gfx,line,y);
  124. //}}}
  125. // Skip lines beyond EOF
  126. if(physicalLine == -1)
  127. return;
  128. //{{{ Paint fold triangles
  129. if(info.firstSubregion
  130. && physicalLine != buffer.getLineCount() - 1
  131. && buffer.isFoldStart(physicalLine))
  132. {
  133. int _y = y + lineHeight / 2;
  134. gfx.setColor(foldColor);
  135. if(textArea.getFoldVisibilityManager()
  136. .isLineVisible(physicalLine + 1))
  137. {
  138. gfx.drawLine(1,_y - 3,10,_y - 3);
  139. gfx.drawLine(2,_y - 2,9,_y - 2);
  140. gfx.drawLine(3,_y - 1,8,_y - 1);
  141. gfx.drawLine(4,_y,7,_y);
  142. gfx.drawLine(5,_y + 1,6,_y + 1);
  143. }
  144. else
  145. {
  146. gfx.drawLine(4,_y - 5,4,_y + 4);
  147. gfx.drawLine(5,_y - 4,5,_y + 3);
  148. gfx.drawLine(6,_y - 3,6,_y + 2);
  149. gfx.drawLine(7,_y - 2,7,_y + 1);
  150. gfx.drawLine(8,_y - 1,8,_y);
  151. }
  152. } //}}}
  153. //{{{ Paint bracket scope
  154. else if(bracketHighlight)
  155. {
  156. int bracketLine = textArea.getBracketLine();
  157. int caretLine = textArea.getCaretLine();
  158. if(textArea.isBracketHighlightVisible()
  159. && physicalLine >= Math.min(caretLine,bracketLine)
  160. && physicalLine <= Math.max(caretLine,bracketLine))
  161. {
  162. int caretScreenLine;
  163. if(caretLine > textArea.getLastPhysicalLine())
  164. caretScreenLine = Integer.MAX_VALUE;
  165. else
  166. {
  167. caretScreenLine = textArea
  168. .getScreenLineOfOffset(
  169. textArea.getCaretPosition());
  170. }
  171. int bracketScreenLine;
  172. if(bracketLine > textArea.getLastPhysicalLine())
  173. bracketScreenLine = Integer.MAX_VALUE;
  174. else
  175. {
  176. bracketScreenLine = textArea.chunkCache
  177. .getScreenLineOfOffset(
  178. bracketLine,
  179. textArea.getBracketPosition());
  180. }
  181. if(caretScreenLine > bracketScreenLine)
  182. {
  183. int tmp = caretScreenLine;
  184. caretScreenLine = bracketScreenLine;
  185. bracketScreenLine = tmp;
  186. }
  187. gfx.setColor(bracketHighlightColor);
  188. if(bracketScreenLine == caretScreenLine)
  189. {
  190. // do nothing
  191. }
  192. else if(line == caretScreenLine)
  193. {
  194. gfx.fillRect(5,
  195. y
  196. + lineHeight / 2,
  197. 5,
  198. 2);
  199. gfx.fillRect(5,
  200. y
  201. + lineHeight / 2,
  202. 2,
  203. lineHeight - lineHeight / 2);
  204. }
  205. else if(line == bracketScreenLine)
  206. {
  207. gfx.fillRect(5,
  208. y,
  209. 2,
  210. lineHeight / 2);
  211. gfx.fillRect(5,
  212. y + lineHeight / 2,
  213. 5,
  214. 2);
  215. }
  216. else if(line > caretScreenLine
  217. && line < bracketScreenLine)
  218. {
  219. gfx.fillRect(5,
  220. y,
  221. 2,
  222. lineHeight);
  223. }
  224. }
  225. } //}}}
  226. //{{{ Paint line numbers
  227. if(info.firstSubregion && expanded)
  228. {
  229. String number = Integer.toString(physicalLine + 1);
  230. int offset;
  231. switch (alignment)
  232. {
  233. case RIGHT:
  234. offset = gutterSize.width - collapsedSize.width
  235. - (fm.stringWidth(number) + 1);
  236. break;
  237. case CENTER:
  238. offset = ((gutterSize.width - collapsedSize.width)
  239. - fm.stringWidth(number)) / 2;
  240. break;
  241. case LEFT: default:
  242. offset = 0;
  243. break;
  244. }
  245. if (physicalLine == textArea.getCaretLine() && highlightCurrentLine)
  246. {
  247. gfx.setColor(currentLineHighlight);
  248. }
  249. else if (interval > 1 && (line
  250. + textArea.getFirstLine() + 1)
  251. % interval == 0)
  252. gfx.setColor(intervalHighlight);
  253. else
  254. gfx.setColor(fg);
  255. gfx.drawString(number, FOLD_MARKER_SIZE + offset,
  256. baseline + y);
  257. } //}}}
  258. }
  259. } //}}}
  260. //{{{ addExtension() method
  261. /**
  262. * Adds a text area extension, which can perform custom painting and
  263. * tool tip handling.
  264. * @param extension The extension
  265. * @since jEdit 4.0pre4
  266. */
  267. public void addExtension(TextAreaExtension extension)
  268. {
  269. extensionMgr.addExtension(DEFAULT_LAYER,extension);
  270. repaint();
  271. } //}}}
  272. //{{{ addExtension() method
  273. /**
  274. * Adds a text area extension, which can perform custom painting and
  275. * tool tip handling.
  276. * @param layer The layer to add the extension to. Note that more than
  277. * extension can share the same layer.
  278. * @param extension The extension
  279. * @since jEdit 4.0pre4
  280. */
  281. public void addExtension(int layer, TextAreaExtension extension)
  282. {
  283. extensionMgr.addExtension(layer,extension);
  284. repaint();
  285. } //}}}
  286. //{{{ removeExtension() method
  287. /**
  288. * Removes a text area extension. It will no longer be asked to
  289. * perform custom painting and tool tip handling.
  290. * @param extension The extension
  291. * @since jEdit 4.0pre4
  292. */
  293. public void removeExtension(TextAreaExtension extension)
  294. {
  295. extensionMgr.removeExtension(extension);
  296. repaint();
  297. } //}}}
  298. //{{{ getExtensions() method
  299. /**
  300. * Returns an array of registered text area extensions. Useful for
  301. * debugging purposes.
  302. * @since jEdit 4.1pre5
  303. */
  304. public TextAreaExtension[] getExtensions()
  305. {
  306. return extensionMgr.getExtensions();
  307. } //}}}
  308. //{{{ getToolTipText() method
  309. /**
  310. * Returns the tool tip to display at the specified location.
  311. * @param evt The mouse event
  312. */
  313. public String getToolTipText(MouseEvent evt)
  314. {
  315. if(!textArea.getBuffer().isLoaded())
  316. return null;
  317. return extensionMgr.getToolTipText(evt.getX(),evt.getY());
  318. } //}}}
  319. //{{{ setBorder() method
  320. /**
  321. * Convenience method for setting a default matte border on the right
  322. * with the specified border width and color
  323. * @param width The border width (in pixels)
  324. * @param color1 The focused border color
  325. * @param color2 The unfocused border color
  326. * @param color3 The gutter/text area gap color
  327. */
  328. public void setBorder(int width, Color color1, Color color2, Color color3)
  329. {
  330. this.borderWidth = width;
  331. focusBorder = new CompoundBorder(new MatteBorder(0,0,0,width,color3),
  332. new MatteBorder(0,0,0,width,color1));
  333. noFocusBorder = new CompoundBorder(new MatteBorder(0,0,0,width,color3),
  334. new MatteBorder(0,0,0,width,color2));
  335. updateBorder();
  336. } //}}}
  337. //{{{ updateBorder() method
  338. /**
  339. * Sets the border differently if the text area has focus or not.
  340. */
  341. public void updateBorder()
  342. {
  343. // because we are called from the text area's focus handler,
  344. // we do an invokeLater() so that the view's focus handler
  345. // has a chance to execute and set the edit pane properly
  346. SwingUtilities.invokeLater(new Runnable()
  347. {
  348. public void run()
  349. {
  350. if(view.getEditPane() == null)
  351. return;
  352. if(view.getEditPane().getTextArea() == textArea)
  353. setBorder(focusBorder);
  354. else
  355. setBorder(noFocusBorder);
  356. }
  357. });
  358. } //}}}
  359. //{{{ setBorder() method
  360. /*
  361. * JComponent.setBorder(Border) is overridden here to cache the left
  362. * inset of the border (if any) to avoid having to fetch it during every
  363. * repaint.
  364. */
  365. public void setBorder(Border border)
  366. {
  367. super.setBorder(border);
  368. if (border == null)
  369. {
  370. collapsedSize.width = 0;
  371. collapsedSize.height = 0;
  372. }
  373. else
  374. {
  375. Insets insets = border.getBorderInsets(this);
  376. collapsedSize.width = FOLD_MARKER_SIZE + insets.right;
  377. collapsedSize.height = gutterSize.height
  378. = insets.top + insets.bottom;
  379. gutterSize.width = FOLD_MARKER_SIZE + insets.right
  380. + fm.stringWidth("12345");
  381. }
  382. revalidate();
  383. } //}}}
  384. //{{{ setFont() method
  385. /*
  386. * JComponent.setFont(Font) is overridden here to cache the baseline for
  387. * the font. This avoids having to get the font metrics during every
  388. * repaint.
  389. */
  390. public void setFont(Font font)
  391. {
  392. super.setFont(font);
  393. fm = getFontMetrics(font);
  394. baseline = fm.getAscent();
  395. Border border = getBorder();
  396. if(border != null)
  397. {
  398. gutterSize.width = FOLD_MARKER_SIZE
  399. + border.getBorderInsets(this).right
  400. + fm.stringWidth("12345");
  401. revalidate();
  402. }
  403. } //}}}
  404. //{{{ Getters and setters
  405. //{{{ getHighlightedForeground() method
  406. /**
  407. * Get the foreground color for highlighted line numbers
  408. * @return The highlight color
  409. */
  410. public Color getHighlightedForeground()
  411. {
  412. return intervalHighlight;
  413. } //}}}
  414. //{{{ setHighlightedForeground() method
  415. public void setHighlightedForeground(Color highlight)
  416. {
  417. intervalHighlight = highlight;
  418. } //}}}
  419. //{{{ getCurrentLineForeground() method
  420. public Color getCurrentLineForeground()
  421. {
  422. return currentLineHighlight;
  423. } //}}}
  424. //{{{ setCurrentLineForeground() method
  425. public void setCurrentLineForeground(Color highlight)
  426. {
  427. currentLineHighlight = highlight;
  428. } //}}}
  429. //{{{ getFoldColor() method
  430. public Color getFoldColor()
  431. {
  432. return foldColor;
  433. } //}}}
  434. //{{{ setFoldColor() method
  435. public void setFoldColor(Color foldColor)
  436. {
  437. this.foldColor = foldColor;
  438. } //}}}
  439. //{{{ getPreferredSize() method
  440. /*
  441. * Component.getPreferredSize() is overridden here to support the
  442. * collapsing behavior.
  443. */
  444. public Dimension getPreferredSize()
  445. {
  446. if (expanded)
  447. return gutterSize;
  448. else
  449. return collapsedSize;
  450. } //}}}
  451. //{{{ getMinimumSize() method
  452. public Dimension getMinimumSize()
  453. {
  454. return getPreferredSize();
  455. } //}}}
  456. //{{{ getLineNumberAlignment() method
  457. /**
  458. * Identifies whether the horizontal alignment of the line numbers.
  459. * @return Gutter.RIGHT, Gutter.CENTER, Gutter.LEFT
  460. */
  461. public int getLineNumberAlignment()
  462. {
  463. return alignment;
  464. } //}}}
  465. //{{{ setLineNumberAlignment() method
  466. /**
  467. * Sets the horizontal alignment of the line numbers.
  468. * @param alignment Gutter.RIGHT, Gutter.CENTER, Gutter.LEFT
  469. */
  470. public void setLineNumberAlignment(int alignment)
  471. {
  472. if (this.alignment == alignment) return;
  473. this.alignment = alignment;
  474. repaint();
  475. } //}}}
  476. //{{{ isExpanded() method
  477. /**
  478. * Identifies whether the gutter is collapsed or expanded.
  479. * @return true if the gutter is expanded, false if it is collapsed
  480. */
  481. public boolean isExpanded()
  482. {
  483. return expanded;
  484. } //}}}
  485. //{{{ setExpanded() method
  486. /**
  487. * Sets whether the gutter is collapsed or expanded and force the text
  488. * area to update its layout if there is a change.
  489. * @param collapsed true if the gutter is expanded,
  490. * false if it is collapsed
  491. */
  492. public void setExpanded(boolean expanded)
  493. {
  494. if (this.expanded == expanded) return;
  495. this.expanded = expanded;
  496. textArea.revalidate();
  497. } //}}}
  498. //{{{ toggleExpanded() method
  499. /**
  500. * Toggles whether the gutter is collapsed or expanded.
  501. */
  502. public void toggleExpanded()
  503. {
  504. setExpanded(!expanded);
  505. } //}}}
  506. //{{{ getHighlightInterval() method
  507. /**
  508. * Sets the number of lines between highlighted line numbers.
  509. * @return The number of lines between highlighted line numbers or
  510. * zero if highlighting is disabled
  511. */
  512. public int getHighlightInterval()
  513. {
  514. return interval;
  515. } //}}}
  516. //{{{ setHighlightInterval() method
  517. /**
  518. * Sets the number of lines between highlighted line numbers. Any value
  519. * less than or equal to one will result in highlighting being disabled.
  520. * @param interval The number of lines between highlighted line numbers
  521. */
  522. public void setHighlightInterval(int interval)
  523. {
  524. if (interval <= 1) interval = 0;
  525. this.interval = interval;
  526. repaint();
  527. } //}}}
  528. //{{{ isCurrentLineHighlightEnabled() method
  529. public boolean isCurrentLineHighlightEnabled()
  530. {
  531. return currentLineHighlightEnabled;
  532. } //}}}
  533. //{{{ setCurrentLineHighlightEnabled() method
  534. public void setCurrentLineHighlightEnabled(boolean enabled)
  535. {
  536. if (currentLineHighlightEnabled == enabled) return;
  537. currentLineHighlightEnabled = enabled;
  538. repaint();
  539. } //}}}
  540. //{{{ getBracketHighlightColor() method
  541. /**
  542. * Returns the bracket highlight color.
  543. */
  544. public final Color getBracketHighlightColor()
  545. {
  546. return bracketHighlightColor;
  547. } //}}}
  548. //{{{ setBracketHighlightColor() method
  549. /**
  550. * Sets the bracket highlight color.
  551. * @param bracketHighlightColor The bracket highlight color
  552. * @since jEdit 4.0pre1
  553. */
  554. public final void setBracketHighlightColor(Color bracketHighlightColor)
  555. {
  556. this.bracketHighlightColor = bracketHighlightColor;
  557. repaint();
  558. } //}}}
  559. //{{{ isBracketHighlightEnabled() method
  560. /**
  561. * Returns true if bracket highlighting is enabled, false otherwise.
  562. * When bracket highlighting is enabled, the bracket matching the
  563. * one before the caret (if any) is highlighted.
  564. * @since jEdit 4.0pre1
  565. */
  566. public final boolean isBracketHighlightEnabled()
  567. {
  568. return bracketHighlight;
  569. } //}}}
  570. //{{{ setBracketHighlightEnabled() method
  571. /**
  572. * Enables or disables bracket highlighting.
  573. * When bracket highlighting is enabled, the bracket matching the
  574. * one before the caret (if any) is highlighted.
  575. * @param bracketHighlight True if bracket highlighting should be
  576. * enabled, false otherwise
  577. * @since jEdit 4.0pre1
  578. */
  579. public final void setBracketHighlightEnabled(boolean bracketHighlight)
  580. {
  581. this.bracketHighlight = bracketHighlight;
  582. repaint();
  583. } //}}}
  584. //{{{ getMarkerHighlightColor() method
  585. public Color getMarkerHighlightColor()
  586. {
  587. return markerHighlightColor;
  588. } //}}}
  589. //{{{ setMarkerHighlightColor() method
  590. public void setMarkerHighlightColor(Color markerHighlightColor)
  591. {
  592. this.markerHighlightColor = markerHighlightColor;
  593. } //}}}
  594. //{{{ isMarkerHighlightEnabled() method
  595. public boolean isMarkerHighlightEnabled()
  596. {
  597. return markerHighlight;
  598. } //}}}
  599. //{{{ isMarkerHighlightEnabled()
  600. public void setMarkerHighlightEnabled(boolean markerHighlight)
  601. {
  602. this.markerHighlight = markerHighlight;
  603. } //}}}
  604. //}}}
  605. //{{{ Private members
  606. private static final int FOLD_MARKER_SIZE = 12;
  607. private View view;
  608. private JEditTextArea textArea;
  609. private ExtensionManager extensionMgr;
  610. private int baseline;
  611. private Dimension gutterSize = new Dimension(0,0);
  612. private Dimension collapsedSize = new Dimension(0,0);
  613. private Color intervalHighlight;
  614. private Color currentLineHighlight;
  615. private Color foldColor;
  616. private FontMetrics fm;
  617. private int alignment;
  618. private int interval;
  619. private boolean currentLineHighlightEnabled;
  620. private boolean expanded;
  621. private boolean bracketHighlight;
  622. private Color bracketHighlightColor;
  623. private boolean markerHighlight;
  624. private Color markerHighlightColor;
  625. private int borderWidth;
  626. private Border focusBorder, noFocusBorder;
  627. //}}}
  628. //{{{ MouseHandler class
  629. class MouseHandler extends MouseInputAdapter
  630. {
  631. boolean drag;
  632. int toolTipInitialDelay, toolTipReshowDelay;
  633. //{{{ mouseEntered() method
  634. public void mouseEntered(MouseEvent e)
  635. {
  636. ToolTipManager ttm = ToolTipManager.sharedInstance();
  637. toolTipInitialDelay = ttm.getInitialDelay();
  638. toolTipReshowDelay = ttm.getReshowDelay();
  639. ttm.setInitialDelay(0);
  640. ttm.setReshowDelay(0);
  641. } //}}}
  642. //{{{ mouseExited() method
  643. public void mouseExited(MouseEvent evt)
  644. {
  645. ToolTipManager ttm = ToolTipManager.sharedInstance();
  646. ttm.setInitialDelay(toolTipInitialDelay);
  647. ttm.setReshowDelay(toolTipReshowDelay);
  648. } //}}}
  649. //{{{ mousePressed() method
  650. public void mousePressed(MouseEvent e)
  651. {
  652. if(GUIUtilities.isPopupTrigger(e)
  653. || e.getX() >= getWidth() - borderWidth * 2)
  654. {
  655. e.translatePoint(-getWidth(),0);
  656. textArea.mouseHandler.mousePressed(e);
  657. drag = true;
  658. }
  659. else
  660. {
  661. Buffer buffer = textArea.getBuffer();
  662. int screenLine = e.getY() / textArea.getPainter()
  663. .getFontMetrics().getHeight();
  664. textArea.chunkCache.updateChunksUpTo(screenLine);
  665. int line = textArea.chunkCache.getLineInfo(screenLine)
  666. .physicalLine;
  667. if(line == -1)
  668. return;
  669. FoldVisibilityManager foldVisibilityManager
  670. = textArea.getFoldVisibilityManager();
  671. //{{{ Clicking on fold triangle does various things
  672. if(buffer.isFoldStart(line))
  673. {
  674. StringBuffer property = new StringBuffer(
  675. "view.gutter.gutter");
  676. if(e.isShiftDown())
  677. property.append("Shift");
  678. if(e.isControlDown())
  679. property.append("Control");
  680. if(e.isAltDown())
  681. property.append("Alt");
  682. property.append("Click");
  683. String action = jEdit.getProperty(property
  684. .toString());
  685. if(action == null)
  686. {
  687. action = jEdit.getProperty(
  688. "view.gutter.gutterClick");
  689. }
  690. if(action == null)
  691. action = "toggleFold";
  692. if(action.equals("selectFold"))
  693. {
  694. foldVisibilityManager
  695. .expandFold(line,true);
  696. textArea.selectFold(line);
  697. }
  698. else if(foldVisibilityManager
  699. .isLineVisible(line + 1))
  700. {
  701. foldVisibilityManager
  702. .collapseFold(line);
  703. }
  704. else
  705. {
  706. if(action.equals(
  707. "toggleFoldFully"))
  708. {
  709. foldVisibilityManager
  710. .expandFold(line,
  711. true);
  712. }
  713. else
  714. {
  715. foldVisibilityManager
  716. .expandFold(line,
  717. false);
  718. }
  719. }
  720. } //}}}
  721. //{{{ Clicking in bracket scope locates matching bracket
  722. else if(bracketHighlight)
  723. {
  724. if(textArea.isBracketHighlightVisible())
  725. {
  726. int bracketLine = textArea.getBracketLine();
  727. int caretLine = textArea.getCaretLine();
  728. if(caretLine != bracketLine)
  729. {
  730. if(caretLine > bracketLine)
  731. {
  732. int tmp = caretLine;
  733. caretLine = bracketLine;
  734. bracketLine = tmp;
  735. }
  736. if(line >= caretLine
  737. && line <= bracketLine)
  738. {
  739. if(e.isControlDown())
  740. textArea.selectToMatchingBracket();
  741. else
  742. textArea.goToMatchingBracket();
  743. }
  744. }
  745. }
  746. } //}}}
  747. }
  748. } //}}}
  749. //{{{ mouseDragged() method
  750. public void mouseDragged(MouseEvent e)
  751. {
  752. if(drag /* && e.getX() >= getWidth() - borderWidth * 2 */)
  753. {
  754. e.translatePoint(-getWidth(),0);
  755. textArea.mouseHandler.mouseDragged(e);
  756. }
  757. } //}}}
  758. //{{{ mouseReleased() method
  759. public void mouseReleased(MouseEvent e)
  760. {
  761. if(drag && e.getX() >= getWidth() - borderWidth * 2)
  762. {
  763. e.translatePoint(-getWidth(),0);
  764. textArea.mouseHandler.mouseReleased(e);
  765. }
  766. drag = false;
  767. } //}}}
  768. } //}}}
  769. //{{{ MarkerHighlight class
  770. class MarkerHighlight extends TextAreaExtension
  771. {
  772. //{{{ paintValidLine() method
  773. public void paintValidLine(Graphics2D gfx, int screenLine,
  774. int physicalLine, int start, int end, int y)
  775. {
  776. if(isMarkerHighlightEnabled())
  777. {
  778. Buffer buffer = textArea.getBuffer();
  779. if(buffer.getMarkerInRange(start,end) != null)
  780. {
  781. gfx.setColor(getMarkerHighlightColor());
  782. FontMetrics fm = textArea.getPainter().getFontMetrics();
  783. gfx.fillRect(0,y,textArea.getGutter()
  784. .getWidth(),fm.getHeight());
  785. }
  786. }
  787. } //}}}
  788. //{{{ getToolTipText() method
  789. public String getToolTipText(int x, int y)
  790. {
  791. if(isMarkerHighlightEnabled())
  792. {
  793. int start = textArea.xyToOffset(0,y);
  794. if(start == -1)
  795. return null;
  796. int end = textArea.getScreenLineEndOffset(
  797. textArea.getScreenLineOfOffset(start));
  798. Marker marker = textArea.getBuffer().getMarkerInRange(start,end);
  799. if(marker != null)
  800. {
  801. char shortcut = marker.getShortcut();
  802. if(shortcut == '\0')
  803. return jEdit.getProperty("view.gutter.marker.no-name");
  804. else
  805. {
  806. String[] args = { String.valueOf(shortcut) };
  807. return jEdit.getProperty("view.gutter.marker",args);
  808. }
  809. }
  810. }
  811. return null;
  812. } //}}}
  813. } //}}}
  814. }