PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
Java | 551 lines | 405 code | 73 blank | 73 comment | 54 complexity | eecba8a4cf991f34e234138cfd0f4712 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. * HyperSearchResults.java - HyperSearch results
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1998, 1999, 2000, 2001 Slava Pestov
  7. * Portions copyright (C) 2002 Peter Cox
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.search;
  24. //{{{ Imports
  25. import javax.swing.*;
  26. import javax.swing.event.*;
  27. import javax.swing.tree.*;
  28. import java.awt.*;
  29. import java.awt.event.*;
  30. import org.gjt.sp.jedit.io.VFSManager;
  31. import org.gjt.sp.jedit.gui.DefaultFocusComponent;
  32. import org.gjt.sp.jedit.gui.RolloverButton;
  33. import org.gjt.sp.jedit.msg.*;
  34. import org.gjt.sp.jedit.textarea.*;
  35. import org.gjt.sp.jedit.*;
  36. //}}}
  37. /**
  38. * HyperSearch results window.
  39. * @author Slava Pestov
  40. * @version $Id: HyperSearchResults.java 4965 2004-02-04 00:07:34Z spestov $
  41. */
  42. public class HyperSearchResults extends JPanel implements EBComponent,
  43. DefaultFocusComponent
  44. {
  45. public static final String NAME = "hypersearch-results";
  46. //{{{ HyperSearchResults constructor
  47. public HyperSearchResults(View view)
  48. {
  49. super(new BorderLayout());
  50. this.view = view;
  51. caption = new JLabel();
  52. Box toolBar = new Box(BoxLayout.X_AXIS);
  53. toolBar.add(caption);
  54. toolBar.add(Box.createGlue());
  55. ActionHandler ah = new ActionHandler();
  56. clear = new RolloverButton(GUIUtilities.loadIcon("Clear.png"));
  57. clear.setToolTipText(jEdit.getProperty(
  58. "hypersearch-results.clear.label"));
  59. clear.addActionListener(ah);
  60. toolBar.add(clear);
  61. multi = new RolloverButton();
  62. multi.setToolTipText(jEdit.getProperty(
  63. "hypersearch-results.multi.label"));
  64. multi.addActionListener(ah);
  65. toolBar.add(multi);
  66. add(BorderLayout.NORTH, toolBar);
  67. resultTreeRoot = new DefaultMutableTreeNode();
  68. resultTreeModel = new DefaultTreeModel(resultTreeRoot);
  69. resultTree = new JTree(resultTreeModel);
  70. resultTree.setCellRenderer(new ResultCellRenderer());
  71. resultTree.setVisibleRowCount(16);
  72. resultTree.setRootVisible(false);
  73. resultTree.setShowsRootHandles(true);
  74. // looks bad with the OS X L&F, apparently...
  75. if(!OperatingSystem.isMacOSLF())
  76. resultTree.putClientProperty("JTree.lineStyle", "Angled");
  77. resultTree.setEditable(false);
  78. resultTree.addKeyListener(new KeyHandler());
  79. resultTree.addMouseListener(new MouseHandler());
  80. JScrollPane scrollPane = new JScrollPane(resultTree);
  81. Dimension dim = scrollPane.getPreferredSize();
  82. dim.width = 400;
  83. scrollPane.setPreferredSize(dim);
  84. add(BorderLayout.CENTER, scrollPane);
  85. } //}}}
  86. //{{{ focusOnDefaultComponent() method
  87. public void focusOnDefaultComponent()
  88. {
  89. resultTree.requestFocus();
  90. } //}}}
  91. //{{{ addNotify() method
  92. public void addNotify()
  93. {
  94. super.addNotify();
  95. EditBus.addToBus(this);
  96. multiStatus = jEdit.getBooleanProperty(
  97. "hypersearch-results.multi");
  98. updateMultiStatus();
  99. } //}}}
  100. //{{{ removeNotify() method
  101. public void removeNotify()
  102. {
  103. super.removeNotify();
  104. EditBus.removeFromBus(this);
  105. jEdit.setBooleanProperty("hypersearch-results.multi",multiStatus);
  106. } //}}}
  107. //{{{ handleMessage() method
  108. public void handleMessage(EBMessage msg)
  109. {
  110. if(msg instanceof BufferUpdate)
  111. {
  112. BufferUpdate bmsg = (BufferUpdate)msg;
  113. Buffer buffer = bmsg.getBuffer();
  114. Object what = bmsg.getWhat();
  115. if(what == BufferUpdate.LOADED ||
  116. what == BufferUpdate.CLOSED)
  117. {
  118. ResultVisitor visitor = null;
  119. if (what == BufferUpdate.LOADED)
  120. {
  121. visitor = new BufferLoadedVisitor();
  122. }
  123. else // BufferUpdate.CLOSED
  124. {
  125. visitor = new BufferClosedVisitor();
  126. }
  127. // impl note: since multiple searches now allowed,
  128. // extra level in hierarchy
  129. for(int i = resultTreeRoot.getChildCount() - 1; i >= 0; i--)
  130. {
  131. DefaultMutableTreeNode searchNode = (DefaultMutableTreeNode)
  132. resultTreeRoot.getChildAt(i);
  133. for(int j = searchNode.getChildCount() - 1;
  134. j >= 0; j--)
  135. {
  136. DefaultMutableTreeNode bufferNode = (DefaultMutableTreeNode)
  137. searchNode.getChildAt(j);
  138. for(int k = bufferNode.getChildCount() - 1;
  139. k >= 0; k--)
  140. {
  141. Object userObject =
  142. ((DefaultMutableTreeNode)bufferNode
  143. .getChildAt(k)).getUserObject();
  144. HyperSearchResult result = (HyperSearchResult)
  145. userObject;
  146. if(buffer.getPath().equals(result.path))
  147. visitor.visit(buffer,result);
  148. }
  149. }
  150. }
  151. }
  152. }
  153. } //}}}
  154. //{{{ getTreeModel() method
  155. public DefaultTreeModel getTreeModel()
  156. {
  157. return resultTreeModel;
  158. } //}}}
  159. //{{{ getTree() method
  160. /**
  161. * Returns the result tree.
  162. * @since jEdit 4.1pre9
  163. */
  164. public JTree getTree()
  165. {
  166. return resultTree;
  167. } //}}}
  168. //{{{ searchStarted() method
  169. public void searchStarted()
  170. {
  171. caption.setText(jEdit.getProperty("hypersearch-results.searching"));
  172. } //}}}
  173. //{{{ searchFailed() method
  174. public void searchFailed()
  175. {
  176. caption.setText(jEdit.getProperty("hypersearch-results.no-results"));
  177. // collapse all nodes, as suggested on user mailing list...
  178. for(int i = 0; i < resultTreeRoot.getChildCount(); i++)
  179. {
  180. DefaultMutableTreeNode node = (DefaultMutableTreeNode)
  181. resultTreeRoot.getChildAt(i);
  182. resultTree.collapsePath(new TreePath(new Object[] {
  183. resultTreeRoot, node }));
  184. }
  185. } //}}}
  186. //{{{ searchDone() method
  187. public void searchDone(final DefaultMutableTreeNode searchNode)
  188. {
  189. final int nodeCount = searchNode.getChildCount();
  190. if (nodeCount < 1)
  191. {
  192. searchFailed();
  193. return;
  194. }
  195. caption.setText(jEdit.getProperty("hypersearch-results.done"));
  196. SwingUtilities.invokeLater(new Runnable()
  197. {
  198. public void run()
  199. {
  200. if(!multiStatus)
  201. {
  202. for(int i = 0; i < resultTreeRoot.getChildCount(); i++)
  203. {
  204. resultTreeRoot.remove(0);
  205. }
  206. }
  207. resultTreeRoot.add(searchNode);
  208. resultTreeModel.reload(resultTreeRoot);
  209. TreePath lastNode = null;
  210. for(int i = 0; i < nodeCount; i++)
  211. {
  212. lastNode = new TreePath(
  213. ((DefaultMutableTreeNode)
  214. searchNode.getChildAt(i))
  215. .getPath());
  216. resultTree.expandPath(lastNode);
  217. }
  218. resultTree.scrollPathToVisible(
  219. new TreePath(new Object[] {
  220. resultTreeRoot,searchNode }));
  221. }
  222. });
  223. } //}}}
  224. //{{{ Private members
  225. private View view;
  226. private JLabel caption;
  227. private JTree resultTree;
  228. private DefaultMutableTreeNode resultTreeRoot;
  229. private DefaultTreeModel resultTreeModel;
  230. private RolloverButton clear;
  231. private RolloverButton multi;
  232. private boolean multiStatus;
  233. //{{{ updateMultiStatus() method
  234. private void updateMultiStatus()
  235. {
  236. if(multiStatus)
  237. multi.setIcon(GUIUtilities.loadIcon("MultipleResults.png"));
  238. else
  239. multi.setIcon(GUIUtilities.loadIcon("SingleResult.png"));
  240. } //}}}
  241. //{{{ goToSelectedNode() method
  242. private void goToSelectedNode()
  243. {
  244. TreePath path = resultTree.getSelectionPath();
  245. if(path == null)
  246. return;
  247. DefaultMutableTreeNode node = (DefaultMutableTreeNode)path
  248. .getLastPathComponent();
  249. Object value = node.getUserObject();
  250. if(node.getParent() == resultTreeRoot)
  251. {
  252. // do nothing if clicked "foo (showing n occurrences in m files)"
  253. }
  254. else if(value instanceof String)
  255. {
  256. Buffer buffer = jEdit.openFile(view,(String)value);
  257. if(buffer == null)
  258. return;
  259. view.goToBuffer(buffer);
  260. // fuck me dead
  261. SwingUtilities.invokeLater(new Runnable()
  262. {
  263. public void run()
  264. {
  265. resultTree.requestFocus();
  266. }
  267. });
  268. }
  269. else if (value instanceof HyperSearchResult)
  270. {
  271. ((HyperSearchResult)value).goTo(view);
  272. }
  273. } //}}}
  274. //}}}
  275. //{{{ ActionHandler class
  276. public class ActionHandler implements ActionListener
  277. {
  278. public void actionPerformed(ActionEvent evt)
  279. {
  280. Object source = evt.getSource();
  281. if(source == clear)
  282. {
  283. resultTreeRoot.removeAllChildren();
  284. resultTreeModel.reload(resultTreeRoot);
  285. }
  286. else if(source == multi)
  287. {
  288. multiStatus = !multiStatus;
  289. updateMultiStatus();
  290. if(!multiStatus)
  291. {
  292. for(int i = resultTreeRoot.getChildCount() - 2; i >= 0; i--)
  293. {
  294. resultTreeModel.removeNodeFromParent(
  295. (MutableTreeNode)resultTreeRoot
  296. .getChildAt(i));
  297. }
  298. }
  299. }
  300. }
  301. } //}}}
  302. //{{{ KeyHandler class
  303. class KeyHandler extends KeyAdapter
  304. {
  305. public void keyPressed(KeyEvent evt)
  306. {
  307. if(evt.getKeyCode() == KeyEvent.VK_ENTER)
  308. {
  309. goToSelectedNode();
  310. // fuck me dead
  311. SwingUtilities.invokeLater(new Runnable()
  312. {
  313. public void run()
  314. {
  315. resultTree.requestFocus();
  316. }
  317. });
  318. evt.consume();
  319. }
  320. }
  321. } //}}}
  322. //{{{ MouseHandler class
  323. class MouseHandler extends MouseAdapter
  324. {
  325. //{{{ mousePressed() method
  326. public void mousePressed(MouseEvent evt)
  327. {
  328. if(evt.isConsumed())
  329. return;
  330. TreePath path1 = resultTree.getPathForLocation(
  331. evt.getX(),evt.getY());
  332. if(path1 == null)
  333. return;
  334. resultTree.setSelectionPath(path1);
  335. if (GUIUtilities.isPopupTrigger(evt))
  336. showPopupMenu(evt);
  337. else
  338. {
  339. goToSelectedNode();
  340. view.toFront();
  341. view.requestFocus();
  342. view.getTextArea().requestFocus();
  343. }
  344. } //}}}
  345. //{{{ Private members
  346. private JPopupMenu popupMenu;
  347. //{{{ showPopupMenu method
  348. private void showPopupMenu(MouseEvent evt)
  349. {
  350. if (popupMenu == null)
  351. {
  352. popupMenu = new JPopupMenu();
  353. popupMenu.add(new RemoveTreeNodeAction());
  354. }
  355. GUIUtilities.showPopupMenu(popupMenu,evt.getComponent(),
  356. evt.getX(),evt.getY());
  357. evt.consume();
  358. } //}}}
  359. //}}}
  360. } //}}}
  361. //{{{ RemoveTreeNodeAction class
  362. class RemoveTreeNodeAction extends AbstractAction
  363. {
  364. public RemoveTreeNodeAction()
  365. {
  366. super(jEdit.getProperty("hypersearch-results.remove-node"));
  367. }
  368. public void actionPerformed(ActionEvent evt)
  369. {
  370. TreePath path = resultTree.getSelectionPath();
  371. if(path == null)
  372. return;
  373. MutableTreeNode value = (MutableTreeNode)path
  374. .getLastPathComponent();
  375. resultTreeModel.removeNodeFromParent(value);
  376. }
  377. }//}}}
  378. //{{{ RemoveAllTreeNodesAction class
  379. class RemoveAllTreeNodesAction extends AbstractAction
  380. {
  381. public RemoveAllTreeNodesAction()
  382. {
  383. super(jEdit.getProperty("hypersearch-results.remove-all-nodes"));
  384. }
  385. public void actionPerformed(ActionEvent evt)
  386. {
  387. resultTreeRoot = new DefaultMutableTreeNode();
  388. resultTreeModel = new DefaultTreeModel(resultTreeRoot);
  389. resultTree.setModel(resultTreeModel);
  390. }
  391. }//}}}
  392. //{{{ ResultCellRenderer class
  393. class ResultCellRenderer extends DefaultTreeCellRenderer
  394. {
  395. Font plainFont, boldFont;
  396. //{{{ ResultCellRenderer constructor
  397. ResultCellRenderer()
  398. {
  399. plainFont = UIManager.getFont("Tree.font");
  400. if(plainFont == null)
  401. plainFont = jEdit.getFontProperty("metal.secondary.font");
  402. boldFont = new Font(plainFont.getName(),Font.BOLD,
  403. plainFont.getSize());
  404. } //}}}
  405. //{{{ getTreeCellRendererComponent() method
  406. public Component getTreeCellRendererComponent(JTree tree,
  407. Object value, boolean sel, boolean expanded,
  408. boolean leaf, int row, boolean hasFocus)
  409. {
  410. Component comp = super.getTreeCellRendererComponent(tree,value,sel,
  411. expanded,leaf,row,hasFocus);
  412. setIcon(null);
  413. DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
  414. if (node.getParent() == resultTreeRoot)
  415. {
  416. ResultCellRenderer.this.setFont(boldFont);
  417. int bufferCount = node.getChildCount();
  418. int resultCount = 0;
  419. for (int i = 0; i < bufferCount; i++)
  420. {
  421. resultCount += node.getChildAt(i).getChildCount();
  422. }
  423. Object[] pp = { node.toString(), new Integer(resultCount), new Integer(bufferCount) };
  424. setText(jEdit.getProperty("hypersearch-results.result-caption",pp));
  425. }
  426. else if(node.getUserObject() instanceof String)
  427. {
  428. // file name
  429. ResultCellRenderer.this.setFont(boldFont);
  430. int count = node.getChildCount();
  431. if(count == 1)
  432. {
  433. setText(jEdit.getProperty("hypersearch-results"
  434. + ".file-caption1",new Object[] {
  435. node.getUserObject()
  436. }));
  437. }
  438. else
  439. {
  440. setText(jEdit.getProperty("hypersearch-results"
  441. + ".file-caption",new Object[] {
  442. node.getUserObject(),
  443. new Integer(count)
  444. }));
  445. }
  446. }
  447. else
  448. {
  449. ResultCellRenderer.this.setFont(plainFont);
  450. }
  451. return this;
  452. } //}}}
  453. } //}}}
  454. // these are used to eliminate code duplication. i don't normally use
  455. // the visitor or "template method" pattern, but this code was contributed
  456. // by Peter Cox and i don't feel like changing it around too much.
  457. //{{{ ResultVisitor interface
  458. interface ResultVisitor
  459. {
  460. public void visit(Buffer buffer, HyperSearchResult result);
  461. } //}}}
  462. //{{{ BufferLoadedVisitor class
  463. class BufferLoadedVisitor implements ResultVisitor
  464. {
  465. public void visit(Buffer buffer, HyperSearchResult result)
  466. {
  467. result.bufferOpened(buffer);
  468. }
  469. } //}}}
  470. //{{{ BufferClosedVisitor class
  471. class BufferClosedVisitor implements ResultVisitor
  472. {
  473. public void visit(Buffer buffer, HyperSearchResult result)
  474. {
  475. result.bufferClosed();
  476. }
  477. } //}}}
  478. }