diff --git a/platform/lang-impl/src/com/intellij/ui/EditorTextFieldActionPromoter.java b/platform/lang-impl/src/com/intellij/ui/EditorTextFieldActionPromoter.java new file mode 100644 index 000000000000..813b0c9e4ad3 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ui/EditorTextFieldActionPromoter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2013 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.ui; + +import com.intellij.openapi.actionSystem.ActionPromoter; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.editor.actionSystem.EditorAction; +import com.intellij.openapi.editor.actions.TextComponentEditorAction; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class EditorTextFieldActionPromoter implements ActionPromoter { + /** + * Encapsulates sorting rule that defines what editor actions have precedence to non-editor actions. Current approach is that + * we want to process text processing-oriented editor actions with higher priority than non-editor actions and all + * other editor actions with lower priority. + *

+ * Rationale: there is at least one commit-specific action that is mapped to the editor action by default + * ('show commit messages history' vs 'scroll to center'). We want to process the former on target + * short key triggering. Another example is that {@code 'Ctrl+Shift+Right/Left Arrow'} shortcut is bound to + * 'expand/reduce selection by word' editor action and 'change dialog width' non-editor action + * and we want to use the first one. + */ + private static final Comparator ACTIONS_COMPARATOR = new Comparator() { + @Override + public int compare(AnAction o1, AnAction o2) { + if (o1 instanceof EditorAction && o2 instanceof EditorAction) { + return 0; + } + if (o1 instanceof TextComponentEditorAction) { + return -1; + } + if (o2 instanceof TextComponentEditorAction) { + return 1; + } + if (o1 instanceof EditorAction) { + return 1; + } + if (o2 instanceof EditorAction) { + return -1; + } + return 0; + } + }; + + @Override + public List promote(List actions, DataContext context) { + Collections.sort(actions, ACTIONS_COMPARATOR); + return actions; + } +} diff --git a/platform/lang-impl/src/com/intellij/ui/EditorTextFieldProviderImpl.java b/platform/lang-impl/src/com/intellij/ui/EditorTextFieldProviderImpl.java index bbdfcc5ed43b..c55bc2b04972 100644 --- a/platform/lang-impl/src/com/intellij/ui/EditorTextFieldProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/EditorTextFieldProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -16,17 +16,12 @@ package com.intellij.ui; import com.intellij.lang.Language; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.EditorSettings; -import com.intellij.openapi.editor.actionSystem.EditorAction; -import com.intellij.openapi.editor.actions.TextComponentEditorAction; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.Comparator; /** * Provides default implementation for {@link EditorTextFieldProvider} service and applies available @@ -36,40 +31,6 @@ import java.util.Comparator; * @since Aug 20, 2010 3:21:03 PM */ public class EditorTextFieldProviderImpl implements EditorTextFieldProvider { - - /** - * Encapsulates sorting rule that defines what editor actions have precedence to non-editor actions. Current approach is that - * we want to process text processing-oriented editor actions with higher priority than non-editor actions and all - * other editor actions with lower priority. - *

- * Rationale: there is at least one commit-specific action that is mapped to the editor action by default - * ('show commit messages history' vs 'scroll to center'). We want to process the former on target - * short key triggering. Another example is that {@code 'Ctrl+Shift+Right/Left Arrow'} shortcut is bound to - * 'expand/reduce selection by word' editor action and 'change dialog width' non-editor action - * and we want to use the first one. - */ - private static final Comparator ACTIONS_COMPARATOR = new Comparator() { - @Override - public int compare(AnAction o1, AnAction o2) { - if (o1 instanceof EditorAction && o2 instanceof EditorAction) { - return 0; - } - if (o1 instanceof TextComponentEditorAction) { - return -1; - } - if (o2 instanceof TextComponentEditorAction) { - return 1; - } - if (o1 instanceof EditorAction) { - return 1; - } - if (o2 instanceof EditorAction) { - return -1; - } - return 0; - } - }; - @NotNull @Override public EditorTextField getEditorField(@NotNull Language language, @NotNull Project project, @@ -112,13 +73,5 @@ public class EditorTextFieldProviderImpl implements EditorTextFieldProvider { protected boolean isOneLineMode() { return false; } - - @Override - public Object getData(String dataId) { - if (PlatformDataKeys.ACTIONS_SORTER.is(dataId)) { - return ACTIONS_COMPARATOR; - } - return super.getData(dataId); - } } } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPromoter.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPromoter.java new file mode 100644 index 000000000000..3cd89d050121 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPromoter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2013 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.actionSystem; + +import com.intellij.openapi.extensions.ExtensionPointName; + +import java.util.List; + +/** + * It's allowed to assign multiple actions to the same keyboard shortcut. Actions system filters them on the current + * context basis during processing (e.g. we can have two actions assigned to the same shortcut but one of them is + * configured to be inapplicable in modal dialog context). + *

+ * However, there is a possible case that there is still more than one action applicable for particular keyboard shortcut + * after filtering. The first one is executed then. Hence, actions processing order becomes very important. + *

+ * Current extension point allows to promote custom actions to use if any depending on data context + * + * @author Konstantin Bulenkov + * @since 13 + */ +public interface ActionPromoter { + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.actionPromoter"); + + List promote(List actions, DataContext context); +} diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/PlatformDataKeys.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/PlatformDataKeys.java index 9b3074069e2f..dbb278712aff 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/PlatformDataKeys.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/PlatformDataKeys.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -98,6 +98,9 @@ public class PlatformDataKeys extends CommonDataKeys { *

* Current key allows to specify custom actions sorter to use if any. I.e. every component can define it's custom * sorting rule in order to define priorities for target actions (classes of actions). + * + * @deprecated use com.intellij.openapi.actionSystem.ActionPromoter */ + @Deprecated public static final DataKey> ACTIONS_SORTER = DataKey.create("actionsSorter"); } diff --git a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java index 8cec64aade01..0cd82455a683 100644 --- a/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/ToolbarDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -15,8 +15,10 @@ */ package com.intellij.ui; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.ActionToolbarPosition; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; @@ -25,7 +27,6 @@ import com.intellij.ui.table.TableView; import com.intellij.util.ui.EditableModel; import com.intellij.util.ui.ElementProducer; import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,19 +44,7 @@ import java.util.List; * @see #createDecorator(javax.swing.JTree) */ @SuppressWarnings("UnusedDeclaration") -public abstract class ToolbarDecorator implements DataProvider, CommonActionsPanel.ListenerFactory { - private static final Comparator ACTION_BUTTONS_SORTER = new Comparator() { - @Override - public int compare(AnAction a1, AnAction a2) { - if (a1 instanceof AnActionButton && a2 instanceof AnActionButton) { - final JComponent c1 = ((AnActionButton)a1).getContextComponent(); - final JComponent c2 = ((AnActionButton)a2).getContextComponent(); - return c1.hasFocus() ? -1 : c2.hasFocus() ? 1 : 0; - } - return 0; - } - }; - +public abstract class ToolbarDecorator implements CommonActionsPanel.ListenerFactory { protected Border myToolbarBorder; protected boolean myAddActionEnabled; protected boolean myEditActionEnabled; @@ -340,7 +329,6 @@ public abstract class ToolbarDecorator implements DataProvider, CommonActionsPan updateButtons(); installDnD(); panel.putClientProperty(ActionToolbar.ACTION_TOOLBAR_PROPERTY_KEY, myActionsPanel.getComponent(0)); - DataManager.registerDataProvider(panel, this); if (myAsUsualTopToolbar) { scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.ALL)); } else { @@ -381,14 +369,6 @@ public abstract class ToolbarDecorator implements DataProvider, CommonActionsPan protected abstract boolean isModelEditable(); - @Override - public Object getData(@NonNls String dataId) { - if (PlatformDataKeys.ACTIONS_SORTER.is(dataId)) { - return ACTION_BUTTONS_SORTER; - } - return null; - } - private Object getPlacement() { switch (myToolbarPosition) { case TOP: return BorderLayout.NORTH; diff --git a/platform/platform-api/src/com/intellij/ui/ToolbarDecoratorActionPromoter.java b/platform/platform-api/src/com/intellij/ui/ToolbarDecoratorActionPromoter.java new file mode 100644 index 000000000000..53e0769da4b2 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/ToolbarDecoratorActionPromoter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2013 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.ui; + +import com.intellij.openapi.actionSystem.ActionPromoter; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DataContext; + +import javax.swing.*; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class ToolbarDecoratorActionPromoter implements ActionPromoter { + private static final Comparator ACTION_BUTTONS_SORTER = new Comparator() { + @Override + public int compare(AnAction a1, AnAction a2) { + if (a1 instanceof AnActionButton && a2 instanceof AnActionButton) { + final JComponent c1 = ((AnActionButton)a1).getContextComponent(); + final JComponent c2 = ((AnActionButton)a2).getContextComponent(); + return c1.hasFocus() ? -1 : c2.hasFocus() ? 1 : 0; + } + return 0; + } + }; + + @Override + public List promote(List actions, DataContext context) { + Collections.sort(actions, ACTION_BUTTONS_SORTER); + return actions; + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java index a9400602ba72..07caf52cad82 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -712,10 +712,16 @@ public final class IdeKeyEventDispatcher implements Disposable { } myContext.setHasSecondStroke(hasSecondStroke); + final List actions = myContext.getActions(); - Comparator comparator = PlatformDataKeys.ACTIONS_SORTER.getData(myContext.getDataContext()); - if (comparator != null) { - Collections.sort(myContext.getActions(), comparator); + if (actions.size() > 1) { + for (ActionPromoter promoter : ActionPromoter.EP_NAME.getExtensions()) { + final List promoted = promoter.promote(actions, myContext.getDataContext()); + if (promoted == actions || promoted.isEmpty()) continue; + + actions.removeAll(promoted); + actions.addAll(0, promoted); + } } return myContext; diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index ad4f99f42640..a232b2858ee0 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -855,6 +855,8 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index 951c4ef4db8c..097168f2cf29 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -118,6 +118,8 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 12869478ffcc..05d740c86e0f 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -310,5 +310,6 @@ +