PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
Java | 1484 lines | 1229 code | 129 blank | 126 comment | 221 complexity | c6702f1f2202778b943ec4d559c63f12 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. * SideKickTree.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2003 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 sidekick;
  23. // {{{ Imports
  24. import java.awt.BorderLayout;
  25. import java.awt.Dimension;
  26. import java.awt.Insets;
  27. import java.awt.Rectangle;
  28. import java.awt.event.ActionEvent;
  29. import java.awt.event.ActionListener;
  30. import java.awt.event.KeyAdapter;
  31. import java.awt.event.KeyEvent;
  32. import java.awt.event.MouseEvent;
  33. import java.awt.event.MouseMotionAdapter;
  34. import java.util.Arrays;
  35. import java.util.Enumeration;
  36. import java.util.Stack;
  37. import java.util.HashSet;
  38. import javax.swing.Box;
  39. import javax.swing.DefaultComboBoxModel;
  40. import javax.swing.Icon;
  41. import javax.swing.JCheckBoxMenuItem;
  42. import javax.swing.JComboBox;
  43. import javax.swing.JTextArea;
  44. import javax.swing.JTextField;
  45. import javax.swing.JMenuItem;
  46. import javax.swing.JPanel;
  47. import javax.swing.JPopupMenu;
  48. import javax.swing.JScrollPane;
  49. import javax.swing.JSplitPane;
  50. import javax.swing.SwingUtilities;
  51. import javax.swing.JToolBar;
  52. import javax.swing.JTree;
  53. import javax.swing.Timer;
  54. import javax.swing.JLabel;
  55. import javax.swing.event.CaretEvent;
  56. import javax.swing.event.CaretListener;
  57. import javax.swing.tree.DefaultMutableTreeNode;
  58. import javax.swing.tree.DefaultTreeModel;
  59. import javax.swing.tree.TreeCellRenderer;
  60. import javax.swing.tree.TreeModel;
  61. import javax.swing.tree.TreeNode;
  62. import javax.swing.tree.TreePath;
  63. import javax.swing.tree.TreeSelectionModel;
  64. import org.gjt.sp.jedit.Buffer;
  65. import org.gjt.sp.jedit.EditBus;
  66. import org.gjt.sp.jedit.EditPane;
  67. import org.gjt.sp.jedit.GUIUtilities;
  68. import org.gjt.sp.jedit.Mode;
  69. import org.gjt.sp.jedit.OperatingSystem;
  70. import org.gjt.sp.jedit.ServiceManager;
  71. import org.gjt.sp.jedit.View;
  72. import org.gjt.sp.jedit.jEdit;
  73. import org.gjt.sp.jedit.EditBus.EBHandler;
  74. import org.gjt.sp.jedit.gui.DefaultFocusComponent;
  75. import org.gjt.sp.jedit.gui.RolloverButton;
  76. import org.gjt.sp.jedit.msg.EditPaneUpdate;
  77. import org.gjt.sp.jedit.msg.PositionChanging;
  78. import org.gjt.sp.jedit.msg.PropertiesChanged;
  79. import org.gjt.sp.jedit.textarea.JEditTextArea;
  80. import org.gjt.sp.jedit.textarea.Selection;
  81. import org.gjt.sp.jedit.textarea.TextArea;
  82. import org.gjt.sp.util.EnhancedTreeCellRenderer;
  83. import org.gjt.sp.util.Log;
  84. import org.gjt.sp.util.StandardUtilities;
  85. import org.gjt.sp.util.StringList;
  86. // }}}
  87. /**
  88. * The Structure Browser dockable. One instance is created for each View.
  89. */
  90. public class SideKickTree extends JPanel implements DefaultFocusComponent
  91. {
  92. // {{{ Instance variables
  93. private RolloverButton parseBtn;
  94. private Icon parseIcon;
  95. private Icon stopIcon;
  96. private JComboBox parserCombo;
  97. protected JTree tree;
  98. // protected JEditorPane status;
  99. protected JTextArea status;
  100. private JPanel topPanel;
  101. private JSplitPane splitter;
  102. private boolean statusShowing = false;
  103. private Buffer lastParsedBuffer = null;
  104. private JToolBar filterBox;
  105. protected JPopupMenu configMenu;
  106. protected JCheckBoxMenuItem onChange;
  107. protected JCheckBoxMenuItem followCaret;
  108. protected JCheckBoxMenuItem onSave;
  109. protected View view;
  110. private Timer caretTimer;
  111. protected SideKickParsedData data;
  112. private int autoExpandTree = 0;
  113. private JPanel toolBox;
  114. private JPanel parserPanel = null;
  115. private JTextField searchField;
  116. // }}}
  117. // {{{ SideKickTree constructor
  118. public SideKickTree(View view, boolean docked)
  119. {
  120. super(new BorderLayout());
  121. this.view = view;
  122. topPanel = new JPanel(new BorderLayout());
  123. // create toolbar with parse button
  124. JToolBar buttonBox = new JToolBar();
  125. buttonBox.setFloatable(false);
  126. filterBox = new JToolBar();
  127. filterBox.setLayout(new BorderLayout());
  128. filterBox.setFloatable(false);
  129. parseIcon = GUIUtilities.loadIcon("Parse.png");
  130. stopIcon = GUIUtilities.loadIcon(jEdit.getProperty("hypersearch-results.stop.icon"));
  131. parseBtn = new RolloverButton(parseIcon);
  132. parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
  133. parseBtn.setMargin(new Insets(0,0,0,0));
  134. parseBtn.setRequestFocusEnabled(false);
  135. parseBtn.setEnabled(true);
  136. ActionListener ah = new ActionHandler();
  137. parseBtn.addActionListener(ah);
  138. RolloverButton propsBtn = new RolloverButton(GUIUtilities.loadIcon("ButtonProperties.png"));
  139. propsBtn.setToolTipText(jEdit.getProperty("sidekick-tree.mode-options"));
  140. propsBtn.addActionListener(new SideKickProperties());
  141. configMenu = new JPopupMenu("Parse");
  142. followCaret = new JCheckBoxMenuItem("Follow Caret");
  143. configMenu.add(followCaret);
  144. // configMenu = new PopupMenu("Parse on...");
  145. JMenuItem item = new JMenuItem("Parse on...");
  146. item.setEnabled(false);
  147. configMenu.add(item);
  148. onChange = new JCheckBoxMenuItem("Buffer change");
  149. onChange.setState(SideKick.isParseOnChange());
  150. onSave = new JCheckBoxMenuItem("Buffer save");
  151. onSave.setState(SideKick.isParseOnSave());
  152. configMenu.add(onChange);
  153. configMenu.add(onSave);
  154. parseBtn.setComponentPopupMenu(configMenu);
  155. onChange.addActionListener(ah);
  156. onSave.addActionListener(ah);
  157. followCaret.addActionListener(ah);
  158. JLabel search = new JLabel(jEdit.getProperty("sidekick-tree.filter.label") + " ");
  159. searchField = new JTextField();
  160. searchField.setToolTipText(jEdit.getProperty("sidekick-tree.filter.tooltip"));
  161. RolloverButton clearSearchBtn = new RolloverButton(GUIUtilities.loadIcon("22x22/actions/edit-clear.png"));
  162. clearSearchBtn.addActionListener(new ActionListener()
  163. {
  164. public void actionPerformed(ActionEvent ae)
  165. {
  166. searchField.setText("");
  167. updateFilter();
  168. }
  169. }
  170. );
  171. clearSearchBtn.setToolTipText(jEdit.getProperty("sidekick-tree.clear-filter.tooltip"));
  172. buttonBox.add(parseBtn);
  173. buttonBox.add(propsBtn);
  174. filterBox.add(search, BorderLayout.WEST);
  175. filterBox.add(searchField, BorderLayout.CENTER);
  176. filterBox.add(clearSearchBtn, BorderLayout.EAST);
  177. buttonBox.add(Box.createGlue());
  178. parserCombo = new JComboBox();
  179. reloadParserCombo();
  180. parserCombo.setToolTipText(jEdit.getProperty("sidekick-tree.parsercombo.tooltip"));
  181. buttonBox.add(parserCombo);
  182. parserCombo.addActionListener(ah);
  183. parserCombo.addActionListener(new ActionListener()
  184. {
  185. public void actionPerformed(ActionEvent ae)
  186. {
  187. searchField.setText("");
  188. updateFilter();
  189. }
  190. }
  191. );
  192. toolBox = new JPanel(new BorderLayout());
  193. toolBox.add(BorderLayout.NORTH, buttonBox);
  194. toolBox.add(BorderLayout.SOUTH, filterBox);
  195. topPanel.add(BorderLayout.NORTH, toolBox);
  196. // create a faux model that will do until a real one arrives
  197. TreeModel emptyModel = new DefaultTreeModel(new DefaultMutableTreeNode(null));
  198. emptyModel = new FilteredTreeModel((DefaultTreeModel) emptyModel, true);
  199. tree = buildTree(emptyModel);
  200. tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
  201. KeyHandler kh = new KeyHandler();
  202. tree.addKeyListener(kh);
  203. if (docked)
  204. {
  205. tree.addMouseMotionListener(new MouseHandler());
  206. }
  207. searchField.addKeyListener(kh);
  208. // looks bad with the OS X L&F, apparently...
  209. if (!OperatingSystem.isMacOSLF())
  210. {
  211. tree.putClientProperty("JTree.lineStyle", "Angled");
  212. }
  213. tree.setVisibleRowCount(10);
  214. tree.setCellRenderer(new Renderer());
  215. topPanel.add(BorderLayout.CENTER, new JScrollPane(tree));
  216. status = new JTextArea();
  217. // status.setContentType("text/html");
  218. status.setEditable(false);
  219. status.setBackground(jEdit.getColorProperty("view.bgColor"));
  220. status.setForeground(jEdit.getColorProperty("view.fgColor"));
  221. status.setFont(view.getEditPane().getTextArea().getPainter().getFont());
  222. JScrollPane status_scroller = new JScrollPane(status);
  223. splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, topPanel, status_scroller);
  224. status_scroller.setMinimumSize(new Dimension(0, 30));
  225. splitter.setOneTouchExpandable(true);
  226. splitter.setResizeWeight(1.0f);
  227. int location = splitter.getSize().height - splitter.getInsets().bottom - splitter.getDividerSize() - status_scroller.getMinimumSize().height;
  228. location = jEdit.getIntegerProperty("sidekick.splitter.location", location);
  229. splitter.setDividerLocation(location);
  230. // add(splitter);
  231. propertiesChanged();
  232. CaretHandler caretListener = new CaretHandler();
  233. EditPane[] editPanes = view.getEditPanes();
  234. for (int i = 0; i < editPanes.length; i++)
  235. {
  236. JEditTextArea textArea = editPanes[i].getTextArea();
  237. textArea.putClientProperty(CaretHandler.class, caretListener);
  238. textArea.addCaretListener(caretListener);
  239. }
  240. update();
  241. } // }}}
  242. public void showStopButton(final boolean show)
  243. {
  244. SwingUtilities.invokeLater (new Runnable()
  245. {
  246. public void run()
  247. {
  248. if (show && parseIcon.equals(parseBtn.getIcon()))
  249. {
  250. parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.stop-parsing"));
  251. parseBtn.setIcon(stopIcon);
  252. }
  253. else
  254. {
  255. parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
  256. parseBtn.setIcon(parseIcon);
  257. }
  258. }
  259. }
  260. );
  261. }
  262. // {{{ focusOnDefaultComponent() method
  263. public void focusOnDefaultComponent()
  264. {
  265. tree.requestFocusInWindow();
  266. } // }}}
  267. // {{{ addNotify() method
  268. public void addNotify()
  269. {
  270. super.addNotify();
  271. EditBus.addToBus(this);
  272. } // }}}
  273. // {{{ removeNotify() method
  274. public void removeNotify()
  275. {
  276. super.removeNotify();
  277. EditBus.removeFromBus(this);
  278. } // }}}
  279. // {{{ selectPath() method
  280. protected void selectPath(TreePath path)
  281. {
  282. tree.setSelectionPath(path);
  283. Rectangle r = tree.getPathBounds(path);
  284. if (r != null)
  285. {
  286. r.width = 1;
  287. tree.scrollRectToVisible(r);
  288. }
  289. } // }}}
  290. // {{{ handleEditPaneUpdate() method
  291. @EBHandler
  292. public void handleEditPaneUpdate(EditPaneUpdate epu)
  293. {
  294. EditPane editPane = epu.getEditPane();
  295. if (epu.getWhat() == EditPaneUpdate.CREATED)
  296. {
  297. CaretHandler listener = new CaretHandler();
  298. JEditTextArea textArea = editPane.getTextArea();
  299. textArea.putClientProperty(CaretHandler.class, listener);
  300. textArea.addCaretListener(listener);
  301. }
  302. } // }}}
  303. // {{{ handlePropertiesChanged method
  304. @EBHandler
  305. public void handlePropertiesChanged(PropertiesChanged msg)
  306. {
  307. propertiesChanged();
  308. } // }}}
  309. // {{{ handleSideKickUpdate() method
  310. @EBHandler
  311. public void handleSideKickUpdate(SideKickUpdate msg)
  312. {
  313. if (msg.getView() == view)
  314. {
  315. update();
  316. }
  317. } // }}}
  318. // {{{ setStatus() method
  319. public void setStatus(String msg)
  320. {
  321. status.setText(msg);
  322. } // }}}
  323. // {{{ addData method
  324. protected void addData(Object obj, Stack<String> keys)
  325. {
  326. if (obj instanceof DefaultMutableTreeNode)
  327. {
  328. DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj;
  329. String cur_key = "";
  330. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  331. try
  332. {
  333. Asset a = (Asset) node.getUserObject();
  334. if (a != null)
  335. {
  336. cur_key = a.getName();
  337. }
  338. }
  339. catch (ClassCastException ex)
  340. {
  341. if (node.toString() != null)
  342. {
  343. cur_key = node.toString();
  344. }
  345. }
  346. keys.push(cur_key);
  347. if (model.isLeaf(node))
  348. {
  349. for (String key : keys)
  350. {
  351. model.addSearchKey(node, key);
  352. }
  353. }
  354. Enumeration<DefaultMutableTreeNode> e;
  355. for (e = node.children(); e.hasMoreElements();)
  356. {
  357. addData(e.nextElement(), keys);
  358. }
  359. keys.pop();
  360. }
  361. else
  362. {
  363. Log.log(Log.DEBUG, this, "addData called on a node that isn't a treenode!!!!!!!!!"); // how exciting!
  364. }
  365. } // }}}
  366. // {{{ updateSearchData() method
  367. protected void updateSearchData()
  368. {
  369. DefaultMutableTreeNode root;
  370. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  371. root = (DefaultMutableTreeNode) model.getRoot();
  372. addData(root, new Stack<String>());
  373. } // }}}
  374. // {{{ update() method
  375. protected void update()
  376. {
  377. onChange.setState(SideKick.isParseOnChange());
  378. onSave.setState(SideKick.isParseOnSave());
  379. Buffer parsedBuffer = view.getBuffer();
  380. SideKickParser parser = SideKickPlugin.getParserForBuffer(parsedBuffer);
  381. if (parser != null)
  382. {
  383. Object item = parserCombo.getSelectedItem();
  384. if (item != parser.getName())
  385. {
  386. parserCombo.setSelectedItem(parser.getName());
  387. }
  388. }
  389. data = SideKickParsedData.getParsedData(view);
  390. if (parser == null || data == null)
  391. {
  392. DefaultMutableTreeNode root = new DefaultMutableTreeNode(parsedBuffer.getName());
  393. root.insert(new DefaultMutableTreeNode(jEdit.getProperty("sidekick-tree.not-parsed")),0);
  394. tree.setModel(new FilteredTreeModel(new DefaultTreeModel(root), true));
  395. lastParsedBuffer = null;
  396. }
  397. else
  398. {
  399. tree.setModel(new FilteredTreeModel(data.tree, true));
  400. lastParsedBuffer = parsedBuffer;
  401. if (SideKick.isFollowCaret())
  402. {
  403. expandTreeAt(view.getTextArea().getCaretPosition());
  404. }
  405. }
  406. updateSearchData();
  407. if (data != null && data.expansionModel != null)
  408. {
  409. // collapse all rows, then expand per the expansion model
  410. for (int i = tree.getRowCount() - 1; i >= 0; i--)
  411. {
  412. tree.collapseRow(i);
  413. }
  414. for (Integer row : data.expansionModel)
  415. {
  416. tree.expandRow(row);
  417. }
  418. }
  419. else
  420. {
  421. if (autoExpandTree == -1)
  422. {
  423. expandAll(true);
  424. }
  425. else if (autoExpandTree == 0)
  426. {
  427. expandAll(false);
  428. }
  429. else if (autoExpandTree > 0)
  430. {
  431. tree.expandRow(0);
  432. for (int i = 1; i < autoExpandTree; i++)
  433. {
  434. for (int j = tree.getRowCount() - 1; j > 0; j--)
  435. {
  436. tree.expandRow(j);
  437. }
  438. }
  439. }
  440. }
  441. if (searchField.getText().length() != 0)
  442. {
  443. updateFilter();
  444. }
  445. } // }}}
  446. // {{{ expandAll() methods
  447. /**
  448. * Expand or collapse all nodes in the tree.
  449. * @param expand if true, expand all nodes, if false, collapse all nodes
  450. */
  451. public void expandAll(boolean expand)
  452. {
  453. TreeNode root = (TreeNode) tree.getModel().getRoot();
  454. expandAll(new TreePath(root), expand);
  455. }
  456. // recursive method to traverse children
  457. private void expandAll(final TreePath parent, final boolean expand)
  458. {
  459. SwingUtilities.invokeLater(new Runnable()
  460. {
  461. public void run()
  462. {
  463. TreeNode node = (TreeNode) parent.getLastPathComponent();
  464. if (node.getChildCount() >= 0)
  465. {
  466. for (Enumeration e = node.children(); e.hasMoreElements();)
  467. {
  468. TreeNode n = (TreeNode) e.nextElement();
  469. TreePath path = parent.pathByAddingChild(n);
  470. expandAll(path, expand);
  471. }
  472. }
  473. // expansion or collapse must be done from the bottom up
  474. if (expand)
  475. {
  476. tree.expandPath(parent);
  477. }
  478. else
  479. {
  480. tree.collapsePath(parent);
  481. }
  482. }
  483. } );
  484. } // }}}
  485. // {{{ buildTree() method
  486. protected JTree buildTree(TreeModel model)
  487. {
  488. return new CustomTree(model);
  489. } // }}}
  490. // {{{ buildActionListener() method
  491. /**
  492. * Creates an action listener for the parse button.
  493. */
  494. protected ActionListener buildActionListener()
  495. {
  496. return new ActionHandler();
  497. } // }}}
  498. // {{{ propertiesChanged() method
  499. protected void propertiesChanged()
  500. {
  501. followCaret.setSelected(SideKick.isFollowCaret());
  502. Mode m = view.getBuffer().getMode();
  503. String mode = m != null ? m.getName() : null;
  504. autoExpandTree = AbstractModeOptionPane.getIntegerProperty(mode, SideKick.AUTO_EXPAND_DEPTH, 1);
  505. // autoExpandTree = ModeOptions.getAutoExpandTreeDepth();
  506. if (AbstractModeOptionPane.getBooleanProperty(mode, SideKick.SHOW_STATUS))
  507. {
  508. if (!statusShowing)
  509. {
  510. remove(topPanel);
  511. splitter.setTopComponent(topPanel);
  512. add(splitter);
  513. }
  514. statusShowing = true;
  515. }
  516. else
  517. {
  518. remove(splitter);
  519. splitter.remove(topPanel);
  520. add(topPanel);
  521. statusShowing = false;
  522. }
  523. // show or hide the filter box
  524. final boolean showFilter = jEdit.getBooleanProperty(SideKick.SHOW_FILTER, true);
  525. if (showFilter != filterBox.isVisible())
  526. {
  527. SwingUtilities.invokeLater(new Runnable()
  528. {
  529. public void run()
  530. {
  531. filterBox.setVisible(showFilter);
  532. searchField.setEnabled(showFilter);
  533. }
  534. } );
  535. }
  536. } // }}}
  537. // {{{ parserList() method
  538. /** @return a list of parsers, sorted, with special choices
  539. * on top */
  540. public static StringList parserList()
  541. {
  542. String[] serviceNames = ServiceManager.getServiceNames(SideKickParser.SERVICE);
  543. Arrays.sort(serviceNames, new StandardUtilities.StringCompare<String>(true));
  544. StringList sl = new StringList();
  545. sl.add(SideKickPlugin.NONE);
  546. sl.add(SideKickPlugin.DEFAULT);
  547. sl.addAll(serviceNames);
  548. return sl;
  549. } // }}}
  550. // {{{ reloadParserCombo() method
  551. void reloadParserCombo()
  552. {
  553. parserCombo.setModel(new DefaultComboBoxModel(parserList().toArray()));
  554. SideKickParser currentParser = SideKickPlugin.getParserForBuffer(view.getBuffer());
  555. if (currentParser != null)
  556. {
  557. String name = currentParser.getName();
  558. if (name == null)
  559. {
  560. name = SideKickPlugin.DEFAULT;
  561. }
  562. parserCombo.setSelectedItem(name);
  563. }
  564. else
  565. {
  566. String pp = view.getBuffer().getStringProperty(SideKickPlugin.PARSER_PROPERTY);
  567. if (pp == SideKickPlugin.NONE)
  568. {
  569. parserCombo.setSelectedItem(SideKickPlugin.NONE);
  570. }
  571. else
  572. {
  573. parserCombo.setSelectedItem(SideKickPlugin.DEFAULT);
  574. }
  575. }
  576. } // }}}
  577. // {{{ addParserPanel() method
  578. void addParserPanel(SideKickParser parser)
  579. {
  580. JPanel newParserPanel = parser.getPanel();
  581. boolean returnFocusToSearchField = searchField.hasFocus();
  582. if (newParserPanel != parserPanel)
  583. {
  584. if (parserPanel != null)
  585. {
  586. toolBox.remove(parserPanel);
  587. parserPanel = null;
  588. }
  589. if (newParserPanel != null)
  590. {
  591. toolBox.add(BorderLayout.WEST, newParserPanel);
  592. parserPanel = newParserPanel;
  593. }
  594. }
  595. if (returnFocusToSearchField)
  596. {
  597. focusOnDefaultComponent();
  598. }
  599. } // }}}
  600. // {{{ removeParserPanel() method
  601. void removeParserPanel()
  602. {
  603. if (parserPanel != null)
  604. {
  605. toolBox.remove(parserPanel);
  606. parserPanel = null;
  607. }
  608. } // }}}
  609. // {{{ expandTreeWithDelay() method
  610. /**
  611. * Expands the tree after a delay.
  612. * The delay timer is restarted each time this method is called.
  613. */
  614. protected void expandTreeWithDelay()
  615. {
  616. if (caretTimer != null)
  617. {
  618. caretTimer.stop();
  619. }
  620. else
  621. {
  622. caretTimer = new Timer(0, new ActionListener()
  623. {
  624. public void actionPerformed(ActionEvent evt)
  625. {
  626. // If the filter is *not* persistent, then clear
  627. // it when the tree is expanded for the current
  628. // caret position.
  629. if (!jEdit.getBooleanProperty("sidekick.persistentFilter"))
  630. {
  631. if (searchField.getText().length() > 0) // NOPMD
  632. {
  633. searchField.setText("");
  634. updateFilter(false);
  635. }
  636. }
  637. TextArea textArea = view.getTextArea();
  638. int caret = textArea.getCaretPosition();
  639. Selection s = textArea.getSelectionAtOffset(caret);
  640. expandTreeAt(s == null ? caret : s.getStart());
  641. }
  642. } );
  643. caretTimer.setInitialDelay(500);
  644. caretTimer.setRepeats(false);
  645. }
  646. caretTimer.start();
  647. } // }}}
  648. // {{{ expandTreeAt() method
  649. protected void expandTreeAt(int dot)
  650. {
  651. if (data == null)
  652. {
  653. return;
  654. }
  655. TreePath treePath = data.getTreePathForPosition(dot);
  656. if (treePath != null)
  657. {
  658. tree.expandPath(treePath);
  659. tree.setSelectionPath(treePath);
  660. if (jEdit.getBooleanProperty("sidekick.scrollToVisible"))
  661. {
  662. Rectangle r = tree.getPathBounds(treePath);
  663. if (r != null)
  664. {
  665. r.width = 1;
  666. tree.scrollRectToVisible(r);
  667. }
  668. else
  669. {
  670. tree.scrollPathToVisible(treePath);
  671. }
  672. }
  673. }
  674. } // }}}
  675. protected void expandCurrentNode()
  676. {
  677. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  678. TreePath path = new TreePath(node.getPath());
  679. tree.expandPath(path);
  680. }
  681. protected void collapseCurrentNode()
  682. {
  683. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  684. TreePath path = new TreePath(node.getPath());
  685. tree.collapsePath(path);
  686. }
  687. // {{{ Inner classes
  688. // {{{ CustomTree class
  689. /**
  690. * A JTree with added mouse handling. Other plugins providing similar trees
  691. * can extend CustomTree and override the mouse methods.
  692. */
  693. protected class CustomTree extends JTree
  694. {
  695. protected CustomTree(TreeModel model)
  696. {
  697. super(model);
  698. }
  699. public Enumeration<TreePath> getExpandedDescendants(TreePath parent)
  700. {
  701. return null;
  702. }
  703. protected void processMouseEvent(MouseEvent evt)
  704. {
  705. switch (evt.getID() )
  706. {
  707. // {{{ MOUSE_PRESSED...
  708. case MouseEvent.MOUSE_PRESSED:
  709. TreePath path = getPathForLocation(evt.getX(), evt.getY());
  710. if (path != null)
  711. {
  712. Object value = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
  713. if (value instanceof IAsset)
  714. {
  715. IAsset asset = (IAsset) value;
  716. JEditTextArea textArea = view.getTextArea();
  717. EditPane editPane = view.getEditPane();
  718. if (evt.getClickCount() == 2)
  719. {
  720. doubleClicked(view, asset, path);
  721. }
  722. else if (evt.isShiftDown())
  723. {
  724. shiftClick(view, asset, path);
  725. }
  726. else if (evt.isControlDown())
  727. {
  728. controlClick(view, asset, path);
  729. }
  730. else
  731. {
  732. EditBus.send(new PositionChanging(editPane));
  733. textArea.setCaretPosition(asset.getStart().getOffset());
  734. }
  735. }
  736. if (!jEdit.getBooleanProperty("sidekick.persistentFilter"))
  737. {
  738. if (searchField.getText().length() > 0) // NOPMD
  739. {
  740. searchField.setText("");
  741. updateFilter(false);
  742. }
  743. }
  744. }
  745. super.processMouseEvent(evt);
  746. searchField.requestFocusInWindow();
  747. if (path != null)
  748. {
  749. selectPath(path);
  750. }
  751. break; // }}}
  752. // {{{ MOUSE_EXITED...
  753. case MouseEvent.MOUSE_EXITED:
  754. view.getStatus().setMessage(null);
  755. super.processMouseEvent(evt);
  756. break; // }}}
  757. default:
  758. super.processMouseEvent(evt);
  759. break;
  760. }
  761. }
  762. protected void doubleClicked(View view, IAsset asset, TreePath path)
  763. {
  764. }
  765. protected void shiftClick(View view, IAsset asset, TreePath path)
  766. {
  767. JEditTextArea textArea = view.getTextArea();
  768. textArea.setCaretPosition(asset.getEnd().getOffset());
  769. Selection.Range range = new Selection.Range(asset.getStart().getOffset(), asset.getEnd().getOffset());
  770. textArea.addToSelection(range);
  771. }
  772. protected void controlClick(View view, IAsset asset, TreePath path)
  773. {
  774. JEditTextArea textArea = view.getTextArea();
  775. textArea.getDisplayManager().narrow(textArea.getLineOfOffset(asset.getStart().getOffset()), textArea.getLineOfOffset(asset.getEnd().getOffset()));
  776. }
  777. } // }}}
  778. // {{{ ActionHandler class
  779. class ActionHandler implements ActionListener
  780. {
  781. /** A counter for counting how deep in recursion we are.
  782. * Since a call to reloadParserCombo can cause itemselected events
  783. * from the parserCombo,
  784. */
  785. int level =0;
  786. public void actionPerformed(ActionEvent evt)
  787. {
  788. // Workaround to avoid infinite recursion as a result of parsercombos
  789. // updating
  790. synchronized (this)
  791. {
  792. if (evt.getSource() == parseBtn)
  793. {
  794. level = 0;
  795. }
  796. level++;
  797. if (level > 1)
  798. {
  799. level--;
  800. return;
  801. }
  802. }
  803. Buffer b = view.getBuffer();
  804. jEdit.setIntegerProperty("sidekick.splitter.location", splitter.getDividerLocation());
  805. if (evt.getSource() == onSave)
  806. {
  807. SideKick.setParseOnSave(onSave.isSelected());
  808. propertiesChanged();
  809. }
  810. if (evt.getSource() == followCaret)
  811. {
  812. boolean v = followCaret.isSelected();
  813. SideKick.setGlobalFollowCaret(followCaret.isSelected());
  814. if (v)
  815. {
  816. onChange.setSelected(true);
  817. }
  818. propertiesChanged();
  819. }
  820. else if (evt.getSource() == onChange)
  821. {
  822. boolean v = onChange.isSelected();
  823. SideKick.setParseOnChange(v);
  824. if (!v)
  825. {
  826. followCaret.setSelected(false);
  827. }
  828. propertiesChanged();
  829. }
  830. else if (evt.getSource() == parserCombo)
  831. {
  832. Object selectedParser = parserCombo.getSelectedItem();
  833. // String preferredParser = b.getStringProperty(SideKickPlugin.PARSER_PROPERTY);
  834. if (selectedParser.toString().equals(SideKickPlugin.NONE))
  835. {
  836. b.setProperty("usermode", Boolean.TRUE);
  837. SideKickPlugin.setParserForBuffer(b, selectedParser.toString());
  838. }
  839. else if (selectedParser.toString().equals(SideKickPlugin.DEFAULT))
  840. {
  841. b = view.getBuffer();
  842. b.setProperty("usermode", Boolean.FALSE);
  843. Mode m = b.getMode();
  844. if (m == null)
  845. {
  846. Log.log(Log.ERROR, this, "SideKick: can't determine mode of current buffer:" + b);
  847. }
  848. else
  849. {
  850. SideKickParser newParser = SideKickPlugin.getParserForMode(m);
  851. if (newParser == null)
  852. {
  853. SideKickPlugin.setParserForBuffer(b, SideKickPlugin.NONE);
  854. }
  855. else
  856. {
  857. SideKickPlugin.setParserForBuffer(b, newParser.getName());
  858. }
  859. }
  860. }
  861. else
  862. {
  863. SideKickPlugin.setParserForBuffer(b, selectedParser.toString());
  864. b.setProperty("usermode", Boolean.TRUE);
  865. }
  866. propertiesChanged();
  867. }
  868. else if (evt.getSource() == parseBtn && stopIcon.equals(parseBtn.getIcon()))
  869. {
  870. SideKickPlugin.stop(view);
  871. SwingUtilities.invokeLater(new Runnable()
  872. {
  873. public void run()
  874. {
  875. parseBtn.setIcon(parseIcon);
  876. parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.parse"));
  877. }
  878. });
  879. }
  880. if (evt.getSource() == parseBtn || evt.getSource() == parserCombo)
  881. {
  882. if (evt.getSource() == parseBtn)
  883. {
  884. SwingUtilities.invokeLater(new Runnable()
  885. {
  886. public void run()
  887. {
  888. parseBtn.setIcon(stopIcon);
  889. parseBtn.setToolTipText(jEdit.getProperty("sidekick-tree.stop-parsing"));
  890. }
  891. });
  892. }
  893. level = 0;
  894. Object usermode = b.getProperty("usermode");
  895. if (usermode == null || usermode == Boolean.FALSE)
  896. {
  897. SideKickParser sp = SideKickPlugin.getParserForBuffer(b);
  898. if (sp == null)
  899. {
  900. return;
  901. }
  902. else
  903. {
  904. reloadParserCombo();
  905. }
  906. }
  907. SideKickPlugin.parse(view, true);
  908. }
  909. level--;
  910. }
  911. } // }}}
  912. // {{{ CaretHandler class
  913. class CaretHandler implements CaretListener
  914. {
  915. public void caretUpdate(CaretEvent evt)
  916. {
  917. if (!view.getBuffer().equals(lastParsedBuffer))
  918. {
  919. return;
  920. }
  921. if (evt.getSource() == view.getTextArea() && SideKick.isFollowCaret())
  922. {
  923. expandTreeWithDelay();
  924. }
  925. }
  926. } // }}}
  927. protected void find_visible_nodes(HashSet<TreePath> set, DefaultMutableTreeNode node)
  928. {
  929. TreePath path = new TreePath(node.getPath());
  930. if (tree.isVisible(path) && tree.isExpanded(path))
  931. {
  932. set.add(new TreePath(node.getPath()));
  933. for (Enumeration e = node.children(); e.hasMoreElements();)
  934. {
  935. find_visible_nodes(set, (DefaultMutableTreeNode) e.nextElement());
  936. }
  937. }
  938. }
  939. protected void filter_visible_nodes(FilteredTreeModel model, HashSet<TreePath> visible, DefaultMutableTreeNode node)
  940. {
  941. if (!jEdit.getBooleanProperty(SideKick.SHOW_FILTER))
  942. {
  943. return;
  944. }
  945. TreePath path = new TreePath(node.getPath());
  946. if (!visible.contains(path))
  947. {
  948. return;
  949. }
  950. tree.expandPath(path);
  951. for (Enumeration e = node.children(); e.hasMoreElements();)
  952. {
  953. filter_visible_nodes(model, visible, (DefaultMutableTreeNode) e.nextElement());
  954. }
  955. }
  956. public void updateFilter(boolean with_delay)
  957. {
  958. if (!jEdit.getBooleanProperty(SideKick.SHOW_FILTER))
  959. {
  960. return;
  961. }
  962. FilteredTreeModel ftm = (FilteredTreeModel) tree.getModel();
  963. if (searchField.getText().length() == 0)
  964. {
  965. ftm.clearFilter();
  966. ftm.reset();
  967. if (autoExpandTree == -1)
  968. {
  969. expandAll(true);
  970. }
  971. else if (autoExpandTree == 0)
  972. {
  973. expandAll(false);
  974. }
  975. else if (autoExpandTree > 0)
  976. {
  977. tree.expandRow(0);
  978. for (int i = 1; i < autoExpandTree; i++)
  979. {
  980. for (int j = tree.getRowCount() - 1; j > 0; j--)
  981. {
  982. tree.expandRow(j);
  983. }
  984. }
  985. }
  986. if (SideKick.isFollowCaret() && with_delay)
  987. {
  988. expandTreeWithDelay();
  989. }
  990. }
  991. else
  992. {
  993. HashSet<TreePath> visible = new HashSet<TreePath>();
  994. find_visible_nodes(visible, (DefaultMutableTreeNode) ftm.getRoot());
  995. ftm.filterByText(searchField.getText());
  996. DefaultMutableTreeNode root = (DefaultMutableTreeNode) ftm.getRoot();
  997. if (jEdit.getBooleanProperty(SideKick.FILTER_VISIBLE))
  998. {
  999. filter_visible_nodes(ftm, visible, root);
  1000. }
  1001. else
  1002. {
  1003. expandAll(true);
  1004. }
  1005. }
  1006. }
  1007. public void updateFilter()
  1008. {
  1009. updateFilter(true);
  1010. }
  1011. public void setSearchFilter(String text)
  1012. {
  1013. searchField.setText(text);
  1014. updateFilter();
  1015. }
  1016. public String getSearchFilter()
  1017. {
  1018. return searchField.getText();
  1019. }
  1020. // {{{ KeyHandler class
  1021. class KeyHandler extends KeyAdapter
  1022. {
  1023. protected void next()
  1024. {
  1025. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  1026. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  1027. if (node == null)
  1028. {
  1029. node = (DefaultMutableTreeNode) model.getRoot();
  1030. }
  1031. // standard tree movement for next:
  1032. // If selected node has children and selected node is expanded,
  1033. // then next is the first child of the selected node, otherwise,
  1034. // next is the next sibling.
  1035. // If selected node is a leaf, then next is next sibling.
  1036. // If next sibling is null, that means selected node is the
  1037. // last child of the parent node, so next is parent.nextSibling
  1038. if (node.getChildCount() > 0)
  1039. {
  1040. DefaultMutableTreeNode firstChild = (DefaultMutableTreeNode) node.getFirstChild();
  1041. TreePath path = new TreePath(firstChild.getPath());
  1042. if (tree.isVisible(path))
  1043. {
  1044. node = firstChild;
  1045. }
  1046. else
  1047. {
  1048. node = (DefaultMutableTreeNode) node.getNextSibling();
  1049. }
  1050. }
  1051. else
  1052. {
  1053. // node is a leaf
  1054. DefaultMutableTreeNode next = (DefaultMutableTreeNode) node.getNextSibling();
  1055. if (next == null)
  1056. {
  1057. // must be last child of parent
  1058. next = (DefaultMutableTreeNode) ((DefaultMutableTreeNode) node.getParent()).getNextSibling();
  1059. }
  1060. node = next;
  1061. }
  1062. if (node != null)
  1063. {
  1064. TreePath p = new TreePath(node.getPath());
  1065. selectPath(p);
  1066. }
  1067. }
  1068. protected void nextLeaf()
  1069. {
  1070. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  1071. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  1072. if (node == null)
  1073. {
  1074. node = (DefaultMutableTreeNode) model.getRoot();
  1075. }
  1076. if (model.isLeaf(node))
  1077. {
  1078. node = node.getNextLeaf();
  1079. }
  1080. else
  1081. {
  1082. Enumeration<DefaultMutableTreeNode> e = node.depthFirstEnumeration();
  1083. node = e.nextElement();
  1084. }
  1085. if (node != null)
  1086. {
  1087. while ((node != null) && !(model.isVisible(node) && tree.isVisible(new TreePath(node.getPath()))))
  1088. {
  1089. node = node.getNextLeaf();
  1090. }
  1091. if (node != null)
  1092. {
  1093. TreePath p = new TreePath(node.getPath());
  1094. selectPath(p);
  1095. }
  1096. }
  1097. }
  1098. protected void prev()
  1099. {
  1100. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  1101. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  1102. if (node == null)
  1103. {
  1104. node = (DefaultMutableTreeNode) model.getRoot();
  1105. }
  1106. // standard movement for previous:
  1107. // Initially, previous is the previous sibling.
  1108. // If previous sibling is null, then that means the current node
  1109. // is the first child of the parent node, so previous is the
  1110. // parent node.
  1111. // If previous sibling has children and is expanded, then previous
  1112. // is the last child of the previous sibling.
  1113. DefaultMutableTreeNode prev = node.getPreviousSibling();
  1114. if (prev == null)
  1115. { // could be first child
  1116. node = (DefaultMutableTreeNode) node.getParent();
  1117. }
  1118. else if (prev.getChildCount() > 0)
  1119. {
  1120. DefaultMutableTreeNode lastChild = (DefaultMutableTreeNode) prev.getLastChild();
  1121. TreePath path = new TreePath(lastChild.getPath());
  1122. if (tree.isVisible(path))
  1123. {
  1124. node = lastChild;
  1125. }
  1126. else
  1127. {
  1128. node = prev;
  1129. }
  1130. }
  1131. else
  1132. {
  1133. node = prev;
  1134. }
  1135. if (node != null)
  1136. {
  1137. TreePath p = new TreePath(node.getPath());
  1138. selectPath(p);
  1139. }
  1140. }
  1141. protected void prevLeaf()
  1142. {
  1143. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
  1144. FilteredTreeModel model = (FilteredTreeModel) tree.getModel();
  1145. if (node == null)
  1146. {
  1147. node = (DefaultMutableTreeNode) model.getRoot();
  1148. }
  1149. // If the node isn't a leaf, use depthFirstEnumeration to find the next
  1150. // leaf (which moves us forward), then get the previous (to get the previous
  1151. // node from where we started).
  1152. if (!model.isLeaf(node))
  1153. {
  1154. Enumeration<DefaultMutableTreeNode> e = node.depthFirstEnumeration();
  1155. node = e.nextElement();
  1156. }
  1157. node = node.getPreviousLeaf();
  1158. if (node != null)
  1159. {
  1160. while ((node != null) && !(model.isVisible(node) && tree.isVisible(new TreePath(node.getPath()))))
  1161. {
  1162. node = node.getPreviousLeaf();
  1163. }
  1164. if (node != null)
  1165. {
  1166. TreePath p = new TreePath(node.getPath());
  1167. selectPath(p);
  1168. }
  1169. }
  1170. }
  1171. public void keyPressed(KeyEvent evt)
  1172. {
  1173. if (caretTimer != null)
  1174. {
  1175. caretTimer.stop();
  1176. }
  1177. switch (evt.getKeyCode() )
  1178. {
  1179. case KeyEvent.VK_ESCAPE:
  1180. evt.consume();
  1181. if (searchField.getText().length() == 0)
  1182. {
  1183. view.getDockableWindowManager().hideDockableWindow(SideKickPlugin.NAME);
  1184. }
  1185. else
  1186. {
  1187. searchField.setText("");
  1188. updateFilter();
  1189. }
  1190. break;
  1191. case KeyEvent.VK_ENTER:
  1192. evt.consume();
  1193. TreePath path = tree.getSelectionPath();
  1194. if (path != null)
  1195. {
  1196. Object value = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
  1197. if (value instanceof IAsset)
  1198. {
  1199. IAsset asset = (IAsset) value;
  1200. JEditTextArea textArea = view.getTextArea();
  1201. if (evt.isShiftDown())
  1202. {
  1203. textArea.setCaretPosition(asset.getEnd().getOffset());
  1204. textArea.addToSelection(new Selection.Range(asset.getStart().getOffset(), asset.getEnd().getOffset() + 1));
  1205. }
  1206. else
  1207. {
  1208. if (!jEdit.getBooleanProperty("sidekick.persistentFilter"))
  1209. {
  1210. if (searchField.getText().length() > 0) // NOPMD
  1211. {
  1212. searchField.setText("");
  1213. updateFilter();
  1214. }
  1215. }
  1216. textArea.setCaretPosition(asset.getStart().getOffset());
  1217. selectPath(path);
  1218. textArea.requestFocus();
  1219. }
  1220. }
  1221. }
  1222. break;
  1223. case KeyEvent.VK_BACK_SPACE:
  1224. evt.consume();
  1225. if (searchField.getText().length() <= 1)
  1226. {
  1227. searchField.setText("");
  1228. }
  1229. else
  1230. {
  1231. String s = searchField.getText();
  1232. s = s.substring(0, s.length() - 1);
  1233. searchField.setText(s);
  1234. }
  1235. updateFilter();
  1236. break;
  1237. case KeyEvent.VK_DOWN:
  1238. evt.consume();
  1239. if (evt.isControlDown())
  1240. {
  1241. nextLeaf();
  1242. }
  1243. else
  1244. {
  1245. next();
  1246. }
  1247. break;
  1248. case KeyEvent.VK_UP:
  1249. evt.consume();
  1250. if (evt.isControlDown())
  1251. {
  1252. prevLeaf();
  1253. }
  1254. else
  1255. {
  1256. prev();
  1257. }
  1258. break;
  1259. case KeyEvent.VK_LEFT:
  1260. collapseCurrentNode();
  1261. break;
  1262. case KeyEvent.VK_RIGHT:
  1263. expandCurrentNode();
  1264. break;
  1265. case KeyEvent.VK_PAGE_UP:
  1266. {
  1267. evt.consume();
  1268. int offset = tree.getScrollableUnitIncrement(tree.getParent().getBounds(), javax.swing.SwingConstants.VERTICAL, 0);
  1269. for (int i = 0; i < offset; ++i)
  1270. {
  1271. if (evt.isControlDown())
  1272. {
  1273. prevLeaf();
  1274. }
  1275. else
  1276. {
  1277. prev();
  1278. }
  1279. }
  1280. }
  1281. break;
  1282. case KeyEvent.VK_PAGE_DOWN:
  1283. {
  1284. evt.consume();
  1285. int offset = tree.getScrollableUnitIncrement(tree.getParent().getBounds(), javax.swing.SwingConstants.VERTICAL, 0);
  1286. for (int i = 0; i < offset; ++i)
  1287. {
  1288. if (evt.isControlDown())
  1289. {
  1290. nextLeaf();
  1291. }
  1292. else
  1293. {
  1294. next();
  1295. }
  1296. }
  1297. }
  1298. break;
  1299. default:
  1300. break;
  1301. }
  1302. }
  1303. public void keyTyped(KeyEvent evt)
  1304. {
  1305. Character c = evt.getKeyChar();
  1306. // TODO: What is the correct combo here to filter
  1307. // non-identifier characters?
  1308. if (Character.isLetterOrDigit(c) || (" _!@$%^&*()_+-=[]{};':\",.<>/?\\|".indexOf(c) != -1))
  1309. {
  1310. evt.consume();
  1311. searchField.setText(searchField.getText() + c);
  1312. updateFilter();
  1313. }
  1314. }
  1315. } // }}}
  1316. // {{{ MouseHandler class
  1317. class MouseHandler extends MouseMotionAdapter
  1318. {
  1319. public void mouseMoved(MouseEvent evt)
  1320. {
  1321. TreePath path = tree.getPathForLocation(evt.getX(), evt.getY());
  1322. if (path == null)
  1323. {
  1324. view.getStatus().setMessage(null);
  1325. }
  1326. else
  1327. {
  1328. Object value = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
  1329. if (value instanceof IAsset)
  1330. {
  1331. String info = ((IAsset) value).getShortString();
  1332. view.getStatus().setMessage(info);
  1333. }
  1334. }
  1335. }
  1336. } // }}}
  1337. // {{{ SidekickProperties class
  1338. /**
  1339. * This class creates an options dialog containing an optionpane
  1340. * for each SideKick service, as well as one for SideKick itself.
  1341. * This properties pane is mode-sensitive.
  1342. *
  1343. * sidekick options, and one for the specific plugin's option pane.
  1344. */
  1345. class SideKickProperties implements ActionListener
  1346. {
  1347. public void actionPerformed(ActionEvent e)
  1348. {
  1349. try
  1350. {
  1351. new ModeOptionsDialog(view);
  1352. }
  1353. catch (Exception ex)
  1354. {
  1355. Log.log(Log.ERROR, this, "dialog create failed",