/*
* Copyright 2010 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.codeStyle;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* Base class for code style settings panels supporting multiple programming languages.
*
* @author rvishnyakov
*/
public abstract class CustomizableLanguageCodeStylePanel extends CodeStyleAbstractPanel implements CodeStyleSettingsCustomizable {
private static final Logger LOG = Logger.getInstance("com.intellij.application.options.codeStyle.MultilanguageCodeStyleAbstractPanel");
protected CustomizableLanguageCodeStylePanel(CodeStyleSettings settings) {
super(settings);
}
protected void init() {
customizeSettings();
}
protected void customizeSettings() {
LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(getDefaultLanguage());
if (provider != null) {
provider.customizeSettings(this, getSettingsType());
}
}
public abstract LanguageCodeStyleSettingsProvider.SettingsType getSettingsType();
protected void resetDefaultNames() {
}
@Override
protected String getPreviewText() {
if (getDefaultLanguage() == null) return "";
return LanguageCodeStyleSettingsProvider.getNotNullCodeSample(getDefaultLanguage(), getSettingsType());
}
@Override
protected PsiFile createFileFromText(final Project project, final String text) {
final PsiFile file = LanguageCodeStyleSettingsProvider.createFileFromText(getDefaultLanguage(), project, text);
return file != null ? file : super.createFileFromText(project, text);
}
@Override
protected int getRightMargin() {
if (getDefaultLanguage() == null) return -1;
return LanguageCodeStyleSettingsProvider.getRightMargin(getDefaultLanguage(), getSettingsType());
}
@Override
protected String getFileExt() {
String fileExt = LanguageCodeStyleSettingsProvider.getFileExt(getDefaultLanguage());
if (fileExt != null) return fileExt;
return super.getFileExt();
}
@NotNull
@Override
protected FileType getFileType() {
if (getDefaultLanguage() != null) {
FileType assocType = getDefaultLanguage().getAssociatedFileType();
if (assocType != null) {
return assocType;
}
}
return PlainTextFileType.INSTANCE;
}
@Override
@Nullable
protected EditorHighlighter createHighlighter(final EditorColorsScheme scheme) {
FileType fileType = getFileType();
return FileTypeEditorHighlighterProviders.INSTANCE.forFileType(fileType).getEditorHighlighter(
ProjectUtil.guessCurrentProject(getPanel()), fileType, null, scheme);
}
@Override
protected PsiFile doReformat(final Project project, final PsiFile psiFile) {
final String text = psiFile.getText();
final PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
final Document doc = manager.getDocument(psiFile);
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
doc.replaceString(0, doc.getTextLength(), text);
manager.commitDocument(doc);
try {
CodeStyleManager.getInstance(project).reformat(psiFile);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
});
}
}, "", "");
if (doc != null) {
manager.commitDocument(doc);
}
return psiFile;
}
protected static JPanel createPreviewPanel() {
return new JPanel(new BorderLayout());
}
@Override
public void moveStandardOption(String fieldName, String newGroup) {
throw new UnsupportedOperationException();
}
protected <T extends OrderedOption>List<T> sortOptions(Collection<T> options) {
Set<String> names = new THashSet<String>(ContainerUtil.map(options, new Function<OrderedOption, String>() {
@Override
public String fun(OrderedOption option) {
return option.getOptionName();
}
}));
List<T> order = new ArrayList<T>(options.size());
MultiMap<String, T> afters = new MultiMap<String, T>();
MultiMap<String, T> befores = new MultiMap<String, T>();
for (T each : options) {
String anchorOptionName = each.getAnchorOptionName();
if (anchorOptionName != null && names.contains(anchorOptionName)) {
if (each.getAnchor() == OptionAnchor.AFTER) {
afters.putValue(anchorOptionName, each);
continue;
}
else if (each.getAnchor() == OptionAnchor.BEFORE) {
befores.putValue(anchorOptionName, each);
continue;
}
}
order.add(each);
}
List<T> result = new ArrayList<T>(options.size());
for (T each : order) {
result.addAll(befores.get(each.getOptionName()));
result.add(each);
result.addAll(afters.get(each.getOptionName()));
}
assert result.size() == options.size();
return result;
}
protected abstract static class OrderedOption {
@NotNull private final String optionName;
@Nullable private final OptionAnchor anchor;
@Nullable private final String anchorOptionName;
protected OrderedOption(@NotNull String optionName,
OptionAnchor anchor,
String anchorOptionName) {
this.optionName = optionName;
this.anchor = anchor;
this.anchorOptionName = anchorOptionName;
}
@NotNull
public String getOptionName() {
return optionName;
}
@Nullable
public OptionAnchor getAnchor() {
return anchor;
}
@Nullable
public String getAnchorOptionName() {
return anchorOptionName;
}
}
}