KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > search > ui > text > AbstractTextSearchViewPage


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.search.ui.text;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import org.eclipse.core.runtime.Assert;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.ISafeRunnable;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.core.runtime.SafeRunner;
23 import org.eclipse.core.runtime.Status;
24
25 import org.eclipse.swt.SWT;
26 import org.eclipse.swt.layout.FillLayout;
27 import org.eclipse.swt.layout.GridData;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Display;
31 import org.eclipse.swt.widgets.Menu;
32 import org.eclipse.swt.widgets.Table;
33 import org.eclipse.swt.widgets.TableItem;
34
35 import org.eclipse.jface.action.Action;
36 import org.eclipse.jface.action.IAction;
37 import org.eclipse.jface.action.IMenuListener;
38 import org.eclipse.jface.action.IMenuManager;
39 import org.eclipse.jface.action.IToolBarManager;
40 import org.eclipse.jface.action.MenuManager;
41 import org.eclipse.jface.dialogs.ErrorDialog;
42 import org.eclipse.jface.dialogs.IDialogSettings;
43 import org.eclipse.jface.util.OpenStrategy;
44 import org.eclipse.jface.viewers.DecoratingLabelProvider;
45 import org.eclipse.jface.viewers.IBaseLabelProvider;
46 import org.eclipse.jface.viewers.IOpenListener;
47 import org.eclipse.jface.viewers.ISelection;
48 import org.eclipse.jface.viewers.ISelectionChangedListener;
49 import org.eclipse.jface.viewers.ISelectionProvider;
50 import org.eclipse.jface.viewers.IStructuredSelection;
51 import org.eclipse.jface.viewers.ITreeContentProvider;
52 import org.eclipse.jface.viewers.OpenEvent;
53 import org.eclipse.jface.viewers.SelectionChangedEvent;
54 import org.eclipse.jface.viewers.StructuredViewer;
55 import org.eclipse.jface.viewers.TableViewer;
56 import org.eclipse.jface.viewers.TreeViewer;
57 import org.eclipse.jface.viewers.Viewer;
58
59 import org.eclipse.jface.text.IRegion;
60 import org.eclipse.jface.text.Position;
61 import org.eclipse.jface.text.Region;
62
63 import org.eclipse.ui.IActionBars;
64 import org.eclipse.ui.IMemento;
65 import org.eclipse.ui.IWorkbenchWindow;
66 import org.eclipse.ui.PartInitException;
67 import org.eclipse.ui.PlatformUI;
68 import org.eclipse.ui.actions.ActionFactory;
69 import org.eclipse.ui.part.IPageSite;
70 import org.eclipse.ui.part.Page;
71 import org.eclipse.ui.part.PageBook;
72 import org.eclipse.ui.progress.UIJob;
73 import org.eclipse.ui.texteditor.IUpdate;
74 import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
75
76 import org.eclipse.search.ui.IContextMenuConstants;
77 import org.eclipse.search.ui.IQueryListener;
78 import org.eclipse.search.ui.ISearchQuery;
79 import org.eclipse.search.ui.ISearchResult;
80 import org.eclipse.search.ui.ISearchResultListener;
81 import org.eclipse.search.ui.ISearchResultPage;
82 import org.eclipse.search.ui.ISearchResultViewPart;
83 import org.eclipse.search.ui.NewSearchUI;
84 import org.eclipse.search.ui.SearchResultEvent;
85
86 import org.eclipse.search.internal.ui.CopyToClipboardAction;
87 import org.eclipse.search.internal.ui.SearchPlugin;
88 import org.eclipse.search.internal.ui.SearchPluginImages;
89 import org.eclipse.search.internal.ui.SelectAllAction;
90
91 import org.eclipse.search2.internal.ui.MatchFilterSelectionAction;
92 import org.eclipse.search2.internal.ui.InternalSearchUI;
93 import org.eclipse.search2.internal.ui.MatchFilterAction;
94 import org.eclipse.search2.internal.ui.SearchMessages;
95 import org.eclipse.search2.internal.ui.SearchView;
96 import org.eclipse.search2.internal.ui.basic.views.CollapseAllAction;
97 import org.eclipse.search2.internal.ui.basic.views.ExpandAllAction;
98 import org.eclipse.search2.internal.ui.basic.views.INavigate;
99 import org.eclipse.search2.internal.ui.basic.views.RemoveAllMatchesAction;
100 import org.eclipse.search2.internal.ui.basic.views.RemoveMatchAction;
101 import org.eclipse.search2.internal.ui.basic.views.RemoveSelectedMatchesAction;
102 import org.eclipse.search2.internal.ui.basic.views.SetLayoutAction;
103 import org.eclipse.search2.internal.ui.basic.views.ShowNextResultAction;
104 import org.eclipse.search2.internal.ui.basic.views.ShowPreviousResultAction;
105 import org.eclipse.search2.internal.ui.basic.views.TableViewerNavigator;
106 import org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator;
107 import org.eclipse.search2.internal.ui.text.AnnotationManagers;
108 import org.eclipse.search2.internal.ui.text.PositionTracker;
109
110 /**
111  * An abstract base implementation for classes showing
112  * <code>AbstractTextSearchResult</code> instances. This class assumes that
113  * the input element set via {@link AbstractTextSearchViewPage#setInput(ISearchResult,Object)}
114  * is a subclass of {@link AbstractTextSearchResult}.
115  * This result page supports a tree and/or a table presentation of search
116  * results. Subclasses can determine which presentations they want to support at
117  * construction time by passing the appropriate flags.
118  * Subclasses must customize the viewers for each presentation with a label
119  * provider and a content provider. <br>
120  * Changes in the search result are handled by updating the viewer in the
121  * <code>elementsChanged()</code> and <code>clear()</code> methods.
122  *
123  * @since 3.0
124  */

125 public abstract class AbstractTextSearchViewPage extends Page implements ISearchResultPage {
126     private class UpdateUIJob extends UIJob {
127         
128         public UpdateUIJob() {
129             super(SearchMessages.AbstractTextSearchViewPage_update_job_name);
130             setSystem(true);
131         }
132         
133         public IStatus runInUIThread(IProgressMonitor monitor) {
134             Control control= getControl();
135             if (control == null || control.isDisposed()) {
136                 // disposed the control while the UI was posted.
137
return Status.OK_STATUS;
138             }
139             runBatchedClear();
140             runBatchedUpdates();
141             if (hasMoreUpdates() || isQueryRunning()) {
142                 schedule(500);
143             } else {
144                 fIsUIUpdateScheduled= false;
145                 turnOnDecoration();
146                 updateBusyLabel();
147                 if (fScheduleEnsureSelection) {
148                     fScheduleEnsureSelection= false;
149                     AbstractTextSearchResult result = getInput();
150                     if (result != null && fViewer.getSelection().isEmpty()) {
151                         navigateNext(true);
152                     }
153                 }
154             }
155             fViewPart.updateLabel();
156             return Status.OK_STATUS;
157         }
158         
159         /*
160          * Undocumented for testing only. Used to find UpdateUIJobs.
161          */

162         public boolean belongsTo(Object JavaDoc family) {
163             return family == AbstractTextSearchViewPage.this;
164         }
165     
166     }
167     
168     private class SelectionProviderAdapter implements ISelectionProvider, ISelectionChangedListener {
169         private ArrayList JavaDoc fListeners= new ArrayList JavaDoc(5);
170         
171         public void addSelectionChangedListener(ISelectionChangedListener listener) {
172             fListeners.add(listener);
173         }
174
175         public ISelection getSelection() {
176             return fViewer.getSelection();
177         }
178
179         public void removeSelectionChangedListener(ISelectionChangedListener listener) {
180             fListeners.remove(listener);
181         }
182
183         public void setSelection(ISelection selection) {
184             fViewer.setSelection(selection);
185         }
186
187         public void selectionChanged(SelectionChangedEvent event) {
188             // forward to my listeners
189
SelectionChangedEvent wrappedEvent= new SelectionChangedEvent(this, event.getSelection());
190             for (Iterator JavaDoc listeners= fListeners.iterator(); listeners.hasNext();) {
191                 ISelectionChangedListener listener= (ISelectionChangedListener) listeners.next();
192                 listener.selectionChanged(wrappedEvent);
193             }
194         }
195
196     }
197
198     private volatile boolean fIsUIUpdateScheduled= false;
199     private volatile boolean fScheduleEnsureSelection= false;
200     private static final String JavaDoc KEY_LAYOUT = "org.eclipse.search.resultpage.layout"; //$NON-NLS-1$
201

202     /**
203      * An empty array.
204      */

205     protected static final Match[] EMPTY_MATCH_ARRAY= new Match[0];
206     
207     private StructuredViewer fViewer;
208     private Composite fViewerContainer;
209     private Control fBusyLabel;
210     private PageBook fPagebook;
211     private boolean fIsBusyShown;
212     private ISearchResultViewPart fViewPart;
213     private Set JavaDoc fBatchedUpdates;
214     private boolean fBatchedClearAll;
215     
216     private ISearchResultListener fListener;
217     private IQueryListener fQueryListener;
218     private MenuManager fMenu;
219     private AbstractTextSearchResult fInput;
220     // Actions
221
private CopyToClipboardAction fCopyToClipboardAction;
222     private Action fRemoveSelectedMatches;
223     private Action fRemoveCurrentMatch;
224     private Action fRemoveAllResultsAction;
225     private Action fShowNextAction;
226     private Action fShowPreviousAction;
227     private SetLayoutAction fFlatAction;
228     private SetLayoutAction fHierarchicalAction;
229     private int fCurrentLayout;
230     private int fCurrentMatchIndex = 0;
231     private String JavaDoc fId;
232     private int fSupportedLayouts;
233     private SelectionProviderAdapter fViewerAdapter;
234     private SelectAllAction fSelectAllAction;
235     
236     private IAction[] fFilterActions;
237     private Integer JavaDoc fElementLimit;
238     
239     /**
240      * Flag (<code>value 1</code>) denoting flat list layout.
241      */

242     public static final int FLAG_LAYOUT_FLAT = 1;
243     /**
244      * Flag (<code>value 2</code>) denoting tree layout.
245      */

246     public static final int FLAG_LAYOUT_TREE = 2;
247
248     
249     /**
250      * This constructor must be passed a combination of layout flags combined
251      * with bitwise or. At least one flag must be passed in (i.e. 0 is not a
252      * permitted value).
253      *
254      * @param supportedLayouts
255      * flags determining which layout options this page supports.
256      * Must not be 0
257      * @see #FLAG_LAYOUT_FLAT
258      * @see #FLAG_LAYOUT_TREE
259      */

260     protected AbstractTextSearchViewPage(int supportedLayouts) {
261         fSupportedLayouts = supportedLayouts;
262         initLayout();
263         fRemoveAllResultsAction = new RemoveAllMatchesAction(this);
264         fRemoveSelectedMatches = new RemoveSelectedMatchesAction(this);
265         fRemoveCurrentMatch = new RemoveMatchAction(this);
266         fShowNextAction = new ShowNextResultAction(this);
267         fShowPreviousAction = new ShowPreviousResultAction(this);
268         fCopyToClipboardAction = new CopyToClipboardAction();
269         fSelectAllAction= new SelectAllAction();
270         createLayoutActions();
271         fBatchedUpdates = new HashSet JavaDoc();
272         fBatchedClearAll= false;
273         
274         fListener = new ISearchResultListener() {
275             public void searchResultChanged(SearchResultEvent e) {
276                 handleSearchResultChanged(e);
277             }
278         };
279         fFilterActions= null;
280         fElementLimit= null;
281     }
282     
283     private void initLayout() {
284         if (supportsTreeLayout())
285             fCurrentLayout = FLAG_LAYOUT_TREE;
286         else
287             fCurrentLayout = FLAG_LAYOUT_FLAT;
288     }
289
290     /**
291      * Constructs this page with the default layout flags.
292      *
293      * @see AbstractTextSearchViewPage#AbstractTextSearchViewPage(int)
294      */

295     protected AbstractTextSearchViewPage() {
296         this(FLAG_LAYOUT_FLAT | FLAG_LAYOUT_TREE);
297     }
298     
299
300     private void createLayoutActions() {
301         if (countBits(fSupportedLayouts) > 1) {
302             fFlatAction = new SetLayoutAction(this, SearchMessages.AbstractTextSearchViewPage_flat_layout_label, SearchMessages.AbstractTextSearchViewPage_flat_layout_tooltip, FLAG_LAYOUT_FLAT);
303             fHierarchicalAction = new SetLayoutAction(this, SearchMessages.AbstractTextSearchViewPage_hierarchical_layout_label, SearchMessages.AbstractTextSearchViewPage_hierarchical_layout_tooltip, FLAG_LAYOUT_TREE);
304             SearchPluginImages.setImageDescriptors(fFlatAction, SearchPluginImages.T_LCL, SearchPluginImages.IMG_LCL_SEARCH_FLAT_LAYOUT);
305             SearchPluginImages.setImageDescriptors(fHierarchicalAction, SearchPluginImages.T_LCL, SearchPluginImages.IMG_LCL_SEARCH_HIERARCHICAL_LAYOUT);
306         }
307     }
308     
309     private int countBits(int layoutFlags) {
310         int bitCount = 0;
311         for (int i = 0; i < 32; i++) {
312             if (layoutFlags % 2 == 1)
313                 bitCount++;
314             layoutFlags >>= 1;
315         }
316         return bitCount;
317     }
318
319     private boolean supportsTreeLayout() {
320         return isLayoutSupported(FLAG_LAYOUT_TREE);
321     }
322
323     /**
324      * Returns a dialog settings object for this search result page. There will be
325      * one dialog settings object per search result page id.
326      *
327      * @return the dialog settings for this search result page
328      * @see AbstractTextSearchViewPage#getID()
329      */

330     protected IDialogSettings getSettings() {
331         IDialogSettings parent = SearchPlugin.getDefault().getDialogSettings();
332         IDialogSettings settings = parent.getSection(getID());
333         if (settings == null)
334             settings = parent.addNewSection(getID());
335         return settings;
336     }
337
338     /**
339      * {@inheritDoc}
340      */

341     public void setID(String JavaDoc id) {
342         fId = id;
343     }
344
345     /**
346      * {@inheritDoc}
347      */

348     public String JavaDoc getID() {
349         return fId;
350     }
351     
352     /**
353      * {@inheritDoc}
354      */

355     public String JavaDoc getLabel() {
356         AbstractTextSearchResult result= getInput();
357         if (result == null)
358             return ""; //$NON-NLS-1$
359
return result.getLabel();
360     }
361
362     /**
363      * Opens an editor on the given element and selects the given range of text.
364      * If a search results implements a <code>IFileMatchAdapter</code>, match
365      * locations will be tracked and the current match range will be passed into
366      * this method.
367      *
368      * @param match
369      * the match to show
370      * @param currentOffset
371      * the current start offset of the match
372      * @param currentLength
373      * the current length of the selection
374      * @throws PartInitException
375      * if an editor can't be opened
376      *
377      * @see org.eclipse.core.filebuffers.ITextFileBufferManager
378      * @see IFileMatchAdapter
379      * @deprecated
380      */

381     protected void showMatch(Match match, int currentOffset, int currentLength) throws PartInitException {
382     }
383
384     /**
385      * Opens an editor on the given element and selects the given range of text.
386      * If a search results implements a <code>IFileMatchAdapter</code>, match
387      * locations will be tracked and the current match range will be passed into
388      * this method.
389      * If the <code>activate</code> parameter is <code>true</code> the opened editor
390      * should have be activated. Otherwise the focus should not be changed.
391      *
392      * @param match
393      * the match to show
394      * @param currentOffset
395      * the current start offset of the match
396      * @param currentLength
397      * the current length of the selection
398      * @param activate
399      * whether to activate the editor.
400      * @throws PartInitException
401      * if an editor can't be opened
402      *
403      * @see org.eclipse.core.filebuffers.ITextFileBufferManager
404      * @see IFileMatchAdapter
405      */

406     protected void showMatch(Match match, int currentOffset, int currentLength, boolean activate) throws PartInitException {
407         showMatch(match, currentOffset, currentLength);
408     }
409
410     /**
411      * This method is called whenever the set of matches for the given elements
412      * changes. This method is guaranteed to be called in the UI thread. Note
413      * that this notification is asynchronous. i.e. further changes may have
414      * occurred by the time this method is called. They will be described in a
415      * future call.
416      *
417      * @param objects
418      * array of objects that has to be refreshed
419      */

420     protected abstract void elementsChanged(Object JavaDoc[] objects);
421
422     /**
423      * This method is called whenever all elements have been removed from the
424      * shown <code>AbstractSearchResult</code>. This method is guaranteed to
425      * be called in the UI thread. Note that this notification is asynchronous.
426      * i.e. further changes may have occurred by the time this method is called.
427      * They will be described in a future call.
428      */

429     protected abstract void clear();
430
431     /**
432      * Configures the given viewer. Implementers have to set at least a content
433      * provider and a label provider. This method may be called if the page was
434      * constructed with the flag <code>FLAG_LAYOUT_TREE</code>.
435      *
436      * @param viewer the viewer to be configured
437      */

438     protected abstract void configureTreeViewer(TreeViewer viewer);
439
440     /**
441      * Configures the given viewer. Implementers have to set at least a content
442      * provider and a label provider. This method may be called if the page was
443      * constructed with the flag <code>FLAG_LAYOUT_FLAT</code>.
444      *
445      * @param viewer the viewer to be configured
446      */

447     protected abstract void configureTableViewer(TableViewer viewer);
448
449     /**
450      * Fills the context menu for this page. Subclasses may override this
451      * method.
452      *
453      * @param mgr the menu manager representing the context menu
454      */

455     protected void fillContextMenu(IMenuManager mgr) {
456         mgr.appendToGroup(IContextMenuConstants.GROUP_SHOW, fShowNextAction);
457         mgr.appendToGroup(IContextMenuConstants.GROUP_SHOW, fShowPreviousAction);
458         mgr.appendToGroup(IContextMenuConstants.GROUP_EDIT, fCopyToClipboardAction);
459         if (getCurrentMatch() != null)
460             mgr.appendToGroup(IContextMenuConstants.GROUP_REMOVE_MATCHES, fRemoveCurrentMatch);
461         if (canRemoveMatchesWith(getViewer().getSelection()))
462             mgr.appendToGroup(IContextMenuConstants.GROUP_REMOVE_MATCHES, fRemoveSelectedMatches);
463         mgr.appendToGroup(IContextMenuConstants.GROUP_REMOVE_MATCHES, fRemoveAllResultsAction);
464     }
465
466     /**
467      * Determines whether the provided selection can be used to remove matches from the result.
468      * @since 3.2
469      */

470     protected boolean canRemoveMatchesWith(ISelection selection) {
471         return !selection.isEmpty();
472     }
473
474     /**
475      * {@inheritDoc}
476      */

477     public void createControl(Composite parent) {
478         fQueryListener = createQueryListener();
479         fMenu = new MenuManager("#PopUp"); //$NON-NLS-1$
480
fMenu.setRemoveAllWhenShown(true);
481         fMenu.setParent(getSite().getActionBars().getMenuManager());
482         fMenu.addMenuListener(new IMenuListener() {
483             public void menuAboutToShow(IMenuManager mgr) {
484                 SearchView.createContextMenuGroups(mgr);
485                 fillContextMenu(mgr);
486                 fViewPart.fillContextMenu(mgr);
487             }
488         });
489         fPagebook = new PageBook(parent, SWT.NULL);
490         fPagebook.setLayoutData(new GridData(GridData.FILL_BOTH));
491         fBusyLabel = createBusyControl();
492         fViewerContainer = new Composite(fPagebook, SWT.NULL);
493         fViewerContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
494         fViewerContainer.setSize(100, 100);
495         fViewerContainer.setLayout(new FillLayout());
496
497         fViewerAdapter= new SelectionProviderAdapter();
498         getSite().setSelectionProvider(fViewerAdapter);
499         // Register menu
500
getSite().registerContextMenu(fViewPart.getViewSite().getId(), fMenu, fViewerAdapter);
501
502         
503         createViewer(fViewerContainer, fCurrentLayout);
504         showBusyLabel(fIsBusyShown);
505         NewSearchUI.addQueryListener(fQueryListener);
506
507     }
508
509     private Control createBusyControl() {
510         Table busyLabel = new Table(fPagebook, SWT.NONE);
511         TableItem item = new TableItem(busyLabel, SWT.NONE);
512         item.setText(SearchMessages.AbstractTextSearchViewPage_searching_label);
513         busyLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
514         return busyLabel;
515     }
516
517     private synchronized void scheduleUIUpdate() {
518         if (!fIsUIUpdateScheduled) {
519             fIsUIUpdateScheduled= true;
520             new UpdateUIJob().schedule();
521         }
522     }
523
524     private IQueryListener createQueryListener() {
525         return new IQueryListener() {
526             public void queryAdded(ISearchQuery query) {
527                 // ignore
528
}
529
530             public void queryRemoved(ISearchQuery query) {
531                 // ignore
532
}
533
534             public void queryStarting(final ISearchQuery query) {
535                 final Runnable JavaDoc runnable1 = new Runnable JavaDoc() {
536                     public void run() {
537                         updateBusyLabel();
538                         AbstractTextSearchResult result = getInput();
539
540                         if (result == null || !result.getQuery().equals(query)) {
541                             return;
542                         }
543                         turnOffDecoration();
544                         scheduleUIUpdate();
545                     }
546
547
548                 };
549                 asyncExec(runnable1);
550             }
551
552             public void queryFinished(final ISearchQuery query) {
553                 // handle the end of the query in the UIUpdateJob, as ui updates
554
// may not be finished here.
555
postEnsureSelection();
556             }
557         };
558     }
559
560     /**
561      * Posts a UI update to make sure an element is selected.
562      * @since 3.2
563      */

564     protected void postEnsureSelection() {
565         fScheduleEnsureSelection= true;
566         scheduleUIUpdate();
567     }
568
569
570     private void updateBusyLabel() {
571         AbstractTextSearchResult result = getInput();
572         boolean shouldShowBusy = result != null && NewSearchUI.isQueryRunning(result.getQuery()) && result.getMatchCount() == 0;
573         if (shouldShowBusy == fIsBusyShown)
574             return;
575         fIsBusyShown = shouldShowBusy;
576         showBusyLabel(fIsBusyShown);
577     }
578
579     private void showBusyLabel(boolean shouldShowBusy) {
580         if (shouldShowBusy)
581             fPagebook.showPage(fBusyLabel);
582         else
583             fPagebook.showPage(fViewerContainer);
584     }
585
586     /**
587      * Determines whether a certain layout is supported by this search result
588      * page.
589      *
590      * @param layout the layout to test for
591      * @return whether the given layout is supported or not
592      *
593      * @see AbstractTextSearchViewPage#AbstractTextSearchViewPage(int)
594      */

595     public boolean isLayoutSupported(int layout) {
596         return (layout & fSupportedLayouts) == layout;
597     }
598
599     /**
600      * Sets the layout of this search result page. The layout must be on of
601      * <code>FLAG_LAYOUT_FLAT</code> or <code>FLAG_LAYOUT_TREE</code> and
602      * it must be one of the values passed during construction of this search
603      * result page.
604      * @param layout the new layout
605      *
606      * @see AbstractTextSearchViewPage#isLayoutSupported(int)
607      */

608     public void setLayout(int layout) {
609         Assert.isTrue(countBits(layout) == 1);
610         Assert.isTrue(isLayoutSupported(layout));
611         if (countBits(fSupportedLayouts) < 2)
612             return;
613         if (fCurrentLayout == layout)
614             return;
615         fCurrentLayout = layout;
616         ISelection selection = fViewer.getSelection();
617         disconnectViewer();
618         disposeViewer();
619         createViewer(fViewerContainer, layout);
620         fViewerContainer.layout(true);
621         connectViewer(fInput);
622         fViewer.setSelection(selection, true);
623         getSettings().put(KEY_LAYOUT, layout);
624         getViewPart().updateLabel();
625     }
626
627     private void disposeViewer() {
628         fViewer.removeSelectionChangedListener(fViewerAdapter);
629         fViewer.getControl().dispose();
630         fViewer = null;
631     }
632
633     private void updateLayoutActions() {
634         if (fFlatAction != null)
635             fFlatAction.setChecked(fCurrentLayout == fFlatAction.getLayout());
636         if (fHierarchicalAction != null)
637             fHierarchicalAction.setChecked(fCurrentLayout == fHierarchicalAction.getLayout());
638     }
639
640     /**
641      * Return the layout this page is currently using.
642      *
643      * @return the layout this page is currently using
644      *
645      * @see #FLAG_LAYOUT_FLAT
646      * @see #FLAG_LAYOUT_TREE
647      */

648     public int getLayout() {
649         return fCurrentLayout;
650     }
651
652     private void createViewer(Composite parent, int layout) {
653         if ((layout & FLAG_LAYOUT_FLAT) != 0) {
654             TableViewer viewer = createTableViewer(parent);
655             fViewer = viewer;
656             configureTableViewer(viewer);
657         } else if ((layout & FLAG_LAYOUT_TREE) != 0) {
658             TreeViewer viewer = createTreeViewer(parent);
659             fViewer = viewer;
660             configureTreeViewer(viewer);
661         }
662         
663         fCopyToClipboardAction.setViewer(fViewer);
664         fSelectAllAction.setViewer(fViewer);
665         
666         IToolBarManager tbm = getSite().getActionBars().getToolBarManager();
667         tbm.removeAll();
668         SearchView.createToolBarGroups(tbm);
669         fillToolbar(tbm);
670         tbm.update(false);
671         
672         fViewer.addOpenListener(new IOpenListener() {
673             public void open(OpenEvent event) {
674                 handleOpen(event);
675             }
676         });
677         fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
678             public void selectionChanged(SelectionChangedEvent event) {
679                 fCurrentMatchIndex = -1;
680                 fRemoveSelectedMatches.setEnabled(canRemoveMatchesWith(event.getSelection()));
681             }
682         });
683         
684         fViewer.addSelectionChangedListener(fViewerAdapter);
685         
686         Menu menu = fMenu.createContextMenu(fViewer.getControl());
687         fViewer.getControl().setMenu(menu);
688         
689         updateLayoutActions();
690         getViewPart().updateLabel();
691     }
692
693     /**
694      * Creates the tree viewer to be shown on this page. Clients may override
695      * this method.
696      *
697      * @param parent the parent widget
698      * @return returns a newly created <code>TreeViewer</code>.
699      */

700     protected TreeViewer createTreeViewer(Composite parent) {
701         return new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
702     }
703
704     /**
705      * Creates the table viewer to be shown on this page. Clients may override
706      * this method.
707      *
708      * @param parent the parent widget
709      * @return returns a newly created <code>TableViewer</code>
710      */

711     protected TableViewer createTableViewer(Composite parent) {
712         return new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
713     }
714
715     /**
716      * {@inheritDoc}
717      */

718     public void setFocus() {
719         Control control = fViewer.getControl();
720         if (control != null && !control.isDisposed())
721             control.setFocus();
722     }
723
724     /**
725      * {@inheritDoc}
726      */

727     public Control getControl() {
728         return fPagebook;
729     }
730
731     /**
732      * {@inheritDoc}
733      */

734     public void setInput(ISearchResult newSearch, Object JavaDoc viewState) {
735         if (newSearch != null && !(newSearch instanceof AbstractTextSearchResult))
736             return; // ignore
737

738         AbstractTextSearchResult oldSearch= fInput;
739         if (oldSearch != null) {
740             disconnectViewer();
741             removeFilterActionsFromViewMenu(fFilterActions);
742             oldSearch.removeListener(fListener);
743             AnnotationManagers.removeSearchResult(getSite().getWorkbenchWindow(), oldSearch);
744         }
745         fInput= (AbstractTextSearchResult) newSearch;
746         
747         if (fInput != null) {
748             AnnotationManagers.addSearchResult(getSite().getWorkbenchWindow(), fInput);
749             
750             fInput.addListener(fListener);
751             connectViewer(fInput);
752             if (viewState instanceof ISelection)
753                 fViewer.setSelection((ISelection) viewState, true);
754             else
755                 navigateNext(true);
756             
757             updateBusyLabel();
758             turnOffDecoration();
759             scheduleUIUpdate();
760             
761             fFilterActions= addFilterActionsToViewMenu();
762         }
763     }
764
765     private void removeFilterActionsFromViewMenu(IAction[] filterActions) {
766         IActionBars bars= getSite().getActionBars();
767         IMenuManager menu= bars.getMenuManager();
768
769         if (filterActions != null) {
770             for (int i= 0; i < filterActions.length; i++) {
771                 menu.remove(filterActions[i].getId());
772             }
773         }
774         menu.remove(MatchFilterSelectionAction.ACTION_ID);
775     }
776     
777     private IAction[] addFilterActionsToViewMenu() {
778         AbstractTextSearchResult input= getInput();
779         if (input == null) {
780             return null;
781         }
782         
783         MatchFilter[] allMatchFilters= input.getAllMatchFilters();
784         if (allMatchFilters == null && getElementLimit() == null) {
785             return null;
786         }
787         
788         IActionBars bars= getSite().getActionBars();
789         IMenuManager menu= bars.getMenuManager();
790         
791         menu.prependToGroup(IContextMenuConstants.GROUP_FILTERING, new MatchFilterSelectionAction(this));
792         
793         if (allMatchFilters != null) {
794             MatchFilterAction[] actions= new MatchFilterAction[allMatchFilters.length];
795             for (int i= allMatchFilters.length - 1; i >= 0; i--) {
796                 MatchFilterAction filterAction= new MatchFilterAction(this, allMatchFilters[i]);
797                 actions[i]= filterAction;
798                 menu.prependToGroup(IContextMenuConstants.GROUP_FILTERING, filterAction);
799             }
800             return actions;
801         }
802         return null;
803     }
804     
805     private void updateFilterActions(IAction[] filterActions) {
806         if (filterActions != null) {
807             for (int i= 0; i < filterActions.length; i++) {
808                 IAction curr= filterActions[i];
809                 if (curr instanceof IUpdate) {
810                     ((IUpdate) curr).update();
811                 }
812             }
813         }
814     }
815
816     /**
817      * {@inheritDoc}
818      */

819     public Object JavaDoc getUIState() {
820         return fViewer.getSelection();
821     }
822
823     private void connectViewer(AbstractTextSearchResult search) {
824         fViewer.setInput(search);
825     }
826
827     private void disconnectViewer() {
828         fViewer.setInput(null);
829     }
830
831     /**
832      * Returns the viewer currently used in this page.
833      *
834      * @return the currently used viewer or <code>null</code> if none has been
835      * created yet.
836      */

837     protected StructuredViewer getViewer() {
838         return fViewer;
839     }
840
841     private void showMatch(final Match match, final boolean activateEditor) {
842         ISafeRunnable runnable = new ISafeRunnable() {
843             public void handleException(Throwable JavaDoc exception) {
844                 if (exception instanceof PartInitException) {
845                     PartInitException pie = (PartInitException) exception;
846                     ErrorDialog.openError(getSite().getShell(), SearchMessages.DefaultSearchViewPage_show_match, SearchMessages.DefaultSearchViewPage_error_no_editor, pie.getStatus());
847                 }
848             }
849
850             public void run() throws Exception JavaDoc {
851                 IRegion location= getCurrentMatchLocation(match);
852                 showMatch(match, location.getOffset(), location.getLength(), activateEditor);
853             }
854         };
855         SafeRunner.run(runnable);
856     }
857
858     /**
859      * Returns the currently shown result.
860      *
861      * @return the previously set result or <code>null</code>
862      *
863      * @see AbstractTextSearchViewPage#setInput(ISearchResult, Object)
864      */

865     public AbstractTextSearchResult getInput() {
866         return fInput;
867     }
868
869     /**
870      * Selects the element corresponding to the next match and shows the match
871      * in an editor. Note that this will cycle back to the first match after the
872      * last match.
873      */

874     public void gotoNextMatch() {
875         gotoNextMatch(false);
876     }
877
878     private void gotoNextMatch(boolean activateEditor) {
879         fCurrentMatchIndex++;
880         Match nextMatch = getCurrentMatch();
881         if (nextMatch == null) {
882             navigateNext(true);
883             fCurrentMatchIndex = 0;
884         }
885         showCurrentMatch(activateEditor);
886     }
887
888     /**
889      * Selects the element corresponding to the previous match and shows the
890      * match in an editor. Note that this will cycle back to the last match
891      * after the first match.
892      */

893     public void gotoPreviousMatch() {
894         gotoPreviousMatch(false);
895     }
896
897     private void gotoPreviousMatch(boolean activateEditor) {
898         fCurrentMatchIndex--;
899         Match nextMatch = getCurrentMatch();
900         if (nextMatch == null) {
901             navigateNext(false);
902             fCurrentMatchIndex = getDisplayedMatchCount(getFirstSelectedElement()) - 1;
903         }
904         showCurrentMatch(activateEditor);
905     }
906     
907     private void navigateNext(boolean forward) {
908         INavigate navigator = null;
909         if (fViewer instanceof TableViewer) {
910             navigator = new TableViewerNavigator((TableViewer) fViewer);
911         } else {
912             navigator = new TreeViewerNavigator(this, (TreeViewer) fViewer);
913         }
914         navigator.navigateNext(forward);
915     }
916
917     private boolean showCurrentMatch(boolean activateEditor) {
918         Match currentMatch = getCurrentMatch();
919         if (currentMatch != null) {
920             showMatch(currentMatch, activateEditor);
921             return true;
922         }
923         return false;
924     }
925
926     /**
927      * Returns the currently selected match.
928      *
929      * @return the selected match or <code>null</code> if none are selected
930      */

931     public Match getCurrentMatch() {
932         Object JavaDoc element = getFirstSelectedElement();
933         if (element != null) {
934             Match[] matches = getDisplayedMatches(element);
935             if (fCurrentMatchIndex >= 0 && fCurrentMatchIndex < matches.length)
936                 return matches[fCurrentMatchIndex];
937         }
938         return null;
939     }
940     
941     /**
942      * Returns the matches that are currently displayed for the given element.
943      * If {@link AbstractTextSearchResult#getActiveMatchFilters()} is not null, only matches are returned
944      * that are not filtered by the match filters. If {@link AbstractTextSearchResult#getActiveMatchFilters()} is
945      * null all matches of the given element are returned.
946      * Any action operating on the visible matches in the search
947      * result page should use this method to get the matches for a search
948      * result (instead of asking the search result directly).
949      *
950      * @param element
951      * The element to get the matches for
952      * @return The matches displayed for the given element. If the current input
953      * of this page is <code>null</code>, an empty array is returned
954      * @see AbstractTextSearchResult#getMatches(Object)
955      */

956     public Match[] getDisplayedMatches(Object JavaDoc element) {
957         AbstractTextSearchResult result= getInput();
958         if (result == null)
959             return EMPTY_MATCH_ARRAY;
960         Match[] matches= result.getMatches(element);
961         if (result.getActiveMatchFilters() == null) // default behaviour: filter state not used, all matches shown
962
return matches;
963
964         int count= 0;
965         for (int i= 0; i < matches.length; i++) {
966             if (matches[i].isFiltered())
967                 matches[i]= null;
968             else
969                 count++;
970         }
971         if (count == matches.length)
972             return matches;
973         
974         Match[] filteredMatches= new Match[count];
975         for (int i= 0, k= 0; i < matches.length; i++) {
976             if (matches[i] != null)
977                 filteredMatches[k++]= matches[i];
978         }
979         return filteredMatches;
980     }
981     
982     /**
983      * Returns the current location of the match. This takes possible
984      * modifications of the file into account. Therefore the result may
985      * differ from the position information that can be obtained directly
986      * off the match.
987      * @param match the match to get the position for.
988      * @return the current position of the match.
989      *
990      * @since 3.2
991      */

992     public IRegion getCurrentMatchLocation(Match match) {
993         PositionTracker tracker= InternalSearchUI.getInstance().getPositionTracker();
994         
995         int offset, length;
996         Position pos= tracker.getCurrentPosition(match);
997         if (pos == null) {
998             offset= match.getOffset();
999             length= match.getLength();
1000        } else {
1001            offset= pos.getOffset();
1002            length= pos.getLength();
1003        }
1004        return new Region(offset, length);
1005    }
1006    
1007    /**
1008     * Returns the number of matches that are currently displayed for the given
1009     * element. If {@link AbstractTextSearchResult#getActiveMatchFilters()} is not null, only matches
1010     * are returned that are not filtered by the match filters.
1011     * Any action operating on the visible matches in the
1012     * search result page should use this method to get the match count for a
1013     * search result (instead of asking the search result directly).
1014     *
1015     * @param element
1016     * The element to get the matches for
1017     * @return The number of matches displayed for the given element. If the
1018     * current input of this page is <code>null</code>, 0 is
1019     * returned
1020     * @see AbstractTextSearchResult#getMatchCount(Object)
1021     */

1022    public int getDisplayedMatchCount(Object JavaDoc element) {
1023        AbstractTextSearchResult result= getInput();
1024        if (result == null)
1025            return 0;
1026        if (result.getActiveMatchFilters() == null) // default behaviour: filter state not used, all matches shown
1027
return result.getMatchCount(element);
1028
1029        int count= 0;
1030        Match[] matches= result.getMatches(element);
1031        for (int i= 0; i < matches.length; i++) {
1032            if (!matches[i].isFiltered())
1033                count++;
1034        }
1035        return count;
1036    }
1037
1038    private Object JavaDoc getFirstSelectedElement() {
1039        IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
1040        if (selection.size() > 0)
1041            return selection.getFirstElement();
1042        return null;
1043    }
1044
1045    /**
1046     * {@inheritDoc}
1047     */

1048    public void dispose() {
1049        AbstractTextSearchResult oldSearch = getInput();
1050        if (oldSearch != null)
1051            AnnotationManagers.removeSearchResult(getSite().getWorkbenchWindow(), oldSearch);
1052        super.dispose();
1053        NewSearchUI.removeQueryListener(fQueryListener);
1054    }
1055
1056    /**
1057     * {@inheritDoc}
1058     */

1059    public void init(IPageSite pageSite) {
1060        super.init(pageSite);
1061        IMenuManager menuManager= pageSite.getActionBars().getMenuManager();
1062        addLayoutActions(menuManager);
1063        initActionDefinitionIDs(pageSite.getWorkbenchWindow());
1064        menuManager.updateAll(true);
1065        pageSite.getActionBars().updateActionBars();
1066    }
1067
1068    private void initActionDefinitionIDs(IWorkbenchWindow window) {
1069        fCopyToClipboardAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
1070        fRemoveSelectedMatches.setActionDefinitionId(IWorkbenchActionDefinitionIds.DELETE);
1071        fShowNextAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_NEXT);
1072        fShowPreviousAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_PREVIOUS);
1073        fSelectAllAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
1074    }
1075
1076    /**
1077     * Fills the toolbar contribution for this page. Subclasses may override
1078     * this method.
1079     *
1080     * @param tbm the tool bar manager representing the view's toolbar
1081     */

1082    protected void fillToolbar(IToolBarManager tbm) {
1083        tbm.appendToGroup(IContextMenuConstants.GROUP_SHOW, fShowNextAction);
1084        tbm.appendToGroup(IContextMenuConstants.GROUP_SHOW, fShowPreviousAction);
1085        tbm.appendToGroup(IContextMenuConstants.GROUP_REMOVE_MATCHES, fRemoveSelectedMatches);
1086        tbm.appendToGroup(IContextMenuConstants.GROUP_REMOVE_MATCHES, fRemoveAllResultsAction);
1087        IActionBars actionBars = getSite().getActionBars();
1088        if (actionBars != null) {
1089            actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), fShowNextAction);
1090            actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), fShowPreviousAction);
1091            actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), fRemoveSelectedMatches);
1092            actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), fCopyToClipboardAction);
1093            actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), fSelectAllAction);
1094        }
1095        if (getLayout() == FLAG_LAYOUT_TREE) {
1096            addTreeActions(tbm);
1097        }
1098    }
1099
1100    private void addTreeActions(IToolBarManager tbm) {
1101        // create new actions, new viewer created
1102
tbm.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, new ExpandAllAction((TreeViewer)getViewer()));
1103        tbm.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, new CollapseAllAction((TreeViewer)getViewer()));
1104    }
1105
1106    private void addLayoutActions(IMenuManager menuManager) {
1107        if (fFlatAction != null)
1108            menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, fFlatAction);
1109        if (fHierarchicalAction != null)
1110            menuManager.appendToGroup(IContextMenuConstants.GROUP_VIEWER_SETUP, fHierarchicalAction);
1111    }
1112
1113    /**
1114     * Sets the view part
1115     * @param part View part to set
1116     */

1117    public void setViewPart(ISearchResultViewPart part) {
1118        fViewPart = part;
1119    }
1120
1121    /**
1122     * Returns the view part set with
1123     * <code>setViewPart(ISearchResultViewPart)</code>.
1124     *
1125     * @return The view part or <code>null</code> if the view part hasn't been
1126     * set yet (or set to null).
1127     */

1128    protected ISearchResultViewPart getViewPart() {
1129        return fViewPart;
1130    }
1131
1132    // multi-threaded update handling.
1133

1134    /**
1135     * Handles a search result event for the current search result.
1136     *
1137     * @since 3.2
1138     */

1139    protected void handleSearchResultChanged(final SearchResultEvent e) {
1140        if (e instanceof MatchEvent) {
1141            postUpdate(((MatchEvent) e).getMatches());
1142        } else if (e instanceof RemoveAllEvent) {
1143            postClear();
1144        } else if (e instanceof FilterUpdateEvent) {
1145            postUpdate(((FilterUpdateEvent) e).getUpdatedMatches());
1146            updateFilterActions(fFilterActions);
1147        }
1148    }
1149
1150    private synchronized void postUpdate(Match[] matches) {
1151        for (int i = 0; i < matches.length; i++) {
1152            fBatchedUpdates.add(matches[i].getElement());
1153        }
1154        scheduleUIUpdate();
1155    }
1156
1157    private synchronized void runBatchedUpdates() {
1158        if (false /*fBatchedUpdates.size() > 50*/) {
1159            Object JavaDoc[] hundredUpdates= new Object JavaDoc[50];
1160            Iterator JavaDoc elements= fBatchedUpdates.iterator();
1161            for (int i= 0; i < hundredUpdates.length; i++) {
1162                hundredUpdates[i]= elements.next();
1163                elements.remove();
1164            }
1165            elementsChanged(hundredUpdates);
1166        } else {
1167            elementsChanged(fBatchedUpdates.toArray());
1168            fBatchedUpdates.clear();
1169        }
1170        updateBusyLabel();
1171    }
1172
1173    private synchronized void postClear() {
1174        fBatchedClearAll= true;
1175        fBatchedUpdates.clear();
1176        scheduleUIUpdate();
1177    }
1178
1179    private synchronized boolean hasMoreUpdates() {
1180        return fBatchedClearAll || fBatchedUpdates.size() > 0;
1181    }
1182
1183    private boolean isQueryRunning() {
1184        AbstractTextSearchResult result= getInput();
1185        if (result != null) {
1186            return NewSearchUI.isQueryRunning(result.getQuery());
1187        }
1188        return false;
1189    }
1190
1191    private void runBatchedClear() {
1192        synchronized(this) {
1193            if (!fBatchedClearAll) {
1194                return;
1195            }
1196            fBatchedClearAll= false;
1197            updateBusyLabel();
1198        }
1199        getViewPart().updateLabel();
1200        clear();
1201    }
1202
1203    private void asyncExec(final Runnable JavaDoc runnable) {
1204        final Control control = getControl();
1205        if (control != null && !control.isDisposed()) {
1206            Display currentDisplay = Display.getCurrent();
1207            if (currentDisplay == null || !currentDisplay.equals(control.getDisplay()))
1208                // meaning we're not executing on the display thread of the
1209
// control
1210
control.getDisplay().asyncExec(new Runnable JavaDoc() {
1211                    public void run() {
1212                        if (!control.isDisposed())
1213                            runnable.run();
1214                    }
1215                });
1216            else
1217                runnable.run();
1218        }
1219    }
1220
1221    /**
1222     * {@inheritDoc}
1223     * Subclasses may extend this method.
1224     */

1225    public void restoreState(IMemento memento) {
1226        if (countBits(fSupportedLayouts) > 1) {
1227            try {
1228                fCurrentLayout = getSettings().getInt(KEY_LAYOUT);
1229                // workaround because the saved value may be 0
1230
if (fCurrentLayout == 0)
1231                    initLayout();
1232            } catch (NumberFormatException JavaDoc e) {
1233                // ignore, signals no value stored.
1234
}
1235            if (memento != null) {
1236                Integer JavaDoc layout = memento.getInteger(KEY_LAYOUT);
1237                if (layout != null) {
1238                    fCurrentLayout = layout.intValue();
1239                    // workaround because the saved value may be 0
1240
if (fCurrentLayout == 0)
1241                        initLayout();
1242                }
1243            }
1244        }
1245    }
1246
1247    /* (non-Javadoc)
1248     * @see org.eclipse.search.ui.ISearchResultPage#saveState(org.eclipse.ui.IMemento)
1249     */

1250    public void saveState(IMemento memento) {
1251        if (countBits(fSupportedLayouts) > 1) {
1252            memento.putInteger(KEY_LAYOUT, fCurrentLayout);
1253        }
1254    }
1255
1256    /**
1257     * Note: this is internal API and should not be called from clients outside
1258     * of the search plug-in.
1259     * <p>
1260     * Removes the currently selected match. Does nothing if no match is
1261     * selected.
1262     * </p>
1263     */

1264    public void internalRemoveSelected() {
1265        AbstractTextSearchResult result = getInput();
1266        if (result == null)
1267            return;
1268        StructuredViewer viewer = getViewer();
1269        IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
1270        HashSet JavaDoc set = new HashSet JavaDoc();
1271        if (viewer instanceof TreeViewer) {
1272            ITreeContentProvider cp = (ITreeContentProvider) viewer.getContentProvider();
1273            collectAllMatchesBelow(result, set, cp, selection.toArray());
1274        } else {
1275            collectAllMatches(set, selection.toArray());
1276        }
1277        Match[] matches = new Match[set.size()];
1278        set.toArray(matches);
1279        result.removeMatches(matches);
1280    }
1281
1282    private void collectAllMatches(HashSet JavaDoc set, Object JavaDoc[] elements) {
1283        for (int j = 0; j < elements.length; j++) {
1284            Match[] matches = getDisplayedMatches(elements[j]);
1285            for (int i = 0; i < matches.length; i++) {
1286                set.add(matches[i]);
1287            }
1288        }
1289    }
1290
1291    private void collectAllMatchesBelow(AbstractTextSearchResult result, Set JavaDoc set, ITreeContentProvider cp, Object JavaDoc[] elements) {
1292        for (int j = 0; j < elements.length; j++) {
1293            Match[] matches = getDisplayedMatches(elements[j]);
1294            for (int i = 0; i < matches.length; i++) {
1295                set.add(matches[i]);
1296            }
1297            Object JavaDoc[] children = cp.getChildren(elements[j]);
1298            collectAllMatchesBelow(result, set, cp, children);
1299        }
1300    }
1301    
1302    private void turnOffDecoration() {
1303        IBaseLabelProvider lp= fViewer.getLabelProvider();
1304        if (lp instanceof DecoratingLabelProvider) {
1305            ((DecoratingLabelProvider)lp).setLabelDecorator(null);
1306        }
1307    }
1308
1309    private void turnOnDecoration() {
1310        IBaseLabelProvider lp= fViewer.getLabelProvider();
1311        if (lp instanceof DecoratingLabelProvider) {
1312            ((DecoratingLabelProvider)lp).setLabelDecorator(PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator());
1313            
1314        }
1315    }
1316
1317    /**
1318     * <p>This method is called when the search page gets an open even from it's
1319     * underlying viewer (for example on double click). The default
1320     * implementation will open the first match on any element that has matches.
1321     * If the element to be opened is an inner node in the tree layout, the node
1322     * will be expanded if it's collapsed and vice versa. Subclasses are allowed
1323     * to override this method.
1324     * </p>
1325     * @param event
1326     * the event sent for the currently shown viewer
1327     *
1328     * @see IOpenListener
1329     */

1330    protected void handleOpen(OpenEvent event) {
1331        Viewer viewer= event.getViewer();
1332        boolean hasCurrentMatch = showCurrentMatch(OpenStrategy.activateOnOpen());
1333        ISelection sel= event.getSelection();
1334        if (viewer instanceof TreeViewer && sel instanceof IStructuredSelection) {
1335            IStructuredSelection selection= (IStructuredSelection) sel;
1336            TreeViewer tv = (TreeViewer) getViewer();
1337            Object JavaDoc element = selection.getFirstElement();
1338            if (element != null) {
1339                if (!hasCurrentMatch && getDisplayedMatchCount(element) > 0)
1340                    gotoNextMatch(OpenStrategy.activateOnOpen());
1341                else
1342                    tv.setExpandedState(element, !tv.getExpandedState(element));
1343            }
1344            return;
1345        } else if (!hasCurrentMatch) {
1346            gotoNextMatch(OpenStrategy.activateOnOpen());
1347        }
1348    }
1349    
1350    /**
1351     * Sets the maximal number of top level elements to be shown in a viewer.
1352     * If <code>null</code> is set, the view page does not support to limit the elements and will not provide
1353     * UI to configure it. If a non-null value is set, configuration UI will be provided. The limit value must be a positive
1354     * number or <code>-1</code> to not limit top level element.
1355     * If enabled, the element limit has to be enforced by the content provider that is implemented by the client. The view
1356     * page just manages the value and configuration.
1357     *
1358     * @param limit the element limit. Valid values are:
1359     * <dl>
1360     * <li><code>null</code> to not limit and not provide configuration UI</li>
1361     * <li><code>-1</code> to not limit and provide configuration UI</li>
1362     * <li><code>positive integer</code> to limit by the given value and provide configuration UI</li>
1363     * </dl>
1364     *
1365     * @since 3.3
1366     */

1367    public void setElementLimit(Integer JavaDoc limit) {
1368        fElementLimit= limit;
1369        
1370        if (fViewer != null) {
1371            fViewer.refresh();
1372        }
1373        if (fViewPart != null) {
1374            fViewPart.updateLabel();
1375        }
1376    }
1377    
1378    /**
1379     * Gets the maximal number of top level elements to be shown in a viewer.
1380     * <code>null</code> means the view page does not limit the elements and will not provide
1381     * UI to configure it. If a non-null value is set, configuration UI will be provided. The limit value must be a positive
1382     * number or <code>-1</code> to not limit top level element.
1383     *
1384     * @return returns the element limit. Valid values are:
1385     * <dl>
1386     * <li><code>null</code> to not limit and not provide configuration UI (default value)</li>
1387     * <li><code>-1</code> to not limit and provide configuration UI</li>
1388     * <li><code>positive integer</code> to limit by the given value and provide configuration UI</li>
1389     * </dl>
1390     *
1391     * @since 3.3
1392     */

1393    public Integer JavaDoc getElementLimit() {
1394        return fElementLimit;
1395    }
1396    
1397    
1398}
1399
Popular Tags