blob: db4ed7645a47611596e23a201e523e718ad457f2 [file] [log] [blame]
/*
* Copyright 2000-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.lang.Language;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.OptionGroup;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;
public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPanel {
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.codeStyle.CodeStyleBlankLinesPanel");
private final List<IntOption> myOptions = new ArrayList<IntOption>();
private final Set<String> myAllowedOptions = new HashSet<String>();
private boolean myAllOptionsAllowed = false;
private boolean myIsFirstUpdate = true;
private final Map<String, String> myRenamedFields = new THashMap<String, String>();
private final MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>> myCustomOptions
= new MultiMap<String, Trinity<Class<? extends CustomCodeStyleSettings>, String, String>>();
private final JPanel myPanel = new JPanel(new GridBagLayout());
public CodeStyleBlankLinesPanel(CodeStyleSettings settings) {
super(settings);
myPanel.setBorder(IdeBorderFactory.createEmptyBorder(2, 2, 2, 2));
init();
}
@Override
protected void init() {
super.init();
JPanel optionsPanel = new JPanel(new GridBagLayout());
OptionGroup keepBlankLinesOptionsGroup = createKeepBlankLinesOptionsGroup();
OptionGroup blankLinesOptionsGroup = createBlankLinesOptionsGroup();
if (keepBlankLinesOptionsGroup != null) {
keepBlankLinesOptionsGroup.setAnchor(keepBlankLinesOptionsGroup.findAnchor());
optionsPanel.add(keepBlankLinesOptionsGroup.createPanel(),
new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
if (blankLinesOptionsGroup != null) {
blankLinesOptionsGroup.setAnchor(blankLinesOptionsGroup.findAnchor());
optionsPanel.add(blankLinesOptionsGroup.createPanel(),
new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
UIUtil.mergeComponentsWithAnchor(keepBlankLinesOptionsGroup, blankLinesOptionsGroup);
optionsPanel.add(new JPanel(),
new GridBagConstraints(0, 2, 1, 1, 0, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0,
0));
JScrollPane scroll = ScrollPaneFactory.createScrollPane(optionsPanel);
scroll.setBorder(null);
scroll.setMinimumSize(new Dimension(optionsPanel.getPreferredSize().width + scroll.getVerticalScrollBar().getPreferredSize().width + 5, -1));
scroll.setPreferredSize(scroll.getMinimumSize());
myPanel
.add(scroll,
new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 5), 0, 0));
final JPanel previewPanel = createPreviewPanel();
myPanel
.add(previewPanel,
new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
installPreviewPanel(previewPanel);
addPanelToWatch(myPanel);
myIsFirstUpdate = false;
}
@Override
public LanguageCodeStyleSettingsProvider.SettingsType getSettingsType() {
return LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS;
}
@Nullable
private OptionGroup createBlankLinesOptionsGroup() {
OptionGroup optionGroup = new OptionGroup(BLANK_LINES);
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.package.statement"), "BLANK_LINES_BEFORE_PACKAGE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.package.statement"), "BLANK_LINES_AFTER_PACKAGE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.imports"), "BLANK_LINES_BEFORE_IMPORTS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.imports"), "BLANK_LINES_AFTER_IMPORTS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.class"), "BLANK_LINES_AROUND_CLASS");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.class.header"), "BLANK_LINES_AFTER_CLASS_HEADER");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.after.anonymous.class.header"),
"BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER");
createOption(optionGroup, "Around field in interface:", "BLANK_LINES_AROUND_FIELD_IN_INTERFACE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.field"), "BLANK_LINES_AROUND_FIELD");
createOption(optionGroup, "Around method in interface:", "BLANK_LINES_AROUND_METHOD_IN_INTERFACE");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.around.method"), "BLANK_LINES_AROUND_METHOD");
createOption(optionGroup, ApplicationBundle.message("editbox.blanklines.before.method.body"), "BLANK_LINES_BEFORE_METHOD_BODY");
initCustomOptions(optionGroup, BLANK_LINES);
if (optionGroup.getComponents().length == 0) return null;
return optionGroup;
}
@Nullable
private OptionGroup createKeepBlankLinesOptionsGroup() {
OptionGroup optionGroup = new OptionGroup(BLANK_LINES_KEEP);
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.in.declarations"), "KEEP_BLANK_LINES_IN_DECLARATIONS");
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.in.code"), "KEEP_BLANK_LINES_IN_CODE");
createOption(optionGroup, ApplicationBundle.message("editbox.keep.blanklines.before.rbrace"), "KEEP_BLANK_LINES_BEFORE_RBRACE");
initCustomOptions(optionGroup, BLANK_LINES_KEEP);
if (optionGroup.getComponents().length == 0) return null;
return optionGroup;
}
private void initCustomOptions(OptionGroup optionGroup, String groupName) {
for (Trinity<Class<? extends CustomCodeStyleSettings>, String, String> each : myCustomOptions.get(groupName)) {
doCreateOption(optionGroup, each.third, new IntOption(each.first, each.second), each.second);
}
}
private void createOption(OptionGroup optionGroup, String title, String fieldName) {
if (myAllOptionsAllowed || myAllowedOptions.contains(fieldName)) {
doCreateOption(optionGroup, title, new IntOption(fieldName), fieldName);
}
}
private void doCreateOption(OptionGroup optionGroup, String title, IntOption option, String fieldName) {
String renamed = myRenamedFields.get(fieldName);
if (renamed != null) title = renamed;
JBLabel l = new JBLabel(title);
optionGroup.add(l, option.myTextField);
myOptions.add(option);
}
@Override
protected void resetImpl(final CodeStyleSettings settings) {
for (IntOption option : myOptions) {
option.setValue(option.getFieldValue(settings));
}
}
@Override
public void apply(CodeStyleSettings settings) {
for (IntOption option : myOptions) {
option.setFieldValue(settings, option.getValue());
}
}
@Override
public boolean isModified(CodeStyleSettings settings) {
for (IntOption option : myOptions) {
if (option.getFieldValue(settings) != option.getValue()) {
return true;
}
}
return false;
}
@Override
public JComponent getPanel() {
return myPanel;
}
@Override
public void showAllStandardOptions() {
myAllOptionsAllowed = true;
for (IntOption option : myOptions) {
option.myTextField.setEnabled(true);
}
}
@Override
public void showStandardOptions(String... optionNames) {
if (myIsFirstUpdate) {
Collections.addAll(myAllowedOptions, optionNames);
}
for (IntOption option : myOptions) {
option.myTextField.setEnabled(false);
for (String optionName : optionNames) {
if (option.myTarget.getName().equals(optionName)) {
option.myTextField.setEnabled(true);
break;
}
}
}
}
@Override
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
String fieldName,
String title,
String groupName, Object... options) {
showCustomOption(settingsClass, fieldName, title, groupName, null, null, options);
}
@Override
public void showCustomOption(Class<? extends CustomCodeStyleSettings> settingsClass,
String fieldName,
String title,
String groupName,
@Nullable OptionAnchor anchor,
@Nullable String anchorFieldName,
Object... options) {
if (myIsFirstUpdate) {
myCustomOptions.putValue(groupName, (Trinity)Trinity.create(settingsClass, fieldName, title));
}
for (IntOption option : myOptions) {
if (option.myTarget.getName().equals(fieldName)) {
option.myTextField.setEnabled(true);
}
}
}
@Override
public void renameStandardOption(String fieldName, String newTitle) {
if (myIsFirstUpdate) {
myRenamedFields.put(fieldName, newTitle);
}
for (IntOption option : myOptions) {
option.myTextField.invalidate();
}
}
@Override
protected void onLanguageChange(Language language) {
resetImpl(getSettings());
}
private class IntOption {
private final JTextField myTextField;
private final Field myTarget;
private Class<? extends CustomCodeStyleSettings> myTargetClass;
private int myCurrValue = Integer.MAX_VALUE;
private IntOption(String fieldName) {
this(CodeStyleSettings.class, fieldName, false);
}
private IntOption(Class<? extends CustomCodeStyleSettings> targetClass, String fieldName) {
this(targetClass, fieldName, false);
myTargetClass = targetClass;
}
private IntOption(Class<?> fieldClass, String fieldName, boolean dummy) {
try {
myTarget = fieldClass.getField(fieldName);
}
catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
myTextField = new JTextField(6);
myTextField.setMinimumSize(new Dimension(30, myTextField.getMinimumSize().height));
}
private int getFieldValue(CodeStyleSettings settings) {
try {
if (myTargetClass != null) {
return myTarget.getInt(settings.getCustomSettings(myTargetClass));
}
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(getSelectedLanguage());
return myTarget.getInt(commonSettings);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public void setFieldValue(CodeStyleSettings settings, int value) {
try {
if (myTargetClass != null) {
myTarget.setInt(settings.getCustomSettings(myTargetClass), value);
}
else {
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(getSelectedLanguage());
myTarget.setInt(commonSettings, value);
}
}
catch (IllegalAccessException e) {
LOG.error(e);
}
}
private int getValue() {
try {
myCurrValue = Integer.parseInt(myTextField.getText());
if (myCurrValue < 0) {
myCurrValue = 0;
}
if (myCurrValue > 10) {
myCurrValue = 10;
}
}
catch (NumberFormatException e) {
//bad number entered
myCurrValue = 0;
}
return myCurrValue;
}
public void setValue(int fieldValue) {
if (fieldValue != myCurrValue) {
myCurrValue = fieldValue;
myTextField.setText(String.valueOf(fieldValue));
}
}
}
@Override
protected String getTabTitle() {
return ApplicationBundle.message("title.blank.lines");
}
}