| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| 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.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| 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.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.dialogs.ProgressMonitorDialog; |
| import org.eclipse.jface.viewers.Viewer; |
| |
| import org.eclipse.ui.actions.WorkspaceModifyOperation; |
| |
| import org.eclipse.search.internal.ui.util.ExceptionHandler; |
| import org.eclipse.search.ui.IGroupByKeyComputer; |
| import org.eclipse.search.ui.SearchUI; |
| |
| |
| /** |
| * Manage search results |
| * @deprecated old search |
| */ |
| @Deprecated |
| public class SearchManager implements IResourceChangeListener { |
| |
| static SearchManager fgDefault; |
| |
| Search fCurrentSearch= null; |
| |
| private SearchManager() { |
| SearchPlugin.getWorkspace().addResourceChangeListener(this); |
| } |
| |
| private HashSet<SearchResultViewer> fListeners= new HashSet<>(); |
| private LinkedList<Search> fPreviousSearches= new LinkedList<>(); |
| private boolean fIsRemoveAll= false; |
| |
| public static synchronized SearchManager getDefault() { |
| if (fgDefault == null) |
| fgDefault= new SearchManager(); |
| return fgDefault; |
| } |
| |
| public void dispose() { |
| SearchPlugin.getWorkspace().removeResourceChangeListener(this); |
| } |
| |
| /** |
| * Returns the list with previous searches (ISearch). |
| * @return previous searches |
| */ |
| LinkedList<Search> getPreviousSearches() { |
| return fPreviousSearches; |
| } |
| /** |
| * Returns the list with current (last) results |
| * @return the current results |
| */ |
| ArrayList<SearchResultViewEntry> getCurrentResults() { |
| if (fCurrentSearch == null) |
| return new ArrayList<>(0); |
| return (ArrayList<SearchResultViewEntry>)fCurrentSearch.getResults(); |
| } |
| |
| public Search getCurrentSearch() { |
| return fCurrentSearch; |
| } |
| |
| void removeAllSearches() { |
| SearchPlugin.getWorkspace().removeResourceChangeListener(this); |
| WorkspaceModifyOperation op= new WorkspaceModifyOperation(null) { |
| @Override |
| protected void execute(IProgressMonitor monitor) throws CoreException { |
| monitor.beginTask(SearchMessages.SearchManager_updating, 100); |
| SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); |
| monitor.worked(100); |
| monitor.done(); |
| } |
| }; |
| boolean isAutoBuilding= SearchPlugin.setAutoBuilding(false); |
| try { |
| ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell()); |
| dialog.run(true, true, op); |
| } catch (InvocationTargetException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_deleteMarkers_title, SearchMessages.Search_Error_deleteMarkers_message); |
| } catch (InterruptedException e) { |
| // Do nothing. Operation has been canceled. |
| } finally { |
| SearchPlugin.getWorkspace().addResourceChangeListener(this); |
| SearchPlugin.setAutoBuilding(isAutoBuilding); |
| } |
| |
| // clear searches |
| fPreviousSearches= new LinkedList<>(); |
| fCurrentSearch= null; |
| |
| // update viewers |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) { |
| SearchResultViewer viewer= iter.next(); |
| handleAllSearchesRemoved(viewer); |
| } |
| } |
| |
| private void handleAllSearchesRemoved(SearchResultViewer viewer) { |
| viewer.handleAllSearchesRemoved(); |
| } |
| |
| void setCurrentSearch(final Search search) { |
| if (fCurrentSearch == search) |
| return; |
| |
| SearchPlugin.getWorkspace().removeResourceChangeListener(this); |
| WorkspaceModifyOperation op= new WorkspaceModifyOperation(null) { |
| @Override |
| protected void execute(IProgressMonitor monitor) throws CoreException { |
| internalSetCurrentSearch(search, monitor); |
| } |
| }; |
| boolean isAutoBuilding= SearchPlugin.setAutoBuilding(false); |
| try { |
| ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell()); |
| dialog.run(true, true, op); |
| } catch (InvocationTargetException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_switchSearch_title, SearchMessages.Search_Error_switchSearch_message); |
| } catch (InterruptedException e) { |
| // Do nothing. Operation has been canceled. |
| } finally { |
| SearchPlugin.setAutoBuilding(isAutoBuilding); |
| } |
| |
| 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.SearchManager_updating, getCurrentResults().size() + 20); |
| |
| // remove current search markers |
| try { |
| SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); |
| } catch (CoreException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_deleteMarkers_title, SearchMessages.Search_Error_deleteMarkers_message); |
| } |
| monitor.worked(10); |
| |
| // add search markers |
| Iterator<SearchResultViewEntry> iter= getCurrentResults().iterator(); |
| ArrayList<SearchResultViewEntry> emptyEntries= new ArrayList<>(10); |
| boolean filesChanged= false; |
| boolean filesDeleted= false; |
| IGroupByKeyComputer groupByKeyComputer= getCurrentSearch().getGroupByKeyComputer(); |
| while (iter.hasNext()) { |
| monitor.worked(1); |
| SearchResultViewEntry entry= iter.next(); |
| Iterator<Map<String, Object>> 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(entry.getMarkerType()); |
| } catch (CoreException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_createMarker_title, SearchMessages.Search_Error_createMarker_message); |
| continue; |
| } |
| try { |
| newMarker.setAttributes(attrPerMarkerIter.next()); |
| if (groupByKeyComputer !=null && groupByKeyComputer.computeGroupByKey(newMarker) == null) { |
| filesDeleted= true; |
| newMarker.delete(); |
| continue; |
| } |
| } catch (CoreException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_markerAttributeAccess_title, SearchMessages.Search_Error_markerAttributeAccess_message); |
| } |
| 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.SearchManager_resourceChanged; |
| if (filesDeleted) { |
| if (warningMessage == null) |
| warningMessage= ""; //$NON-NLS-1$ |
| else |
| warningMessage += "\n"; //$NON-NLS-1$ |
| warningMessage += SearchMessages.SearchManager_resourceDeleted; |
| } |
| if (warningMessage != null) { |
| if (display != null && !display.isDisposed()) { |
| final String warningTitle= SearchMessages.SearchManager_resourceChangedWarning; |
| final String warningMsg= warningMessage; |
| display.syncExec(() -> MessageDialog.openWarning(getShell(), warningTitle, warningMsg)); |
| } |
| } |
| |
| // update viewers |
| Iterator<SearchResultViewer> iter2= fListeners.iterator(); |
| if (display != null && !display.isDisposed()) { |
| final Viewer visibleViewer= ((SearchResultView)SearchUI.getSearchResultView()).getViewer(); |
| while (iter2.hasNext()) { |
| final SearchResultViewer viewer= iter2.next(); |
| display.syncExec(() -> { |
| if (previousSearch != null && viewer == visibleViewer) |
| previousSearch.setSelection(viewer.getSelection()); |
| viewer.setInput(null); |
| viewer.setPageId(search.getPageId()); |
| viewer.setGotoMarkerAction(search.getGotoMarkerAction()); |
| viewer.setContextMenuTarget(search.getContextMenuContributor()); |
| viewer.setActionGroupFactory(null); |
| viewer.setInput(getCurrentResults()); |
| viewer.setActionGroupFactory(search.getActionGroupFactory()); |
| viewer.setSelection(fCurrentSearch.getSelection(), true); |
| }); |
| } |
| } |
| monitor.done(); |
| } |
| |
| /** |
| * Returns the number of matches |
| * @return the number of matches |
| */ |
| int getCurrentItemCount() { |
| if (fCurrentSearch != null) |
| return fCurrentSearch.getItemCount(); |
| return 0; |
| } |
| |
| void removeAllResults() { |
| fIsRemoveAll= true; |
| try { |
| SearchPlugin.getWorkspace().getRoot().deleteMarkers(SearchUI.SEARCH_MARKER, true, IResource.DEPTH_INFINITE); |
| } catch (CoreException ex) { |
| ExceptionHandler.handle(ex, SearchMessages.Search_Error_deleteMarkers_title, SearchMessages.Search_Error_deleteMarkers_message); |
| fIsRemoveAll= false; |
| } |
| } |
| |
| void addNewSearch(final Search newSearch) { |
| |
| SearchPlugin.getWorkspace().removeResourceChangeListener(this); |
| |
| // Clear the viewers |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| Display display= getDisplay(); |
| if (display != null && !display.isDisposed()) { |
| final Viewer visibleViewer= ((SearchResultView)SearchUI.getSearchResultView()).getViewer(); |
| while (iter.hasNext()) { |
| final SearchResultViewer viewer= iter.next(); |
| display.syncExec(() -> { |
| if (fCurrentSearch != null && viewer == visibleViewer) |
| fCurrentSearch.setSelection(viewer.getSelection()); |
| setNewSearch(viewer, newSearch); |
| }); |
| } |
| } |
| |
| 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.Search_Error_deleteMarkers_title, SearchMessages.Search_Error_deleteMarkers_message); |
| } |
| } |
| |
| void searchFinished(ArrayList<SearchResultViewEntry> results) { |
| Assert.isNotNull(results); |
| getCurrentSearch().setResults(results); |
| |
| Display display= getDisplay(); |
| if (display == null || display.isDisposed()) |
| return; |
| |
| if (Thread.currentThread() == display.getThread()) |
| handleNewSearchResult(); |
| else { |
| display.syncExec(this::handleNewSearchResult); |
| } |
| SearchPlugin.getWorkspace().addResourceChangeListener(this); |
| } |
| |
| //--- Change event handling ------------------------------------------------- |
| |
| void addSearchChangeListener(SearchResultViewer viewer) { |
| fListeners.add(viewer); |
| } |
| |
| void removeSearchChangeListener(SearchResultViewer viewer) { |
| Assert.isNotNull(viewer); |
| fListeners.remove(viewer); |
| } |
| |
| private final void handleSearchMarkersChanged(IMarkerDelta[] markerDeltas) { |
| if (fIsRemoveAll) { |
| handleRemoveAll(); |
| fIsRemoveAll= false; |
| return; |
| } |
| |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().getControl().setRedraw(false); |
| |
| for (IMarkerDelta markerDelta : markerDeltas) { |
| handleSearchMarkerChanged(markerDelta); |
| } |
| |
| iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().getControl().setRedraw(true); |
| |
| } |
| |
| private void handleSearchMarkerChanged(IMarkerDelta markerDelta) { |
| int kind= markerDelta.getKind(); |
| // don't listen for adds will be done by ISearchResultView.addMatch(...) |
| if (((kind & IResourceDelta.REMOVED) != 0)) |
| handleRemoveMatch(markerDelta.getMarker()); |
| else if ((kind & IResourceDelta.CHANGED) != 0) |
| handleUpdateMatch(markerDelta.getMarker()); |
| } |
| |
| private void handleRemoveAll() { |
| if (fCurrentSearch != null) |
| fCurrentSearch.removeResults(); |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().handleRemoveAll(); |
| } |
| |
| private void handleNewSearchResult() { |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) { |
| SearchResultViewer viewer= iter.next(); |
| viewer.setInput(getCurrentResults()); |
| } |
| } |
| |
| private void setNewSearch(SearchResultViewer viewer, Search search) { |
| viewer.setInput(null); |
| viewer.clearTitle(); |
| viewer.setPageId(search.getPageId()); |
| viewer.setGotoMarkerAction(search.getGotoMarkerAction()); |
| viewer.setContextMenuTarget(search.getContextMenuContributor()); |
| viewer.setActionGroupFactory(search.getActionGroupFactory()); |
| } |
| |
| private void handleRemoveMatch(IMarker marker) { |
| SearchResultViewEntry entry= findEntry(marker); |
| if (entry != null) { |
| entry.remove(marker); |
| if (entry.getMatchCount() == 0) { |
| getCurrentResults().remove(entry); |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().handleRemoveMatch(entry); |
| } |
| else { |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().handleUpdateMatch(entry, true); |
| } |
| } |
| } |
| |
| private void handleUpdateMatch(IMarker marker) { |
| SearchResultViewEntry entry= findEntry(marker); |
| if (entry != null) { |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) |
| iter.next().handleUpdateMatch(entry, false); |
| } |
| } |
| |
| private SearchResultViewEntry findEntry(IMarker marker) { |
| Iterator<SearchResultViewEntry> entries= getCurrentResults().iterator(); |
| while (entries.hasNext()) { |
| SearchResultViewEntry entry= entries.next(); |
| if (entry.contains(marker)) |
| 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. |
| * @param event the event |
| */ |
| @Override |
| 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= () -> { |
| if (getCurrentSearch() != null) { |
| handleSearchMarkersChanged(markerDeltas); |
| // update title and actions |
| Iterator<SearchResultViewer> iter= fListeners.iterator(); |
| while (iter.hasNext()) { |
| SearchResultViewer viewer= iter.next(); |
| viewer.enableActions(); |
| viewer.updateTitle(); |
| } |
| } |
| }; |
| display.syncExec(runnable); |
| } |
| /** |
| * Find and return a valid display |
| * @return the display |
| */ |
| private Display getDisplay() { |
| Iterator<SearchResultViewer> 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 |
| * @return the shell |
| */ |
| private Shell getShell() { |
| return SearchPlugin.getActiveWorkbenchShell(); |
| } |
| } |
| |