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

/bundles/plugins-trunk/SideKick/sidekick/SideKick.java

#
Java | 623 lines | 438 code | 86 blank | 99 comment | 100 complexity | b4448012776b0682a627092bc05c0013 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. * SideKick.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2003, 2005 Slava Pestov
  7. * Copyright (c) 2006, 2009 by the jEdit developer team
  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 sidekick;
  24. //{{{ Imports
  25. import java.awt.event.ActionEvent;
  26. import java.awt.event.ActionListener;
  27. import javax.swing.SwingWorker;
  28. import javax.swing.Timer;
  29. import javax.swing.tree.DefaultMutableTreeNode;
  30. import org.gjt.sp.jedit.Buffer;
  31. import org.gjt.sp.jedit.EditBus;
  32. import org.gjt.sp.jedit.EditPane;
  33. import org.gjt.sp.jedit.View;
  34. import org.gjt.sp.jedit.jEdit;
  35. import org.gjt.sp.jedit.EditBus.EBHandler;
  36. import org.gjt.sp.jedit.buffer.BufferAdapter;
  37. import org.gjt.sp.jedit.buffer.JEditBuffer;
  38. import org.gjt.sp.jedit.msg.BufferUpdate;
  39. import org.gjt.sp.jedit.msg.BufferChanging;
  40. import org.gjt.sp.jedit.msg.EditPaneUpdate;
  41. import org.gjt.sp.jedit.msg.EditorExiting;
  42. import org.gjt.sp.jedit.msg.PluginUpdate;
  43. import org.gjt.sp.jedit.msg.PropertiesChanged;
  44. import org.gjt.sp.jedit.msg.ViewUpdate;
  45. import org.gjt.sp.util.Log;
  46. import errorlist.DefaultErrorSource;
  47. import errorlist.ErrorSource;
  48. //}}}
  49. /** This is an EBComponent that manages a SideKick parser.
  50. * Each jEdit View needs its own parser.
  51. *
  52. * SideKick is not a visible component itself, but rather, serves as the underlying
  53. * data model for a tree in a dockable Component, as determined by dockables.xml.
  54. * It happens to be sidekick.enhanced.SourceTree.
  55. *
  56. */
  57. public class SideKick
  58. {
  59. //{{{ static members
  60. public static final String BUFFER_CHANGE = "sidekick.buffer-change-parse";
  61. public static final String BUFFER_SAVE = "sidekick.buffer-save-parse";
  62. public static final String FOLLOW_CARET = "sidekick-tree.follows-caret";
  63. public static final String AUTO_EXPAND_DEPTH = "sidekick-tree.auto-expand-tree-depth";
  64. public static final String SHOW_STATUS= "sidekick.showStatusWindow.label";
  65. public static final String FILTER_VISIBLE = "sidekick.filter-visible-assets";
  66. public static final String SHOW_FILTER = "sidekick.showFilter";
  67. static private boolean exiting = false;
  68. // }}}
  69. //{{{ Instance variables
  70. private View view;
  71. private EditPane editPane;
  72. private Buffer buffer;
  73. private SideKickParser parser;
  74. private DefaultErrorSource errorSource;
  75. private boolean showParsingMessage;
  76. private int delay;
  77. private Timer keystrokeTimer;
  78. private BufferChangeListener bufferListener;
  79. private boolean addedBufferListener;
  80. //}}}
  81. //{{{ SideKick constructor
  82. SideKick(View view)
  83. {
  84. this.view = view;
  85. editPane = view.getEditPane();
  86. bufferListener = new BufferChangeListener();
  87. propertiesChanged();
  88. keystrokeTimer = new Timer(0,new ActionListener()
  89. {
  90. public void actionPerformed(ActionEvent evt)
  91. {
  92. parse(false);
  93. }
  94. });
  95. buffer = view.getBuffer();
  96. EditBus.addToBus(this);
  97. } //}}}
  98. // {{{ property getters/setters
  99. public static boolean isFollowCaret() {
  100. try {
  101. String currentMode = jEdit.getActiveView().getBuffer().getMode().getName();
  102. return AbstractModeOptionPane.getBooleanProperty(currentMode, SideKick.FOLLOW_CARET);
  103. }
  104. catch (NullPointerException npe) {
  105. return jEdit.getBooleanProperty(SideKick.FOLLOW_CARET) ;
  106. }
  107. }
  108. public static boolean isGlobalFollowCaret() {
  109. return jEdit.getBooleanProperty(SideKick.FOLLOW_CARET);
  110. }
  111. public static void setGlobalFollowCaret(boolean fc) {
  112. jEdit.setBooleanProperty( SideKick.FOLLOW_CARET, fc);
  113. }
  114. public static void setParseOnSave(boolean val) {
  115. jEdit.setBooleanProperty(BUFFER_SAVE, val);
  116. }
  117. public static void setParseOnChange(boolean val) {
  118. jEdit.setBooleanProperty(BUFFER_CHANGE, val);
  119. }
  120. public static boolean isParseOnSave() {
  121. return jEdit.getBooleanProperty(BUFFER_SAVE);
  122. }
  123. public static boolean isParseOnChange() {
  124. return jEdit.getBooleanProperty(BUFFER_CHANGE);
  125. } // }}}
  126. //{{{ parse() method
  127. /**
  128. * Immediately begins parsing the current buffer in a background thread.
  129. * @param showParsingMessage Clear the tree and show a status message
  130. * there?
  131. */
  132. void parse(final boolean showParsingMessage)
  133. {
  134. if(keystrokeTimer.isRunning())
  135. keystrokeTimer.stop();
  136. if(!buffer.isLoaded())
  137. return;
  138. if(SideKickPlugin.isParsingBuffer(buffer))
  139. return;
  140. else
  141. SideKickPlugin.startParsingBuffer(buffer);
  142. this.showParsingMessage = showParsingMessage;
  143. // unconditionally get the right parser
  144. parser = SideKickPlugin.getParserForBuffer(buffer);
  145. //{{{ check for unknown file
  146. if (parser == null) {
  147. Log.log(Log.DEBUG,this,"No parser");
  148. setErrorSource(null);
  149. showNotParsedMessage();
  150. SideKickPlugin.finishParsingBuffer(buffer);
  151. return;
  152. } //}}}
  153. //{{{ Show 'parsing in progress' message
  154. else if(showParsingMessage)
  155. {
  156. SideKickParsedData data = new SideKickParsedData(buffer.getName());
  157. data.root.add(new DefaultMutableTreeNode(
  158. jEdit.getProperty("sidekick-tree.parsing")));
  159. SideKickParsedData.setParsedData(view,data);
  160. sendUpdate();
  161. } //}}}
  162. ///DefaultErrorSource errorSource = new DefaultErrorSource("SideKick"); /// why is this here? Why not have ParseRequest create it?
  163. ///SideKickParsedData[] data = new SideKickParsedData[1]; /// why is this an array? Why is this even here?
  164. ///ParseRequest parseRequest = new ParseRequest(
  165. /// parser, buffer, errorSource, data);
  166. ParseRequestWorker parseRequest = new ParseRequestWorker(parser, buffer);
  167. SideKickPlugin.execute(view, parseRequest);
  168. } //}}}
  169. //{{{ dispose() method
  170. void dispose()
  171. {
  172. setErrorSource(null);
  173. EditBus.removeFromBus(this);
  174. removeBufferChangeListener(buffer);
  175. } //}}}
  176. //{{{ getParser() method
  177. SideKickParser getParser()
  178. {
  179. return parser;
  180. } //}}}
  181. //{{{ setParser() method
  182. void setParser(Buffer newBuffer)
  183. {
  184. deactivateParser();
  185. if (newBuffer != null) buffer = newBuffer;
  186. parser = SideKickPlugin.getParserForBuffer(buffer);
  187. activateParser();
  188. // autoParse();
  189. } //}}}
  190. //{{{ handlePropertiesChanged() method
  191. @EBHandler
  192. public void handlePropertiesChanged(PropertiesChanged msg)
  193. {
  194. propertiesChanged();
  195. } //}}}
  196. //{{{ handleEditorExiting() method
  197. @EBHandler
  198. public void handleEditorExiting(EditorExiting msg)
  199. {
  200. exiting = true;
  201. } //}}}
  202. //{{{ handleBufferUpdate() method
  203. @EBHandler
  204. public void handleBufferUpdate(BufferUpdate bmsg)
  205. {
  206. if (bmsg.getWhat() == BufferUpdate.PROPERTIES_CHANGED &&
  207. view.getBuffer() == bmsg.getBuffer()) {
  208. String prevMode =
  209. buffer.getStringProperty(SideKickPlugin.PARSER_MODE_PROPERTY);
  210. String currMode = (buffer.getMode() != null) ? buffer.getMode().getName() : "";
  211. if (! currMode.equals(prevMode)) {
  212. buffer.unsetProperty(SideKickPlugin.PARSER_PROPERTY);
  213. setParser(view.getBuffer());
  214. }
  215. }
  216. if (bmsg.getView() != view &&
  217. (bmsg.getView() != null || bmsg.getBuffer() != view.getBuffer()))
  218. return;
  219. if (bmsg.getWhat() == BufferUpdate.SAVED && isParseOnSave())
  220. setParser(buffer);
  221. else if (bmsg.getWhat() == BufferUpdate.LOADED && isParseOnChange())
  222. parse(true);
  223. else if(bmsg.getWhat() == BufferUpdate.CLOSED)
  224. setErrorSource(null);
  225. } //}}}
  226. //{{{ handleBufferChange() method
  227. @EBHandler
  228. public void handleBufferChange(BufferChanging bmsg) {
  229. buffer = bmsg.getBuffer();
  230. buffer.setProperty(SideKickPlugin.PARSER_PROPERTY, null);
  231. } //}}}
  232. //{{{ handleEditPaneUpdate() method
  233. @EBHandler
  234. public void handleEditPaneUpdate(EditPaneUpdate epu)
  235. {
  236. editPane = epu.getEditPane();
  237. View v = editPane.getView();
  238. if (v == null) v=jEdit.getActiveView();
  239. if (v == null || v != view )
  240. return;
  241. if(epu.getWhat() == EditPaneUpdate.DESTROYED)
  242. {
  243. // check if this is the currently focused edit pane
  244. if(editPane == v.getEditPane())
  245. {
  246. removeBufferChangeListener(this.buffer);
  247. deactivateParser();
  248. }
  249. }
  250. else if(epu.getWhat() == EditPaneUpdate.BUFFER_CHANGED)
  251. {
  252. if (!isParseOnChange()) {
  253. SideKickTree tree = (SideKickTree) view.getDockableWindowManager().getDockable("sidekick");
  254. if (tree != null) tree.reloadParserCombo();
  255. return;
  256. }
  257. // check if this is the currently focused edit pane
  258. if(editPane == view.getEditPane())
  259. {
  260. removeBufferChangeListener(this.buffer);
  261. deactivateParser();
  262. buffer = editPane.getBuffer();
  263. if (! buffer.isLoaded())
  264. return;
  265. parser = SideKickPlugin.getParserForBuffer(buffer);
  266. activateParser();
  267. parse(true);
  268. }
  269. }
  270. } //}}}
  271. //{{{ handleViewUpdate() method
  272. @EBHandler
  273. public void handleViewUpdate(ViewUpdate vu)
  274. {
  275. if(vu.getView() == view && buffer != view.getBuffer()
  276. && vu.getWhat() == ViewUpdate.EDIT_PANE_CHANGED)
  277. {
  278. if (!isParseOnChange()) return;
  279. removeBufferChangeListener(this.buffer);
  280. deactivateParser();
  281. buffer = view.getBuffer();
  282. this.editPane = view.getEditPane();
  283. parser = SideKickPlugin.getParserForBuffer(buffer);
  284. activateParser();
  285. parse(true);
  286. }
  287. } //}}}
  288. //{{{ handlePluginUpdate() method
  289. @EBHandler
  290. public void handlePluginUpdate(PluginUpdate pmsg)
  291. {
  292. if(!exiting)
  293. {
  294. if(pmsg.getWhat() == PluginUpdate.UNLOADED
  295. || pmsg.getWhat() == PluginUpdate.LOADED)
  296. {
  297. /* Pick a parser again in case our parser
  298. plugin was loaded or unloaded. */
  299. setParser(null);
  300. }
  301. }
  302. } //}}}
  303. /*
  304. //{{{ autoParse() method
  305. private void autoParse()
  306. {
  307. if(buffer.getBooleanProperty(
  308. "sidekick.buffer-change-parse") ||
  309. || buffer.getBooleanProperty(
  310. "sidekick.keystroke-parse"))
  311. {
  312. parse(true);
  313. }
  314. else
  315. {
  316. showNotParsedMessage();
  317. }
  318. } //}}}
  319. */
  320. //{{{ setErrorSource() method
  321. private void setErrorSource(DefaultErrorSource errorSource)
  322. {
  323. if(this.errorSource != null)
  324. {
  325. ErrorSource.unregisterErrorSource(this.errorSource);
  326. this.errorSource.clear();
  327. }
  328. this.errorSource = errorSource;
  329. if(errorSource != null)
  330. {
  331. int errorCount = errorSource.getErrorCount();
  332. if(errorCount != 0)
  333. ErrorSource.registerErrorSource(errorSource);
  334. }
  335. } //}}}
  336. //{{{ addBufferChangeListener() method
  337. private void addBufferChangeListener(Buffer buffer)
  338. {
  339. if(!addedBufferListener)
  340. {
  341. buffer.addBufferListener(bufferListener = new BufferChangeListener());
  342. addedBufferListener = true;
  343. }
  344. } //}}}
  345. //{{{ removeBufferChangeListener() method
  346. private void removeBufferChangeListener(Buffer buffer)
  347. {
  348. if(addedBufferListener)
  349. {
  350. buffer.removeBufferListener(bufferListener);
  351. addedBufferListener = false;
  352. }
  353. } //}}}
  354. //{{{ propertiesChanged() method
  355. /** called when the sidekick's properties are changed */
  356. @EBHandler
  357. private void propertiesChanged()
  358. {
  359. if (!isParseOnChange()) return;
  360. try
  361. {
  362. delay = Integer.parseInt(jEdit.getProperty(
  363. "sidekick.auto-parse-delay"));
  364. }
  365. catch(NumberFormatException nf)
  366. {
  367. delay = 1500;
  368. }
  369. } //}}}
  370. //{{{ showNotParsedMessage() method
  371. private void showNotParsedMessage()
  372. {
  373. setErrorSource(null);
  374. SideKickParsedData data = new SideKickParsedData(buffer.getName());
  375. data.root.add(new DefaultMutableTreeNode(
  376. jEdit.getProperty("sidekick-tree.not-parsed")));
  377. SideKickParsedData.setParsedData(view,data);
  378. sendUpdate();
  379. } //}}}
  380. //{{{ parseWithDelay() method
  381. private void parseWithDelay()
  382. {
  383. if(parser != null)
  384. {
  385. parser.stop();
  386. if(keystrokeTimer.isRunning())
  387. keystrokeTimer.stop();
  388. keystrokeTimer.setInitialDelay(delay);
  389. keystrokeTimer.setRepeats(false);
  390. keystrokeTimer.start();
  391. }
  392. } //}}}
  393. //{{{ sendUpdate() method
  394. private void sendUpdate()
  395. {
  396. if(view.isClosed())
  397. return;
  398. EditBus.send(new SideKickUpdate(view));
  399. } //}}}
  400. //{{{ deactivateParser() method
  401. private void deactivateParser()
  402. {
  403. if(parser != null)
  404. {
  405. if(this.editPane == null)
  406. Log.log(Log.ERROR,this,"Null editPane!");
  407. else
  408. parser.deactivate(this.editPane);
  409. // this.editPane = null;
  410. SideKickTree tree = (SideKickTree) view.getDockableWindowManager().getDockable("sidekick-tree");
  411. if (tree == null) return;
  412. tree.removeParserPanel();
  413. }
  414. } //}}}
  415. //{{{ activateParser() method
  416. private void activateParser()
  417. {
  418. EditPane editPane = view.getEditPane();
  419. if(parser != null)
  420. {
  421. addBufferChangeListener(buffer);
  422. this.editPane = editPane;
  423. parser.activate(editPane);
  424. }
  425. else
  426. removeBufferChangeListener(buffer);
  427. SideKickTree tree = (SideKickTree) view.getDockableWindowManager().getDockable("sidekick-tree");
  428. if (tree == null) return;
  429. tree.reloadParserCombo();
  430. if (parser != null)
  431. tree.addParserPanel(parser);
  432. parse(true);
  433. } //}}}
  434. //{{{ Inner classes
  435. class ParseRequestWorker extends SwingWorker<SideKickParsedData, Object>
  436. {
  437. SideKickParser parser;
  438. Buffer buffer;
  439. DefaultErrorSource errorSource;
  440. ParseRequestWorker(SideKickParser parser, Buffer buffer)
  441. {
  442. this.parser = parser;
  443. this.buffer = buffer;
  444. errorSource = new DefaultErrorSource("SideKick");
  445. }
  446. @Override
  447. public SideKickParsedData doInBackground()
  448. {
  449. SideKickTree tree = (SideKickTree) view.getDockableWindowManager().getDockable("sidekick-tree");
  450. if (tree != null)
  451. {
  452. tree.showStopButton(true);
  453. }
  454. try
  455. {
  456. buffer.readLock();
  457. SideKickParsedData data = parser.parse(buffer, errorSource);
  458. return data;
  459. }
  460. finally
  461. {
  462. buffer.readUnlock();
  463. }
  464. }
  465. @Override
  466. public void done()
  467. {
  468. SideKickPlugin.cleanup(view);
  469. try
  470. {
  471. if (isCancelled())
  472. {
  473. parser.stop();
  474. return;
  475. }
  476. SideKickParsedData data = get();
  477. setErrorSource(errorSource);
  478. int errorCount = errorSource.getErrorCount();
  479. if(showParsingMessage || errorCount != 0)
  480. {
  481. String label = jEdit.getProperty("sidekick.parser."
  482. + parser.getName() + ".label");
  483. Object[] pp = { label, Integer.valueOf(errorCount)};
  484. view.getStatus().setMessageAndClear(jEdit.getProperty(
  485. "sidekick.parsing-complete",pp));
  486. }
  487. buffer.setProperty(SideKickPlugin.PARSED_DATA_PROPERTY, data);
  488. if(buffer.getProperty("folding").equals("sidekick"))
  489. buffer.invalidateCachedFoldLevels();
  490. View _view = jEdit.getFirstView();
  491. while(_view != null)
  492. {
  493. if(_view.getBuffer() == buffer)
  494. SideKickParsedData.setParsedData(_view, data);
  495. _view = _view.getNext();
  496. }
  497. sendUpdate();
  498. }
  499. catch(Exception ie)
  500. {
  501. showNotParsedMessage();
  502. }
  503. finally
  504. {
  505. SideKickPlugin.finishParsingBuffer(buffer);
  506. SideKickTree tree = (SideKickTree) view.getDockableWindowManager().getDockable("sidekick-tree");
  507. if (tree != null)
  508. {
  509. tree.showStopButton(false);
  510. }
  511. }
  512. }
  513. }
  514. // {{{ BufferChangeListener class
  515. /**
  516. * @since jedit 4.3pre2
  517. */
  518. class BufferChangeListener extends BufferAdapter {
  519. private void parseOnKeyStroke(JEditBuffer buffer)
  520. {
  521. if(buffer != SideKick.this.buffer)
  522. {
  523. return;
  524. }
  525. if(buffer.getBooleanProperty("sidekick.keystroke-parse"))
  526. parseWithDelay();
  527. }
  528. public void contentInserted(JEditBuffer buffer, int startLine, int offset, int numLines, int length)
  529. {
  530. parseOnKeyStroke(buffer);
  531. }
  532. public void contentRemoved(JEditBuffer buffer, int startLine, int offset, int numLines, int length)
  533. {
  534. parseOnKeyStroke(buffer);
  535. }
  536. } //}}}
  537. }