diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesActions.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesActions.java index e2a5e91c795e..e87a560b1a0b 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesActions.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesActions.java @@ -18,7 +18,7 @@ package com.intellij.application.options.codeStyle; import com.intellij.application.options.SaveSchemeDialog; import com.intellij.application.options.SchemesToImportPopup; import com.intellij.application.options.schemes.AbstractSchemesPanel; -import com.intellij.application.options.schemes.DefaultSchemeActions; +import com.intellij.application.options.schemes.AbstractSchemeActions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; @@ -44,7 +44,7 @@ import java.io.OutputStream; import java.util.Collection; import java.util.List; -abstract class CodeStyleSchemesActions extends DefaultSchemeActions { +abstract class CodeStyleSchemesActions extends AbstractSchemeActions { private final static String SHARED_IMPORT_SOURCE = ApplicationBundle.message("import.scheme.shared"); @@ -135,16 +135,6 @@ abstract class CodeStyleSchemesActions extends DefaultSchemeActions @Override - protected DefaultSchemeActions createSchemeActions() { + protected AbstractSchemeActions createSchemeActions() { return new CodeStyleSchemesActions(this) { @@ -103,23 +105,61 @@ public class CodeStyleSchemesPanel extends AbstractSchemesPanel return myModel; } - @Nullable - @Override - protected CodeStyleScheme getCurrentScheme() { - return getSelectedScheme(); - } - - @Override - public SchemeLevel getSchemeLevel(@NotNull CodeStyleScheme scheme) { - return myModel.isProjectScheme(scheme) ? SchemeLevel.Project : SchemeLevel.IDE; - } - @Override protected void onSchemeChanged(@Nullable CodeStyleScheme scheme) { if (!myIsReset) { ApplicationManager.getApplication().invokeLater(() -> onCombo()); } } + + @Override + protected void doRename(@NotNull CodeStyleScheme scheme, @NotNull String newName) { + CodeStyleSchemeImpl newScheme = new CodeStyleSchemeImpl(newName, false, scheme); + myModel.addScheme(newScheme, false); + myModel.removeScheme(scheme); + myModel.selectScheme(newScheme, null); + } }; } + + @Override + public SchemeListItem createItem(@NotNull CodeStyleScheme scheme) { + return new SchemeListItem(scheme) { + @Override + public boolean isDuplicateAvailable() { + return !myModel.isProjectScheme(scheme); + } + + @Override + public boolean isResetAvailable() { + return true; + } + + @Override + public boolean isDeleteAvailable() { + return !myModel.isProjectScheme(scheme) && !scheme.isDefault(); + } + + @Override + public SchemeLevel getSchemeLevel() { + return myModel.isProjectScheme(scheme) ? SchemeLevel.Project : SchemeLevel.IDE; + } + + @Override + public boolean isRenameAvailable() { + return isDeleteAvailable(); + } + + @Nullable + @Override + public String validateSchemeName(@NotNull String name) { + for (CodeStyleScheme scheme : myModel.getSchemes()) { + if (name.equals(scheme.getName()) && scheme != getScheme()) { + return NAME_ALREADY_EXISTS_MESSAGE; + } + } + return super.validateSchemeName(name); + } + }; + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 538a4348db07..57f96fd7c749 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -201,22 +201,30 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract public void saveSchemeAs(String name) { MyColorScheme scheme = mySelectedScheme; if (scheme == null) return; + saveSchemeAs(scheme, name); + } - EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone(); - scheme.apply(clone); - if (clone instanceof AbstractColorsScheme) { - ((AbstractColorsScheme)clone).setSaveNeeded(true); + public boolean saveSchemeAs(@NotNull EditorColorsScheme editorScheme, @NotNull String name) { + if (editorScheme instanceof MyColorScheme) { + MyColorScheme scheme = (MyColorScheme)editorScheme; + EditorColorsScheme clone = (EditorColorsScheme)scheme.getOriginalScheme().clone(); + scheme.apply(clone); + if (clone instanceof AbstractColorsScheme) { + ((AbstractColorsScheme)clone).setSaveNeeded(true); + } + + clone.setName(name); + MyColorScheme newScheme = new MyColorScheme(clone); + initScheme(newScheme); + + newScheme.setIsNew(); + + mySchemes.put(name, newScheme); + selectScheme(newScheme.getName()); + resetSchemesCombo(null); + return true; } - - clone.setName(name); - MyColorScheme newScheme = new MyColorScheme(clone); - initScheme(newScheme); - - newScheme.setIsNew(); - - mySchemes.put(name, newScheme); - selectScheme(newScheme.getName()); - resetSchemesCombo(null); + return false; } public void addImportedScheme(@NotNull EditorColorsScheme imported) { diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorSchemeActions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorSchemeActions.java index 35ae024a02d6..3ea549e16874 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorSchemeActions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorSchemeActions.java @@ -17,13 +17,12 @@ package com.intellij.application.options.colors; import com.intellij.application.options.SaveSchemeDialog; import com.intellij.application.options.schemes.AbstractSchemesPanel; -import com.intellij.application.options.schemes.DefaultSchemeActions; +import com.intellij.application.options.schemes.AbstractSchemeActions; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.impl.AbstractColorsScheme; import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl; import com.intellij.openapi.editor.colors.impl.EmptyColorScheme; -import com.intellij.openapi.editor.colors.impl.ReadOnlyColorsScheme; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.options.*; import com.intellij.openapi.project.DefaultProjectFactory; @@ -37,7 +36,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -public abstract class ColorSchemeActions extends DefaultSchemeActions { +public abstract class ColorSchemeActions extends AbstractSchemeActions { protected ColorSchemeActions(@NotNull AbstractSchemesPanel schemesPanel) { super(schemesPanel); @@ -120,21 +119,6 @@ public abstract class ColorSchemeActions extends DefaultSchemeActions imple } @Override - protected DefaultSchemeActions createSchemeActions() { + protected AbstractSchemeActions createSchemeActions() { return new ColorSchemeActions(this) { @@ -92,19 +96,62 @@ public class SchemesPanel extends AbstractSchemesPanel imple } } - @Nullable @Override - protected EditorColorsScheme getCurrentScheme() { - EditorColorsScheme selectedScheme = getSelectedScheme(); - return selectedScheme != null ? myOptions.getScheme(selectedScheme.getName()) : null; - } - - @Override - public SchemeLevel getSchemeLevel(@NotNull EditorColorsScheme scheme) { - return SchemeLevel.IDE_Only; + protected void doRename(@NotNull EditorColorsScheme scheme, @NotNull String newName) { + if (myOptions.saveSchemeAs(scheme, newName)) { + myOptions.removeScheme(scheme.getName()); + myOptions.selectScheme(newName); + } } }; } - + + @Override + public SchemeListItem createItem(@NotNull EditorColorsScheme scheme) { + return new SchemeListItem(scheme) { + @Override + public boolean isDuplicateAvailable() { + return true; + } + + @Override + public boolean isResetAvailable() { + AbstractColorsScheme originalScheme = + scheme instanceof AbstractColorsScheme ? ((AbstractColorsScheme)scheme).getOriginal() : null; + return + !ColorAndFontOptions.isReadOnly(scheme) && + scheme.getName().startsWith(SchemeManager.EDITABLE_COPY_PREFIX) && + originalScheme instanceof ReadOnlyColorsScheme; + } + + @Override + public boolean isDeleteAvailable() { + return !ColorAndFontOptions.isReadOnly(scheme) && ColorAndFontOptions.canBeDeleted(scheme); + } + + @Override + public SchemeLevel getSchemeLevel() { + return SchemeLevel.IDE_Only; + } + + @Override + public boolean isRenameAvailable() { + return isDeleteAvailable(); + } + + @Nullable + @Override + public String validateSchemeName(@NotNull String name) { + EditorColorsScheme scheme = myOptions.getScheme(name); + if (scheme == null) { + scheme = myOptions.getScheme(SchemeManager.EDITABLE_COPY_PREFIX + name); + } + if (scheme != null && name.equals(SchemeManager.getDisplayName(scheme)) && scheme != getScheme()) { + return NAME_ALREADY_EXISTS_MESSAGE; + } + return super.validateSchemeName(name); + } + }; + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/DefaultSchemeActions.java b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java similarity index 84% rename from platform/lang-impl/src/com/intellij/application/options/schemes/DefaultSchemeActions.java rename to platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java index b3addab2ce9e..66d977b691d6 100644 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/DefaultSchemeActions.java +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java @@ -30,16 +30,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -public abstract class DefaultSchemeActions { +public abstract class AbstractSchemeActions { private final Collection mySchemeImportersNames; private final Collection mySchemeExporterNames; private AbstractSchemesPanel mySchemesPanel; - public enum SchemeLevel { - IDE_Only, IDE, Project - } - - protected DefaultSchemeActions(@NotNull AbstractSchemesPanel schemesPanel) { + protected AbstractSchemeActions(@NotNull AbstractSchemesPanel schemesPanel) { mySchemesPanel = schemesPanel; mySchemeImportersNames = getSchemeImportersNames(); mySchemeExporterNames = getSchemeExporterNames(); @@ -65,6 +61,7 @@ public abstract class DefaultSchemeActions { public final Collection getActions() { List actions = new ArrayList<>(); actions.add(new CopyAction()); + actions.add(new RenameAction()); actions.add(new ResetAction()); actions.add(new DeleteAction()); if (!mySchemeExporterNames.isEmpty()) { @@ -109,8 +106,8 @@ public abstract class DefaultSchemeActions { @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - T currentScheme = getCurrentScheme(); - p.setEnabled(currentScheme != null && isResetAvailable(currentScheme)); + SchemeListItem item = mySchemesPanel.getSelectedItem(); + p.setEnabled(item != null && item.isResetAvailable()); } } @@ -131,8 +128,30 @@ public abstract class DefaultSchemeActions { @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); + SchemeListItem item = mySchemesPanel.getSelectedItem(); + p.setEnabledAndVisible(item != null && item.isDuplicateAvailable()); + } + } + + + private class RenameAction extends DumbAwareAction { + public RenameAction() { + super("Rename..."); + } + + @Override + public void actionPerformed(AnActionEvent e) { T currentScheme = getCurrentScheme(); - p.setEnabledAndVisible(currentScheme != null && isCopyToAvailable(currentScheme)); + if (currentScheme != null) { + mySchemesPanel.startEdit(); + } + } + + @Override + public void update(AnActionEvent e) { + Presentation p = e.getPresentation(); + SchemeListItem item = mySchemesPanel.getSelectedItem(); + p.setEnabled(item != null && item.isRenameAvailable()); } } @@ -152,8 +171,8 @@ public abstract class DefaultSchemeActions { @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - T currentScheme = getCurrentScheme(); - p.setEnabledAndVisible(currentScheme != null && isDeleteAvailable(currentScheme)); + SchemeListItem item = mySchemesPanel.getSelectedItem(); + p.setEnabledAndVisible(item != null && item.isDeleteAvailable()); } } @@ -225,29 +244,21 @@ public abstract class DefaultSchemeActions { protected abstract void doDelete(@NotNull T scheme); - protected abstract boolean isDeleteAvailable(@NotNull T scheme); - - protected boolean isResetAvailable(@NotNull T scheme) { - return true; - } - - protected boolean isCopyToAvailable(@NotNull T scheme) { - return true; - } - protected abstract void doExport(@NotNull T scheme, @NotNull String exporterName); - + protected abstract void onSchemeChanged(@Nullable T scheme); + protected abstract void doRename(@NotNull T scheme, @NotNull String newName); + @Nullable - protected abstract T getCurrentScheme(); + protected final T getCurrentScheme() { + return mySchemesPanel.getSelectedScheme(); + } protected abstract Class getSchemeType(); public AbstractSchemesPanel getSchemesPanel() { return mySchemesPanel; } - - public abstract SchemeLevel getSchemeLevel(@NotNull T scheme); } diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemesPanel.java b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemesPanel.java index 79ff67e07031..633c81c135e6 100644 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemesPanel.java @@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.options.Scheme; import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.ui.MessageType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,11 +28,12 @@ import javax.swing.*; import java.awt.*; import java.util.Collection; -public abstract class AbstractSchemesPanel extends JPanel { +public abstract class AbstractSchemesPanel extends JPanel implements SchemeListItemFactory { private SchemesCombo mySchemesCombo; - private DefaultSchemeActions myActions; + private AbstractSchemeActions myActions; private JComponent myToolbar; + private JLabel myInfoLabel; public AbstractSchemesPanel() { setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -44,11 +46,14 @@ public abstract class AbstractSchemesPanel extends JPanel { controlsPanel.add(new JLabel(ApplicationBundle.message("editbox.scheme.name"))); controlsPanel.add(Box.createRigidArea(new Dimension(10, 0))); myActions = createSchemeActions(); - mySchemesCombo = new SchemesCombo<>(myActions); - controlsPanel.add(mySchemesCombo.getComboBox()); + mySchemesCombo = new SchemesCombo<>(this); + controlsPanel.add(mySchemesCombo.getComponent()); myToolbar = createToolbar(); controlsPanel.add(myToolbar); - controlsPanel.setMaximumSize(new Dimension(controlsPanel.getMaximumSize().width, mySchemesCombo.getComboBox().getPreferredSize().height)); + myInfoLabel = new JLabel(); + controlsPanel.add(myInfoLabel); + controlsPanel.add(Box.createHorizontalGlue()); + controlsPanel.setMaximumSize(new Dimension(controlsPanel.getMaximumSize().width, mySchemesCombo.getComponent().getPreferredSize().height)); add(controlsPanel); add(Box.createVerticalGlue()); add(Box.createRigidArea(new Dimension(0, 10))); @@ -58,7 +63,9 @@ public abstract class AbstractSchemesPanel extends JPanel { DefaultActionGroup toolbarActionGroup = new DefaultActionGroup(); toolbarActionGroup.add(new TopActionGroup()); ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.TOOLBAR, toolbarActionGroup, true); - return toolbar.getComponent(); + JComponent toolbarComponent = toolbar.getComponent(); + toolbarComponent.setMaximumSize(new Dimension(toolbarComponent.getPreferredSize().width, Short.MAX_VALUE)); + return toolbarComponent; } @@ -85,12 +92,16 @@ public abstract class AbstractSchemesPanel extends JPanel { return myToolbar; } - protected abstract DefaultSchemeActions createSchemeActions(); + protected abstract AbstractSchemeActions createSchemeActions(); public T getSelectedScheme() { return mySchemesCombo.getSelectedScheme(); } + public SchemeListItem getSelectedItem() { + return mySchemesCombo.getSelectedItem(); + } + public void selectScheme(@Nullable T scheme) { mySchemesCombo.selectScheme(scheme); } @@ -102,4 +113,72 @@ public abstract class AbstractSchemesPanel extends JPanel { public void disposeUIResources() { removeAll(); } + + public void startEdit() { + mySchemesCombo.startEdit(); + } + + public void showInfo(@Nullable String message, @NotNull MessageType messageType) { + myInfoLabel.setText(message); + myInfoLabel.setForeground(messageType.getTitleForeground()); + } + + public void clearInfo() { + myInfoLabel.setText(null); + } + + public AbstractSchemeActions getActions() { + return myActions; + } + + @Override + public SchemeListItem createSeparator(@NotNull String title) { + return new SeparatorItem(title); + } + + private class SeparatorItem extends SchemeListItem { + + private String myTitle; + + public SeparatorItem(@NotNull String title) { + super(null); + myTitle = title; + } + + @Override + public boolean isSeparator() { + return true; + } + + @Override + public boolean isDuplicateAvailable() { + return false; + } + + @Override + public boolean isResetAvailable() { + return false; + } + + @Override + public boolean isDeleteAvailable() { + return false; + } + + @Override + public SchemeLevel getSchemeLevel() { + return SchemeLevel.IDE_Only; + } + + @Override + public boolean isRenameAvailable() { + return false; + } + + @NotNull + @Override + public String getPresentableText() { + return myTitle; + } + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItem.java b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItem.java new file mode 100644 index 000000000000..c1d41ca21622 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItem.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2017 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.application.options.schemes; + +import com.intellij.openapi.options.Scheme; +import com.intellij.openapi.options.SchemeManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class SchemeListItem { + + public static final String EMPTY_NAME_MESSAGE = "The name must not be empty"; + public static final String NAME_ALREADY_EXISTS_MESSAGE = "The name already exists"; + + public enum SchemeLevel { + IDE_Only, IDE, Project + } + + private @Nullable T myScheme; + + public SchemeListItem(@Nullable T scheme) { + myScheme = scheme; + } + + @Nullable + public String getSchemeName() { + return myScheme != null ? myScheme.getName() : null; + } + + @Nullable + public T getScheme() { + return myScheme; + } + + @NotNull + public String getPresentableText() { + return myScheme != null ? SchemeManager.getDisplayName(myScheme) : ""; + } + + public boolean isSeparator() { + return false; + } + + public abstract boolean isDuplicateAvailable(); + + public abstract boolean isResetAvailable(); + + public abstract boolean isDeleteAvailable(); + + public abstract SchemeLevel getSchemeLevel(); + + public abstract boolean isRenameAvailable(); + + @Nullable + public String validateSchemeName(@NotNull String name) { + if (name.isEmpty()) { + return EMPTY_NAME_MESSAGE; + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItemFactory.java b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItemFactory.java new file mode 100644 index 000000000000..84a9413be74e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItemFactory.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2017 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.application.options.schemes; + +import com.intellij.openapi.options.Scheme; +import org.jetbrains.annotations.NotNull; + +public interface SchemeListItemFactory { + + SchemeListItem createItem(@NotNull T scheme); + + SchemeListItem createSeparator(@NotNull String title); +} diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemesCombo.java b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemesCombo.java index ccd90c94a55f..d6e3e7919e56 100644 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemesCombo.java +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemesCombo.java @@ -16,8 +16,8 @@ package com.intellij.application.options.schemes; import com.intellij.openapi.options.Scheme; -import com.intellij.openapi.options.SchemeManager; import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.MessageType; import com.intellij.ui.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,26 +26,81 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.util.Collection; public class SchemesCombo { - private ComboBox myComboBox; - private DefaultSchemeActions myActions; + private ComboBox> myComboBox; + private JPanel myRootPanel; + private AbstractSchemesPanel mySchemesPanel; + private final CardLayout myLayout; + private final JTextField myNameEditorField; + + private final static KeyStroke ESC_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false); + private final static KeyStroke ENTER_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false); - public SchemesCombo(@NotNull DefaultSchemeActions actions) { - myActions = actions; + public SchemesCombo(@NotNull AbstractSchemesPanel schemesPanel) { + mySchemesPanel = schemesPanel; + myLayout = new CardLayout(); + myRootPanel = new JPanel(myLayout); + createCombo(); + myRootPanel.add(myComboBox); + myNameEditorField = createNameEditorField(); + myRootPanel.add(myNameEditorField); + myRootPanel.setMaximumSize(new Dimension(myNameEditorField.getPreferredSize().width, Short.MAX_VALUE)); + } + + private JTextField createNameEditorField() { + JTextField nameEditorField = new JTextField(15); + nameEditorField.registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + cancelEdit(); + } + }, ESC_KEY_STROKE, JComponent.WHEN_FOCUSED); + nameEditorField.registerKeyboardAction(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + stopEdit(); + } + }, ENTER_KEY_STROKE, JComponent.WHEN_FOCUSED); + return nameEditorField; + } + + private void stopEdit() { + String newName = myNameEditorField.getText(); + SchemeListItem selectedItem = getSelectedItem(); + String validationMessage = selectedItem != null ? selectedItem.validateSchemeName(newName) : null; + if (validationMessage != null) { + mySchemesPanel.showInfo(validationMessage, MessageType.ERROR); + } + else { + cancelEdit(); + if (selectedItem != null && selectedItem.getScheme() != null) { + mySchemesPanel.getActions().doRename(selectedItem.getScheme(), newName); + } + } + } + + private void cancelEdit() { + mySchemesPanel.clearInfo(); + myLayout.first(myRootPanel); + myRootPanel.requestFocus(); + } + + private void createCombo() { myComboBox = new ComboBox<>(); myComboBox.setRenderer(new MyListCellRenderer()); myComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - myActions.onSchemeChanged(getSelectedScheme()); + mySchemesPanel.getActions().onSchemeChanged(getSelectedScheme()); } }); - myComboBox.setModel(new DefaultComboBoxModel() { + myComboBox.setModel(new DefaultComboBoxModel>() { @Override public void setSelectedItem(Object anObject) { - if (anObject instanceof OptionalSeparatorItem && ((OptionalSeparatorItem)anObject).isSeparator()) { + if (anObject instanceof SchemeListItem && ((SchemeListItem)anObject).isSeparator()) { return; } super.setSelectedItem(anObject); @@ -53,30 +108,40 @@ public class SchemesCombo { }); } - private SimpleTextAttributes getSchemeAttributes(@NotNull T scheme) { - return myActions.isDeleteAvailable(scheme) ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; + public void startEdit() { + T scheme = getSelectedScheme(); + if (scheme != null) { + myNameEditorField.setText(scheme.getName()); + myLayout.last(myRootPanel); + myNameEditorField.requestFocus(); + } + } + + private SimpleTextAttributes getSchemeAttributes(@NotNull SchemeListItem item) { + return item.isDeleteAvailable() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; } public void resetSchemes(@NotNull Collection schemes) { myComboBox.removeAllItems(); - DefaultSchemeActions.SchemeLevel currSchemeLevel = DefaultSchemeActions.SchemeLevel.IDE_Only; + SchemeListItem.SchemeLevel currSchemeLevel = SchemeListItem.SchemeLevel.IDE_Only; for (T scheme : schemes) { - DefaultSchemeActions.SchemeLevel schemeLevel = myActions.getSchemeLevel(scheme); + SchemeListItem item = mySchemesPanel.createItem(scheme); + SchemeListItem.SchemeLevel schemeLevel = item.getSchemeLevel(); if (!currSchemeLevel.equals(schemeLevel)) { currSchemeLevel = schemeLevel; - if (!schemeLevel.equals(DefaultSchemeActions.SchemeLevel.IDE_Only)) { - myComboBox.addItem(new MySchemeItem(currSchemeLevel.toString())); + if (!schemeLevel.equals(SchemeListItem.SchemeLevel.IDE_Only)) { + myComboBox.addItem(mySchemesPanel.createSeparator(currSchemeLevel.toString())); } } - myComboBox.addItem(new MySchemeItem(scheme)); + myComboBox.addItem(item); } } - private class MyListCellRenderer extends ColoredListCellRenderer { - private ListCellRendererWrapper myWrapper = new ListCellRendererWrapper() { + private class MyListCellRenderer extends ColoredListCellRenderer> { + private ListCellRendererWrapper myWrapper = new ListCellRendererWrapper() { @Override public void customize(JList list, - MySchemeItem value, + SchemeListItem value, int index, boolean selected, boolean hasFocus) { @@ -88,8 +153,8 @@ public class SchemesCombo { }; @Override - public Component getListCellRendererComponent(JList list, - MySchemeItem value, + public Component getListCellRendererComponent(JList> list, + SchemeListItem value, int index, boolean selected, boolean hasFocus) { @@ -104,15 +169,15 @@ public class SchemesCombo { } @Override - protected void customizeCellRenderer(@NotNull JList list, - MySchemeItem value, + protected void customizeCellRenderer(@NotNull JList> list, + SchemeListItem value, int index, boolean selected, boolean hasFocus) { if (value.getScheme() != null) { - append(value.getPresentableText(), getSchemeAttributes(value.getScheme())); - DefaultSchemeActions.SchemeLevel schemeLevel = myActions.getSchemeLevel(value.getScheme()); - if (index == -1 && !DefaultSchemeActions.SchemeLevel.IDE_Only.equals(schemeLevel)) { + append(value.getPresentableText(), getSchemeAttributes(value)); + SchemeListItem.SchemeLevel schemeLevel = value.getSchemeLevel(); + if (index == -1 && !SchemeListItem.SchemeLevel.IDE_Only.equals(schemeLevel)) { append(" " + schemeLevel.toString(), SimpleTextAttributes.GRAY_ATTRIBUTES); } } @@ -121,8 +186,14 @@ public class SchemesCombo { @Nullable public T getSelectedScheme() { + SchemeListItem item = getSelectedItem(); + return item != null ? item.getScheme() : null; + } + + @Nullable + public SchemeListItem getSelectedItem() { int i = myComboBox.getSelectedIndex(); - return i >= 0 ? myComboBox.getItemAt(i).getScheme() : null; + return i >= 0 ? myComboBox.getItemAt(i) : null; } public void selectScheme(@Nullable T scheme) { @@ -134,44 +205,8 @@ public class SchemesCombo { } } - public ComboBox getComboBox() { - return myComboBox; - } - - private interface OptionalSeparatorItem { - boolean isSeparator(); - } - - private final class MySchemeItem implements OptionalSeparatorItem { - private @Nullable T myScheme; - private @Nullable String myText; - - public MySchemeItem(@NotNull String text) { - myText = text; - } - - public MySchemeItem(@Nullable T scheme) { - myScheme = scheme; - } - - @Nullable - public String getSchemeName() { - return myScheme != null ? myScheme.getName() : null; - } - - @Nullable - public T getScheme() { - return myScheme; - } - - @NotNull - public String getPresentableText() { - return myScheme != null ? SchemeManager.getDisplayName(myScheme) : myText != null ? myText : ""; - } - - @Override - public boolean isSeparator() { - return myScheme == null; - } + public JComponent getComponent() { + return myRootPanel; } + }