Schemes UI refactoring, JavaDoc

This commit is contained in:
Rustam Vishnyakov
2017-01-30 13:21:22 +03:00
parent 8def1c3756
commit af3a1eae2b
9 changed files with 260 additions and 124 deletions
@@ -19,19 +19,13 @@ import com.intellij.application.options.SchemesToImportPopup;
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.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.Separator;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
import com.intellij.openapi.fileChooser.FileSaverDialog;
import com.intellij.openapi.options.*;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
@@ -43,7 +37,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.OutputStream;
import java.util.List;
abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleScheme> {
@@ -53,59 +46,6 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
super(schemesPanel);
}
@Override
protected void addAdditionalActions(@NotNull List<AnAction> defaultActions) {
defaultActions.add(0, new CopyToProjectAction());
defaultActions.add(1, new CopyToIDEAction());
defaultActions.add(2, new Separator());
}
private class CopyToProjectAction extends DumbAwareAction {
public CopyToProjectAction() {
super(ApplicationBundle.message("settings.editor.scheme.copy.to.project"));
}
@Override
public void actionPerformed(AnActionEvent e) {
CodeStyleScheme currentScheme = getCurrentScheme();
if (currentScheme != null && !getSchemesModel().isProjectScheme(currentScheme)) {
copyToProject(currentScheme);
}
}
@Override
public void update(AnActionEvent e) {
Presentation p = e.getPresentation();
CodeStyleScheme currentScheme = getCurrentScheme();
p.setEnabledAndVisible(currentScheme != null && !getSchemesModel().isProjectScheme(currentScheme));
}
}
private class CopyToIDEAction extends DumbAwareAction {
public CopyToIDEAction() {
super(ApplicationBundle.message("settings.editor.scheme.copy.to.ide"));
}
@Override
public void actionPerformed(AnActionEvent e) {
CodeStyleScheme currentScheme = getCurrentScheme();
if (currentScheme != null && getSchemesModel().isProjectScheme(currentScheme)) {
exportProjectScheme();
}
}
@Override
public void update(AnActionEvent e) {
Presentation p = e.getPresentation();
CodeStyleScheme currentScheme = getCurrentScheme();
p.setEnabledAndVisible(currentScheme != null && getSchemesModel().isProjectScheme(currentScheme));
}
}
@Override
protected void resetScheme(@NotNull CodeStyleScheme scheme) {
if (Messages
@@ -113,21 +53,21 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
ApplicationBundle.message("settings.code.style.reset.to.defaults.title"), Messages.getQuestionIcon()) ==
Messages.OK) {
scheme.resetToDefaults();
getSchemesModel().fireSchemeChanged(scheme);
getModel().fireSchemeChanged(scheme);
}
}
@Override
protected void duplicateScheme(@NotNull CodeStyleScheme scheme, @NotNull String newName) {
if (!getSchemesModel().isProjectScheme(scheme)) {
CodeStyleScheme newScheme = getSchemesModel().createNewScheme(newName, getCurrentScheme());
getSchemesModel().addScheme(newScheme, true);
if (!getModel().isProjectScheme(scheme)) {
CodeStyleScheme newScheme = getModel().createNewScheme(newName, getCurrentScheme());
getModel().addScheme(newScheme, true);
}
}
@Override
protected void deleteScheme(@NotNull CodeStyleScheme scheme) {
getSchemesModel().removeScheme(scheme);
getModel().removeScheme(scheme);
}
@Override
@@ -138,12 +78,13 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
}
}
private void exportProjectScheme() {
@Override
protected void copyToIDE(@NotNull CodeStyleScheme scheme) {
String name =
SchemeNameGenerator.getUniqueName(getProjectName(), schemeName -> getSchemesModel().nameExists(schemeName));
CodeStyleScheme newScheme = getSchemesModel().exportProjectScheme(name);
getSchemesModel().setUsePerProjectSettings(false);
getSchemesModel().selectScheme(newScheme, null);
SchemeNameGenerator.getUniqueName(getProjectName(), schemeName -> getModel().containsScheme(schemeName));
CodeStyleScheme newScheme = getModel().exportProjectScheme(name);
getModel().setUsePerProjectSettings(false);
getModel().selectScheme(newScheme, null);
getSchemesPanel().startEdit();
}
@@ -159,10 +100,10 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
@Override
protected void onSchemeSelected(CodeStyleScheme scheme) {
if (scheme != null) {
getSchemesModel().addScheme(scheme, true);
getModel().addScheme(scheme, true);
}
}
}.show(getSchemesModel().getSchemes());
}.show(getModel().getSchemes());
}
else {
final SchemeImporter<CodeStyleScheme> importer = SchemeImporterEP.getImporter(importerName, CodeStyleScheme.class);
@@ -198,13 +139,13 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
CodeStyleSchemesUIConfiguration.Util.setRecentImportFile(selectedFile);
final SchemeCreator schemeCreator = new SchemeCreator();
final CodeStyleScheme
schemeImported = importer.importScheme(getSchemesModel().getProject(), selectedFile, currentScheme, schemeCreator);
schemeImported = importer.importScheme(getModel().getProject(), selectedFile, currentScheme, schemeCreator);
if (schemeImported != null) {
if (schemeCreator.isSchemeWasCreated()) {
getSchemesModel().fireSchemeListChanged();
getModel().fireSchemeListChanged();
}
else {
getSchemesModel().fireSchemeChanged(schemeImported);
getModel().fireSchemeChanged(schemeImported);
}
return schemeImported;
}
@@ -219,8 +160,8 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
public CodeStyleScheme createNewScheme(@Nullable String targetName) {
mySchemeWasCreated = true;
if (targetName == null) targetName = ApplicationBundle.message("code.style.scheme.import.unnamed");
CodeStyleScheme newScheme = getSchemesModel().createNewScheme(targetName, getCurrentScheme());
getSchemesModel().addScheme(newScheme, true);
CodeStyleScheme newScheme = getModel().createNewScheme(targetName, getCurrentScheme());
getModel().addScheme(newScheme, true);
return newScheme;
}
@@ -234,14 +175,15 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
return CodeStyleScheme.class;
}
public void copyToProject(CodeStyleScheme scheme) {
@Override
public void copyToProject(@NotNull CodeStyleScheme scheme) {
int copyToProjectConfirmation = Messages
.showYesNoDialog(ApplicationBundle.message("settings.editor.scheme.copy.to.project.message", scheme.getName()),
ApplicationBundle.message("settings.editor.scheme.copy.to.project.title"),
Messages.getQuestionIcon());
if (copyToProjectConfirmation == Messages.YES) {
getSchemesModel().copyToProject(scheme);
getSchemesModel().setUsePerProjectSettings(true, true);
getModel().copyToProject(scheme);
getModel().setUsePerProjectSettings(true, true);
}
}
@@ -290,6 +232,11 @@ abstract class CodeStyleSchemesActions extends AbstractSchemeActions<CodeStyleSc
}
}
}
protected abstract CodeStyleSchemesModel getSchemesModel();
@NotNull
@Override
protected CodeStyleSchemesModel getModel() {
return (CodeStyleSchemesModel)super.getModel();
}
}
@@ -174,6 +174,7 @@ public class CodeStyleSchemesModel implements SchemesModel<CodeStyleScheme> {
mySettingsToClone.clear();
}
@SuppressWarnings("unused")
@Deprecated
public static boolean cannotBeModified(final CodeStyleScheme currentScheme) {
return false;
@@ -213,7 +214,7 @@ public class CodeStyleSchemesModel implements SchemesModel<CodeStyleScheme> {
}
public CodeStyleScheme createNewScheme(final String preferredName, final CodeStyleScheme parentScheme) {
return new CodeStyleSchemeImpl(SchemeNameGenerator.getUniqueName(preferredName, parentScheme, name -> nameExists(name)),
return new CodeStyleSchemeImpl(SchemeNameGenerator.getUniqueName(preferredName, parentScheme, name -> containsScheme(name)),
false,
parentScheme);
}
@@ -261,7 +262,7 @@ public class CodeStyleSchemesModel implements SchemesModel<CodeStyleScheme> {
}
@Override
public boolean nameExists(@NotNull String name) {
public boolean containsScheme(@NotNull String name) {
return findSchemeByName(name) != null;
}
@@ -100,11 +100,6 @@ public class CodeStyleSchemesPanel extends AbstractSchemesPanel<CodeStyleScheme>
return
new CodeStyleSchemesActions(this) {
@Override
protected CodeStyleSchemesModel getSchemesModel() {
return myModel;
}
@Override
protected void onSchemeChanged(@Nullable CodeStyleScheme scheme) {
if (!myIsReset) {
@@ -189,7 +189,7 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
}
@Override
public boolean nameExists(@NotNull String name) {
public boolean containsScheme(@NotNull String name) {
return mySchemes.get(name) != null || mySchemes.get(SchemeManager.EDITABLE_COPY_PREFIX + name) != null;
}
@@ -69,7 +69,7 @@ public abstract class ColorSchemeActions extends AbstractSchemeActions<EditorCol
name -> {
String newName = SchemeNameGenerator.getUniqueName(name != null ? name : "Unnamed",
candidate -> getSchemesPanel().getModel()
.nameExists(candidate));
.containsScheme(candidate));
AbstractColorsScheme newScheme = new EditorColorsSchemeImpl(EmptyColorScheme.INSTANCE);
newScheme.setName(newName);
newScheme.setDefaultMetaInfo(EmptyColorScheme.INSTANCE);
@@ -28,12 +28,27 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* <p>
* A standard set of scheme actions: copy, reset, rename, etc. used in {@link AbstractSchemesPanel}. More actions can be added via
* {@link #addAdditionalActions(List)} method. Available actions depend on {@link SchemesModel}. If schemes model supports both IDE and
* project schemes, {@link #copyToIDE(Scheme)} and {@link #copyToProject(Scheme)} must be overridden to do the actual job, default
* implementation for the methods does nothing.
* <p>
* Import and export actions are available only if there are importer/exporter implementations for the actual scheme type.
*
* @param <T> The actual scheme type.
* @see AbstractSchemesPanel
* @see SchemesModel
* @see SchemeImporter
* @see SchemeExporter
*/
public abstract class AbstractSchemeActions<T extends Scheme> {
private final Collection<String> mySchemeImportersNames;
private final Collection<String> mySchemeExporterNames;
private AbstractSchemesPanel<T> mySchemesPanel;
private final AbstractSchemesPanel<T> mySchemesPanel;
protected AbstractSchemeActions(@NotNull AbstractSchemesPanel<T> schemesPanel) {
mySchemesPanel = schemesPanel;
mySchemeImportersNames = getSchemeImportersNames();
@@ -59,6 +74,11 @@ public abstract class AbstractSchemeActions<T extends Scheme> {
public final Collection<AnAction> getActions() {
List<AnAction> actions = new ArrayList<>();
if (getModel().supportsProjectSchemes()) {
actions.add(new CopyToProjectAction());
actions.add(new CopyToIDEAction());
actions.add(new Separator());
}
actions.add(new CopyAction());
actions.add(new RenameAction());
actions.add(new ResetAction());
@@ -86,7 +106,53 @@ public abstract class AbstractSchemeActions<T extends Scheme> {
return actions;
}
@SuppressWarnings("unused")
protected void addAdditionalActions(@NotNull List<AnAction> defaultActions) {}
private class CopyToProjectAction extends DumbAwareAction {
public CopyToProjectAction() {
super(ApplicationBundle.message("settings.editor.scheme.copy.to.project"));
}
@Override
public void actionPerformed(AnActionEvent e) {
T currentScheme = getCurrentScheme();
if (currentScheme != null && !getModel().isProjectScheme(currentScheme)) {
copyToProject(currentScheme);
}
}
@Override
public void update(AnActionEvent e) {
Presentation p = e.getPresentation();
T currentScheme = getCurrentScheme();
p.setEnabledAndVisible(currentScheme != null && !getModel().isProjectScheme(currentScheme));
}
}
private class CopyToIDEAction extends DumbAwareAction {
public CopyToIDEAction() {
super(ApplicationBundle.message("settings.editor.scheme.copy.to.ide"));
}
@Override
public void actionPerformed(AnActionEvent e) {
T currentScheme = getCurrentScheme();
if (currentScheme != null && getModel().isProjectScheme(currentScheme)) {
copyToIDE(currentScheme);
}
}
@Override
public void update(AnActionEvent e) {
Presentation p = e.getPresentation();
T currentScheme = getCurrentScheme();
p.setEnabledAndVisible(currentScheme != null && getModel().isProjectScheme(currentScheme));
}
}
private class ResetAction extends DumbAwareAction {
@@ -131,7 +197,7 @@ public abstract class AbstractSchemeActions<T extends Scheme> {
duplicateScheme(currentScheme,
SchemeNameGenerator.getUniqueName(
SchemeManager.getDisplayName(currentScheme),
name -> mySchemesPanel.getModel().nameExists(name)));
name -> mySchemesPanel.getModel().containsScheme(name)));
currentScheme = getCurrentScheme();
if (currentScheme != null) {
mySchemesPanel.startEdit();
@@ -252,29 +318,95 @@ public abstract class AbstractSchemeActions<T extends Scheme> {
}
}
}
/**
* Import a scheme using the given importer name.
*
* @param importerName The importer name.
* @see SchemeImporter
* @see SchemeImporterEP
*/
protected abstract void importScheme(@NotNull String importerName);
/**
* Reset scheme's settings to their default values (presets).
*
* @param scheme The scheme to reset.
*/
protected abstract void resetScheme(@NotNull T scheme);
/**
* Creates a copy of the scheme with a different name.
*
* @param scheme The scheme to copy.
* @param newName New name.
*/
protected abstract void duplicateScheme(@NotNull T scheme, @NotNull String newName);
/**
* Delete the scheme.
*
* @param scheme The scheme to delete.
*/
protected abstract void deleteScheme(@NotNull T scheme);
/**
* Export the scheme using the given exporter name.
*
* @param scheme The scheme to export.
* @param exporterName The exporter name.
* @see SchemeExporter
* @see SchemeExporterEP
*/
protected abstract void exportScheme(@NotNull T scheme, @NotNull String exporterName);
/**
* Make necessary configurable updates when another scheme has been selected.
*
* @param scheme The new current scheme.
*/
protected abstract void onSchemeChanged(@Nullable T scheme);
/**
* Change scheme's name to the new one. Called when a user stops editing by pressing Enter.
*
* @param scheme The scheme to rename.
* @param newName New scheme name.
*/
protected abstract void renameScheme(@NotNull T scheme, @NotNull String newName);
/**
* Copy the scheme to project. The implementation may decide what name to use.
*
* @param scheme The scheme to copy.
*/
protected void copyToProject(@NotNull T scheme) {
}
/**
* Copy the scheme to IDE (application). The implementation may decide what name to use.
*
* @param scheme The scheme to copy.
*/
protected void copyToIDE(@NotNull T scheme) {
}
@NotNull
protected SchemesModel<T> getModel() {
return mySchemesPanel.getModel();
}
@Nullable
protected final T getCurrentScheme() {
return mySchemesPanel.getSelectedScheme();
}
/**
* @return The actual scheme type.
*/
protected abstract Class<T> getSchemeType();
public AbstractSchemesPanel<T> getSchemesPanel() {
public final AbstractSchemesPanel<T> getSchemesPanel() {
return mySchemesPanel;
}
}
@@ -28,6 +28,14 @@ import javax.swing.*;
import java.awt.*;
import java.util.Collection;
/**
* Base panel for schemes combo box and related actions. When settings change, {@link #updateOnCurrentSettingsChange()} method must be
* called to reflect the change in schemes panel. The method should be added to settings model listener.
*
* @param <T> The actual scheme type.
* @see AbstractSchemeActions
* @see SchemesModel
*/
public abstract class AbstractSchemesPanel<T extends Scheme> extends JPanel {
private SchemesCombo<T> mySchemesCombo;
@@ -88,21 +96,26 @@ public abstract class AbstractSchemesPanel<T extends Scheme> extends JPanel {
}
}
public JComponent getToolbar() {
public final JComponent getToolbar() {
return myToolbar;
}
/**
* Creates schemes actions. Used when panel UI components are created.
* @return Scheme actions associated with the panel.
* @see AbstractSchemeActions
*/
protected abstract AbstractSchemeActions<T> createSchemeActions();
public T getSelectedScheme() {
public final T getSelectedScheme() {
return mySchemesCombo.getSelectedScheme();
}
public void selectScheme(@Nullable T scheme) {
public final void selectScheme(@Nullable T scheme) {
mySchemesCombo.selectScheme(scheme);
}
public void resetSchemes(@NotNull Collection<T> schemes) {
public final void resetSchemes(@NotNull Collection<T> schemes) {
mySchemesCombo.resetSchemes(schemes);
}
@@ -110,31 +123,38 @@ public abstract class AbstractSchemesPanel<T extends Scheme> extends JPanel {
removeAll();
}
public void startEdit() {
public final void startEdit() {
mySchemesCombo.startEdit();
}
public void cancelEdit() {
public final void cancelEdit() {
mySchemesCombo.cancelEdit();
}
public void showInfo(@Nullable String message, @NotNull MessageType messageType) {
public final void showInfo(@Nullable String message, @NotNull MessageType messageType) {
myInfoLabel.setText(message);
myInfoLabel.setForeground(messageType.getTitleForeground());
}
public void clearInfo() {
public final void clearInfo() {
myInfoLabel.setText(null);
}
public AbstractSchemeActions<T> getActions() {
public final AbstractSchemeActions<T> getActions() {
return myActions;
}
/**
* @return Schemes model implementation.
* @see SchemesModel
*/
@NotNull
public abstract SchemesModel<T> getModel();
public void updateOnCurrentSettingsChange() {
/**
* Must be called when any settings are changed.
*/
public final void updateOnCurrentSettingsChange() {
mySchemesCombo.updateSelected();
}
}
@@ -294,7 +294,7 @@ public class SchemesCombo<T extends Scheme> {
if (name.isEmpty()) {
return EMPTY_NAME_MESSAGE;
}
else if (mySchemesPanel.getModel().nameExists(name)) {
else if (mySchemesPanel.getModel().containsScheme(name)) {
return NAME_ALREADY_EXISTS_MESSAGE;
}
return null;
@@ -18,20 +18,61 @@ package com.intellij.application.options.schemes;
import com.intellij.openapi.options.Scheme;
import org.jetbrains.annotations.NotNull;
/**
* A generic schemes model used in schemes UI: schemes combo box and related actions.
*
* @param <T> Actual scheme type derived from {@code Scheme}
* @see AbstractSchemesPanel
* @see AbstractSchemeActions
*/
public interface SchemesModel<T extends Scheme> {
/**
* @return True if the model may contain both projects and IDE (application) schemes.
*/
boolean supportsProjectSchemes();
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);
/**
* @param scheme The scheme to check.
* @return True if the scheme can be duplicated with a different name.
*/
boolean canDuplicateScheme(@NotNull T scheme );
/**
* @param scheme The scheme to check.
* @return True if the scheme can be reset from default values (presets) in principle regardless of whether scheme settings actually
* differ from presets or not.
* @see #differsFromDefault(Scheme)
*/
boolean canResetScheme(@NotNull T scheme);
/**
* @param scheme The scheme to check.
* @return True if the scheme can be deleted, normally applies to custom schemes created by a user.
*/
boolean canDeleteScheme(@NotNull T scheme);
/**
* @param scheme The scheme to check.
* @return True if the given scheme is a project one. Always {@code false} if project schemes are not supported.
*/
boolean isProjectScheme(@NotNull T scheme);
/**
* @param scheme The scheme to check.
* @return True if scheme's name can be edited.
*/
boolean canRenameScheme(@NotNull T scheme);
/**
* @param name The scheme to check.
* @return True if a scheme by the given name already exists.
*/
boolean containsScheme(@NotNull String name);
/**
* @param scheme The scheme to check.
* @return True if scheme's settings differ from default values (presets). The method is called only if {@link #canResetScheme(Scheme)}
* returns {@code true}.
*/
boolean differsFromDefault(@NotNull T scheme);
}