diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/EditorNotificationInfo.java b/platform/lang-api/src/com/intellij/psi/codeStyle/EditorNotificationInfo.java new file mode 100644 index 000000000000..59315c245631 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/EditorNotificationInfo.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2015 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.psi.codeStyle; + +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.Collections; +import java.util.List; + +public class EditorNotificationInfo { + + private String myTitle; + private Icon myIcon; + private List myLabelsWithActions = ContainerUtil.newArrayList(); + + public EditorNotificationInfo(@NotNull String title, + @NotNull LabelWithAction firstLabel, + @Nullable LabelWithAction... otherLabels) + { + myTitle = title; + myLabelsWithActions.add(firstLabel); + if (otherLabels != null) { + Collections.addAll(myLabelsWithActions, otherLabels); + } + } + + public EditorNotificationInfo(@NotNull String title, + @NotNull Icon icon, + @NotNull LabelWithAction firstLabel, + @Nullable LabelWithAction... otherLabels) + { + this(title, firstLabel, otherLabels); + myIcon = icon; + } + + @NotNull + public List getLabelAndActions() { + return myLabelsWithActions; + } + + @Nullable + public Icon getIcon() { + return myIcon; + } + + @NotNull + public String getTitle() { + return myTitle; + } + +} + + diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/FileIndentOptionsProvider.java b/platform/lang-api/src/com/intellij/psi/codeStyle/FileIndentOptionsProvider.java index 3003d23e4f06..6c06a9216027 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/FileIndentOptionsProvider.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/FileIndentOptionsProvider.java @@ -16,9 +16,11 @@ package com.intellij.psi.codeStyle; import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.ui.EditorNotificationPanel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +29,7 @@ import javax.swing.*; /** * @author Rustam Vishnyakov */ -public abstract class FileIndentOptionsProvider { +public abstract class FileIndentOptionsProvider { public final static ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.fileIndentOptionsProvider"); /** @@ -48,36 +50,18 @@ public abstract class FileIndentOptionsProvider { } /** - * @return A name which will be used to notify a user on overwritten indent options. If the option is null, no notification + * @return information used to create user notification in editor. If the option is null, no notification * will be shown. */ @Nullable - public String getDisplayName() { + public EditorNotificationInfo getNotificationInfo(@NotNull Project project, + @NotNull VirtualFile file, + @NotNull FileEditor fileEditor, + @NotNull CommonCodeStyleSettings.IndentOptions user, + @NotNull CommonCodeStyleSettings.IndentOptions detected) { return null; } - - /** - * @return The icon to be displayed in a notification message, can be null (no icon). - */ - @Nullable - public Icon getIcon() { - return null; - } - - /** - * @return True if the provider can be disabled (default is false). - */ - public boolean canBeDisabled() { - return false; - } - - /** - * Disables the provider. - * @param project The project to disable the provider for. - */ - public void disable(@NotNull Project project) { - } - + /** * Tells if there should not be any notification for this specific file. * @param file The file to check. diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/LabelWithAction.java b/platform/lang-api/src/com/intellij/psi/codeStyle/LabelWithAction.java new file mode 100644 index 000000000000..b39afc320102 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/LabelWithAction.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2015 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.psi.codeStyle; + +import org.jetbrains.annotations.NotNull; + +public class LabelWithAction { + + public final String label; + public final Runnable action; + + public LabelWithAction(@NotNull String label, @NotNull Runnable action) { + this.label = label; + this.action = action; + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java index 36677c4cdb8d..1687817f5a22 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectableIndentOptionsProvider.java @@ -15,16 +15,19 @@ */ package com.intellij.psi.codeStyle.autodetect; +import com.intellij.ide.actions.ShowSettingsUtilImpl; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.psi.codeStyle.FileIndentOptionsProvider; +import com.intellij.psi.codeStyle.*; import com.intellij.testFramework.LightVirtualFile; +import com.intellij.ui.EditorNotifications; import com.intellij.util.containers.WeakList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,6 +41,7 @@ import java.util.List; public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider { private boolean myIsEnabledInTest; private final List myAcceptedFiles = new WeakList(); + private final List myDisabledFiles = new WeakList(); @Nullable @Override @@ -60,7 +64,7 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider { return myIsEnabledInTest; } VirtualFile vFile = file.getVirtualFile(); - if (vFile == null || vFile instanceof LightVirtualFile) return false; + if (vFile == null || vFile instanceof LightVirtualFile || myDisabledFiles.contains(vFile)) return false; return settings.AUTODETECT_INDENTS; } @@ -72,21 +76,83 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider { @Nullable @Override - public String getDisplayName() { - return ApplicationBundle.message("code.style.indents.detector.display.name"); + public EditorNotificationInfo getNotificationInfo(@NotNull final Project project, + @NotNull final VirtualFile file, + @NotNull final FileEditor fileEditor, + @NotNull CommonCodeStyleSettings.IndentOptions userOptions, + @NotNull CommonCodeStyleSettings.IndentOptions detectedOptions) + { + NotificationLabels labels = getNotificationLabels(userOptions, detectedOptions); + final Editor editor = fileEditor instanceof TextEditor ? ((TextEditor)fileEditor).getEditor() : null; + if (labels == null || editor == null) return null; + + LabelWithAction okAction = new LabelWithAction( + ApplicationBundle.message("code.style.indents.detector.accept"), + new Runnable() { + @Override + public void run() { + setAccepted(file); + EditorNotifications.getInstance(project).updateAllNotifications(); + } + } + ); + + LabelWithAction disableForSingleFile = new LabelWithAction( + labels.revertToOldSettingsLabel, + new Runnable() { + @Override + public void run() { + disableForFile(file); + if (editor instanceof EditorEx) { + ((EditorEx)editor).reinitSettings(); + } + EditorNotifications.getInstance(project).updateAllNotifications(); + } + } + ); + + LabelWithAction showSettings = new LabelWithAction( + ApplicationBundle.message("code.style.indents.detector.show.settings"), + new Runnable() { + @Override + public void run() { + ShowSettingsUtilImpl.showSettingsDialog(project, "preferences.sourceCode", + ApplicationBundle.message("settings.code.style.general.autodetect.indents")); + EditorNotifications.getInstance(project).updateAllNotifications(); + } + } + ); + + return new EditorNotificationInfo(labels.title, okAction, disableForSingleFile, showSettings); } - @Override - public boolean canBeDisabled() { - return true; + @Nullable + private static NotificationLabels getNotificationLabels(@NotNull CommonCodeStyleSettings.IndentOptions userOptions, + @NotNull CommonCodeStyleSettings.IndentOptions detectedOptions) { + if (userOptions.USE_TAB_CHARACTER) { + if (!detectedOptions.USE_TAB_CHARACTER) { + return new NotificationLabels(ApplicationBundle.message("code.style.space.indent.detected", detectedOptions.INDENT_SIZE), + ApplicationBundle.message("code.style.detector.use.tabs")); + } + } + else { + String restoreToSpaces = ApplicationBundle.message("code.style.detector.use.spaces", userOptions.INDENT_SIZE); + if (detectedOptions.USE_TAB_CHARACTER) { + return new NotificationLabels(ApplicationBundle.message("code.style.tab.usage.detected", userOptions.INDENT_SIZE), + restoreToSpaces); + } + if (userOptions.INDENT_SIZE != detectedOptions.INDENT_SIZE) { + return new NotificationLabels(ApplicationBundle.message("code.style.different.indent.size.detected", detectedOptions.INDENT_SIZE, userOptions.INDENT_SIZE), + restoreToSpaces); + } + } + return null; } - @Override - public void disable(@NotNull Project project) { - CodeStyleSettingsManager.getSettings(project).AUTODETECT_INDENTS = false; - myAcceptedFiles.clear(); + private void disableForFile(@NotNull VirtualFile file) { + myDisabledFiles.add(file); } - + @Override public void setAccepted(@NotNull VirtualFile file) { myAcceptedFiles.add(file); @@ -96,4 +162,14 @@ public class DetectableIndentOptionsProvider extends FileIndentOptionsProvider { public boolean isAcceptedWithoutWarning(@NotNull VirtualFile file) { return myAcceptedFiles.contains(file); } + + private static class NotificationLabels { + public final String title; + public final String revertToOldSettingsLabel; + + public NotificationLabels(@NotNull String title, @NotNull String revertToOldSettingsLabel) { + this.title = title; + this.revertToOldSettingsLabel = revertToOldSettingsLabel; + } + } } diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java index 81b0485d5881..b0be0cee284f 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/autodetect/DetectedIndentOptionsNotificationProvider.java @@ -15,10 +15,8 @@ */ package com.intellij.psi.codeStyle.autodetect; -import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.Project; @@ -27,10 +25,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import com.intellij.psi.codeStyle.FileIndentOptionsProvider; +import com.intellij.psi.codeStyle.*; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotifications; import com.intellij.util.Processor; @@ -73,41 +68,17 @@ public class DetectedIndentOptionsNotificationProvider extends EditorNotificatio } }); final FileIndentOptionsProvider provider = indentOptionsProviderRef.get(); - if (provider != null && - !provider.isAcceptedWithoutWarning(file) && - provider.getDisplayName() != null && - !userOptions.equals(detectedOptions)) { - final EditorNotificationPanel panel = - new EditorNotificationPanel() - .text(ApplicationBundle.message("code.style.indents.detector.message", provider.getDisplayName(), - getOptionDiffInfoString(userOptions, detectedOptions))); - if (provider.getIcon() != null) { - panel.icon(provider.getIcon()); + EditorNotificationInfo info = provider != null && !provider.isAcceptedWithoutWarning(file) && !userOptions.equals(detectedOptions) + ? provider.getNotificationInfo(project, file, fileEditor, userOptions, detectedOptions) + : null; + + if (info != null) { + EditorNotificationPanel panel = new EditorNotificationPanel().text(info.getTitle()); + if (info.getIcon() != null) { + panel.icon(info.getIcon()); } - panel.createActionLabel( - ApplicationBundle.message("code.style.indents.detector.accept"), - new Runnable() { - @Override - public void run() { - provider.setAccepted(file); - EditorNotifications.getInstance(project).updateAllNotifications(); - } - } - ); - if (provider.canBeDisabled()) { - panel.createActionLabel( - ApplicationBundle.message("code.style.indents.detector.disable"), - new Runnable() { - @Override - public void run() { - provider.disable(project); - if (editor instanceof EditorEx) { - ((EditorEx)editor).reinitSettings(); - } - EditorNotifications.getInstance(project).updateAllNotifications(); - } - } - ); + for (LabelWithAction action : info.getLabelAndActions()) { + panel.createActionLabel(action.label, action.action); } return panel; } @@ -116,26 +87,4 @@ public class DetectedIndentOptionsNotificationProvider extends EditorNotificatio } return null; } - - @NotNull - private static String getOptionDiffInfoString(CommonCodeStyleSettings.IndentOptions user, - CommonCodeStyleSettings.IndentOptions detected) { - StringBuilder sb = new StringBuilder(); - if (user.INDENT_SIZE != detected.INDENT_SIZE) { - sb.append("indent size=").append(detected.INDENT_SIZE); - } - if (user.TAB_SIZE != detected.TAB_SIZE) { - if (sb.length() > 0) sb.append(", "); - sb.append("tab size=").append(detected.TAB_SIZE); - } - if (user.USE_TAB_CHARACTER != detected.USE_TAB_CHARACTER) { - if (sb.length() > 0) sb.append(", "); - sb.append(detected.USE_TAB_CHARACTER ? "tabs" : "no tabs"); - } - if (user.SMART_TABS != detected.SMART_TABS) { - if (sb.length() > 0) sb.append(", "); - sb.append(detected.SMART_TABS ? "smart tabs" : "no smart tabs"); - } - return sb.toString(); - } } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index fc6522fcb747..187ff0ae6ae5 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -685,7 +685,12 @@ reformat.changed.text.file.too.big.notification.text=file {0} is too big or ther bulk.reformat.prepare.progress.text=Preparing... bulk.reformat.process.progress.text=Processing... -code.style.indents.detector.display.name=Automatic indent options detector -code.style.indents.detector.message=Indent options for the file are overwritten by {0} ({1}) -code.style.indents.detector.accept=OK -code.style.indents.detector.disable=Disable for all files \ No newline at end of file +code.style.different.indent.size.detected=This file is indented with {0} spaces instead of {1} +code.style.tab.usage.detected=This file is indented with tabs instead of {0} spaces +code.style.space.indent.detected=This file is indented with {0} spaces instead of the tab character + +code.style.detector.use.spaces=Indent with {0} spaces +code.style.detector.use.tabs=Indent with tab + +code.style.indents.detector.show.settings=Show Settings +code.style.indents.detector.accept=OK \ No newline at end of file