/jEdit/tags/jedit-4-3-pre11/org/gjt/sp/jedit/EditPane.java

# · Java · 1117 lines · 755 code · 125 blank · 237 comment · 201 complexity · ef6367e0cf9ff42192cb6025ebb2914c MD5 · raw file

  1. /*
  2. * EditPane.java - Text area and buffer switcher
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2005 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit;
  23. //{{{ Imports
  24. import javax.swing.*;
  25. import java.awt.event.*;
  26. import java.awt.*;
  27. import java.util.HashMap;
  28. import java.util.Map;
  29. import org.gjt.sp.jedit.gui.*;
  30. import org.gjt.sp.jedit.io.VFSManager;
  31. import org.gjt.sp.jedit.msg.*;
  32. import org.gjt.sp.jedit.options.GlobalOptions;
  33. import org.gjt.sp.jedit.syntax.SyntaxStyle;
  34. import org.gjt.sp.jedit.textarea.*;
  35. import org.gjt.sp.jedit.buffer.JEditBuffer;
  36. //}}}
  37. /**
  38. * A panel containing a text area.<p>
  39. *
  40. * In a BeanShell script, you can obtain the current edit pane from the
  41. * <code>editPane</code> variable.<p>
  42. *
  43. *
  44. * Each View can have multiple editPanes, one is active at a time.
  45. * Each EditPane has a single JEditTextArea, and is operating on single buffer.
  46. * The EditPane also can switch buffers.
  47. *
  48. * This is the "controller" between a JEditTextArea (view) and a buffer (model).
  49. *
  50. * This class does not have a public constructor.
  51. * Edit panes can be created and destroyed using methods in the
  52. * {@link View} class.<p>
  53. *
  54. *
  55. * @see View#splitHorizontally()
  56. * @see View#splitVertically()
  57. * @see View#unsplitCurrent()
  58. * @see View#unsplit()
  59. * @see View#getEditPane()
  60. * @see View#getEditPanes()
  61. *
  62. * @author Slava Pestov
  63. * @version $Id: EditPane.java 10771 2007-09-30 09:56:17Z kpouer $
  64. */
  65. public class EditPane extends JPanel implements EBComponent
  66. {
  67. //{{{ getView() method
  68. /**
  69. * Returns the view containing this edit pane.
  70. * @since jEdit 2.5pre2
  71. */
  72. public View getView()
  73. {
  74. return view;
  75. } //}}}
  76. //{{{ getBuffer() method
  77. /**
  78. * Returns the current buffer.
  79. * @since jEdit 2.5pre2
  80. */
  81. public Buffer getBuffer()
  82. {
  83. return buffer;
  84. } //}}}
  85. //{{{ setBuffer() method
  86. /**
  87. * Sets the current buffer.
  88. * @param buffer The buffer to edit.
  89. * @since jEdit 2.5pre2
  90. */
  91. public void setBuffer(Buffer buffer)
  92. {
  93. setBuffer(buffer, true);
  94. } //}}}
  95. //{{{ setBuffer() method
  96. /**
  97. * Sets the current buffer.
  98. * @param buffer The buffer to edit.
  99. * @param requestFocus true if the textarea should request focus, false otherwise
  100. * @since jEdit 4.3pre6
  101. */
  102. public void setBuffer(final Buffer buffer, boolean requestFocus)
  103. {
  104. if(buffer == null)
  105. throw new NullPointerException();
  106. if(this.buffer == buffer)
  107. return;
  108. //if(buffer.insideCompoundEdit())
  109. // buffer.endCompoundEdit();
  110. EditBus.send(new BufferChanging(this, buffer));
  111. recentBuffer = this.buffer;
  112. if(recentBuffer != null)
  113. saveCaretInfo();
  114. this.buffer = buffer;
  115. textArea.setBuffer(buffer);
  116. if(!init)
  117. {
  118. view.updateTitle();
  119. if(bufferSwitcher != null)
  120. {
  121. if(bufferSwitcher.getSelectedItem() != buffer)
  122. bufferSwitcher.setSelectedItem(buffer);
  123. bufferSwitcher.setToolTipText(buffer.getPath());
  124. }
  125. EditBus.send(new EditPaneUpdate(this,EditPaneUpdate
  126. .BUFFER_CHANGED));
  127. }
  128. if (requestFocus)
  129. {
  130. SwingUtilities.invokeLater(new Runnable()
  131. {
  132. public void run()
  133. {
  134. // only do this if we are the current edit pane
  135. if(view.getEditPane() == EditPane.this
  136. && (bufferSwitcher == null
  137. || !bufferSwitcher.isPopupVisible()))
  138. {
  139. textArea.requestFocus();
  140. }
  141. }
  142. });
  143. }
  144. // Only do this after all I/O requests are complete
  145. Runnable runnable = new Runnable()
  146. {
  147. public void run()
  148. {
  149. // avoid a race condition
  150. // see bug #834338
  151. if(buffer == getBuffer())
  152. loadCaretInfo();
  153. }
  154. };
  155. if(buffer.isPerformingIO())
  156. VFSManager.runInAWTThread(runnable);
  157. else
  158. runnable.run();
  159. } //}}}
  160. //{{{ prevBuffer() method
  161. /**
  162. * Selects the previous buffer.
  163. * @since jEdit 2.7pre2
  164. */
  165. public void prevBuffer()
  166. {
  167. Buffer buffer = this.buffer.getPrev();
  168. if(buffer == null)
  169. setBuffer(jEdit.getLastBuffer());
  170. else
  171. setBuffer(buffer);
  172. } //}}}
  173. //{{{ nextBuffer() method
  174. /**
  175. * Selects the next buffer.
  176. * @since jEdit 2.7pre2
  177. */
  178. public void nextBuffer()
  179. {
  180. Buffer buffer = this.buffer.getNext();
  181. if(buffer == null)
  182. setBuffer(jEdit.getFirstBuffer());
  183. else
  184. setBuffer(buffer);
  185. } //}}}
  186. //{{{ recentBuffer() method
  187. /**
  188. * Selects the most recently edited buffer.
  189. * @since jEdit 2.7pre2
  190. */
  191. public void recentBuffer()
  192. {
  193. if(recentBuffer != null)
  194. setBuffer(recentBuffer);
  195. else
  196. getToolkit().beep();
  197. } //}}}
  198. //{{{ focusOnTextArea() method
  199. /**
  200. * Sets the focus onto the text area.
  201. * @since jEdit 2.5pre2
  202. */
  203. public void focusOnTextArea()
  204. {
  205. SwingUtilities.invokeLater(new Runnable()
  206. {
  207. public void run()
  208. {
  209. textArea.requestFocus();
  210. }
  211. });
  212. } //}}}
  213. //{{{ getTextArea() method
  214. /**
  215. * Returns the view's text area.
  216. * @since jEdit 2.5pre2
  217. */
  218. public JEditTextArea getTextArea()
  219. {
  220. return textArea;
  221. } //}}}
  222. //{{{ getBufferSwitcher() method
  223. /**
  224. * Returns the buffer switcher combo box instance.
  225. * @since jEdit 4.1pre8
  226. */
  227. public BufferSwitcher getBufferSwitcher()
  228. {
  229. return bufferSwitcher;
  230. } //}}}
  231. //{{{ showBufferSwitcher() method
  232. /**
  233. * Shows the buffer switcher combo box.
  234. * @since jEdit 4.1pre8
  235. */
  236. public void showBufferSwitcher()
  237. {
  238. if(bufferSwitcher == null)
  239. getToolkit().beep();
  240. else
  241. {
  242. bufferSwitcher.requestFocus();
  243. bufferSwitcher.showPopup();
  244. }
  245. } //}}}
  246. //{{{ saveCaretInfo() method
  247. /**
  248. * Saves the caret information to the current buffer.
  249. * @since jEdit 2.5pre2
  250. */
  251. public void saveCaretInfo()
  252. {
  253. if(!buffer.isLoaded())
  254. return;
  255. buffer.setIntegerProperty(Buffer.CARET,
  256. textArea.getCaretPosition());
  257. // save a map of buffer.getPath() -> CaretInfo, this is necessary for
  258. // when the same buffer is open in more than one EditPane and the user
  259. // is switching between buffers. We want to keep the caret in the
  260. // right position in each EditPane, which won't be the case if we
  261. // just use the buffer caret property.
  262. Map<String, CaretInfo> carets = (Map<String, CaretInfo>)getClientProperty(CARETS);
  263. if (carets == null)
  264. {
  265. carets = new HashMap<String, CaretInfo>();
  266. putClientProperty(CARETS, carets);
  267. }
  268. CaretInfo caretInfo = carets.get(buffer.getPath());
  269. if (caretInfo == null)
  270. {
  271. caretInfo = new CaretInfo();
  272. carets.put(buffer.getPath(), caretInfo);
  273. }
  274. caretInfo.caret = textArea.getCaretPosition();
  275. Selection[] selection = textArea.getSelection();
  276. for(int i = 0; i < selection.length; i++)
  277. selection[i] = (Selection)selection[i].clone();
  278. buffer.setProperty(Buffer.SELECTION,selection);
  279. caretInfo.selection = selection;
  280. caretInfo.rectangularSelection = textArea.isRectangularSelectionEnabled();
  281. caretInfo.multipleSelection = textArea.isMultipleSelectionEnabled();
  282. buffer.setIntegerProperty(Buffer.SCROLL_VERT,
  283. textArea.getFirstPhysicalLine());
  284. caretInfo.scrollVert = textArea.getFirstPhysicalLine();
  285. buffer.setIntegerProperty(Buffer.SCROLL_HORIZ,
  286. textArea.getHorizontalOffset());
  287. caretInfo.scrollHoriz = textArea.getHorizontalOffset();
  288. if (!buffer.isUntitled())
  289. {
  290. BufferHistory.setEntry(buffer.getPath(), textArea.getCaretPosition(),
  291. (Selection[])buffer.getProperty(Buffer.SELECTION),
  292. buffer.getStringProperty(JEditBuffer.ENCODING),
  293. buffer.getMode().getName());
  294. }
  295. } //}}}
  296. //{{{ loadCaretInfo() method
  297. /**
  298. * Loads the caret and selection information from this EditPane, fall
  299. * back to the information from the current buffer if none is already
  300. * in this EditPane.
  301. * @since jEdit 2.5pre2
  302. */
  303. public void loadCaretInfo()
  304. {
  305. // get our internal map of buffer -> CaretInfo since there might
  306. // be current info already
  307. Map<String, CaretInfo> carets = (Map<String, CaretInfo>) getClientProperty(CARETS);
  308. if (carets == null)
  309. {
  310. carets = new HashMap<String, CaretInfo>();
  311. putClientProperty(CARETS, carets);
  312. }
  313. CaretInfo caretInfo = carets.get(buffer.getPath());
  314. if (caretInfo == null)
  315. {
  316. caretInfo = new CaretInfo();
  317. }
  318. // set the position of the caret itself.
  319. // Caret position could be stored in the internal map already,
  320. // if so, use that one first. Otherwise, fall back to any
  321. // previously saved caret position that was stored in the
  322. // buffer properties.
  323. int caret = caretInfo.caret;
  324. if (caret == -1 || buffer.getBooleanProperty(Buffer.CARET_POSITIONED))
  325. {
  326. Integer i = (Integer) buffer.getProperty(Buffer.CARET);
  327. caret = i == null ? -1 : i;
  328. }
  329. buffer.unsetProperty(Buffer.CARET_POSITIONED);
  330. if(caret != -1)
  331. textArea.setCaretPosition(Math.min(caret,
  332. buffer.getLength()));
  333. // set any selections
  334. Selection[] selection = caretInfo.selection;
  335. if ( selection == null ) {
  336. selection = (Selection[])buffer.getProperty(Buffer.SELECTION);
  337. }
  338. if(selection != null)
  339. {
  340. for(int i = 0; i < selection.length; i++)
  341. {
  342. Selection s = selection[i];
  343. int max = buffer.getLength();
  344. if(s.getStart() > max || s.getEnd() > max)
  345. selection[i] = null;
  346. }
  347. }
  348. textArea.setSelection(selection);
  349. textArea.setRectangularSelectionEnabled(caretInfo.rectangularSelection);
  350. textArea.setMultipleSelectionEnabled(caretInfo.multipleSelection);
  351. // set firstLine value
  352. int firstLine = caretInfo.scrollVert;
  353. if ( firstLine == -1 )
  354. {
  355. Integer i = (Integer) buffer.getProperty(Buffer.SCROLL_VERT);
  356. firstLine = i == null ? -1 : i;
  357. }
  358. if(firstLine != -1)
  359. textArea.setFirstPhysicalLine(firstLine);
  360. // set horizontal offset
  361. int horizontalOffset = caretInfo.scrollHoriz;
  362. if (horizontalOffset == -1)
  363. {
  364. Integer i = (Integer) buffer.getProperty(Buffer.SCROLL_HORIZ);
  365. horizontalOffset = i == null ? -1 : i;
  366. }
  367. if(horizontalOffset != -1)
  368. textArea.setHorizontalOffset(horizontalOffset);
  369. /* Silly bug workaround #8694. If you look at the above code,
  370. * note that we restore the saved caret position first, then
  371. * scroll to the saved location. However, the caret changing
  372. * can itself result in scrolling to a different location than
  373. * what was saved; and since moveCaretPosition() calls
  374. * updateBracketHighlight(), the bracket highlight's out of
  375. * bounds calculation will rely on a different set of physical
  376. * first/last lines than what we will end up with eventually.
  377. * Instead of confusing the user with status messages that
  378. * appear at random when switching buffers, we simply hide the
  379. * message altogether. */
  380. view.getStatus().setMessage(null);
  381. } //}}}
  382. //{{{ bufferRenamed() method
  383. /**
  384. * This method should be called by the Buffer when the path is changing.
  385. * @param oldPath the old path of the buffer
  386. * @param newPath the new path of the buffer
  387. */
  388. void bufferRenamed(String oldPath, String newPath)
  389. {
  390. Map<String, CaretInfo> carets = (Map<String, CaretInfo>) getClientProperty(CARETS);
  391. if (carets == null)
  392. return;
  393. CaretInfo caretInfo = carets.remove(oldPath);
  394. if (caretInfo != null)
  395. carets.put(newPath, caretInfo);
  396. } //}}}
  397. //{{{
  398. /**
  399. * Need to track this info for each buffer that this EditPane might edit
  400. * since a buffer may be open in more than one EditPane at a time. That
  401. * means we need to track this info at the EditPane level rather than
  402. * the buffer level.
  403. */
  404. private static class CaretInfo
  405. {
  406. public int caret = -1;
  407. public Selection[] selection;
  408. public int scrollVert = -1;
  409. public int scrollHoriz = -1;
  410. public boolean rectangularSelection;
  411. public boolean multipleSelection;
  412. } //}}}
  413. //{{{ goToNextMarker() method
  414. /**
  415. * Moves the caret to the next marker.
  416. * @since jEdit 4.3pre3
  417. */
  418. public void goToNextMarker(boolean select)
  419. {
  420. java.util.List<Marker> markers = buffer.getMarkers();
  421. if(markers.isEmpty())
  422. {
  423. getToolkit().beep();
  424. return;
  425. }
  426. Marker marker = null;
  427. int caret = textArea.getCaretPosition();
  428. for(int i = 0; i < markers.size(); i++)
  429. {
  430. Marker _marker = markers.get(i);
  431. if(_marker.getPosition() > caret)
  432. {
  433. marker = _marker;
  434. break;
  435. }
  436. }
  437. // the markers list is not empty at this point
  438. if(marker == null)
  439. marker = markers.get(0);
  440. if(select)
  441. textArea.extendSelection(caret,marker.getPosition());
  442. else if(!textArea.isMultipleSelectionEnabled())
  443. textArea.selectNone();
  444. textArea.moveCaretPosition(marker.getPosition());
  445. } //}}}
  446. //{{{ goToPrevMarker() method
  447. /**
  448. * Moves the caret to the previous marker.
  449. * @since jEdit 2.7pre2
  450. */
  451. public void goToPrevMarker(boolean select)
  452. {
  453. java.util.List<Marker> markers = buffer.getMarkers();
  454. if(markers.isEmpty())
  455. {
  456. getToolkit().beep();
  457. return;
  458. }
  459. int caret = textArea.getCaretPosition();
  460. Marker marker = null;
  461. for(int i = markers.size() - 1; i >= 0; i--)
  462. {
  463. Marker _marker = markers.get(i);
  464. if(_marker.getPosition() < caret)
  465. {
  466. marker = _marker;
  467. break;
  468. }
  469. }
  470. if(marker == null)
  471. marker = markers.get(markers.size() - 1);
  472. if(select)
  473. textArea.extendSelection(caret,marker.getPosition());
  474. else if(!textArea.isMultipleSelectionEnabled())
  475. textArea.selectNone();
  476. textArea.moveCaretPosition(marker.getPosition());
  477. } //}}}
  478. //{{{ goToMarker() method
  479. /**
  480. * Moves the caret to the marker with the specified shortcut.
  481. * @param shortcut The shortcut
  482. * @param select True if the selection should be extended,
  483. * false otherwise
  484. * @since jEdit 3.2pre2
  485. */
  486. public void goToMarker(char shortcut, boolean select)
  487. {
  488. Marker marker = buffer.getMarker(shortcut);
  489. if(marker == null)
  490. {
  491. getToolkit().beep();
  492. return;
  493. }
  494. int pos = marker.getPosition();
  495. if(select)
  496. textArea.extendSelection(textArea.getCaretPosition(),pos);
  497. else if(!textArea.isMultipleSelectionEnabled())
  498. textArea.selectNone();
  499. textArea.moveCaretPosition(pos);
  500. } //}}}
  501. //{{{ addMarker() method
  502. /**
  503. * Adds a marker at the caret position.
  504. * @since jEdit 3.2pre1
  505. */
  506. public void addMarker()
  507. {
  508. int caretLine = textArea.getCaretLine();
  509. // always add markers on selected lines
  510. Selection[] selection = textArea.getSelection();
  511. for(int i = 0; i < selection.length; i++)
  512. {
  513. Selection s = selection[i];
  514. if(s.getStartLine() != s.getEndLine())
  515. {
  516. if(s.getStartLine() != caretLine)
  517. buffer.addMarker('\0',s.getStart());
  518. }
  519. if(s.getEndLine() != caretLine)
  520. buffer.addMarker('\0',s.getEnd());
  521. }
  522. // toggle marker on caret line
  523. buffer.addOrRemoveMarker('\0',textArea.getCaretPosition());
  524. } //}}}
  525. //{{{ swapMarkerAndCaret() method
  526. /**
  527. * Moves the caret to the marker with the specified shortcut,
  528. * then sets the marker position to the former caret position.
  529. * @param shortcut The shortcut
  530. * @since jEdit 3.2pre2
  531. */
  532. public void swapMarkerAndCaret(char shortcut)
  533. {
  534. Marker marker = buffer.getMarker(shortcut);
  535. if(marker == null)
  536. {
  537. getToolkit().beep();
  538. return;
  539. }
  540. int caret = textArea.getCaretPosition();
  541. textArea.setCaretPosition(marker.getPosition());
  542. buffer.addMarker(shortcut,caret);
  543. } //}}}
  544. //{{{ handleMessage() method
  545. public void handleMessage(EBMessage msg)
  546. {
  547. if(msg instanceof PropertiesChanged)
  548. {
  549. propertiesChanged();
  550. loadBufferSwitcher();
  551. }
  552. else if(msg instanceof BufferUpdate)
  553. handleBufferUpdate((BufferUpdate)msg);
  554. } //}}}
  555. //{{{ getMinimumSize() method
  556. /**
  557. * Returns 0,0 for split pane compatibility.
  558. */
  559. public final Dimension getMinimumSize()
  560. {
  561. return new Dimension(0,0);
  562. } //}}}
  563. //{{{ toString() method
  564. public String toString()
  565. {
  566. return getClass().getName() + '['
  567. + (view.getEditPane() == this
  568. ? "active" : "inactive")
  569. + ']';
  570. } //}}}
  571. //{{{ Package-private members
  572. //{{{ EditPane constructor
  573. EditPane(View view, Buffer buffer)
  574. {
  575. super(new BorderLayout());
  576. init = true;
  577. this.view = view;
  578. EditBus.addToBus(this);
  579. textArea = new JEditTextArea(view);
  580. textArea.getPainter().setAntiAlias(new AntiAlias(jEdit.getProperty("view.antiAlias")));
  581. textArea.setMouseHandler(new MouseHandler(textArea));
  582. textArea.setTransferHandler(new TextAreaTransferHandler());
  583. markerHighlight = new MarkerHighlight();
  584. textArea.getGutter().addExtension(markerHighlight);
  585. textArea.addStatusListener(new StatusHandler());
  586. add(BorderLayout.CENTER,textArea);
  587. propertiesChanged();
  588. if(buffer == null)
  589. setBuffer(jEdit.getFirstBuffer());
  590. else
  591. setBuffer(buffer);
  592. loadBufferSwitcher();
  593. init = false;
  594. } //}}}
  595. //{{{ close() method
  596. void close()
  597. {
  598. saveCaretInfo();
  599. EditBus.send(new EditPaneUpdate(this,EditPaneUpdate.DESTROYED));
  600. EditBus.removeFromBus(this);
  601. textArea.dispose();
  602. } //}}}
  603. //}}}
  604. //{{{ Private members
  605. //{{{ Instance variables
  606. private boolean init;
  607. /** The View where the edit pane is. */
  608. private final View view;
  609. /** The current buffer. */
  610. private Buffer buffer;
  611. private Buffer recentBuffer;
  612. private BufferSwitcher bufferSwitcher;
  613. /** The textArea inside the edit pane. */
  614. private final JEditTextArea textArea;
  615. private final MarkerHighlight markerHighlight;
  616. private static final String CARETS = "Buffer->caret";
  617. //}}}
  618. //{{{ propertiesChanged() method
  619. private void propertiesChanged()
  620. {
  621. TextAreaPainter painter = textArea.getPainter();
  622. painter.setFont(jEdit.getFontProperty("view.font"));
  623. painter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
  624. "view.structureHighlight"));
  625. painter.setStructureHighlightColor(
  626. jEdit.getColorProperty("view.structureHighlightColor"));
  627. painter.setEOLMarkersPainted(jEdit.getBooleanProperty(
  628. "view.eolMarkers"));
  629. painter.setEOLMarkerColor(
  630. jEdit.getColorProperty("view.eolMarkerColor"));
  631. painter.setWrapGuidePainted(jEdit.getBooleanProperty(
  632. "view.wrapGuide"));
  633. painter.setWrapGuideColor(
  634. jEdit.getColorProperty("view.wrapGuideColor"));
  635. painter.setCaretColor(
  636. jEdit.getColorProperty("view.caretColor"));
  637. painter.setSelectionColor(
  638. jEdit.getColorProperty("view.selectionColor"));
  639. painter.setMultipleSelectionColor(
  640. jEdit.getColorProperty("view.multipleSelectionColor"));
  641. painter.setBackground(
  642. jEdit.getColorProperty("view.bgColor"));
  643. painter.setForeground(
  644. jEdit.getColorProperty("view.fgColor"));
  645. painter.setBlockCaretEnabled(jEdit.getBooleanProperty(
  646. "view.blockCaret"));
  647. painter.setLineHighlightEnabled(jEdit.getBooleanProperty(
  648. "view.lineHighlight"));
  649. painter.setLineHighlightColor(
  650. jEdit.getColorProperty("view.lineHighlightColor"));
  651. painter.setAntiAlias(new AntiAlias(jEdit.getProperty("view.antiAlias")));
  652. painter.setFractionalFontMetricsEnabled(jEdit.getBooleanProperty(
  653. "view.fracFontMetrics"));
  654. String defaultFont = jEdit.getProperty("view.font");
  655. int defaultFontSize = jEdit.getIntegerProperty("view.fontsize",12);
  656. painter.setStyles(GUIUtilities.loadStyles(defaultFont,defaultFontSize));
  657. SyntaxStyle[] foldLineStyle = new SyntaxStyle[4];
  658. for(int i = 0; i <= 3; i++)
  659. {
  660. foldLineStyle[i] = GUIUtilities.parseStyle(
  661. jEdit.getProperty("view.style.foldLine." + i),
  662. defaultFont,defaultFontSize);
  663. }
  664. painter.setFoldLineStyle(foldLineStyle);
  665. Gutter gutter = textArea.getGutter();
  666. gutter.setExpanded(jEdit.getBooleanProperty(
  667. "view.gutter.lineNumbers"));
  668. int interval = jEdit.getIntegerProperty(
  669. "view.gutter.highlightInterval",5);
  670. gutter.setHighlightInterval(interval);
  671. gutter.setCurrentLineHighlightEnabled(jEdit.getBooleanProperty(
  672. "view.gutter.highlightCurrentLine"));
  673. gutter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
  674. "view.gutter.structureHighlight"));
  675. gutter.setStructureHighlightColor(
  676. jEdit.getColorProperty("view.gutter.structureHighlightColor"));
  677. gutter.setBackground(
  678. jEdit.getColorProperty("view.gutter.bgColor"));
  679. gutter.setForeground(
  680. jEdit.getColorProperty("view.gutter.fgColor"));
  681. gutter.setHighlightedForeground(
  682. jEdit.getColorProperty("view.gutter.highlightColor"));
  683. gutter.setFoldColor(
  684. jEdit.getColorProperty("view.gutter.foldColor"));
  685. markerHighlight.setMarkerHighlightColor(
  686. jEdit.getColorProperty("view.gutter.markerColor"));
  687. markerHighlight.setMarkerHighlightEnabled(jEdit.getBooleanProperty(
  688. "view.gutter.markerHighlight"));
  689. gutter.setCurrentLineForeground(
  690. jEdit.getColorProperty("view.gutter.currentLineColor"));
  691. String alignment = jEdit.getProperty(
  692. "view.gutter.numberAlignment");
  693. if ("right".equals(alignment))
  694. {
  695. gutter.setLineNumberAlignment(Gutter.RIGHT);
  696. }
  697. else if ("center".equals(alignment))
  698. {
  699. gutter.setLineNumberAlignment(Gutter.CENTER);
  700. }
  701. else // left == default case
  702. {
  703. gutter.setLineNumberAlignment(Gutter.LEFT);
  704. }
  705. gutter.setFont(jEdit.getFontProperty("view.gutter.font"));
  706. int width = jEdit.getIntegerProperty(
  707. "view.gutter.borderWidth",3);
  708. gutter.setBorder(width,
  709. jEdit.getColorProperty("view.gutter.focusBorderColor"),
  710. jEdit.getColorProperty("view.gutter.noFocusBorderColor"),
  711. textArea.getPainter().getBackground());
  712. textArea.setCaretBlinkEnabled(jEdit.getBooleanProperty(
  713. "view.caretBlink"));
  714. textArea.setElectricScroll(jEdit.getIntegerProperty(
  715. "view.electricBorders",0));
  716. // Set up the right-click popup menu
  717. JPopupMenu popup = GUIUtilities.loadPopupMenu("view.context");
  718. JMenuItem customize = new JMenuItem(jEdit.getProperty(
  719. "view.context.customize"));
  720. customize.addActionListener(new ActionListener()
  721. {
  722. public void actionPerformed(ActionEvent evt)
  723. {
  724. new GlobalOptions(view,"context");
  725. }
  726. });
  727. popup.addSeparator();
  728. popup.add(customize);
  729. textArea.setRightClickPopup(popup);
  730. // use old property name for backwards compatibility
  731. textArea.setQuickCopyEnabled(jEdit.getBooleanProperty(
  732. "view.middleMousePaste"));
  733. textArea.setDragEnabled(jEdit.getBooleanProperty(
  734. "view.dragAndDrop"));
  735. textArea.setJoinNonWordChars(jEdit.getBooleanProperty(
  736. "view.joinNonWordChars"));
  737. textArea.setCtrlForRectangularSelection(jEdit.getBooleanProperty(
  738. "view.ctrlForRectangularSelection"));
  739. textArea.propertiesChanged();
  740. if (bufferSwitcher != null) {
  741. bufferSwitcher.setMaximumRowCount(jEdit.getIntegerProperty(
  742. "bufferSwitcher.maxRowCount",10));
  743. }
  744. } //}}}
  745. //{{{ loadBufferSwitcher() method
  746. private void loadBufferSwitcher()
  747. {
  748. if(jEdit.getBooleanProperty("view.showBufferSwitcher"))
  749. {
  750. if(bufferSwitcher == null)
  751. {
  752. bufferSwitcher = new BufferSwitcher(this);
  753. add(BorderLayout.NORTH,bufferSwitcher);
  754. bufferSwitcher.updateBufferList();
  755. revalidate();
  756. }
  757. }
  758. else if(bufferSwitcher != null)
  759. {
  760. remove(bufferSwitcher);
  761. revalidate();
  762. bufferSwitcher = null;
  763. }
  764. } //}}}
  765. //{{{ handleBufferUpdate() method
  766. private void handleBufferUpdate(BufferUpdate msg)
  767. {
  768. Buffer _buffer = msg.getBuffer();
  769. if(msg.getWhat() == BufferUpdate.CREATED)
  770. {
  771. if(bufferSwitcher != null)
  772. bufferSwitcher.updateBufferList();
  773. /* When closing the last buffer, the BufferUpdate.CLOSED
  774. * handler doesn't call setBuffer(), because null buffers
  775. * are not supported. Instead, it waits for the subsequent
  776. * 'Untitled' file creation. */
  777. if(buffer.isClosed())
  778. {
  779. setBuffer(jEdit.getFirstBuffer(), msg.getView() == view);
  780. // since recentBuffer will be set to the one that
  781. // was closed
  782. recentBuffer = null;
  783. }
  784. }
  785. else if(msg.getWhat() == BufferUpdate.CLOSED)
  786. {
  787. if(bufferSwitcher != null)
  788. bufferSwitcher.updateBufferList();
  789. if(_buffer == buffer)
  790. {
  791. // The closed buffer is the current buffer
  792. Buffer newBuffer = recentBuffer != null ?
  793. recentBuffer : _buffer.getPrev();
  794. if(newBuffer != null && !newBuffer.isClosed())
  795. {
  796. setBuffer(newBuffer);
  797. recentBuffer = newBuffer.getPrev();
  798. }
  799. else if(jEdit.getBufferCount() != 0)
  800. {
  801. setBuffer(jEdit.getFirstBuffer());
  802. recentBuffer = null;
  803. }
  804. }
  805. else if(_buffer == recentBuffer)
  806. recentBuffer = null;
  807. Buffer closedBuffer = msg.getBuffer();
  808. if (closedBuffer.isUntitled())
  809. {
  810. // the buffer was a new file so I do not need to keep it's informations
  811. Map<String, CaretInfo> carets = (Map<String, CaretInfo>) getClientProperty(CARETS);
  812. if (carets != null)
  813. carets.remove(closedBuffer.getPath());
  814. }
  815. }
  816. else if(msg.getWhat() == BufferUpdate.LOAD_STARTED)
  817. {
  818. if(_buffer == buffer)
  819. {
  820. textArea.setCaretPosition(0);
  821. textArea.getPainter().repaint();
  822. }
  823. }
  824. else if(msg.getWhat() == BufferUpdate.LOADED)
  825. {
  826. if(_buffer == buffer)
  827. {
  828. textArea.repaint();
  829. if(bufferSwitcher != null)
  830. bufferSwitcher.updateBufferList();
  831. if(view.getEditPane() == this)
  832. {
  833. StatusBar status = view.getStatus();
  834. status.updateCaretStatus();
  835. status.updateBufferStatus();
  836. status.updateMiscStatus();
  837. }
  838. loadCaretInfo();
  839. }
  840. }
  841. else if(msg.getWhat() == BufferUpdate.DIRTY_CHANGED)
  842. {
  843. if(_buffer == buffer)
  844. {
  845. if(bufferSwitcher != null)
  846. {
  847. if(buffer.isDirty())
  848. bufferSwitcher.repaint();
  849. else
  850. bufferSwitcher.updateBufferList();
  851. }
  852. }
  853. }
  854. else if(msg.getWhat() == BufferUpdate.MARKERS_CHANGED)
  855. {
  856. if(_buffer == buffer)
  857. textArea.getGutter().repaint();
  858. }
  859. else if(msg.getWhat() == BufferUpdate.PROPERTIES_CHANGED)
  860. {
  861. if(_buffer == buffer && buffer.isLoaded())
  862. {
  863. textArea.propertiesChanged();
  864. if(view.getEditPane() == this)
  865. view.getStatus().updateBufferStatus();
  866. }
  867. }
  868. else if(msg.getWhat() == BufferUpdate.SAVED)
  869. {
  870. if(_buffer == buffer)
  871. textArea.propertiesChanged();
  872. }
  873. } //}}}
  874. //}}}
  875. //{{{ StatusHandler class
  876. class StatusHandler implements StatusListener
  877. {
  878. public void statusChanged(org.gjt.sp.jedit.textarea.TextArea textArea, int flag, boolean value)
  879. {
  880. StatusBar status = view.getStatus();
  881. if(status == null)
  882. return;
  883. switch(flag)
  884. {
  885. case OVERWRITE_CHANGED:
  886. status.setMessageAndClear(
  887. jEdit.getProperty("view.status.overwrite-changed",
  888. new Integer[] { value ? 1 : 0 }));
  889. break;
  890. case MULTI_SELECT_CHANGED:
  891. status.setMessageAndClear(
  892. jEdit.getProperty("view.status.multi-changed",
  893. new Integer[] { value ? 1 : 0 }));
  894. break;
  895. case RECT_SELECT_CHANGED:
  896. status.setMessageAndClear(
  897. jEdit.getProperty("view.status.rect-select-changed",
  898. new Integer[] { value ? 1 : 0 }));
  899. break;
  900. }
  901. status.updateMiscStatus();
  902. }
  903. public void bracketSelected(org.gjt.sp.jedit.textarea.TextArea textArea, int line, String text)
  904. {
  905. StatusBar status = view.getStatus();
  906. if(status == null)
  907. return;
  908. status.setMessageAndClear(jEdit.getProperty(
  909. "view.status.bracket",new Object[] {
  910. line, text }));
  911. }
  912. public void narrowActive(org.gjt.sp.jedit.textarea.TextArea textArea)
  913. {
  914. StatusBar status = view.getStatus();
  915. if(status == null)
  916. return;
  917. status.setMessageAndClear(
  918. jEdit.getProperty("view.status.narrow"));
  919. }
  920. } //}}}
  921. //{{{ MarkerHighlight class
  922. class MarkerHighlight extends TextAreaExtension
  923. {
  924. private boolean markerHighlight;
  925. private Color markerHighlightColor;
  926. //{{{ getMarkerHighlightColor() method
  927. public Color getMarkerHighlightColor()
  928. {
  929. return markerHighlightColor;
  930. } //}}}
  931. //{{{ setMarkerHighlightColor() method
  932. public void setMarkerHighlightColor(Color markerHighlightColor)
  933. {
  934. this.markerHighlightColor = markerHighlightColor;
  935. } //}}}
  936. //{{{ isMarkerHighlightEnabled() method
  937. public boolean isMarkerHighlightEnabled()
  938. {
  939. return markerHighlight;
  940. } //}}}
  941. //{{{ isMarkerHighlightEnabled()
  942. public void setMarkerHighlightEnabled(boolean markerHighlight)
  943. {
  944. this.markerHighlight = markerHighlight;
  945. } //}}}
  946. //{{{ paintValidLine() method
  947. public void paintValidLine(Graphics2D gfx, int screenLine,
  948. int physicalLine, int start, int end, int y)
  949. {
  950. if(isMarkerHighlightEnabled())
  951. {
  952. Buffer buffer = (Buffer)textArea.getBuffer();
  953. if(buffer.getMarkerInRange(start,end) != null)
  954. {
  955. gfx.setColor(getMarkerHighlightColor());
  956. FontMetrics fm = textArea.getPainter().getFontMetrics();
  957. gfx.fillRect(0,y,textArea.getGutter()
  958. .getWidth(),fm.getHeight());
  959. }
  960. }
  961. } //}}}
  962. //{{{ getToolTipText() method
  963. public String getToolTipText(int x, int y)
  964. {
  965. if(isMarkerHighlightEnabled())
  966. {
  967. int lineHeight = textArea.getPainter().getFontMetrics().getHeight();
  968. if(lineHeight == 0)
  969. return null;
  970. int line = y / lineHeight;
  971. int start = textArea.getScreenLineStartOffset(line);
  972. int end = textArea.getScreenLineEndOffset(line);
  973. if(start == -1 || end == -1)
  974. return null;
  975. Buffer buffer = (Buffer)textArea.getBuffer();
  976. Marker marker = buffer.getMarkerInRange(start,end);
  977. if(marker != null)
  978. {
  979. char shortcut = marker.getShortcut();
  980. if(shortcut == '\0')
  981. return jEdit.getProperty("view.gutter.marker.no-name");
  982. else
  983. {
  984. String[] args = { String.valueOf(shortcut) };
  985. return jEdit.getProperty("view.gutter.marker",args);
  986. }
  987. }
  988. }
  989. return null;
  990. } //}}}
  991. } //}}}
  992. }