PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/EditPane.java

#
Java | 680 lines | 453 code | 73 blank | 154 comment | 114 complexity | 0110387449a2320acda24798891ca630 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. * EditPane.java - Text area and buffer switcher
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2004 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.lang.reflect.Method;
  28. import org.gjt.sp.jedit.gui.*;
  29. import org.gjt.sp.jedit.io.VFSManager;
  30. import org.gjt.sp.jedit.msg.*;
  31. import org.gjt.sp.jedit.options.GlobalOptions;
  32. import org.gjt.sp.jedit.syntax.SyntaxStyle;
  33. import org.gjt.sp.jedit.textarea.*;
  34. import org.gjt.sp.util.Log;
  35. //}}}
  36. /**
  37. * A panel containing a text area.<p>
  38. *
  39. * In a BeanShell script, you can obtain the current edit pane from the
  40. * <code>editPane</code> variable.<p>
  41. *
  42. * This class does not have a public constructor.
  43. * Edit panes can be created and destroyed using methods in the
  44. * {@link View} class.<p>
  45. *
  46. * Each edit pane can edit one buffer at a time.
  47. *
  48. * @see View#splitHorizontally()
  49. * @see View#splitVertically()
  50. * @see View#unsplitCurrent()
  51. * @see View#unsplit()
  52. * @see View#getEditPane()
  53. * @see View#getEditPanes()
  54. *
  55. * @author Slava Pestov
  56. * @version $Id: EditPane.java 4959 2004-01-25 01:38:30Z spestov $
  57. */
  58. public class EditPane extends JPanel implements EBComponent
  59. {
  60. //{{{ getView() method
  61. /**
  62. * Returns the view containing this edit pane.
  63. * @since jEdit 2.5pre2
  64. */
  65. public View getView()
  66. {
  67. return view;
  68. } //}}}
  69. //{{{ getBuffer() method
  70. /**
  71. * Returns the current buffer.
  72. * @since jEdit 2.5pre2
  73. */
  74. public Buffer getBuffer()
  75. {
  76. return buffer;
  77. } //}}}
  78. //{{{ setBuffer() method
  79. /**
  80. * Sets the current buffer.
  81. * @param buffer The buffer to edit.
  82. * @since jEdit 2.5pre2
  83. */
  84. public void setBuffer(final Buffer buffer)
  85. {
  86. if(buffer == null)
  87. throw new NullPointerException();
  88. if(this.buffer == buffer)
  89. return;
  90. //if(buffer.insideCompoundEdit())
  91. // buffer.endCompoundEdit();
  92. recentBuffer = this.buffer;
  93. if(recentBuffer != null)
  94. saveCaretInfo();
  95. this.buffer = buffer;
  96. textArea.setBuffer(buffer);
  97. if(!init)
  98. {
  99. view.updateTitle();
  100. if(bufferSwitcher != null)
  101. {
  102. if(bufferSwitcher.getSelectedItem() != buffer)
  103. bufferSwitcher.setSelectedItem(buffer);
  104. }
  105. EditBus.send(new EditPaneUpdate(this,EditPaneUpdate
  106. .BUFFER_CHANGED));
  107. }
  108. SwingUtilities.invokeLater(new Runnable()
  109. {
  110. public void run()
  111. {
  112. // only do this if we are the current edit pane
  113. if(view.getEditPane() == EditPane.this
  114. && (bufferSwitcher == null
  115. || !bufferSwitcher.isPopupVisible()))
  116. {
  117. textArea.requestFocus();
  118. }
  119. }
  120. });
  121. // Only do this after all I/O requests are complete
  122. Runnable runnable = new Runnable()
  123. {
  124. public void run()
  125. {
  126. // avoid a race condition
  127. // see bug #834338
  128. if(buffer == getBuffer())
  129. loadCaretInfo();
  130. }
  131. };
  132. if(buffer.isPerformingIO())
  133. VFSManager.runInAWTThread(runnable);
  134. else
  135. runnable.run();
  136. } //}}}
  137. //{{{ prevBuffer() method
  138. /**
  139. * Selects the previous buffer.
  140. * @since jEdit 2.7pre2
  141. */
  142. public void prevBuffer()
  143. {
  144. Buffer buffer = this.buffer.getPrev();
  145. if(buffer == null)
  146. setBuffer(jEdit.getLastBuffer());
  147. else
  148. setBuffer(buffer);
  149. } //}}}
  150. //{{{ nextBuffer() method
  151. /**
  152. * Selects the next buffer.
  153. * @since jEdit 2.7pre2
  154. */
  155. public void nextBuffer()
  156. {
  157. Buffer buffer = this.buffer.getNext();
  158. if(buffer == null)
  159. setBuffer(jEdit.getFirstBuffer());
  160. else
  161. setBuffer(buffer);
  162. } //}}}
  163. //{{{ recentBuffer() method
  164. /**
  165. * Selects the most recently edited buffer.
  166. * @since jEdit 2.7pre2
  167. */
  168. public void recentBuffer()
  169. {
  170. if(recentBuffer != null)
  171. setBuffer(recentBuffer);
  172. else
  173. getToolkit().beep();
  174. } //}}}
  175. //{{{ focusOnTextArea() method
  176. /**
  177. * Sets the focus onto the text area.
  178. * @since jEdit 2.5pre2
  179. */
  180. public void focusOnTextArea()
  181. {
  182. SwingUtilities.invokeLater(new Runnable()
  183. {
  184. public void run()
  185. {
  186. textArea.requestFocus();
  187. }
  188. });
  189. } //}}}
  190. //{{{ getTextArea() method
  191. /**
  192. * Returns the view's text area.
  193. * @since jEdit 2.5pre2
  194. */
  195. public JEditTextArea getTextArea()
  196. {
  197. return textArea;
  198. } //}}}
  199. //{{{ getBufferSwitcher() method
  200. /**
  201. * Returns the buffer switcher combo box instance.
  202. * @since jEdit 4.1pre8
  203. */
  204. public BufferSwitcher getBufferSwitcher()
  205. {
  206. return bufferSwitcher;
  207. } //}}}
  208. //{{{ showBufferSwitcher() method
  209. /**
  210. * Shows the buffer switcher combo box.
  211. * @since jEdit 4.1pre8
  212. */
  213. public void showBufferSwitcher()
  214. {
  215. if(bufferSwitcher == null)
  216. getToolkit().beep();
  217. else
  218. {
  219. bufferSwitcher.requestFocus();
  220. bufferSwitcher.showPopup();
  221. }
  222. } //}}}
  223. //{{{ saveCaretInfo() method
  224. /**
  225. * Saves the caret information to the current buffer.
  226. * @since jEdit 2.5pre2
  227. */
  228. public void saveCaretInfo()
  229. {
  230. buffer.setIntegerProperty(Buffer.CARET,
  231. textArea.getCaretPosition());
  232. /*Selection[] selection = textArea.getSelection();
  233. if(selection != null)
  234. buffer.setProperty(Buffer.SELECTION,selection);*/
  235. buffer.setIntegerProperty(Buffer.SCROLL_VERT,
  236. textArea.getFirstPhysicalLine());
  237. buffer.setIntegerProperty(Buffer.SCROLL_HORIZ,
  238. textArea.getHorizontalOffset());
  239. } //}}}
  240. //{{{ loadCaretInfo() method
  241. /**
  242. * Loads the caret information from the current buffer.
  243. * @since jEdit 2.5pre2
  244. */
  245. public void loadCaretInfo()
  246. {
  247. Integer caret = (Integer)buffer.getProperty(Buffer.CARET);
  248. //Selection[] selection = (Selection[])buffer.getProperty(Buffer.SELECTION);
  249. Integer firstLine = (Integer)buffer.getProperty(Buffer.SCROLL_VERT);
  250. Integer horizontalOffset = (Integer)buffer.getProperty(Buffer.SCROLL_HORIZ);
  251. if(caret != null)
  252. {
  253. textArea.setCaretPosition(Math.min(caret.intValue(),
  254. buffer.getLength()));
  255. }
  256. /*if(selection != null)
  257. textArea.setSelection(selection);*/
  258. if(firstLine != null)
  259. textArea.setFirstPhysicalLine(firstLine.intValue());
  260. if(horizontalOffset != null)
  261. textArea.setHorizontalOffset(horizontalOffset.intValue());
  262. /* Silly bug workaround #8694. If you look at the above code,
  263. * note that we restore the saved caret position first, then
  264. * scroll to the saved location. However, the caret changing
  265. * can itself result in scrolling to a different location than
  266. * what was saved; and since moveCaretPosition() calls
  267. * updateBracketHighlight(), the bracket highlight's out of
  268. * bounds calculation will rely on a different set of physical
  269. * first/last lines than what we will end up with eventually.
  270. * Instead of confusing the user with status messages that
  271. * appear at random when switching buffers, we simply hide the
  272. * message altogether. */
  273. view.getStatus().setMessage(null);
  274. } //}}}
  275. //{{{ handleMessage() method
  276. public void handleMessage(EBMessage msg)
  277. {
  278. if(msg instanceof PropertiesChanged)
  279. {
  280. propertiesChanged();
  281. loadBufferSwitcher();
  282. }
  283. else if(msg instanceof BufferUpdate)
  284. handleBufferUpdate((BufferUpdate)msg);
  285. } //}}}
  286. //{{{ getMinimumSize() method
  287. /**
  288. * Returns 0,0 for split pane compatibility.
  289. */
  290. public final Dimension getMinimumSize()
  291. {
  292. return new Dimension(0,0);
  293. } //}}}
  294. //{{{ toString() method
  295. public String toString()
  296. {
  297. return getClass().getName() + "["
  298. + (view.getEditPane() == this
  299. ? "active" : "inactive")
  300. + "]";
  301. } //}}}
  302. //{{{ Package-private members
  303. //{{{ EditPane constructor
  304. EditPane(View view, Buffer buffer)
  305. {
  306. super(new BorderLayout());
  307. init = true;
  308. this.view = view;
  309. EditBus.addToBus(this);
  310. textArea = new JEditTextArea(view);
  311. add(BorderLayout.CENTER,textArea);
  312. propertiesChanged();
  313. if(buffer == null)
  314. setBuffer(jEdit.getFirstBuffer());
  315. else
  316. setBuffer(buffer);
  317. loadBufferSwitcher();
  318. init = false;
  319. } //}}}
  320. //{{{ close() method
  321. void close()
  322. {
  323. saveCaretInfo();
  324. EditBus.send(new EditPaneUpdate(this,EditPaneUpdate.DESTROYED));
  325. EditBus.removeFromBus(this);
  326. textArea.dispose();
  327. } //}}}
  328. //}}}
  329. //{{{ Private members
  330. private static Method initBufferSwitcher;
  331. static
  332. {
  333. if(OperatingSystem.hasJava14())
  334. {
  335. try
  336. {
  337. initBufferSwitcher = Java14.class
  338. .getMethod("initBufferSwitcher",
  339. new Class[] { EditPane.class,
  340. BufferSwitcher.class });
  341. }
  342. catch(Exception e)
  343. {
  344. Log.log(Log.ERROR,EditPane.class,e);
  345. }
  346. }
  347. }
  348. //{{{ Instance variables
  349. private boolean init;
  350. private View view;
  351. private Buffer buffer;
  352. private Buffer recentBuffer;
  353. private BufferSwitcher bufferSwitcher;
  354. private JEditTextArea textArea;
  355. //}}}
  356. //{{{ propertiesChanged() method
  357. private void propertiesChanged()
  358. {
  359. TextAreaPainter painter = textArea.getPainter();
  360. painter.setFont(jEdit.getFontProperty("view.font"));
  361. painter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
  362. "view.structureHighlight"));
  363. painter.setStructureHighlightColor(
  364. jEdit.getColorProperty("view.structureHighlightColor"));
  365. painter.setEOLMarkersPainted(jEdit.getBooleanProperty(
  366. "view.eolMarkers"));
  367. painter.setEOLMarkerColor(
  368. jEdit.getColorProperty("view.eolMarkerColor"));
  369. painter.setWrapGuidePainted(jEdit.getBooleanProperty(
  370. "view.wrapGuide"));
  371. painter.setWrapGuideColor(
  372. jEdit.getColorProperty("view.wrapGuideColor"));
  373. painter.setCaretColor(
  374. jEdit.getColorProperty("view.caretColor"));
  375. painter.setSelectionColor(
  376. jEdit.getColorProperty("view.selectionColor"));
  377. painter.setMultipleSelectionColor(
  378. jEdit.getColorProperty("view.multipleSelectionColor"));
  379. painter.setBackground(
  380. jEdit.getColorProperty("view.bgColor"));
  381. painter.setForeground(
  382. jEdit.getColorProperty("view.fgColor"));
  383. painter.setBlockCaretEnabled(jEdit.getBooleanProperty(
  384. "view.blockCaret"));
  385. painter.setLineHighlightEnabled(jEdit.getBooleanProperty(
  386. "view.lineHighlight"));
  387. painter.setLineHighlightColor(
  388. jEdit.getColorProperty("view.lineHighlightColor"));
  389. painter.setAntiAliasEnabled(jEdit.getBooleanProperty(
  390. "view.antiAlias"));
  391. painter.setFractionalFontMetricsEnabled(jEdit.getBooleanProperty(
  392. "view.fracFontMetrics"));
  393. String defaultFont = jEdit.getProperty("view.font");
  394. int defaultFontSize = jEdit.getIntegerProperty("view.fontsize",12);
  395. painter.setStyles(GUIUtilities.loadStyles(defaultFont,defaultFontSize));
  396. SyntaxStyle[] foldLineStyle = new SyntaxStyle[4];
  397. for(int i = 0; i <= 3; i++)
  398. {
  399. foldLineStyle[i] = GUIUtilities.parseStyle(
  400. jEdit.getProperty("view.style.foldLine." + i),
  401. defaultFont,defaultFontSize);
  402. }
  403. painter.setFoldLineStyle(foldLineStyle);
  404. Gutter gutter = textArea.getGutter();
  405. gutter.setExpanded(jEdit.getBooleanProperty(
  406. "view.gutter.lineNumbers"));
  407. int interval = jEdit.getIntegerProperty(
  408. "view.gutter.highlightInterval",5);
  409. gutter.setHighlightInterval(interval);
  410. gutter.setCurrentLineHighlightEnabled(jEdit.getBooleanProperty(
  411. "view.gutter.highlightCurrentLine"));
  412. gutter.setStructureHighlightEnabled(jEdit.getBooleanProperty(
  413. "view.gutter.structureHighlight"));
  414. gutter.setStructureHighlightColor(
  415. jEdit.getColorProperty("view.gutter.structureHighlightColor"));
  416. gutter.setBackground(
  417. jEdit.getColorProperty("view.gutter.bgColor"));
  418. gutter.setForeground(
  419. jEdit.getColorProperty("view.gutter.fgColor"));
  420. gutter.setHighlightedForeground(
  421. jEdit.getColorProperty("view.gutter.highlightColor"));
  422. gutter.setFoldColor(
  423. jEdit.getColorProperty("view.gutter.foldColor"));
  424. gutter.setMarkerHighlightColor(
  425. jEdit.getColorProperty("view.gutter.markerColor"));
  426. gutter.setMarkerHighlightEnabled(jEdit.getBooleanProperty(
  427. "view.gutter.markerHighlight"));
  428. gutter.setCurrentLineForeground(
  429. jEdit.getColorProperty("view.gutter.currentLineColor"));
  430. String alignment = jEdit.getProperty(
  431. "view.gutter.numberAlignment");
  432. if ("right".equals(alignment))
  433. {
  434. gutter.setLineNumberAlignment(Gutter.RIGHT);
  435. }
  436. else if ("center".equals(alignment))
  437. {
  438. gutter.setLineNumberAlignment(Gutter.CENTER);
  439. }
  440. else // left == default case
  441. {
  442. gutter.setLineNumberAlignment(Gutter.LEFT);
  443. }
  444. gutter.setFont(jEdit.getFontProperty("view.gutter.font"));
  445. int width = jEdit.getIntegerProperty(
  446. "view.gutter.borderWidth",3);
  447. gutter.setBorder(width,
  448. jEdit.getColorProperty("view.gutter.focusBorderColor"),
  449. jEdit.getColorProperty("view.gutter.noFocusBorderColor"),
  450. textArea.getPainter().getBackground());
  451. textArea.setCaretBlinkEnabled(jEdit.getBooleanProperty(
  452. "view.caretBlink"));
  453. textArea.setElectricScroll(jEdit.getIntegerProperty(
  454. "view.electricBorders",0));
  455. // Set up the right-click popup menu
  456. JPopupMenu popup = GUIUtilities.loadPopupMenu("view.context");
  457. JMenuItem customize = new JMenuItem(jEdit.getProperty(
  458. "view.context.customize"));
  459. customize.addActionListener(new ActionListener()
  460. {
  461. public void actionPerformed(ActionEvent evt)
  462. {
  463. new GlobalOptions(view,"context");
  464. }
  465. });
  466. popup.addSeparator();
  467. popup.add(customize);
  468. textArea.setRightClickPopup(popup);
  469. // use old property name for backwards compatibility
  470. textArea.setQuickCopyEnabled(jEdit.getBooleanProperty(
  471. "view.middleMousePaste"));
  472. textArea.setDragEnabled(jEdit.getBooleanProperty(
  473. "view.dragAndDrop"));
  474. textArea.propertiesChanged();
  475. } //}}}
  476. //{{{ loadBufferSwitcher() method
  477. private void loadBufferSwitcher()
  478. {
  479. if(jEdit.getBooleanProperty("view.showBufferSwitcher"))
  480. {
  481. if(bufferSwitcher == null)
  482. {
  483. bufferSwitcher = new BufferSwitcher(this);
  484. if(initBufferSwitcher != null)
  485. {
  486. try
  487. {
  488. initBufferSwitcher.invoke(
  489. null,new Object[] {
  490. EditPane.this,
  491. bufferSwitcher
  492. });
  493. }
  494. catch(Exception e)
  495. {
  496. Log.log(Log.ERROR,this,e);
  497. }
  498. }
  499. add(BorderLayout.NORTH,bufferSwitcher);
  500. bufferSwitcher.updateBufferList();
  501. revalidate();
  502. }
  503. }
  504. else if(bufferSwitcher != null)
  505. {
  506. remove(bufferSwitcher);
  507. revalidate();
  508. bufferSwitcher = null;
  509. }
  510. } //}}}
  511. //{{{ handleBufferUpdate() method
  512. private void handleBufferUpdate(BufferUpdate msg)
  513. {
  514. Buffer _buffer = msg.getBuffer();
  515. if(msg.getWhat() == BufferUpdate.CREATED)
  516. {
  517. if(bufferSwitcher != null)
  518. bufferSwitcher.updateBufferList();
  519. /* When closing the last buffer, the BufferUpdate.CLOSED
  520. * handler doesn't call setBuffer(), because null buffers
  521. * are not supported. Instead, it waits for the subsequent
  522. * 'Untitled' file creation. */
  523. if(buffer.isClosed())
  524. {
  525. setBuffer(jEdit.getFirstBuffer());
  526. // since recentBuffer will be set to the one that
  527. // was closed
  528. recentBuffer = null;
  529. }
  530. }
  531. else if(msg.getWhat() == BufferUpdate.CLOSED)
  532. {
  533. if(bufferSwitcher != null)
  534. bufferSwitcher.updateBufferList();
  535. if(_buffer == buffer)
  536. {
  537. Buffer newBuffer = (recentBuffer != null ?
  538. recentBuffer : _buffer.getPrev());
  539. if(newBuffer != null && !newBuffer.isClosed())
  540. setBuffer(newBuffer);
  541. else if(jEdit.getBufferCount() != 0)
  542. setBuffer(jEdit.getFirstBuffer());
  543. recentBuffer = null;
  544. }
  545. else if(_buffer == recentBuffer)
  546. recentBuffer = null;
  547. }
  548. else if(msg.getWhat() == BufferUpdate.LOAD_STARTED)
  549. {
  550. if(_buffer == buffer)
  551. {
  552. textArea.setCaretPosition(0);
  553. textArea.getPainter().repaint();
  554. }
  555. }
  556. else if(msg.getWhat() == BufferUpdate.LOADED)
  557. {
  558. if(_buffer == buffer)
  559. {
  560. textArea.repaint();
  561. if(bufferSwitcher != null)
  562. bufferSwitcher.updateBufferList();
  563. if(view.getEditPane() == this)
  564. {
  565. StatusBar status = view.getStatus();
  566. status.updateCaretStatus();
  567. status.updateBufferStatus();
  568. status.updateMiscStatus();
  569. }
  570. loadCaretInfo();
  571. }
  572. }
  573. else if(msg.getWhat() == BufferUpdate.DIRTY_CHANGED)
  574. {
  575. if(_buffer == buffer)
  576. {
  577. if(bufferSwitcher != null)
  578. {
  579. if(buffer.isDirty())
  580. bufferSwitcher.repaint();
  581. else
  582. bufferSwitcher.updateBufferList();
  583. }
  584. }
  585. }
  586. else if(msg.getWhat() == BufferUpdate.MARKERS_CHANGED)
  587. {
  588. if(_buffer == buffer)
  589. textArea.getGutter().repaint();
  590. }
  591. else if(msg.getWhat() == BufferUpdate.PROPERTIES_CHANGED)
  592. {
  593. if(_buffer == buffer)
  594. {
  595. textArea.propertiesChanged();
  596. if(view.getEditPane() == this)
  597. view.getStatus().updateBufferStatus();
  598. }
  599. }
  600. else if(msg.getWhat() == BufferUpdate.SAVED)
  601. {
  602. if(_buffer == buffer)
  603. textArea.propertiesChanged();
  604. }
  605. } //}}}
  606. //}}}
  607. }