/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
package org.eclipse.search.internal.ui; | |
import java.lang.reflect.InvocationTargetException; | |
import java.util.ArrayList; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.Map; | |
import org.eclipse.core.resources.IMarker; | |
import org.eclipse.core.resources.IMarkerDelta; | |
import org.eclipse.core.resources.IResource; | |
import org.eclipse.core.resources.IResourceChangeEvent; | |
import org.eclipse.core.resources.IResourceChangeListener; | |
import org.eclipse.core.resources.IResourceDelta; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.swt.widgets.Control; | |
import org.eclipse.swt.widgets.Display; | |
import org.eclipse.swt.widgets.Shell; | |
import org.eclipse.jface.dialogs.MessageDialog; | |
import org.eclipse.jface.dialogs.ProgressMonitorDialog; | |
import org.eclipse.jface.util.Assert; | |
import org.eclipse.jface.viewers.StructuredSelection; | |
import org.eclipse.jface.viewers.Viewer; | |
import org.eclipse.ui.actions.WorkspaceModifyOperation; | |
import org.eclipse.search.ui.IGroupByKeyComputer; | |
import org.eclipse.search.ui.SearchUI; | |
import org.eclipse.search.internal.ui.util.ExceptionHandler; | |
/** | |
* Manage search results | |
*/ | |
public class SearchManager implements IResourceChangeListener { | |
static final SearchManager fgDefault= new SearchManager(); | |
Search fCurrentSearch= null; | |
private SearchManager() { | |
SearchPlugin.getWorkspace().addResourceChangeListener(this); | |
} | |
private HashSet fListeners= new HashSet(); | |
private LinkedList fPreviousSearches= new LinkedList(); | |
private boolean fIsNewSearch= false; | |
public static SearchManager getDefault() { | |
return fgDefault; | |
} | |
/** | |
* Returns the list with previous searches (ISearch). | |
*/ | |
LinkedList getPreviousSearches() { | |
return fPreviousSearches; | |
} | |
/** | |
* Returns the list with current (last) results | |
*/ | |
ArrayList getCurrentResults() { | |
if (fCurrentSearch == null) | |
return new ArrayList(0); | |
else | |
return (ArrayList)fCurrentSearch.getResults(); | |
} | |
Search getCurrentSearch() { | |
return fCurrentSearch; | |
} | |
void removeAllSearches() { | |
SearchPlugin.getWorkspace().removeResourceChangeListener(this); | |
WorkspaceModifyOperation op= new WorkspaceModifyOperation() { | |
protected void execute(IProgressMonitor monitor) throws CoreException { | |
monitor.beginTask(SearchMessages.getString("SearchManager.updating"), 100); //$NON-NLS-1$ | |
SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); | |
monitor.worked(100); | |
monitor.done(); | |
} | |
}; | |
boolean isAutoBuilding= SearchPlugin.getWorkspace().isAutoBuilding(); | |
if (isAutoBuilding) | |
// disable auto-build during search operation | |
SearchPlugin.setAutoBuilding(false); | |
try { | |
ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell()); | |
dialog.run(true, true, op); | |
} catch (InvocationTargetException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.deleteMarkers.title"), SearchMessages.getString("Search.Error.deleteMarkers.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
} catch (InterruptedException e) { | |
// Do nothing. Operation has been canceled. | |
} finally { | |
SearchPlugin.getWorkspace().addResourceChangeListener(this); | |
if (isAutoBuilding) | |
// enable auto-building again | |
SearchPlugin.setAutoBuilding(true); | |
} | |
// clear searches | |
fPreviousSearches= new LinkedList(); | |
fCurrentSearch= null; | |
// update viewers | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) { | |
SearchResultViewer viewer= (SearchResultViewer)iter.next(); | |
viewer.setInput(null); | |
} | |
} | |
void setCurrentSearch(final Search search) { | |
if (fCurrentSearch == search) | |
return; | |
SearchPlugin.getWorkspace().removeResourceChangeListener(this); | |
WorkspaceModifyOperation op= new WorkspaceModifyOperation() { | |
protected void execute(IProgressMonitor monitor) throws CoreException { | |
internalSetCurrentSearch(search, monitor); | |
} | |
}; | |
boolean isAutoBuilding= SearchPlugin.getWorkspace().isAutoBuilding(); | |
if (isAutoBuilding) | |
// disable auto-build during search operation | |
SearchPlugin.setAutoBuilding(false); | |
try { | |
ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell()); | |
dialog.run(true, true, op); | |
} catch (InvocationTargetException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.switchSearch.title"), SearchMessages.getString("Search.Error.switchSearch.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
} catch (InterruptedException e) { | |
// Do nothing. Operation has been canceled. | |
} finally { | |
SearchPlugin.getWorkspace().addResourceChangeListener(this); | |
if (isAutoBuilding) | |
// enable auto-building again | |
SearchPlugin.setAutoBuilding(true); | |
} | |
getPreviousSearches().remove(search); | |
getPreviousSearches().addFirst(search); | |
} | |
void internalSetCurrentSearch(final Search search, IProgressMonitor monitor) { | |
if (fCurrentSearch != null) | |
fCurrentSearch.backupMarkers(); | |
final Search previousSearch= fCurrentSearch; | |
fCurrentSearch= search; | |
monitor.beginTask(SearchMessages.getString("SearchManager.updating"), getCurrentResults().size() + 20); //$NON-NLS-1$ | |
// remove current search markers | |
try { | |
SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); | |
} catch (CoreException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.deleteMarkers.title"), SearchMessages.getString("Search.Error.deleteMarkers.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
} | |
monitor.worked(10); | |
// add search markers | |
Iterator iter= getCurrentResults().iterator(); | |
ArrayList emptyEntries= new ArrayList(10); | |
boolean filesChanged= false; | |
boolean filesDeleted= false; | |
IGroupByKeyComputer groupByKeyComputer= getCurrentSearch().getGroupByKeyComputer(); | |
while (iter.hasNext()) { | |
monitor.worked(1); | |
SearchResultViewEntry entry= (SearchResultViewEntry)iter.next(); | |
Iterator attrPerMarkerIter= entry.getAttributesPerMarker().iterator(); | |
entry.clearMarkerList(); | |
if (entry.getResource() == null || !entry.getResource().exists()) { | |
emptyEntries.add(entry); | |
filesDeleted= true; | |
continue; | |
} | |
while (attrPerMarkerIter.hasNext()) { | |
IMarker newMarker= null; | |
try { | |
newMarker= entry.getResource().createMarker(SearchUI.SEARCH_MARKER); | |
} catch (CoreException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.createMarker.title"), SearchMessages.getString("Search.Error.createMarker.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
continue; | |
} | |
try { | |
newMarker.setAttributes((Map)attrPerMarkerIter.next()); | |
if (groupByKeyComputer !=null && groupByKeyComputer.computeGroupByKey(newMarker) == null) { | |
filesDeleted= true; | |
newMarker.delete(); | |
continue; | |
} | |
} catch (CoreException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.markerAttributeAccess.title"), SearchMessages.getString("Search.Error.markerAttributeAccess.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
} | |
entry.add(newMarker); | |
} | |
if (entry.getMatchCount() == 0) | |
emptyEntries.add(entry); | |
else if (!filesChanged && entry.getResource().getModificationStamp() != entry.getModificationStamp()) | |
filesChanged= true; | |
} | |
getCurrentResults().removeAll(emptyEntries); | |
monitor.worked(10); | |
String warningMessage= null; | |
Display display= getDisplay(); | |
if (filesChanged) | |
warningMessage= SearchMessages.getString("SearchManager.resourceChanged"); //$NON-NLS-1$ | |
if (filesDeleted) { | |
if (warningMessage == null) | |
warningMessage= ""; //$NON-NLS-1$ | |
else | |
warningMessage += "\n"; //$NON-NLS-1$ | |
warningMessage += SearchMessages.getString("SearchManager.resourceDeleted"); //$NON-NLS-1$ | |
} | |
if (warningMessage != null) { | |
if (display != null && !display.isDisposed()) { | |
final String warningTitle= SearchMessages.getString("SearchManager.resourceChangedWarning"); //$NON-NLS-1$ | |
final String warningMsg= warningMessage; | |
display.syncExec(new Runnable() { | |
public void run() { | |
MessageDialog.openWarning(getShell(), warningTitle, warningMsg); | |
} | |
}); | |
} | |
} | |
// update viewers | |
iter= fListeners.iterator(); | |
if (display != null && !display.isDisposed()) { | |
final Viewer visibleViewer= ((SearchResultView)SearchPlugin.getSearchResultView()).getViewer(); | |
while (iter.hasNext()) { | |
final SearchResultViewer viewer= (SearchResultViewer)iter.next(); | |
viewer.setGotoMarkerAction(search.getGotoMarkerAction()); | |
viewer.setContextMenuTarget(search.getContextMenuContributor()); | |
display.syncExec(new Runnable() { | |
public void run() { | |
if (previousSearch != null && viewer == visibleViewer) | |
previousSearch.setSelection(viewer.getSelection()); | |
viewer.setPageId(search.getPageId()); | |
viewer.setInput(getCurrentResults()); | |
viewer.setSelection(fCurrentSearch.getSelection(), true); | |
if (viewer.getSelectedEntriesCount() == 0 && !getCurrentResults().isEmpty()) | |
viewer.setSelection(new StructuredSelection(getCurrentResults().get(0))); | |
} | |
}); | |
} | |
} | |
monitor.done(); | |
} | |
/** | |
* Returns the list with current (last) results | |
*/ | |
int getCurrentItemCount() { | |
if (fCurrentSearch != null) | |
return fCurrentSearch.getItemCount(); | |
else | |
return 0; | |
} | |
void addNewSearch(Search newSearch) { | |
// Clear the viewers | |
Iterator iter= fListeners.iterator(); | |
Display display= getDisplay(); | |
if (display != null && !display.isDisposed()) { | |
final Viewer visibleViewer= ((SearchResultView)SearchPlugin.getSearchResultView()).getViewer(); | |
while (iter.hasNext()) { | |
final SearchResultViewer viewer= (SearchResultViewer)iter.next(); | |
display.syncExec(new Runnable() { | |
public void run() { | |
if (fCurrentSearch != null && viewer == visibleViewer) | |
fCurrentSearch.setSelection(viewer.getSelection()); | |
viewer.handleRemoveAll(); | |
viewer.clearTitle(); | |
} | |
}); | |
} | |
} | |
if (fCurrentSearch != null) { | |
if (fCurrentSearch.isSameSearch(newSearch)) | |
getPreviousSearches().remove(fCurrentSearch); | |
else | |
fCurrentSearch.backupMarkers(); | |
} | |
fCurrentSearch= newSearch; | |
getPreviousSearches().addFirst(fCurrentSearch); | |
// Remove the markers | |
try { | |
SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); | |
} catch (CoreException ex) { | |
ExceptionHandler.handle(ex, SearchMessages.getString("Search.Error.deleteMarkers.title"), SearchMessages.getString("Search.Error.deleteMarkers.message")); //$NON-NLS-2$ //$NON-NLS-1$ | |
} | |
} | |
void setCurrentResults(ArrayList results) { | |
Assert.isNotNull(results); | |
((Search)getCurrentSearch()).setResults(results); | |
if (results.isEmpty()) { | |
// directly update because there will be no delta | |
Display display= getDisplay(); | |
if (display == null || display.isDisposed()) | |
return; | |
display.syncExec(new Runnable() { | |
public void run() { | |
handleNewSearchResult(); | |
} | |
}); | |
} | |
else | |
fIsNewSearch= true; | |
} | |
//--- Change event handling ------------------------------------------------- | |
void addSearchChangeListener(SearchResultViewer viewer) { | |
fListeners.add(viewer); | |
} | |
void removeSearchChangeListener(SearchResultViewer viewer) { | |
Assert.isNotNull(viewer); | |
fListeners.remove(viewer); | |
} | |
private final void handleSearchMarkersChanged(final IResourceChangeEvent event, IMarkerDelta[] markerDeltas) { | |
if (fIsNewSearch) { | |
fIsNewSearch= false; | |
handleNewSearchResult(); | |
return; | |
} | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).getControl().setRedraw(false); | |
for (int i=0; i < markerDeltas.length; i++) | |
handleSearchMarkerChanged(markerDeltas[i]); | |
iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).getControl().setRedraw(true); | |
} | |
private void handleSearchMarkerChanged(IMarkerDelta markerDelta) { | |
int kind= markerDelta.getKind(); | |
if ((kind & IResourceDelta.ADDED) != 0) | |
handleAddMatch(markerDelta.getMarker()); | |
else if (((kind & IResourceDelta.REMOVED) != 0)) | |
handleRemoveMatch(markerDelta.getMarker()); | |
else if ((kind & IResourceDelta.CHANGED) != 0) | |
handleUpdateMatch(markerDelta.getMarker()); | |
} | |
private void handleRemoveAll() { | |
if (fCurrentSearch != null) | |
((Search)fCurrentSearch).removeResults(); | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleRemoveAll(); | |
} | |
private void handleAddMatch(IMarker marker) { | |
Object groupByKey= getCurrentSearch().getGroupByKeyComputer().computeGroupByKey(marker); | |
SearchResultViewEntry entry= findEntry(groupByKey); | |
if (entry == null) { | |
entry= new SearchResultViewEntry(groupByKey, marker.getResource()); | |
getCurrentResults().add(entry); | |
entry.add(marker); | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleAddMatch(entry); | |
} | |
else { | |
entry.add(marker); | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleUpdateMatch(entry); | |
} | |
} | |
private void handleNewSearchResult() { | |
Iterator iter= fListeners.iterator(); | |
final Search search= getCurrentSearch(); | |
while (iter.hasNext()) { | |
SearchResultViewer viewer= (SearchResultViewer)iter.next(); | |
viewer.setPageId(search.getPageId()); | |
viewer.setContextMenuTarget(search.getContextMenuContributor()); | |
viewer.setGotoMarkerAction(search.getGotoMarkerAction()); | |
viewer.setInput(getCurrentResults()); | |
} | |
} | |
private void handleRemoveMatch(IMarker marker) { | |
SearchResultViewEntry entry= findEntry(marker); | |
if (entry != null) { | |
entry.remove(marker); | |
if (entry.getMatchCount() == 0) { | |
getCurrentResults().remove(entry); | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleRemoveMatch(entry); | |
} | |
else { | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleUpdateMatch(entry); | |
} | |
} | |
} | |
private void handleUpdateMatch(IMarker marker) { | |
SearchResultViewEntry entry= findEntry(marker); | |
if (entry != null) { | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) | |
((SearchResultViewer)iter.next()).handleUpdateMatch(entry); | |
} | |
} | |
private SearchResultViewEntry findEntry(IMarker marker) { | |
Iterator entries= getCurrentResults().iterator(); | |
while (entries.hasNext()) { | |
SearchResultViewEntry entry= (SearchResultViewEntry)entries.next(); | |
if (entry.contains(marker)) | |
return entry; | |
} | |
return null; | |
} | |
private SearchResultViewEntry findEntry(Object key) { | |
if (key == null) | |
return null; | |
Iterator entries= getCurrentResults().iterator(); | |
while (entries.hasNext()) { | |
SearchResultViewEntry entry= (SearchResultViewEntry)entries.next(); | |
if (key.equals(entry.getGroupByKey())) | |
return entry; | |
} | |
return null; | |
} | |
/** | |
* Received a resource event. Since the delta could be created in a | |
* separate thread this methods post the event into the viewer's | |
* display thread. | |
*/ | |
public final void resourceChanged(final IResourceChangeEvent event) { | |
if (event == null) | |
return; | |
final IMarkerDelta[] markerDeltas= event.findMarkerDeltas(SearchUI.SEARCH_MARKER, true); | |
if (markerDeltas == null || markerDeltas.length < 1) | |
return; | |
Display display= getDisplay(); | |
if (display == null || display.isDisposed()) | |
return; | |
Runnable runnable= new Runnable() { | |
public void run() { | |
handleSearchMarkersChanged(event, markerDeltas); | |
// update title and actions | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) { | |
SearchResultViewer viewer= (SearchResultViewer)iter.next(); | |
viewer.enableActions(); | |
viewer.updateTitle(); | |
} | |
} | |
}; | |
display.syncExec(runnable); | |
} | |
/** | |
* Find and return a valid display | |
*/ | |
private Display getDisplay() { | |
Iterator iter= fListeners.iterator(); | |
while (iter.hasNext()) { | |
Control control= ((Viewer)iter.next()).getControl(); | |
if (control != null && !control.isDisposed()) { | |
Display display= control.getDisplay(); | |
if (display != null && !display.isDisposed()) | |
return display; | |
} | |
} | |
return null; | |
} | |
/** | |
* Find and return a valid shell | |
*/ | |
private Shell getShell() { | |
return SearchPlugin.getActiveWorkbenchShell(); | |
} | |
} | |