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