PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 573 lines | 423 code | 77 blank | 73 comment | 55 complexity | a904abee5e13e563e7424304382db3cf 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 4761 2003-06-05 00:44:54Z 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. multiStatus = jEdit.getBooleanProperty(
  67. "hypersearch-results.multi");
  68. updateMultiStatus();
  69. add(BorderLayout.NORTH, toolBar);
  70. resultTreeRoot = new DefaultMutableTreeNode();
  71. resultTreeModel = new DefaultTreeModel(resultTreeRoot);
  72. resultTree = new JTree(resultTreeModel);
  73. resultTree.setCellRenderer(new ResultCellRenderer());
  74. resultTree.setVisibleRowCount(16);
  75. resultTree.setRootVisible(false);
  76. resultTree.setShowsRootHandles(true);
  77. // looks bad with the OS X L&F, apparently...
  78. if(!OperatingSystem.isMacOSLF())
  79. resultTree.putClientProperty("JTree.lineStyle", "Angled");
  80. resultTree.setEditable(false);
  81. resultTree.addKeyListener(new KeyHandler());
  82. resultTree.addMouseListener(new MouseHandler());
  83. JScrollPane scrollPane = new JScrollPane(resultTree);
  84. Dimension dim = scrollPane.getPreferredSize();
  85. dim.width = 400;
  86. scrollPane.setPreferredSize(dim);
  87. add(BorderLayout.CENTER, scrollPane);
  88. } //}}}
  89. //{{{ focusOnDefaultComponent() method
  90. public void focusOnDefaultComponent()
  91. {
  92. resultTree.requestFocus();
  93. } //}}}
  94. //{{{ addNotify() method
  95. public void addNotify()
  96. {
  97. super.addNotify();
  98. EditBus.addToBus(this);
  99. multi.setSelected(jEdit.getBooleanProperty("hypersearch-results.multi-toggle"));
  100. } //}}}
  101. //{{{ removeNotify() method
  102. public void removeNotify()
  103. {
  104. super.removeNotify();
  105. EditBus.removeFromBus(this);
  106. jEdit.setBooleanProperty("hypersearch-results.multi-toggle",multi.isSelected());
  107. } //}}}
  108. //{{{ handleMessage() method
  109. public void handleMessage(EBMessage msg)
  110. {
  111. if(msg instanceof BufferUpdate)
  112. {
  113. BufferUpdate bmsg = (BufferUpdate)msg;
  114. Buffer buffer = bmsg.getBuffer();
  115. Object what = bmsg.getWhat();
  116. if(what == BufferUpdate.LOADED ||
  117. what == BufferUpdate.CLOSED)
  118. {
  119. ResultVisitor visitor = null;
  120. if (what == BufferUpdate.LOADED)
  121. {
  122. visitor = new BufferLoadedVisitor();
  123. }
  124. else // BufferUpdate.CLOSED
  125. {
  126. visitor = new BufferClosedVisitor();
  127. }
  128. // impl note: since multiple searches now allowed,
  129. // extra level in hierarchy
  130. for(int i = resultTreeRoot.getChildCount() - 1; i >= 0; i--)
  131. {
  132. DefaultMutableTreeNode searchNode = (DefaultMutableTreeNode)
  133. resultTreeRoot.getChildAt(i);
  134. for(int j = searchNode.getChildCount() - 1;
  135. j >= 0; j--)
  136. {
  137. DefaultMutableTreeNode bufferNode = (DefaultMutableTreeNode)
  138. searchNode.getChildAt(j);
  139. for(int k = bufferNode.getChildCount() - 1;
  140. k >= 0; k--)
  141. {
  142. Object userObject =
  143. ((DefaultMutableTreeNode)bufferNode
  144. .getChildAt(k)).getUserObject();
  145. HyperSearchResult result = (HyperSearchResult)
  146. userObject;
  147. if(buffer.getPath().equals(result.path))
  148. visitor.visit(buffer,result);
  149. }
  150. }
  151. }
  152. }
  153. }
  154. } //}}}
  155. //{{{ getTreeModel() method
  156. public DefaultTreeModel getTreeModel()
  157. {
  158. return resultTreeModel;
  159. } //}}}
  160. //{{{ getTree() method
  161. /**
  162. * Returns the result tree.
  163. * @since jEdit 4.1pre9
  164. */
  165. public JTree getTree()
  166. {
  167. return resultTree;
  168. } //}}}
  169. //{{{ searchStarted() method
  170. public void searchStarted()
  171. {
  172. caption.setText(jEdit.getProperty("hypersearch-results.searching"));
  173. } //}}}
  174. //{{{ searchFailed() method
  175. public void searchFailed()
  176. {
  177. caption.setText(jEdit.getProperty("hypersearch-results.no-results"));
  178. // collapse all nodes, as suggested on user mailing list...
  179. for(int i = 0; i < resultTreeRoot.getChildCount(); i++)
  180. {
  181. DefaultMutableTreeNode node = (DefaultMutableTreeNode)
  182. resultTreeRoot.getChildAt(i);
  183. resultTree.collapsePath(new TreePath(new Object[] {
  184. resultTreeRoot, node }));
  185. }
  186. } //}}}
  187. //{{{ searchDone() method
  188. public void searchDone(final DefaultMutableTreeNode searchNode)
  189. {
  190. final int nodeCount = searchNode.getChildCount();
  191. if (nodeCount < 1)
  192. {
  193. searchFailed();
  194. return;
  195. }
  196. caption.setText(jEdit.getProperty("hypersearch-results.done"));
  197. SwingUtilities.invokeLater(new Runnable()
  198. {
  199. public void run()
  200. {
  201. if(!multi.isSelected())
  202. {
  203. for(int i = 0; i < resultTreeRoot.getChildCount(); i++)
  204. {
  205. resultTreeRoot.remove(0);
  206. }
  207. }
  208. resultTreeRoot.add(searchNode);
  209. resultTreeModel.reload(resultTreeRoot);
  210. TreePath lastNode = null;
  211. for(int i = 0; i < nodeCount; i++)
  212. {
  213. lastNode = new TreePath(
  214. ((DefaultMutableTreeNode)
  215. searchNode.getChildAt(i))
  216. .getPath());
  217. resultTree.expandPath(lastNode);
  218. }
  219. resultTree.scrollPathToVisible(
  220. new TreePath(new Object[] {
  221. resultTreeRoot,searchNode }));
  222. }
  223. });
  224. } //}}}
  225. //{{{ Private members
  226. private View view;
  227. private JLabel caption;
  228. private JTree resultTree;
  229. private DefaultMutableTreeNode resultTreeRoot;
  230. private DefaultTreeModel resultTreeModel;
  231. private RolloverButton clear;
  232. private RolloverButton multi;
  233. private boolean multiStatus;
  234. //{{{ updateMultiStatus() method
  235. private void updateMultiStatus()
  236. {
  237. if(multiStatus)
  238. multi.setIcon(GUIUtilities.loadIcon("SingleResult.png"));
  239. else
  240. multi.setIcon(GUIUtilities.loadIcon("MultipleResults.png"));
  241. } //}}}
  242. //{{{ goToSelectedNode() method
  243. private void goToSelectedNode()
  244. {
  245. TreePath path = resultTree.getSelectionPath();
  246. if(path == null)
  247. return;
  248. DefaultMutableTreeNode node = (DefaultMutableTreeNode)path
  249. .getLastPathComponent();
  250. Object value = node.getUserObject();
  251. if(node.getParent() == resultTreeRoot)
  252. {
  253. // do nothing if clicked "foo (showing n occurrences in m files)"
  254. }
  255. else if(value instanceof String)
  256. {
  257. Buffer buffer = jEdit.openFile(view,(String)value);
  258. if(buffer == null)
  259. return;
  260. view.goToBuffer(buffer);
  261. // fuck me dead
  262. SwingUtilities.invokeLater(new Runnable()
  263. {
  264. public void run()
  265. {
  266. resultTree.requestFocus();
  267. }
  268. });
  269. }
  270. else if (value instanceof HyperSearchResult)
  271. {
  272. final HyperSearchResult result = (HyperSearchResult)value;
  273. final Buffer buffer = result.getBuffer();
  274. if(buffer == null)
  275. return;
  276. VFSManager.runInAWTThread(new Runnable()
  277. {
  278. public void run()
  279. {
  280. int start = result.startPos.getOffset();
  281. int end = result.endPos.getOffset();
  282. Selection s = new Selection.Range(start,end);
  283. EditPane pane = view.goToBuffer(buffer);
  284. JEditTextArea textArea = pane.getTextArea();
  285. if(textArea.isMultipleSelectionEnabled())
  286. textArea.addToSelection(s);
  287. else
  288. textArea.setSelection(s);
  289. textArea.moveCaretPosition(end);
  290. }
  291. });
  292. }
  293. } //}}}
  294. //}}}
  295. //{{{ ActionHandler class
  296. public class ActionHandler implements ActionListener
  297. {
  298. public void actionPerformed(ActionEvent evt)
  299. {
  300. Object source = evt.getSource();
  301. if(source == clear)
  302. {
  303. resultTreeRoot.removeAllChildren();
  304. resultTreeModel.reload(resultTreeRoot);
  305. }
  306. else if(source == multi)
  307. {
  308. multiStatus = !multiStatus;
  309. updateMultiStatus();
  310. if(!multiStatus)
  311. {
  312. for(int i = resultTreeRoot.getChildCount() - 2; i >= 0; i--)
  313. {
  314. resultTreeModel.removeNodeFromParent(
  315. (MutableTreeNode)resultTreeRoot
  316. .getChildAt(i));
  317. }
  318. }
  319. }
  320. }
  321. } //}}}
  322. //{{{ KeyHandler class
  323. class KeyHandler extends KeyAdapter
  324. {
  325. public void keyPressed(KeyEvent evt)
  326. {
  327. if(evt.getKeyCode() == KeyEvent.VK_ENTER)
  328. {
  329. goToSelectedNode();
  330. // fuck me dead
  331. SwingUtilities.invokeLater(new Runnable()
  332. {
  333. public void run()
  334. {
  335. resultTree.requestFocus();
  336. }
  337. });
  338. evt.consume();
  339. }
  340. }
  341. } //}}}
  342. //{{{ MouseHandler class
  343. class MouseHandler extends MouseAdapter
  344. {
  345. //{{{ mousePressed() method
  346. public void mousePressed(MouseEvent evt)
  347. {
  348. if(evt.isConsumed())
  349. return;
  350. TreePath path1 = resultTree.getPathForLocation(
  351. evt.getX(),evt.getY());
  352. if(path1 == null)
  353. return;
  354. resultTree.setSelectionPath(path1);
  355. if (GUIUtilities.isPopupTrigger(evt))
  356. showPopupMenu(evt);
  357. else
  358. {
  359. goToSelectedNode();
  360. view.toFront();
  361. view.requestFocus();
  362. view.getTextArea().requestFocus();
  363. }
  364. } //}}}
  365. //{{{ Private members
  366. private JPopupMenu popupMenu;
  367. //{{{ showPopupMenu method
  368. private void showPopupMenu(MouseEvent evt)
  369. {
  370. if (popupMenu == null)
  371. {
  372. popupMenu = new JPopupMenu();
  373. popupMenu.add(new RemoveTreeNodeAction());
  374. }
  375. GUIUtilities.showPopupMenu(popupMenu,evt.getComponent(),
  376. evt.getX(),evt.getY());
  377. evt.consume();
  378. } //}}}
  379. //}}}
  380. } //}}}
  381. //{{{ RemoveTreeNodeAction class
  382. class RemoveTreeNodeAction extends AbstractAction
  383. {
  384. public RemoveTreeNodeAction()
  385. {
  386. super(jEdit.getProperty("hypersearch-results.remove-node"));
  387. }
  388. public void actionPerformed(ActionEvent evt)
  389. {
  390. TreePath path = resultTree.getSelectionPath();
  391. if(path == null)
  392. return;
  393. MutableTreeNode value = (MutableTreeNode)path
  394. .getLastPathComponent();
  395. resultTreeModel.removeNodeFromParent(value);
  396. }
  397. }//}}}
  398. //{{{ RemoveAllTreeNodesAction class
  399. class RemoveAllTreeNodesAction extends AbstractAction
  400. {
  401. public RemoveAllTreeNodesAction()
  402. {
  403. super(jEdit.getProperty("hypersearch-results.remove-all-nodes"));
  404. }
  405. public void actionPerformed(ActionEvent evt)
  406. {
  407. resultTreeRoot = new DefaultMutableTreeNode();
  408. resultTreeModel = new DefaultTreeModel(resultTreeRoot);
  409. resultTree.setModel(resultTreeModel);
  410. }
  411. }//}}}
  412. //{{{ ResultCellRenderer class
  413. class ResultCellRenderer extends DefaultTreeCellRenderer
  414. {
  415. Font plainFont, boldFont;
  416. //{{{ ResultCellRenderer constructor
  417. ResultCellRenderer()
  418. {
  419. plainFont = UIManager.getFont("Tree.font");
  420. boldFont = new Font(plainFont.getName(),Font.BOLD,
  421. plainFont.getSize());
  422. } //}}}
  423. //{{{ getTreeCellRendererComponent() method
  424. public Component getTreeCellRendererComponent(JTree tree,
  425. Object value, boolean sel, boolean expanded,
  426. boolean leaf, int row, boolean hasFocus)
  427. {
  428. Component comp = super.getTreeCellRendererComponent(tree,value,sel,
  429. expanded,leaf,row,hasFocus);
  430. setIcon(null);
  431. DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
  432. if (node.getParent() == resultTreeRoot)
  433. {
  434. ResultCellRenderer.this.setFont(boldFont);
  435. int bufferCount = node.getChildCount();
  436. int resultCount = 0;
  437. for (int i = 0; i < bufferCount; i++)
  438. {
  439. resultCount += node.getChildAt(i).getChildCount();
  440. }
  441. Object[] pp = { node.toString(), new Integer(resultCount), new Integer(bufferCount) };
  442. setText(jEdit.getProperty("hypersearch-results.result-caption",pp));
  443. }
  444. else if(node.getUserObject() instanceof String)
  445. {
  446. // file name
  447. ResultCellRenderer.this.setFont(boldFont);
  448. int count = node.getChildCount();
  449. if(count == 1)
  450. {
  451. setText(jEdit.getProperty("hypersearch-results"
  452. + ".file-caption1",new Object[] {
  453. node.getUserObject()
  454. }));
  455. }
  456. else
  457. {
  458. setText(jEdit.getProperty("hypersearch-results"
  459. + ".file-caption",new Object[] {
  460. node.getUserObject(),
  461. new Integer(count)
  462. }));
  463. }
  464. }
  465. else
  466. {
  467. ResultCellRenderer.this.setFont(plainFont);
  468. }
  469. return this;
  470. } //}}}
  471. } //}}}
  472. // these are used to eliminate code duplication. i don't normally use
  473. // the visitor or "template method" pattern, but this code was contributed
  474. // by Peter Cox and i don't feel like changing it around too much.
  475. //{{{ ResultVisitor interface
  476. interface ResultVisitor
  477. {
  478. public void visit(Buffer buffer, HyperSearchResult result);
  479. } //}}}
  480. //{{{ BufferLoadedVisitor class
  481. class BufferLoadedVisitor implements ResultVisitor
  482. {
  483. public void visit(Buffer buffer, HyperSearchResult result)
  484. {
  485. result.bufferOpened(buffer);
  486. }
  487. } //}}}
  488. //{{{ BufferClosedVisitor class
  489. class BufferClosedVisitor implements ResultVisitor
  490. {
  491. public void visit(Buffer buffer, HyperSearchResult result)
  492. {
  493. result.bufferClosed();
  494. }
  495. } //}}}
  496. }