diff options
Diffstat (limited to 'platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java')
-rw-r--r-- | platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java new file mode 100644 index 000000000000..1885a852c5da --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsFilter.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed 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 com.intellij.openapi.options.newEditor; + +import com.intellij.ide.ui.search.ConfigurableHit; +import com.intellij.ide.ui.search.SearchableOptionsRegistrar; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurableGroup; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.ui.DocumentAdapter; +import com.intellij.ui.LightColors; +import com.intellij.ui.SearchTextField; +import com.intellij.ui.speedSearch.ElementFilter; +import com.intellij.ui.treeStructure.SimpleNode; +import com.intellij.util.ui.UIUtil; + +import javax.swing.event.DocumentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Set; + +abstract class SettingsFilter extends ElementFilter.Active.Impl<SimpleNode> { + final OptionsEditorContext myContext = new OptionsEditorContext(this); + final Project myProject; + + boolean myDocumentWasChanged; + + private final SearchTextField mySearch; + private final ConfigurableGroup[] myGroups; + + private SearchableOptionsRegistrar myRegistrar = SearchableOptionsRegistrar.getInstance(); + private Set<Configurable> myFiltered; + private ConfigurableHit myHits; + + private boolean myUpdateRejected; + private Configurable myLastSelected; + + SettingsFilter(Project project, ConfigurableGroup[] groups, SearchTextField search) { + myProject = project; + myGroups = groups; + mySearch = search; + mySearch.addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent event) { + update(event.getType(), true, false); + } + }); + mySearch.getTextEditor().addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent event) { + if (!mySearch.getText().isEmpty()) { + if (!myContext.isHoldingFilter()) { + setHoldingFilter(true); + } + if (!mySearch.getTextEditor().isFocusOwner()) { + mySearch.selectText(); + } + } + } + }); + } + + abstract Configurable getConfigurable(SimpleNode node); + + abstract SimpleNode findNode(Configurable configurable); + + abstract void updateSpotlight(boolean now); + + @Override + public boolean shouldBeShowing(SimpleNode node) { + if (myFiltered != null) { + Configurable configurable = getConfigurable(node); + if (configurable != null) { + if (!myFiltered.contains(configurable)) { + if (myHits != null) { + Set<Configurable> configurables = myHits.getNameFullHits(); + while (node != null) { + if (configurable != null) { + if (configurables.contains(configurable)) { + return true; + } + } + node = node.getParent(); + configurable = getConfigurable(node); + } + } + return false; + } + } + } + return true; + } + + String getFilterText() { + String text = mySearch.getText(); + return text == null ? "" : text.trim(); + } + + void setHoldingFilter(boolean holding) { + myContext.setHoldingFilter(holding); + updateSpotlight(false); + } + + boolean contains(Configurable configurable) { + return myHits != null && myHits.getNameHits().contains(configurable); + } + + ActionCallback update(boolean adjustSelection, boolean now) { + return update(DocumentEvent.EventType.CHANGE, adjustSelection, now); + } + + ActionCallback update(String text, boolean adjustSelection, boolean now) { + try { + myUpdateRejected = true; + mySearch.setText(text); + } + finally { + myUpdateRejected = false; + } + return update(adjustSelection, now); + } + + private ActionCallback update(DocumentEvent.EventType type, boolean adjustSelection, boolean now) { + if (myUpdateRejected) { + return new ActionCallback.Rejected(); + } + String text = getFilterText(); + if (text.isEmpty()) { + myContext.setHoldingFilter(false); + myFiltered = null; + } + else { + myContext.setHoldingFilter(true); + myHits = myRegistrar.getConfigurables(myGroups, type, myFiltered, text, myProject); + myFiltered = myHits.getAll(); + } + mySearch.getTextEditor().setBackground(myFiltered != null && myFiltered.isEmpty() + ? LightColors.RED + : UIUtil.getTextFieldBackground()); + + + Configurable current = myContext.getCurrentConfigurable(); + + boolean shouldMoveSelection = myHits == null || ( + !myHits.getNameFullHits().contains(current) && + !myHits.getContentHits().contains(current)); + + if (shouldMoveSelection && type != DocumentEvent.EventType.INSERT && (myFiltered == null || myFiltered.contains(current))) { + shouldMoveSelection = false; + } + + Configurable candidate = adjustSelection ? current : null; + if (shouldMoveSelection && myHits != null) { + if (!myHits.getNameHits().isEmpty()) { + candidate = findConfigurable(myHits.getNameHits(), myHits.getNameFullHits()); + } + else if (!myHits.getContentHits().isEmpty()) { + candidate = findConfigurable(myHits.getContentHits(), null); + } + } + updateSpotlight(false); + + if ((myFiltered == null || !myFiltered.isEmpty()) && candidate == null && myLastSelected != null) { + candidate = myLastSelected; + myLastSelected = null; + } + if (candidate == null && current != null) { + myLastSelected = current; + } + SimpleNode node = !adjustSelection ? null : findNode(candidate); + ActionCallback callback = fireUpdate(node, adjustSelection, now); + myDocumentWasChanged = true; + return callback; + } + + private static Configurable findConfigurable(Set<Configurable> configurables, Set<Configurable> hits) { + Configurable candidate = null; + for (Configurable configurable : configurables) { + if (hits != null && hits.contains(configurable)) { + return configurable; + } + if (candidate == null && !isEmptyParent(configurable)) { + candidate = configurable; + } + } + return candidate; + } + + private static boolean isEmptyParent(Configurable configurable) { + if (configurable instanceof SearchableConfigurable.Parent) { + SearchableConfigurable.Parent parent = (SearchableConfigurable.Parent)configurable; + return !parent.hasOwnContent(); + } + return false; + } +} |