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 e87a560b1a0b..c952ce184746 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 @@ -15,10 +15,9 @@ */ 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.AbstractSchemeActions; +import com.intellij.application.options.schemes.AbstractSchemesPanel; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; @@ -36,12 +35,10 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWrapper; import com.intellij.psi.codeStyle.CodeStyleScheme; -import com.intellij.psi.impl.source.codeStyle.CodeStyleSchemesImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.OutputStream; -import java.util.Collection; import java.util.List; abstract class CodeStyleSchemesActions extends AbstractSchemeActions { @@ -106,7 +103,7 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions names = CodeStyleSchemesImpl.getSchemeManager().getAllSchemeNames(); - SaveSchemeDialog saveDialog = - new SaveSchemeDialog(getSchemesPanel(), ApplicationBundle.message("title.save.code.style.scheme.as"), names, selectedName); - if (saveDialog.showAndGet()) { - CodeStyleScheme newScheme = getSchemesModel().createNewScheme(saveDialog.getSchemeName(), getCurrentScheme()); - getSchemesModel().addScheme(newScheme, true); - } + CodeStyleScheme newScheme = getSchemesModel().createNewScheme(newName, getCurrentScheme()); + getSchemesModel().addScheme(newScheme, true); } } @Override - protected void doDelete(@NotNull CodeStyleScheme scheme) { + protected void deleteScheme(@NotNull CodeStyleScheme scheme) { getSchemesModel().removeScheme(scheme); } @Override - protected void doImport(@NotNull String importerName) { + protected void importScheme(@NotNull String importerName) { CodeStyleScheme currentScheme = getCurrentScheme(); if (currentScheme != null) { chooseAndImport(currentScheme, importerName); @@ -254,7 +245,7 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions exporter = SchemeExporterEP.getExporter(exporterName, CodeStyleScheme.class); if (exporter != null) { String ext = exporter.getExtension(); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesModel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesModel.java index 9dd0a949d626..208fe8df9cf9 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesModel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesModel.java @@ -15,6 +15,8 @@ */ package com.intellij.application.options.codeStyle; +import com.intellij.application.options.schemes.SchemesModel; +import com.intellij.application.options.schemes.SchemeNameGenerator; import com.intellij.openapi.project.Project; import com.intellij.psi.codeStyle.CodeStyleScheme; import com.intellij.psi.codeStyle.CodeStyleSchemes; @@ -30,7 +32,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -public class CodeStyleSchemesModel { +public class CodeStyleSchemesModel implements SchemesModel { private final List mySchemes = new ArrayList<>(); private CodeStyleScheme myGlobalSelected; private final CodeStyleSchemeImpl myProjectScheme; @@ -207,29 +209,9 @@ public class CodeStyleSchemesModel { } public CodeStyleScheme createNewScheme(final String preferredName, final CodeStyleScheme parentScheme) { - String name; - if (preferredName == null) { - if (parentScheme == null) throw new IllegalArgumentException("parentScheme must not be null"); - // Generate using parent name - name = null; - for (int i = 1; name == null; i++) { - String currName = parentScheme.getName() + " (" + i + ")"; - if (findSchemeByName(currName) == null) { - name = currName; - } - } - } - else { - name = null; - for (int i = 0; name == null; i++) { - String currName = i == 0 ? preferredName : preferredName + " (" + i + ")"; - if (findSchemeByName(currName) == null) { - name = currName; - } - } - } - - return new CodeStyleSchemeImpl(name, false, parentScheme); + return new CodeStyleSchemeImpl(SchemeNameGenerator.getUniqueName(preferredName, parentScheme, name -> nameExists(name)), + false, + parentScheme); } @Nullable @@ -244,10 +226,41 @@ public class CodeStyleSchemesModel { return myProjectScheme; } - public boolean isProjectScheme(CodeStyleScheme scheme) { + @Override + public boolean supportsProjectSchemes() { + return true; + } + + @Override + public boolean canDuplicateScheme(@NotNull CodeStyleScheme scheme) { + return !isProjectScheme(scheme); + } + + @Override + public boolean canResetScheme(@NotNull CodeStyleScheme scheme) { + return true; + } + + @Override + public boolean canDeleteScheme(@NotNull CodeStyleScheme scheme) { + return !isProjectScheme(scheme) && !scheme.isDefault(); + } + + @Override + public boolean isProjectScheme(@NotNull CodeStyleScheme scheme) { return myProjectScheme == scheme; } + @Override + public boolean canRenameScheme(@NotNull CodeStyleScheme scheme) { + return canDeleteScheme(scheme); + } + + @Override + public boolean nameExists(@NotNull String name) { + return findSchemeByName(name) != null; + } + public List getAllSortedSchemes() { List schemes = new ArrayList<>(); schemes.addAll(getSchemes()); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesPanel.java index 6275c77d7918..b16adac591a7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleSchemesPanel.java @@ -17,9 +17,9 @@ package com.intellij.application.options.codeStyle; -import com.intellij.application.options.schemes.AbstractSchemesPanel; import com.intellij.application.options.schemes.AbstractSchemeActions; -import com.intellij.application.options.schemes.SchemeListItem; +import com.intellij.application.options.schemes.AbstractSchemesPanel; +import com.intellij.application.options.schemes.SchemesModel; import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.codeStyle.CodeStyleScheme; import com.intellij.psi.impl.source.codeStyle.CodeStyleSchemeImpl; @@ -113,7 +113,7 @@ public class CodeStyleSchemesPanel extends AbstractSchemesPanel } @Override - protected void doRename(@NotNull CodeStyleScheme scheme, @NotNull String newName) { + protected void renameScheme(@NotNull CodeStyleScheme scheme, @NotNull String newName) { CodeStyleSchemeImpl newScheme = new CodeStyleSchemeImpl(newName, false, scheme); myModel.addScheme(newScheme, false); myModel.removeScheme(scheme); @@ -122,44 +122,10 @@ public class CodeStyleSchemesPanel extends AbstractSchemesPanel }; } + @NotNull @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); - } - }; + public SchemesModel getModel() { + return myModel; } + } 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 57f96fd7c749..3d8b36e3989e 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 @@ -18,6 +18,7 @@ package com.intellij.application.options.colors; import com.intellij.application.options.OptionsContainingConfigurable; import com.intellij.application.options.editor.EditorOptionsProvider; +import com.intellij.application.options.schemes.SchemesModel; import com.intellij.execution.impl.ConsoleViewUtil; import com.intellij.ide.ui.LafManager; import com.intellij.ide.ui.laf.LafManagerImpl; @@ -54,7 +55,6 @@ import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.ui.ColorUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.EventDispatcher; import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; @@ -70,7 +70,8 @@ import java.awt.*; import java.util.*; import java.util.List; -public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract implements EditorOptionsProvider { +public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract + implements EditorOptionsProvider, SchemesModel { public static final String ID = "reference.settingsdialog.IDE.editor.colors"; private Map mySchemes; @@ -143,23 +144,6 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return mySchemes.get(name); } - @NotNull - public String getUniqueName(@NotNull String preferredName) { - String name; - if (mySchemes.containsKey(preferredName)) { - for (int i = 1; ; i++) { - name = preferredName + " (" + i + ")"; - if (!mySchemes.containsKey(name)) { - break; - } - } - } - else { - name = preferredName; - } - return name; - } - public EditorColorsScheme getSelectedScheme() { return mySelectedScheme; } @@ -168,6 +152,46 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return mySelectedScheme.getDescriptors(); } + @Override + public boolean supportsProjectSchemes() { + return false; + } + + @Override + public boolean canDuplicateScheme(@NotNull EditorColorsScheme scheme) { + return true; + } + + @Override + public boolean canResetScheme(@NotNull EditorColorsScheme scheme) { + AbstractColorsScheme originalScheme = + scheme instanceof AbstractColorsScheme ? ((AbstractColorsScheme)scheme).getOriginal() : null; + return + !isReadOnly(scheme) && + scheme.getName().startsWith(SchemeManager.EDITABLE_COPY_PREFIX) && + originalScheme instanceof ReadOnlyColorsScheme; + } + + @Override + public boolean canDeleteScheme(@NotNull EditorColorsScheme scheme) { + return !isReadOnly(scheme) && canBeDeleted(scheme); + } + + @Override + public boolean isProjectScheme(@NotNull EditorColorsScheme scheme) { + return false; + } + + @Override + public boolean canRenameScheme(@NotNull EditorColorsScheme scheme) { + return canDeleteScheme(scheme); + } + + @Override + public boolean nameExists(@NotNull String name) { + return mySchemes.get(name) != null || mySchemes.get(SchemeManager.EDITABLE_COPY_PREFIX + name) != null; + } + public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) { return ((MyColorScheme)scheme).isReadOnly(); } @@ -175,16 +199,6 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract public static boolean canBeDeleted(@NotNull final EditorColorsScheme scheme) { return scheme instanceof MyColorScheme && ((MyColorScheme)scheme).canBeDeleted(); } - - @NotNull - public String[] getSchemeNames() { - List names = new ArrayList<>(); - for (EditorColorsScheme scheme : getOrderedSchemes()) { - names.add(scheme.getName()); - } - - return ArrayUtil.toStringArray(names); - } @NotNull public Collection getOrderedSchemes() { @@ -198,12 +212,6 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract return new ArrayList<>(mySchemes.values()); } - public void saveSchemeAs(String name) { - MyColorScheme scheme = mySelectedScheme; - if (scheme == null) return; - saveSchemeAs(scheme, name); - } - public boolean saveSchemeAs(@NotNull EditorColorsScheme editorScheme, @NotNull String name) { if (editorScheme instanceof MyColorScheme) { MyColorScheme scheme = (MyColorScheme)editorScheme; 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 3ea549e16874..d926cf7f572c 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 @@ -15,21 +15,23 @@ */ 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.AbstractSchemeActions; +import com.intellij.application.options.schemes.AbstractSchemesPanel; +import com.intellij.application.options.schemes.SchemeNameGenerator; 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.extensions.Extensions; -import com.intellij.openapi.options.*; +import com.intellij.openapi.options.SchemeImportException; +import com.intellij.openapi.options.SchemeImportUtil; +import com.intellij.openapi.options.SchemeImporter; +import com.intellij.openapi.options.SchemeImporterEP; import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -53,7 +55,7 @@ public abstract class ColorSchemeActions extends AbstractSchemeActions { - String newName = getOptions().getUniqueName(name != null ? name : "Unnamed"); + String newName = SchemeNameGenerator.getUniqueName(name != null ? name : "Unnamed", + candidate -> getSchemesPanel().getModel() + .nameExists(candidate)); AbstractColorsScheme newScheme = new EditorColorsSchemeImpl(EmptyColorScheme.INSTANCE); newScheme.setName(newName); newScheme.setDefaultMetaInfo(EmptyColorScheme.INSTANCE); @@ -95,7 +99,7 @@ public abstract class ColorSchemeActions extends AbstractSchemeActions names = ContainerUtil.newArrayList(getOptions().getSchemeNames()); - String selectedName = SchemeManager.getDisplayName(scheme); - SaveSchemeDialog dialog = - new SaveSchemeDialog(getSchemesPanel(), ApplicationBundle.message("title.save.color.scheme.as"), names, selectedName); - if (dialog.showAndGet()) { - getOptions().saveSchemeAs(dialog.getSchemeName()); - } + protected void duplicateScheme(@NotNull EditorColorsScheme scheme, @NotNull String newName) { + getOptions().saveSchemeAs(scheme, newName); } @Override - protected void doDelete(@NotNull EditorColorsScheme scheme) { + protected void deleteScheme(@NotNull EditorColorsScheme scheme) { getOptions().removeScheme(scheme.getName()); } @Override - protected void doExport(@NotNull EditorColorsScheme scheme, @NotNull String exporterName) { + protected void exportScheme(@NotNull EditorColorsScheme scheme, @NotNull String exporterName) { // Unsupported for now. } diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java index 77133eb680b7..cc72e21c67e7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java @@ -17,13 +17,10 @@ package com.intellij.application.options.colors; import com.intellij.application.options.SkipSelfSearchComponent; -import com.intellij.application.options.schemes.AbstractSchemesPanel; import com.intellij.application.options.schemes.AbstractSchemeActions; -import com.intellij.application.options.schemes.SchemeListItem; +import com.intellij.application.options.schemes.AbstractSchemesPanel; +import com.intellij.application.options.schemes.SchemesModel; import com.intellij.openapi.editor.colors.EditorColorsScheme; -import com.intellij.openapi.editor.colors.impl.AbstractColorsScheme; -import com.intellij.openapi.editor.colors.impl.ReadOnlyColorsScheme; -import com.intellij.openapi.options.SchemeManager; import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -97,7 +94,7 @@ public class SchemesPanel extends AbstractSchemesPanel imple } @Override - protected void doRename(@NotNull EditorColorsScheme scheme, @NotNull String newName) { + protected void renameScheme(@NotNull EditorColorsScheme scheme, @NotNull String newName) { if (myOptions.saveSchemeAs(scheme, newName)) { myOptions.removeScheme(scheme.getName()); myOptions.selectScheme(newName); @@ -106,52 +103,10 @@ public class SchemesPanel extends AbstractSchemesPanel imple }; } - + @NotNull @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); - } - }; + public SchemesModel getModel() { + return myOptions; } + } diff --git a/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java index 66d977b691d6..51c1bbf16556 100644 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/AbstractSchemeActions.java @@ -17,9 +17,7 @@ package com.intellij.application.options.schemes; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.options.Scheme; -import com.intellij.openapi.options.SchemeExporterEP; -import com.intellij.openapi.options.SchemeImporterEP; +import com.intellij.openapi.options.*; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; @@ -31,6 +29,7 @@ import java.util.Collection; import java.util.List; public abstract class AbstractSchemeActions { + private final Collection mySchemeImportersNames; private final Collection mySchemeExporterNames; private AbstractSchemesPanel mySchemesPanel; @@ -99,15 +98,16 @@ public abstract class AbstractSchemeActions { public void actionPerformed(AnActionEvent e) { T currentScheme = getCurrentScheme(); if (currentScheme != null) { - doReset(currentScheme); - } + mySchemesPanel.cancelEdit(); + resetScheme(currentScheme); + } } @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - SchemeListItem item = mySchemesPanel.getSelectedItem(); - p.setEnabled(item != null && item.isResetAvailable()); + T scheme = getCurrentScheme(); + p.setEnabled(scheme != null && mySchemesPanel.getModel().canResetScheme(scheme)); } } @@ -121,15 +121,23 @@ public abstract class AbstractSchemeActions { public void actionPerformed(AnActionEvent e) { T currentScheme = getCurrentScheme(); if (currentScheme != null) { - doSaveAs(currentScheme); + mySchemesPanel.cancelEdit(); + duplicateScheme(currentScheme, + SchemeNameGenerator.getUniqueName( + SchemeManager.getDisplayName(currentScheme), + name -> mySchemesPanel.getModel().nameExists(name))); + currentScheme = getCurrentScheme(); + if (currentScheme != null) { + mySchemesPanel.startEdit(); + } } } @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - SchemeListItem item = mySchemesPanel.getSelectedItem(); - p.setEnabledAndVisible(item != null && item.isDuplicateAvailable()); + T scheme = getCurrentScheme(); + p.setEnabledAndVisible(scheme != null && mySchemesPanel.getModel().canDuplicateScheme(scheme)); } } @@ -150,8 +158,8 @@ public abstract class AbstractSchemeActions { @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - SchemeListItem item = mySchemesPanel.getSelectedItem(); - p.setEnabled(item != null && item.isRenameAvailable()); + T scheme = getCurrentScheme(); + p.setEnabledAndVisible(scheme != null && mySchemesPanel.getModel().canRenameScheme(scheme)); } } @@ -164,15 +172,16 @@ public abstract class AbstractSchemeActions { public void actionPerformed(AnActionEvent e) { T currentScheme = getCurrentScheme(); if (currentScheme != null) { - doDelete(currentScheme); + mySchemesPanel.cancelEdit(); + deleteScheme(currentScheme); } } @Override public void update(AnActionEvent e) { Presentation p = e.getPresentation(); - SchemeListItem item = mySchemesPanel.getSelectedItem(); - p.setEnabledAndVisible(item != null && item.isDeleteAvailable()); + T scheme = getCurrentScheme(); + p.setEnabledAndVisible(scheme != null && mySchemesPanel.getModel().canDeleteScheme(scheme)); } } @@ -215,7 +224,8 @@ public abstract class AbstractSchemeActions { @Override public void actionPerformed(AnActionEvent e) { - doImport(myImporterName); + mySchemesPanel.cancelEdit(); + importScheme(myImporterName); } } @@ -231,24 +241,25 @@ public abstract class AbstractSchemeActions { public void actionPerformed(AnActionEvent e) { T currentScheme = getCurrentScheme(); if (currentScheme != null) { - doExport(currentScheme, myExporterName); + mySchemesPanel.cancelEdit(); + exportScheme(currentScheme, myExporterName); } } } + + protected abstract void importScheme(@NotNull String importerName); - protected abstract void doImport(@NotNull String importerName); - - protected abstract void doReset(@NotNull T scheme); + protected abstract void resetScheme(@NotNull T scheme); - protected abstract void doSaveAs(@NotNull T scheme); + protected abstract void duplicateScheme(@NotNull T scheme, @NotNull String newName); - protected abstract void doDelete(@NotNull T scheme); + protected abstract void deleteScheme(@NotNull T scheme); - protected abstract void doExport(@NotNull T scheme, @NotNull String exporterName); + protected abstract void exportScheme(@NotNull T scheme, @NotNull String exporterName); protected abstract void onSchemeChanged(@Nullable T scheme); - protected abstract void doRename(@NotNull T scheme, @NotNull String newName); + protected abstract void renameScheme(@NotNull T scheme, @NotNull String newName); @Nullable protected final T getCurrentScheme() { 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 633c81c135e6..5c74ac2ab9bb 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 @@ -28,7 +28,7 @@ import javax.swing.*; import java.awt.*; import java.util.Collection; -public abstract class AbstractSchemesPanel extends JPanel implements SchemeListItemFactory { +public abstract class AbstractSchemesPanel extends JPanel { private SchemesCombo mySchemesCombo; private AbstractSchemeActions myActions; @@ -98,10 +98,6 @@ public abstract class AbstractSchemesPanel extends JPanel impl return mySchemesCombo.getSelectedScheme(); } - public SchemeListItem getSelectedItem() { - return mySchemesCombo.getSelectedItem(); - } - public void selectScheme(@Nullable T scheme) { mySchemesCombo.selectScheme(scheme); } @@ -117,6 +113,10 @@ public abstract class AbstractSchemesPanel extends JPanel impl public void startEdit() { mySchemesCombo.startEdit(); } + + public void cancelEdit() { + mySchemesCombo.cancelEdit(); + } public void showInfo(@Nullable String message, @NotNull MessageType messageType) { myInfoLabel.setText(message); @@ -131,54 +131,6 @@ public abstract class AbstractSchemesPanel extends JPanel impl 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; - } - } + @NotNull + public abstract SchemesModel getModel(); } 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 deleted file mode 100644 index c1d41ca21622..000000000000 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItem.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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/SchemeNameGenerator.java b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeNameGenerator.java new file mode 100644 index 000000000000..03cf63b3d8dc --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeNameGenerator.java @@ -0,0 +1,59 @@ +/* + * 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; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +public class SchemeNameGenerator { + private final static String COPY_NAME_SUFFIX = "copy"; + + private SchemeNameGenerator() { + } + + public static String getUniqueName(@NotNull String preferredName, @NotNull Function nameExistsFunction) { + if (nameExistsFunction.apply(preferredName)) { + int numberPos = preferredName.length() - 1; + while (numberPos >= 0 && Character.isDigit(preferredName.charAt(numberPos))) { + numberPos--; + } + String baseName = numberPos >= 0 ? preferredName.substring(0, numberPos + 1) : preferredName; + if (!baseName.endsWith(COPY_NAME_SUFFIX)) { + baseName = preferredName + " " + COPY_NAME_SUFFIX; + } + if (!nameExistsFunction.apply(baseName)) return baseName; + int i = 1; + while (true) { + String newName = baseName + i; + if (!nameExistsFunction.apply(newName)) return newName; + i++; + } + } + return preferredName; + } + + + public static String getUniqueName(@Nullable String preferredName, + @Nullable Scheme parentScheme, + @NotNull Function nameExistsFunction) { + assert preferredName != null || parentScheme != null : "Either preferredName or parentScheme must be non-null"; + String baseName = preferredName != null ? preferredName : parentScheme.getName(); + return getUniqueName(baseName, nameExistsFunction); + } +} 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 d6e3e7919e56..b8d84c2b3a42 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,6 +16,7 @@ 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.*; @@ -28,9 +29,18 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.Collection; +import java.util.function.Function; public class SchemesCombo { - private ComboBox> myComboBox; + + // region Message constants + public static final String PROJECT_LEVEL = "Project"; + public static final String IDE_LEVEL = "IDE"; + 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"; + // endregion + + private ComboBox> myComboBox; private JPanel myRootPanel; private AbstractSchemesPanel mySchemesPanel; private final CardLayout myLayout; @@ -69,20 +79,26 @@ public class SchemesCombo { 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); + MySchemeListItem selectedItem = getSelectedItem(); + if (selectedItem != null) { + if (newName.equals(selectedItem.getSchemeName())) { + cancelEdit(); + return; + } + String validationMessage = validateSchemeName(newName); + if (validationMessage != null) { + mySchemesPanel.showInfo(validationMessage, MessageType.ERROR); + } + else { + cancelEdit(); + if (selectedItem.getScheme() != null) { + mySchemesPanel.getActions().renameScheme(selectedItem.getScheme(), newName); + } } } } - private void cancelEdit() { + public void cancelEdit() { mySchemesPanel.clearInfo(); myLayout.first(myRootPanel); myRootPanel.requestFocus(); @@ -97,10 +113,10 @@ public class SchemesCombo { mySchemesPanel.getActions().onSchemeChanged(getSelectedScheme()); } }); - myComboBox.setModel(new DefaultComboBoxModel>() { + myComboBox.setModel(new DefaultComboBoxModel>() { @Override public void setSelectedItem(Object anObject) { - if (anObject instanceof SchemeListItem && ((SchemeListItem)anObject).isSeparator()) { + if (anObject instanceof MySchemeListItem && ((MySchemeListItem)anObject).isSeparator()) { return; } super.setSelectedItem(anObject); @@ -117,31 +133,40 @@ public class SchemesCombo { } } - private SimpleTextAttributes getSchemeAttributes(@NotNull SchemeListItem item) { - return item.isDeleteAvailable() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; + private SimpleTextAttributes getSchemeAttributes(@NotNull MySchemeListItem item) { + T scheme = item.getScheme(); + return scheme != null && mySchemesPanel.getModel().canDeleteScheme(scheme) + ? SimpleTextAttributes.REGULAR_ATTRIBUTES + : SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; } - + public void resetSchemes(@NotNull Collection schemes) { myComboBox.removeAllItems(); - SchemeListItem.SchemeLevel currSchemeLevel = SchemeListItem.SchemeLevel.IDE_Only; + SchemesModel model = mySchemesPanel.getModel(); + if (model.supportsProjectSchemes()) { + myComboBox.addItem(new MySeparatorItem(PROJECT_LEVEL)); + addItems(schemes, scheme -> model.isProjectScheme(scheme)); + myComboBox.addItem(new MySeparatorItem(IDE_LEVEL)); + addItems(schemes, scheme -> !model.isProjectScheme(scheme)); + } + else { + addItems(schemes, scheme -> true); + } + } + + private void addItems(@NotNull Collection schemes, Function filter) { for (T scheme : schemes) { - SchemeListItem item = mySchemesPanel.createItem(scheme); - SchemeListItem.SchemeLevel schemeLevel = item.getSchemeLevel(); - if (!currSchemeLevel.equals(schemeLevel)) { - currSchemeLevel = schemeLevel; - if (!schemeLevel.equals(SchemeListItem.SchemeLevel.IDE_Only)) { - myComboBox.addItem(mySchemesPanel.createSeparator(currSchemeLevel.toString())); - } + if (filter.apply(scheme)) { + myComboBox.addItem(new MySchemeListItem<>(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, - SchemeListItem value, + MySchemeListItem value, int index, boolean selected, boolean hasFocus) { @@ -153,8 +178,8 @@ public class SchemesCombo { }; @Override - public Component getListCellRendererComponent(JList> list, - SchemeListItem value, + public Component getListCellRendererComponent(JList> list, + MySchemeListItem value, int index, boolean selected, boolean hasFocus) { @@ -169,29 +194,32 @@ public class SchemesCombo { } @Override - protected void customizeCellRenderer(@NotNull JList> list, - SchemeListItem value, + protected void customizeCellRenderer(@NotNull JList> list, + MySchemeListItem value, int index, boolean selected, boolean hasFocus) { - if (value.getScheme() != null) { + T scheme = value.getScheme(); + if (scheme != null) { 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); + if (mySchemesPanel.getModel().supportsProjectSchemes()) { + if (index == -1) { + append(" " + (mySchemesPanel.getModel().isProjectScheme(scheme) ? PROJECT_LEVEL : IDE_LEVEL), + SimpleTextAttributes.GRAY_ATTRIBUTES); + } } } } } - + @Nullable public T getSelectedScheme() { - SchemeListItem item = getSelectedItem(); + MySchemeListItem item = getSelectedItem(); return item != null ? item.getScheme() : null; } @Nullable - public SchemeListItem getSelectedItem() { + public MySchemeListItem getSelectedItem() { int i = myComboBox.getSelectedIndex(); return i >= 0 ? myComboBox.getItemAt(i) : null; } @@ -209,4 +237,64 @@ public class SchemesCombo { return myRootPanel; } + private class MySeparatorItem extends MySchemeListItem { + + private String myTitle; + + public MySeparatorItem(@NotNull String title) { + super(null); + myTitle = title; + } + + @Override + public boolean isSeparator() { + return true; + } + + @NotNull + @Override + public String getPresentableText() { + return myTitle; + } + } + + private static class MySchemeListItem { + + private @Nullable T myScheme; + + public MySchemeListItem(@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; + } + + } + + @Nullable + public String validateSchemeName(@NotNull String name) { + if (name.isEmpty()) { + return EMPTY_NAME_MESSAGE; + } + else if (mySchemesPanel.getModel().nameExists(name)) { + return NAME_ALREADY_EXISTS_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/SchemesModel.java similarity index 66% rename from platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItemFactory.java rename to platform/lang-impl/src/com/intellij/application/options/schemes/SchemesModel.java index 84a9413be74e..b2771ccb43a6 100644 --- a/platform/lang-impl/src/com/intellij/application/options/schemes/SchemeListItemFactory.java +++ b/platform/lang-impl/src/com/intellij/application/options/schemes/SchemesModel.java @@ -18,9 +18,18 @@ package com.intellij.application.options.schemes; import com.intellij.openapi.options.Scheme; import org.jetbrains.annotations.NotNull; -public interface SchemeListItemFactory { +public interface SchemesModel { + boolean supportsProjectSchemes(); - SchemeListItem createItem(@NotNull T scheme); - - SchemeListItem createSeparator(@NotNull String title); + boolean canDuplicateScheme(@NotNull T scheme ); + + boolean canResetScheme(@NotNull T scheme); + + boolean canDeleteScheme(@NotNull T scheme); + + boolean isProjectScheme(@NotNull T scheme); + + boolean canRenameScheme(@NotNull T scheme); + + boolean nameExists(@NotNull String name); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java index d0a42646ebb7..1310aea3feb0 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.codeStyle; +import com.intellij.application.options.schemes.SchemeNameGenerator; import com.intellij.configurationStore.LazySchemeProcessor; import com.intellij.configurationStore.SchemeDataHolder; import com.intellij.openapi.options.SchemeManager; @@ -63,28 +64,10 @@ public abstract class CodeStyleSchemesImpl extends CodeStyleSchemes { @SuppressWarnings("ForLoopThatDoesntUseLoopVariable") @Override public CodeStyleScheme createNewScheme(String preferredName, CodeStyleScheme parentScheme) { - String name; - if (preferredName == null) { - if (parentScheme == null) throw new IllegalArgumentException("parentScheme must not be null"); - // Generate using parent name - name = null; - for (int i = 1; name == null; i++) { - String currName = parentScheme.getName() + " (" + i + ")"; - if (mySchemeManager.findSchemeByName(currName) == null) { - name = currName; - } - } - } - else { - name = null; - for (int i = 0; name == null; i++) { - String currName = i == 0 ? preferredName : preferredName + " (" + i + ")"; - if (mySchemeManager.findSchemeByName(currName) == null) { - name = currName; - } - } - } - return new CodeStyleSchemeImpl(name, false, parentScheme); + return new CodeStyleSchemeImpl( + SchemeNameGenerator.getUniqueName(preferredName, parentScheme, name -> mySchemeManager.findSchemeByName(name) != null), + false, + parentScheme); } @Override