| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.search; |
| |
| import java.util.List; |
| import javax.swing.JComponent; |
| import javax.swing.event.ChangeEvent; |
| import javax.swing.event.ChangeListener; |
| import org.netbeans.api.annotations.common.NonNull; |
| import org.netbeans.api.annotations.common.NullAllowed; |
| import org.netbeans.api.search.SearchPattern; |
| import org.netbeans.api.search.SearchScopeOptions; |
| import org.netbeans.api.search.provider.SearchInfo; |
| import org.netbeans.modules.search.IgnoreListPanel.IgnoreListManager; |
| import org.netbeans.modules.search.MatchingObject.Def; |
| import org.netbeans.modules.search.matcher.AbstractMatcher; |
| import org.netbeans.modules.search.matcher.DefaultMatcher; |
| import org.netbeans.modules.search.ui.UiUtils; |
| import org.netbeans.spi.search.SearchFilterDefinition; |
| import org.netbeans.spi.search.SearchFilterDefinition.FolderResult; |
| import org.netbeans.spi.search.SearchScopeDefinition; |
| import org.netbeans.spi.search.provider.SearchComposition; |
| import org.netbeans.spi.search.provider.SearchProvider; |
| import org.openide.DialogDisplayer; |
| import org.openide.NotificationLineSupport; |
| import org.openide.NotifyDescriptor; |
| import org.openide.filesystems.FileObject; |
| import org.openide.util.HelpCtx; |
| import org.openide.util.Lookup; |
| import org.openide.util.lookup.ServiceProvider; |
| import org.openide.util.lookup.ServiceProviders; |
| |
| /** Basic Search provider |
| * |
| * @author jhavlin |
| */ |
| @ServiceProviders(value = { |
| @ServiceProvider(service = SearchProvider.class, position = 0), |
| @ServiceProvider(service = BasicSearchProvider.class, position = 0)}) |
| public class BasicSearchProvider extends SearchProvider { |
| |
| /** |
| * Presenter is {@link BasicSearchPresenter}. |
| */ |
| @Override |
| public Presenter createPresenter(boolean replaceMode) { |
| return new BasicSearchPresenter(replaceMode, null, null, this); |
| } |
| |
| /** |
| * Replacing is supported. |
| */ |
| @Override |
| public boolean isReplaceSupported() { |
| return true; |
| } |
| |
| /** |
| * This search provider is always enabled. |
| */ |
| @Override |
| public boolean isEnabled() { |
| return true; |
| } |
| |
| public static Presenter createBasicPresenter(boolean replacing) { |
| return new BasicSearchPresenter(replacing, null, null); |
| } |
| |
| public static Presenter createBasicPresenter( |
| boolean replacing, |
| @NullAllowed SearchPattern searchPattern, |
| @NullAllowed String replaceString, |
| @NullAllowed Boolean preserveCase, |
| @NullAllowed SearchScopeOptions searchScopeOptions, |
| @NullAllowed Boolean useIgnoreList, |
| @NullAllowed String scopeId, |
| @NonNull SearchScopeDefinition... extraSearchScopes |
| ) { |
| BasicSearchCriteria bsc = createCriteria(searchScopeOptions, |
| useIgnoreList, searchPattern, preserveCase, replacing, |
| replaceString); |
| return new BasicSearchPresenter(replacing, scopeId, bsc, |
| extraSearchScopes); |
| } |
| |
| @Override |
| public String getTitle() { |
| return UiUtils.getText("BasicSearchForm.tabText"); //NOI18N |
| } |
| |
| /** |
| * |
| */ |
| private static class BasicSearchPresenter |
| extends BasicSearchProvider.Presenter { |
| |
| BasicSearchForm form = null; |
| private String scopeId; |
| private BasicSearchCriteria explicitCriteria; |
| private SearchScopeDefinition[] extraSearchScopes; |
| private boolean wasUsableAlready = false; |
| |
| public BasicSearchPresenter(boolean replacing, String scopeId, |
| BasicSearchCriteria explicitCriteria, |
| SearchScopeDefinition... extraSearchScopes) { |
| this(replacing, scopeId, explicitCriteria, |
| Lookup.getDefault().lookup(BasicSearchProvider.class), |
| extraSearchScopes); |
| } |
| |
| public BasicSearchPresenter(boolean replacing, String scopeId, |
| BasicSearchCriteria explicitCriteria, |
| BasicSearchProvider provider, |
| SearchScopeDefinition... extraSearchScopes) { |
| super(provider, replacing); |
| this.scopeId = scopeId; |
| this.explicitCriteria = explicitCriteria; |
| this.extraSearchScopes = extraSearchScopes; |
| } |
| |
| @Override |
| public JComponent getForm() { |
| if (form == null) { |
| String scopeToUse = chooseSearchScope(scopeId); |
| form = new BasicSearchForm(scopeToUse, isReplacing(), |
| explicitCriteria, extraSearchScopes); |
| form.setUsabilityChangeListener(new ChangeListener() { |
| @Override |
| public void stateChanged(ChangeEvent e) { |
| fireChange(); |
| } |
| }); |
| } |
| return form; |
| } |
| |
| private String chooseSearchScope(String preferredscopeId) { |
| return preferredscopeId == null |
| ? FindDialogMemory.getDefault().getScopeTypeId() |
| : preferredscopeId; |
| } |
| |
| @Override |
| public HelpCtx getHelpCtx() { |
| return new HelpCtx(SearchPanel.class.getCanonicalName() |
| + "." + isReplacing()); //NOI18N |
| } |
| |
| @Override |
| public SearchComposition<Def> composeSearch() { |
| |
| String msg = Manager.getInstance().mayStartSearching(); |
| if (msg != null) { |
| /* |
| * Search cannot be started, for example because the replace |
| * operation has not finished yet. |
| */ |
| DialogDisplayer.getDefault().notify( |
| new NotifyDescriptor.Message( |
| msg, |
| NotifyDescriptor.INFORMATION_MESSAGE)); |
| return null; |
| } |
| |
| form.onOk(); |
| BasicSearchCriteria basicSearchCriteria = |
| form.getBasicSearchCriteria(); |
| |
| SearchScopeOptions so = basicSearchCriteria.getSearcherOptions(); |
| if (basicSearchCriteria.isUseIgnoreList()) { |
| so.addFilter(new IgnoreListFilter()); |
| } |
| SearchInfo ssi = form.getSearchInfo(); |
| AbstractMatcher am = new DefaultMatcher( |
| basicSearchCriteria.getSearchPattern()); |
| am.setStrict(isReplacing()); |
| return new BasicComposition( |
| ssi, am, basicSearchCriteria, form.getSelectedScopeName()); |
| } |
| |
| @Override |
| public boolean isUsable(NotificationLineSupport notifySupport) { |
| boolean usable = form.isUsable(); |
| BasicSearchCriteria bsc = form.getBasicSearchCriteria(); |
| if (!usable) { |
| String msg; |
| if (bsc.isTextPatternInvalid()) { |
| msg = "BasicSearchForm.txtErrorTextPattern"; //NOI18N |
| } else if (bsc.isSearchAndReplace() |
| && bsc.isReplacePatternInvalid()) { |
| msg = "BasicSearchForm.txtErrorReplacePattern"; //NOI18N |
| } else if (bsc.isFileNamePatternInvalid()) { |
| msg = "BasicSearchForm.txtErrorFileName"; //NOI18N |
| } else { |
| msg = "BasicSearchForm.txtErrorMissingCriteria"; //NOI18N |
| if (!wasUsableAlready) { // #212614 |
| notifySupport.setInformationMessage( |
| UiUtils.getText(msg)); |
| return false; |
| } |
| } |
| notifySupport.setErrorMessage(UiUtils.getText(msg)); |
| } else { |
| wasUsableAlready = true; |
| if (!bsc.isFileNameRegexp() |
| && !bsc.getFileNamePatternExpr().isEmpty() |
| && bsc.getFileNamePatternExpr().matches( |
| "^[\\w-]*$")) { //NOI18N |
| notifySupport.setInformationMessage(UiUtils.getText( |
| "BasicSearchForm.txtInfoNoWildcards")); //NOI18N |
| } else { |
| notifySupport.clearMessages(); |
| } |
| } |
| return usable; |
| } |
| |
| @Override |
| public void clean() { |
| super.clean(); |
| } |
| } |
| |
| private static class IgnoreListFilter extends SearchFilterDefinition { |
| |
| private IgnoreListManager ignoreListManager; |
| |
| @Override |
| public boolean searchFile(FileObject file) |
| throws IllegalArgumentException { |
| if (file.isFolder()) { |
| throw new IllegalArgumentException(file |
| + " is folder, but should be regular file."); //NOI18N |
| } |
| return !isIgnored(file); |
| } |
| |
| @Override |
| public FolderResult traverseFolder(FileObject folder) |
| throws IllegalArgumentException { |
| if (!folder.isFolder()) { |
| throw new IllegalArgumentException(folder |
| + " is file, but should be folder."); //NOI18N |
| } |
| if (isIgnored(folder)) { |
| return FolderResult.DO_NOT_TRAVERSE; |
| } else { |
| return FolderResult.TRAVERSE; |
| } |
| } |
| |
| /** |
| * Check whether the passed file object should be ignored. Use global |
| * ignore list. |
| * |
| * @return true if the file object is ignored, false otherwise. |
| */ |
| private boolean isIgnored(FileObject fileObj) { |
| return getIgnoreListManager().isIgnored(fileObj); |
| } |
| |
| /** |
| * Get ignore list manager. If not yet initialized, initialize it. |
| */ |
| IgnoreListPanel.IgnoreListManager getIgnoreListManager() { |
| if (ignoreListManager == null) { |
| List<String> il = FindDialogMemory.getDefault().getIgnoreList(); |
| ignoreListManager = new IgnoreListPanel.IgnoreListManager(il); |
| } |
| return ignoreListManager; |
| } |
| } |
| |
| /** |
| * Start a search task with specified parameters. |
| */ |
| public static void startSearch( |
| @NonNull SearchPattern searchPattern, |
| @NonNull SearchScopeOptions searchScopeOptions, |
| @NullAllowed String scopeId) throws IllegalArgumentException { |
| |
| BasicSearchCriteria criteria = createCriteria(searchScopeOptions, |
| Boolean.FALSE, searchPattern, null, false, null); |
| if (!criteria.isUsable()) { |
| throw new IllegalArgumentException( |
| "Search cannot be started - No restrictions set."); //NOI18N |
| } |
| SearchScopeDefinition bestScope = findBestSearchScope(scopeId); |
| BasicComposition composition = new BasicComposition( |
| bestScope.getSearchInfo(), new DefaultMatcher(searchPattern), |
| criteria, null); |
| Manager.getInstance().scheduleSearchTask( |
| new SearchTask(composition, false)); |
| } |
| |
| /** |
| * Create basic search criteria instance for passed arguments. |
| */ |
| private static BasicSearchCriteria createCriteria( |
| SearchScopeOptions searchScopeOptions, Boolean useIgnoreList, |
| SearchPattern searchPattern, Boolean preserveCase, |
| boolean replacing, String replaceString) { |
| BasicSearchCriteria bsc = new BasicSearchCriteria(); |
| bsc.setFileNamePattern(searchScopeOptions.getPattern()); |
| bsc.setFileNameRegexp(searchScopeOptions.isRegexp()); |
| bsc.setTextPattern(searchPattern.getSearchExpression()); |
| bsc.setCaseSensitive(searchPattern.isMatchCase()); |
| bsc.setWholeWords(searchPattern.isWholeWords()); |
| bsc.setMatchType(searchPattern.getMatchType()); |
| if (preserveCase != null) { |
| bsc.setPreserveCase(preserveCase); |
| } |
| if (useIgnoreList != null) { |
| bsc.setUseIgnoreList(useIgnoreList); |
| } |
| if (replacing) { |
| bsc.setReplaceExpr(replaceString); |
| } else { |
| bsc.setSearchInArchives(searchScopeOptions.isSearchInArchives()); |
| bsc.setSearchInGenerated(searchScopeOptions.isSearchInGenerated()); |
| } |
| return bsc; |
| } |
| |
| /** |
| * Find best available search scope. |
| */ |
| private static SearchScopeDefinition findBestSearchScope( |
| String preferredscopeId) throws IllegalStateException { |
| SearchScopeList ssl = new SearchScopeList(); |
| SearchScopeDefinition bestScope = null; |
| for (SearchScopeDefinition ssd : ssl.getSeachScopeDefinitions()) { |
| if (ssd.isApplicable()) { |
| if (preferredscopeId != null && ssd.getTypeId().equals(preferredscopeId)) { |
| bestScope = ssd; |
| break; |
| } else if (bestScope == null) { |
| bestScope = ssd; |
| } |
| } |
| } |
| if (bestScope == null) { |
| throw new IllegalStateException("No default search scope"); //NOI18N |
| } |
| return bestScope; |
| } |
| |
| /** |
| * Create filter for actual ignore list. |
| */ |
| public static SearchFilterDefinition getIgnoreListFilter() { |
| return new IgnoreListFilter(); |
| } |
| } |