diff -r 75d9490492dc utilities.project/src/org/netbeans/modules/search/project/SearchScopeOpenProjects.java --- a/utilities.project/src/org/netbeans/modules/search/project/SearchScopeOpenProjects.java Fri Aug 07 05:13:25 2015 +0000 +++ b/utilities.project/src/org/netbeans/modules/search/project/SearchScopeOpenProjects.java Fri Aug 07 12:52:55 2015 +0200 @@ -44,12 +44,22 @@ package org.netbeans.modules.search.project; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.net.URI; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.Icon; import org.netbeans.api.annotations.common.StaticResource; import org.netbeans.api.project.Project; import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.api.search.SearchRoot; +import org.netbeans.api.search.SearchScopeOptions; import org.netbeans.api.search.provider.SearchInfo; import org.netbeans.api.search.provider.SearchInfoUtils; +import org.netbeans.api.search.provider.SearchListener; +import org.openide.filesystems.FileObject; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; @@ -90,28 +100,11 @@ @Override public SearchInfo getSearchInfo() { - Project[] openProjects = OpenProjects.getDefault().getOpenProjects(); - if (openProjects.length == 0) { - /* - * We cannot prevent this situation. The action may be invoked - * between moment the last project had been removed and the removal - * notice was distributed to the open projects listener (and this - * action disabled). This may happen if the the last project - * is being removed in another thread than this action was - * invoked from. - */ - return SearchInfoUtils.createEmptySearchInfo(); - } - - if (openProjects.length == 1) { - return createSingleProjectSearchInfo(openProjects[0]); - } - - SearchInfo[] prjSearchInfos = new SearchInfo[openProjects.length]; - for (int i = 0; i < prjSearchInfos.length; i++) { - prjSearchInfos[i] = createSingleProjectSearchInfo(openProjects[i]); - } - return SearchInfoUtils.createCompoundSearchInfo(prjSearchInfos); + + /** + * Search info alway takes currently opened projects. See bug 253015. + */ + return new OpenProjectsSearchInfo(); } @Override @@ -128,4 +121,122 @@ public Icon getIcon() { return ICON; } + + private static class OpenProjectsSearchInfo extends SearchInfo { + + private Reference delegate = null; + private Reference[] lastOpenProjects = null; + + /** + * Check whether open projects has changed since last invocation of this + * method. + * + * @param openProjects Current list of open projects. + * + * @return True if the list has changed since the last time. + */ + private synchronized boolean openProjectsHasChanged( + Project[] openProjects) { + + boolean differ = false; + if (lastOpenProjects == null) { + differ = true; + } else if (lastOpenProjects.length != openProjects.length) { + differ = true; + } else { + for (int i = 0; i < openProjects.length; i++) { + if (openProjects[i] != lastOpenProjects[i].get()) { + differ = true; + break; + } + } + } + if (differ) { + lastOpenProjects = new Reference[openProjects.length]; + for (int i = 0; i < openProjects.length; i++) { + lastOpenProjects[i] + = new WeakReference(openProjects[i]); + } + return true; + } else { + return false; + } + } + + /** + * Get cached or new delegate search info. + * + * @return Search info. + */ + private SearchInfo getDelegate() { + Project[] current = OpenProjects.getDefault().getOpenProjects(); + SearchInfo del = delegate == null ? null : delegate.get(); + if (del != null && !openProjectsHasChanged(current)) { + return del; + } else { + del = getDelegate(current); + delegate = new WeakReference(del); + return del; + } + } + + /** + * Create delegate search info for an array of open projects. + * + * @param openProjects + * @return Search info. + */ + private SearchInfo getDelegate(Project[] openProjects) { + + if (openProjects.length == 0) { + /* + * We cannot prevent this situation. The action may be invoked + * between moment the last project had been removed and the removal + * notice was distributed to the open projects listener (and this + * action disabled). This may happen if the the last project + * is being removed in another thread than this action was + * invoked from. + */ + return SearchInfoUtils.createEmptySearchInfo(); + } + + if (openProjects.length == 1) { + return createSingleProjectSearchInfo(openProjects[0]); + } + + SearchInfo[] prjSearchInfos = new SearchInfo[openProjects.length]; + for (int i = 0; i < prjSearchInfos.length; i++) { + prjSearchInfos[i] = createSingleProjectSearchInfo(openProjects[i]); + } + return SearchInfoUtils.createCompoundSearchInfo(prjSearchInfos); + } + + @Override + public boolean canSearch() { + return getDelegate().canSearch(); + } + + @Override + public List getSearchRoots() { + return getDelegate().getSearchRoots(); + } + + @Override + protected Iterator createFilesToSearchIterator( + SearchScopeOptions options, SearchListener listener, + AtomicBoolean terminated) { + + return getDelegate().getFilesToSearch( + options, listener, terminated).iterator(); + } + + @Override + protected Iterator createUrisToSearchIterator( + SearchScopeOptions options, SearchListener listener, + AtomicBoolean terminated) { + + return getDelegate().getUrisToSearch( + options, listener, terminated).iterator(); + } + } }