code style import: refactor to allow custom pre-import settings dialog

eclipse importer refactored
This commit is contained in:
irengrig
2015-04-21 16:45:29 +02:00
parent c2b631de28
commit b70d1c6d32
7 changed files with 485 additions and 416 deletions
@@ -1,7 +1,7 @@
package com.intellij.application.options;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.options.Scheme;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBList;
import org.jetbrains.annotations.NotNull;
@@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@@ -26,10 +25,10 @@ public class ImportSchemeChooserDialog extends DialogWrapper {
private final static String UNNAMED_SCHEME_ITEM = "<" + ApplicationBundle.message("code.style.scheme.import.unnamed") + ">";
private final List<String> myNames = new ArrayList<String>();
public ImportSchemeChooserDialog(@NotNull Component parent,
public ImportSchemeChooserDialog(@NotNull Project project,
String[] schemeNames,
final @Nullable String currScheme) {
super(parent, false);
super(project, false);
if (schemeNames.length > 0) {
myNames.addAll(Arrays.asList(schemeNames));
}
@@ -279,4 +279,8 @@ public class CodeStyleSchemesModel {
});
return schemes;
}
public Project getProject() {
return myProject;
}
}
@@ -15,7 +15,6 @@
*/
package com.intellij.application.options.codeStyle;
import com.intellij.application.options.ImportSchemeChooserDialog;
import com.intellij.application.options.ImportSourceChooserDialog;
import com.intellij.application.options.SaveSchemeDialog;
import com.intellij.application.options.SchemesToImportPopup;
@@ -39,6 +38,7 @@ import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.table.JBTable;
import com.intellij.util.PairConvertor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,8 +51,6 @@ import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.List;
@@ -184,84 +182,42 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper {
private String importExternalCodeStyle(String importerName) throws SchemeImportException {
final SchemeImporter<CodeStyleScheme> importer = SchemeImporterEP.getImporter(importerName, CodeStyleScheme.class);
if (importer != null) {
final Set<String> extensions = new HashSet<String>(Arrays.asList(importer.getSourceExtensions()));
FileChooserDialog fileChooser = FileChooserFactory.getInstance()
.createFileChooser(new FileChooserDescriptor(true, false, false, false, false, false) {
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
return file.isDirectory() || extensions.contains(file.getExtension());
}
@Override
public boolean isFileSelectable(VirtualFile file) {
return !file.isDirectory() && extensions.contains(file.getExtension());
}
}, null, myContentPane);
VirtualFile[] selection = fileChooser.choose(null, CodeStyleSchemesUIConfiguration.Util.getRecentImportFile());
if (selection.length == 1) {
VirtualFile selectedFile = selection[0];
selectedFile.refresh(false, false);
final VirtualFile selectedFile = selectImportSource(importer.getSourceExtensions());
if (selectedFile != null) {
CodeStyleSchemesUIConfiguration.Util.setRecentImportFile(selectedFile);
try {
InputStream nameInputStream = selectedFile.getInputStream();
String[] schemeNames;
try {
schemeNames = importer.readSchemeNames(nameInputStream);
}
finally {
nameInputStream.close();
}
CodeStyleScheme currScheme = myModel.getSelectedScheme();
ImportSchemeChooserDialog schemeChooserDialog =
new ImportSchemeChooserDialog(myContentPane, schemeNames, !currScheme.isDefault() ? currScheme.getName() : null);
if (schemeChooserDialog.showAndGet()) {
String schemeName = schemeChooserDialog.getSelectedName();
String targetName = schemeChooserDialog.getTargetName();
CodeStyleScheme targetScheme = null;
if (schemeChooserDialog.isUseCurrentScheme()) {
targetScheme = myModel.getSelectedScheme();
}
else {
if (targetName == null) targetName = ApplicationBundle.message("code.style.scheme.import.unnamed");
for (CodeStyleScheme scheme : myModel.getSchemes()) {
if (targetName.equals(scheme.getName())) {
targetScheme = scheme;
break;
}
}
if (targetScheme == null) {
int row = mySchemesTableModel.createNewScheme(getSelectedScheme(), targetName);
mySchemesTable.getSelectionModel().setSelectionInterval(row, row);
targetScheme = mySchemesTableModel.getSchemeAt(row);
}
else {
int result = Messages.showYesNoDialog(myContentPane,
ApplicationBundle.message("message.code.style.scheme.already.exists", targetName),
ApplicationBundle.message("title.code.style.settings.import"),
Messages.getQuestionIcon());
if (result != Messages.YES) {
return null;
}
}
}
InputStream dataInputStream = selectedFile.getInputStream();
try {
importer.importScheme(dataInputStream, schemeName, targetScheme);
myModel.fireSchemeChanged(targetScheme);
}
finally {
dataInputStream.close();
}
return targetScheme.getName();
}
final SchemeCreator schemeCreator = new SchemeCreator();
final boolean schemeImported = importer.importScheme(myModel.getProject(), selectedFile, myModel.getSelectedScheme(), schemeCreator);
if (schemeImported) {
final CodeStyleScheme targetScheme = schemeCreator.getTargetScheme();
myModel.fireSchemeChanged(targetScheme);
return targetScheme.getName();
}
catch (IOException e) {
throw new SchemeImportException(e);
}
}
}
return null;
}
@Nullable
private VirtualFile selectImportSource(final String[] sourceExtensions) {
final Set<String> extensions = new HashSet<String>(Arrays.asList(sourceExtensions));
FileChooserDialog fileChooser = FileChooserFactory.getInstance()
.createFileChooser(new FileChooserDescriptor(true, false, false, false, false, false) {
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
return file.isDirectory() || extensions.contains(file.getExtension());
}
@Override
public boolean isFileSelectable(VirtualFile file) {
return !file.isDirectory() && extensions.contains(file.getExtension());
}
}, null, myContentPane);
final VirtualFile[] virtualFiles = fileChooser.choose(null, CodeStyleSchemesUIConfiguration.Util.getRecentImportFile());
if (virtualFiles.length != 1) return null;
virtualFiles[0].refresh(false, false);
return virtualFiles[0];
}
private void updateActions() {
CodeStyleScheme selectedScheme = getSelectedScheme();
myDeleteButton.setEnabled(!(selectedScheme.isDefault() || mySchemesTableModel.isProjectScheme(selectedScheme)));
@@ -302,6 +258,39 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper {
mySchemesTable = new MySchemesTable();
}
private class SchemeCreator implements PairConvertor<String, Boolean, CodeStyleScheme> {
private CodeStyleScheme myTargetScheme;
@Override
public CodeStyleScheme convert(String targetName, final Boolean useCurrent) {
if (Boolean.TRUE.equals(useCurrent)) {
myTargetScheme = myModel.getSelectedScheme();
} else {
if (targetName == null) targetName = ApplicationBundle.message("code.style.scheme.import.unnamed");
for (CodeStyleScheme scheme : myModel.getSchemes()) {
if (targetName.equals(scheme.getName())) {
int result = Messages.showYesNoDialog(myContentPane,
ApplicationBundle.message("message.code.style.scheme.already.exists", targetName),
ApplicationBundle.message("title.code.style.settings.import"),
Messages.getQuestionIcon());
if (result != Messages.YES) {
return null;
}
}
}
int row = mySchemesTableModel.createNewScheme(getSelectedScheme(), targetName);
mySchemesTable.getSelectionModel().setSelectionInterval(row, row);
myTargetScheme = mySchemesTableModel.getSchemeAt(row);
}
return myTargetScheme;
}
public CodeStyleScheme getTargetScheme() {
return myTargetScheme;
}
}
private class MySchemesTable extends JBTable {
private final TableCellRenderer myFixedItemsRenderer;
@@ -1,9 +1,9 @@
package com.intellij.openapi.options;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PairConvertor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
/**
* Provides functionality to import a scheme from another non-IntelliJ IDEA format.
@@ -19,22 +19,14 @@ public interface SchemeImporter <T extends Scheme> {
String[] getSourceExtensions();
/**
* Attempts to read scheme names from the given stream. The stream may contain several schemes in which case all the available
* names are returned.
*
* @param inputStream The input stream to read the name from.
* @return Either scheme name or null if the scheme doesn't have a name.
* @throws SchemeImportException
* Import a scheme from the given virtual file
* @param project
* @param selectedFile The input file to import from.
* @param currentScheme
* @param schemeCreator Callback that provides the target scheme receiving data.
*/
@NotNull
String[] readSchemeNames(@NotNull InputStream inputStream) throws SchemeImportException;
/**
* Import a scheme from the given stream and source scheme name.
*
* @param inputStream The input stream to import from.
* @param sourceScheme The source scheme name (one of returned by <code>readSchemeNames</code> method).
* @param scheme The target scheme receiving data.
*/
void importScheme(@NotNull InputStream inputStream, @Nullable String sourceScheme, T scheme) throws SchemeImportException;
boolean importScheme(@NotNull Project project,
@NotNull VirtualFile selectedFile,
T currentScheme,
@NotNull PairConvertor<String, Boolean, T> schemeCreator) throws SchemeImportException;
}
@@ -0,0 +1,344 @@
/*
* 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 org.jetbrains.idea.eclipse.importer;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.options.SchemeImportException;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.lang.reflect.Field;
/**
* @author Irina.Chernushina on 4/21/2015.
*/
public class EclipseCodeStyleImportWorker implements EclipseXmlProfileElements {
private static final Logger LOG = Logger.getInstance("#" + EclipseCodeStyleImportWorker.class.getName());
private final static String PROGRAMMATIC_IMPORT_KEY = "<Programmatic>";
private final EclipseImportMap myImportMap;
public EclipseCodeStyleImportWorker() {
myImportMap = new EclipseImportMap();
myImportMap.load();
}
public void importScheme(@NotNull InputStream inputStream, final @Nullable String sourceScheme, final CodeStyleScheme scheme)
throws SchemeImportException {
final CodeStyleSettings settings = scheme.getCodeStyleSettings();
EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
private String myCurrScheme;
@Override
public void handleOption(@NotNull String eclipseKey, @NotNull String value) throws SchemeImportException {
if (sourceScheme == null || myCurrScheme != null && myCurrScheme.equals(sourceScheme)) {
setCodeStyleOption(settings, eclipseKey, value);
}
}
@Override
public void handleName(String name) {
myCurrScheme = name;
}
});
reader.readSettings(inputStream);
}
private void setCodeStyleOption(@NotNull CodeStyleSettings settings, @NotNull String key, @NotNull String value)
throws SchemeImportException {
EclipseImportMap.ImportDescriptor importDescriptor = myImportMap.getImportDescriptor(key);
if (importDescriptor != null) {
try {
if (importDescriptor.isLanguageSpecific()) {
CommonCodeStyleSettings languageSettings = settings.getCommonSettings(importDescriptor.getLanguage());
if (languageSettings != null) {
if (importDescriptor.isIndentOptions()) {
CommonCodeStyleSettings.IndentOptions indentOptions = languageSettings.getIndentOptions();
if (indentOptions != null) {
setValue(indentOptions, key, importDescriptor.getFieldName(), value);
}
}
else {
setValue(languageSettings, key, importDescriptor.getFieldName(), value);
}
}
}
else {
setValue(settings, key, importDescriptor.getFieldName(), value);
}
}
catch (Exception e) {
throw new SchemeImportException(e);
}
}
}
private static void setValue(Object object, String key, String fieldName, String value) throws SchemeImportException {
if (PROGRAMMATIC_IMPORT_KEY.equalsIgnoreCase(fieldName)) {
setProgrammatically(object, key, value);
return;
}
try {
Field targetField = object.getClass().getField(fieldName);
Class<?> fieldType = targetField.getType();
if (fieldType.isPrimitive()) {
if (Boolean.TYPE.equals(fieldType)) {
targetField.setBoolean(object, valueToBoolean(key, value));
}
else if (Integer.TYPE.equals(fieldType)) {
targetField.setInt(object, valueToInt(value));
}
}
else if (fieldType.equals(String.class)) {
targetField.set(object, value);
}
}
catch (IllegalAccessException e) {
LOG.error(e);
}
catch (NoSuchFieldException e) {
LOG.error("Field '" + fieldName + "' does not exist in " + object.getClass().getName(), e);
}
}
private static boolean valueToBoolean(@NotNull String key, @NotNull String value) throws SchemeImportException {
if (VALUE_INSERT.equals(value) ||
VALUE_TRUE.equals(value)) {
return true;
}
if (!(VALUE_DO_NOT_INSERT.equals(value) ||
VALUE_FALSE.equals(value))) {
throw new SchemeImportException("Unrecognized boolean value: " + value + ", key: " + key);
}
return false;
}
private static int valueToInt(@NotNull String value) {
if (VALUE_END_OF_LINE.equals(value)) return CommonCodeStyleSettings.END_OF_LINE;
if (VALUE_NEXT_LINE.equals(value)) return CommonCodeStyleSettings.NEXT_LINE;
if (VALUE_NEXT_LINE_SHIFTED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_SHIFTED;
if (VALUE_NEXT_LINE_IF_WRAPPED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED;
return Integer.parseInt(value);
}
private static class AlignmentAndWrapValueDecoder {
int myEncodedValue;
public AlignmentAndWrapValueDecoder(int encodedValue) {
myEncodedValue = encodedValue;
}
public int getWrapType() {
switch (getEclipseWrap()) {
case WRAP_WHERE_NECESSARY:
case WRAP_FIRST_OTHERS_WHERE_NECESSARY:
return CommonCodeStyleSettings.WRAP_AS_NEEDED;
case WRAP_ALL_EXCEPT_FIRST:
case WRAP_ALL_INDENT_EXCEPT_FIRST:
case WRAP_ALL_ON_NEW_LINE_EACH:
return CommonCodeStyleSettings.WRAP_AS_NEEDED | CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM;
}
return CommonCodeStyleSettings.DO_NOT_WRAP;
}
public int getFirstElementWrapType() {
return isNewLineBeforeFirst() ? CommonCodeStyleSettings.WRAP_ALWAYS :
getEclipseWrap() == WRAP_ALL_EXCEPT_FIRST ? CommonCodeStyleSettings.DO_NOT_WRAP :
CommonCodeStyleSettings.WRAP_AS_NEEDED;
}
public boolean isFirstElementWrapped() {
int eclipseWrapValue = getEclipseWrap();
return eclipseWrapValue == WRAP_FIRST_OTHERS_WHERE_NECESSARY ||
eclipseWrapValue == WRAP_ALL_INDENT_EXCEPT_FIRST ||
eclipseWrapValue == WRAP_ALL_ON_NEW_LINE_EACH ||
isNewLineBeforeFirst();
}
public boolean isNewLineBeforeFirst() {
return (myEncodedValue & 1) != 0;
}
public boolean isAlignmentOn() {
return (myEncodedValue & 2) != 0;
}
public int getEclipseWrap() {
return myEncodedValue & WRAP_MASK;
}
}
private static void setProgrammatically(@NotNull Object object, @NotNull String key, @NotNull String value) throws SchemeImportException {
if (key.contains("alignment") && value.matches("\\d*") && object instanceof CommonCodeStyleSettings) {
if (setAlignmentAndWrappingOptions((CommonCodeStyleSettings)object, key, value)) return;
}
if (object instanceof CodeStyleSettings) {
CodeStyleSettings settings = (CodeStyleSettings)object;
if (OPTION_REMOVE_JAVADOC_BLANK_LINES.equals(key)) {
settings.JD_KEEP_EMPTY_LINES = !valueToBoolean(key, value);
}
else if (OPTION_NEW_LINE_AT_EOF.equals(key)) {
EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
editorSettings.setEnsureNewLineAtEOF(valueToBoolean(key, value));
}
}
else if (object instanceof CommonCodeStyleSettings) {
CommonCodeStyleSettings commonSettings = (CommonCodeStyleSettings)object;
if (OPTION_SPACE_AFTER_BINARY_OPERATOR.equals(key)) {
boolean addSpace = valueToBoolean(key, value);
commonSettings.SPACE_AROUND_ADDITIVE_OPERATORS =
commonSettings.SPACE_AROUND_BITWISE_OPERATORS =
commonSettings.SPACE_AROUND_LOGICAL_OPERATORS =
commonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS =
commonSettings.SPACE_AROUND_RELATIONAL_OPERATORS =
commonSettings.SPACE_AROUND_SHIFT_OPERATORS =
commonSettings.SPACE_AROUND_EQUALITY_OPERATORS =
addSpace;
}
else if (OPTION_INDENT_CLASS_BODY_DECL.equals(key)) {
commonSettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS = !valueToBoolean(key, value);
}
else if (OPTION_BLANK_LINES_BEFORE_FIRST_DECLARATION_IN_CLASS.equals(key)) {
int intValue = valueToInt(value);
commonSettings.BLANK_LINES_AFTER_CLASS_HEADER = intValue;
commonSettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER = intValue;
}
else if (OPTION_EMPTY_LINES_TO_PRESERVE.equals(key)) {
int intValue = valueToInt(value);
commonSettings.KEEP_BLANK_LINES_IN_CODE = intValue;
commonSettings.KEEP_BLANK_LINES_IN_DECLARATIONS = intValue;
commonSettings.KEEP_BLANK_LINES_BEFORE_RBRACE = intValue;
}
else if (OPTION_SPACE_AFTER_CLOSING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_ELSE_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_KEYWORD = insertSpace;
}
else if (OPTION_SPACE_BEFORE_OPENING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_IF_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FOR_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_WHILE_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_DO_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_TRY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE = insertSpace;
}
else if (OPTION_JOIN_WRAPPED_LINES.equals(key)) {
commonSettings.KEEP_LINE_BREAKS = !valueToBoolean(key, value);
}
}
else if (object instanceof CommonCodeStyleSettings.IndentOptions) {
CommonCodeStyleSettings.IndentOptions indentOptions = (CommonCodeStyleSettings.IndentOptions)object;
if (OPTION_TAB_CHAR.equals(key)) {
if (TAB_CHAR_TAB.equals(value) || TAB_CHAR_MIXED.equals(value)) {
indentOptions.USE_TAB_CHARACTER = true;
}
else if (TAB_CHAR_SPACE.equals(value)) {
indentOptions.USE_TAB_CHARACTER = false;
}
}
else if (OPTION_CONTINUATION_INDENT.equals(key)) {
indentOptions.CONTINUATION_INDENT_SIZE = indentOptions.TAB_SIZE * valueToInt(value);
}
else if (OPTION_TAB_SIZE.equals(key)) {
int newTabSize = valueToInt(value);
int continuationTabs = indentOptions.TAB_SIZE > 0 ? indentOptions.CONTINUATION_INDENT_SIZE / indentOptions.TAB_SIZE : -1;
indentOptions.TAB_SIZE = newTabSize;
if (continuationTabs >= 0) {
indentOptions.CONTINUATION_INDENT_SIZE = continuationTabs * newTabSize;
}
}
}
}
private static boolean setAlignmentAndWrappingOptions(@NotNull CommonCodeStyleSettings settings,
@NotNull String key,
@NotNull String value) {
int encodedValue = Integer.parseInt(value);
AlignmentAndWrapValueDecoder decoder = new AlignmentAndWrapValueDecoder(encodedValue);
if (OPTION_ALIGN_ARGS_IN_ANNOTATION.equals(key)) {
settings.FIELD_ANNOTATION_WRAP =
settings.METHOD_ANNOTATION_WRAP =
settings.PARAMETER_ANNOTATION_WRAP =
settings.VARIABLE_ANNOTATION_WRAP =
settings.CLASS_ANNOTATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_EXPR_IN_ARRAY_INITIALIZER.equals(key)) {
settings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION = decoder.isAlignmentOn();
settings.ARRAY_INITIALIZER_WRAP = decoder.getWrapType();
settings.ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_ARGS_IN_METHOD_INVOCATION.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = decoder.isAlignmentOn();
settings.CALL_PARAMETERS_WRAP = decoder.getWrapType();
settings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_INTERFACES_IN_TYPE_DECL.equals(key)) {
settings.ALIGN_MULTILINE_EXTENDS_LIST = decoder.isAlignmentOn();
settings.EXTENDS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.EXTENDS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_ASSIGNMENT.equals(key)) {
settings.ALIGN_MULTILINE_ASSIGNMENT = decoder.isAlignmentOn();
settings.ASSIGNMENT_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_METHOD_DECL_PARAMETERS.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS = decoder.isAlignmentOn();
settings.METHOD_PARAMETERS_WRAP = decoder.getWrapType();
settings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_BINARY_EXPR.equals(key)) {
settings.ALIGN_MULTILINE_BINARY_OPERATION = decoder.isAlignmentOn();
settings.BINARY_OPERATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_THROWS_IN_METHOD_DECL.equals(key)) {
settings.ALIGN_MULTILINE_THROWS_LIST = decoder.isAlignmentOn();
settings.THROWS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.THROWS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_RESOURCES_IN_TRY.equals(key)) {
settings.ALIGN_MULTILINE_RESOURCES = decoder.isAlignmentOn();
settings.RESOURCE_LIST_WRAP = decoder.getWrapType();
settings.RESOURCE_LIST_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_CHAINED_CALLS.equals(key)) {
settings.METHOD_CALL_CHAIN_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_CHAINED_METHODS = decoder.isAlignmentOn();
}
else if (OPTION_ALIGN_CONDITIONALS.equals(key)) {
settings.TERNARY_OPERATION_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_TERNARY_OPERATION = decoder.isAlignmentOn();
}
return false;
}
}
@@ -16,19 +16,19 @@
package org.jetbrains.idea.eclipse.importer;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.application.options.ImportSchemeChooserDialog;
import com.intellij.openapi.options.SchemeImportException;
import com.intellij.openapi.options.SchemeImporter;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairConvertor;
import com.intellij.util.ThrowableConsumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
@@ -36,29 +36,45 @@ import java.util.Set;
* @author Rustam Vishnyakov
*/
public class EclipseCodeStyleSchemeImporter implements SchemeImporter<CodeStyleScheme>, EclipseXmlProfileElements {
private static final Logger LOG = Logger.getInstance("#" + EclipseCodeStyleSchemeImporter.class.getName());
private final static String PROGRAMMATIC_IMPORT_KEY = "<Programmatic>";
private final EclipseImportMap myImportMap;
public EclipseCodeStyleSchemeImporter() {
myImportMap = new EclipseImportMap();
myImportMap.load();
}
@NotNull
@Override
public String[] getSourceExtensions() {
return new String[]{"xml"};
}
@NotNull
@Override
public String[] readSchemeNames(@NotNull InputStream inputStream) throws SchemeImportException {
public boolean importScheme(@NotNull final Project project,
@NotNull final VirtualFile selectedFile,
final CodeStyleScheme currentScheme,
@NotNull final PairConvertor<String, Boolean, CodeStyleScheme> schemeCreator) throws SchemeImportException {
final String[] schemeNames = readSchemeNames(selectedFile);
final ImportSchemeChooserDialog schemeChooserDialog =
new ImportSchemeChooserDialog(project, schemeNames, !currentScheme.isDefault() ? currentScheme.getName() : null);
if (! schemeChooserDialog.showAndGet()) return false;
final CodeStyleScheme scheme = schemeCreator.convert(schemeChooserDialog.getTargetName(), schemeChooserDialog.isUseCurrentScheme());
if (scheme == null) return false;
readFromStream(selectedFile, new ThrowableConsumer<InputStream, SchemeImportException>() {
@Override
public void consume(InputStream stream) throws SchemeImportException {
new EclipseCodeStyleImportWorker().importScheme(stream, schemeChooserDialog.getSelectedName(), scheme);
}
});
return true;
}
/**
* Attempts to read scheme names from the given stream. The stream may contain several schemes in which case all the available
* names are returned.
*
* @param inputStream The input stream to read the name from.
* @return Either scheme name or null if the scheme doesn't have a name.
* @throws SchemeImportException
*/
@NotNull
private String[] readSchemeNames(@NotNull VirtualFile selectedFile) throws SchemeImportException {
final Set<String> names = new HashSet<String>();
EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
final EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
@Override
public void handleOption(@NotNull String eclipseKey, @NotNull String value) throws SchemeImportException {
// Ignore
@@ -68,308 +84,34 @@ public class EclipseCodeStyleSchemeImporter implements SchemeImporter<CodeStyleS
names.add(name);
}
});
reader.readSettings(inputStream);
readFromStream(selectedFile, new ThrowableConsumer<InputStream, SchemeImportException>() {
@Override
public void consume(InputStream stream) throws SchemeImportException {
reader.readSettings(stream);
}
});
return ArrayUtil.toStringArray(names);
}
@Override
public void importScheme(@NotNull InputStream inputStream, final @Nullable String sourceScheme, final CodeStyleScheme scheme)
private static void readFromStream(@NotNull final VirtualFile file,
@NotNull final ThrowableConsumer<InputStream, SchemeImportException> consumer)
throws SchemeImportException {
final CodeStyleSettings settings = scheme.getCodeStyleSettings();
EclipseXmlProfileReader reader = new EclipseXmlProfileReader(new EclipseXmlProfileReader.OptionHandler() {
private String myCurrScheme;
@Override
public void handleOption(@NotNull String eclipseKey, @NotNull String value) throws SchemeImportException {
if (sourceScheme == null || myCurrScheme != null && myCurrScheme.equals(sourceScheme)) {
setCodeStyleOption(settings, eclipseKey, value);
}
}
@Override
public void handleName(String name) {
myCurrScheme = name;
}
});
reader.readSettings(inputStream);
}
private void setCodeStyleOption(@NotNull CodeStyleSettings settings, @NotNull String key, @NotNull String value)
throws SchemeImportException {
EclipseImportMap.ImportDescriptor importDescriptor = myImportMap.getImportDescriptor(key);
if (importDescriptor != null) {
try {
if (importDescriptor.isLanguageSpecific()) {
CommonCodeStyleSettings languageSettings = settings.getCommonSettings(importDescriptor.getLanguage());
if (languageSettings != null) {
if (importDescriptor.isIndentOptions()) {
CommonCodeStyleSettings.IndentOptions indentOptions = languageSettings.getIndentOptions();
if (indentOptions != null) {
setValue(indentOptions, key, importDescriptor.getFieldName(), value);
}
}
else {
setValue(languageSettings, key, importDescriptor.getFieldName(), value);
}
}
}
else {
setValue(settings, key, importDescriptor.getFieldName(), value);
}
}
catch (Exception e) {
throw new SchemeImportException(e);
}
}
}
private static void setValue(Object object, String key, String fieldName, String value) throws SchemeImportException {
if (PROGRAMMATIC_IMPORT_KEY.equalsIgnoreCase(fieldName)) {
setProgrammatically(object, key, value);
return;
}
InputStream inputStream = null;
try {
Field targetField = object.getClass().getField(fieldName);
Class<?> fieldType = targetField.getType();
if (fieldType.isPrimitive()) {
if (Boolean.TYPE.equals(fieldType)) {
targetField.setBoolean(object, valueToBoolean(key, value));
inputStream = file.getInputStream();
consumer.consume(inputStream);
} catch (IOException e) {
throw new SchemeImportException(e);
}
finally {
if (inputStream != null) {
try {
inputStream.close();
}
else if (Integer.TYPE.equals(fieldType)) {
targetField.setInt(object, valueToInt(value));
}
}
else if (fieldType.equals(String.class)) {
targetField.set(object, value);
}
}
catch (IllegalAccessException e) {
LOG.error(e);
}
catch (NoSuchFieldException e) {
LOG.error("Field '" + fieldName + "' does not exist in " + object.getClass().getName(), e);
}
}
private static boolean valueToBoolean(@NotNull String key, @NotNull String value) throws SchemeImportException {
if (VALUE_INSERT.equals(value) ||
VALUE_TRUE.equals(value)) {
return true;
}
if (!(VALUE_DO_NOT_INSERT.equals(value) ||
VALUE_FALSE.equals(value))) {
throw new SchemeImportException("Unrecognized boolean value: " + value + ", key: " + key);
}
return false;
}
private static int valueToInt(@NotNull String value) {
if (VALUE_END_OF_LINE.equals(value)) return CommonCodeStyleSettings.END_OF_LINE;
if (VALUE_NEXT_LINE.equals(value)) return CommonCodeStyleSettings.NEXT_LINE;
if (VALUE_NEXT_LINE_SHIFTED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_SHIFTED;
if (VALUE_NEXT_LINE_IF_WRAPPED.equals(value)) return CommonCodeStyleSettings.NEXT_LINE_IF_WRAPPED;
return Integer.parseInt(value);
}
private static class AlignmentAndWrapValueDecoder {
int myEncodedValue;
public AlignmentAndWrapValueDecoder(int encodedValue) {
myEncodedValue = encodedValue;
}
public int getWrapType() {
switch (getEclipseWrap()) {
case WRAP_WHERE_NECESSARY:
case WRAP_FIRST_OTHERS_WHERE_NECESSARY:
return CommonCodeStyleSettings.WRAP_AS_NEEDED;
case WRAP_ALL_EXCEPT_FIRST:
case WRAP_ALL_INDENT_EXCEPT_FIRST:
case WRAP_ALL_ON_NEW_LINE_EACH:
return CommonCodeStyleSettings.WRAP_AS_NEEDED | CommonCodeStyleSettings.WRAP_ON_EVERY_ITEM;
}
return CommonCodeStyleSettings.DO_NOT_WRAP;
}
public int getFirstElementWrapType() {
return isNewLineBeforeFirst() ? CommonCodeStyleSettings.WRAP_ALWAYS :
getEclipseWrap() == WRAP_ALL_EXCEPT_FIRST ? CommonCodeStyleSettings.DO_NOT_WRAP :
CommonCodeStyleSettings.WRAP_AS_NEEDED;
}
public boolean isFirstElementWrapped() {
int eclipseWrapValue = getEclipseWrap();
return eclipseWrapValue == WRAP_FIRST_OTHERS_WHERE_NECESSARY ||
eclipseWrapValue == WRAP_ALL_INDENT_EXCEPT_FIRST ||
eclipseWrapValue == WRAP_ALL_ON_NEW_LINE_EACH ||
isNewLineBeforeFirst();
}
public boolean isNewLineBeforeFirst() {
return (myEncodedValue & 1) != 0;
}
public boolean isAlignmentOn() {
return (myEncodedValue & 2) != 0;
}
public int getEclipseWrap() {
return myEncodedValue & WRAP_MASK;
}
}
private static void setProgrammatically(@NotNull Object object, @NotNull String key, @NotNull String value) throws SchemeImportException {
if (key.contains("alignment") && value.matches("\\d*") && object instanceof CommonCodeStyleSettings) {
if (setAlignmentAndWrappingOptions((CommonCodeStyleSettings)object, key, value)) return;
}
if (object instanceof CodeStyleSettings) {
CodeStyleSettings settings = (CodeStyleSettings)object;
if (OPTION_REMOVE_JAVADOC_BLANK_LINES.equals(key)) {
settings.JD_KEEP_EMPTY_LINES = !valueToBoolean(key, value);
}
else if (OPTION_NEW_LINE_AT_EOF.equals(key)) {
EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
editorSettings.setEnsureNewLineAtEOF(valueToBoolean(key, value));
}
}
else if (object instanceof CommonCodeStyleSettings) {
CommonCodeStyleSettings commonSettings = (CommonCodeStyleSettings)object;
if (OPTION_SPACE_AFTER_BINARY_OPERATOR.equals(key)) {
boolean addSpace = valueToBoolean(key, value);
commonSettings.SPACE_AROUND_ADDITIVE_OPERATORS =
commonSettings.SPACE_AROUND_BITWISE_OPERATORS =
commonSettings.SPACE_AROUND_LOGICAL_OPERATORS =
commonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS =
commonSettings.SPACE_AROUND_RELATIONAL_OPERATORS =
commonSettings.SPACE_AROUND_SHIFT_OPERATORS =
commonSettings.SPACE_AROUND_EQUALITY_OPERATORS =
addSpace;
}
else if (OPTION_INDENT_CLASS_BODY_DECL.equals(key)) {
commonSettings.DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS = !valueToBoolean(key, value);
}
else if (OPTION_BLANK_LINES_BEFORE_FIRST_DECLARATION_IN_CLASS.equals(key)) {
int intValue = valueToInt(value);
commonSettings.BLANK_LINES_AFTER_CLASS_HEADER = intValue;
commonSettings.BLANK_LINES_AFTER_ANONYMOUS_CLASS_HEADER = intValue;
}
else if (OPTION_EMPTY_LINES_TO_PRESERVE.equals(key)) {
int intValue = valueToInt(value);
commonSettings.KEEP_BLANK_LINES_IN_CODE = intValue;
commonSettings.KEEP_BLANK_LINES_IN_DECLARATIONS = intValue;
commonSettings.KEEP_BLANK_LINES_BEFORE_RBRACE = intValue;
}
else if (OPTION_SPACE_AFTER_CLOSING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_ELSE_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_KEYWORD = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_KEYWORD = insertSpace;
}
else if (OPTION_SPACE_BEFORE_OPENING_BRACE_IN_BLOCK.equals(key)) {
boolean insertSpace = valueToBoolean(key, value);
commonSettings.SPACE_BEFORE_IF_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FOR_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_WHILE_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_DO_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_TRY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_CATCH_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_FINALLY_LBRACE = insertSpace;
commonSettings.SPACE_BEFORE_SYNCHRONIZED_LBRACE = insertSpace;
}
else if (OPTION_JOIN_WRAPPED_LINES.equals(key)) {
commonSettings.KEEP_LINE_BREAKS = !valueToBoolean(key, value);
}
}
else if (object instanceof CommonCodeStyleSettings.IndentOptions) {
CommonCodeStyleSettings.IndentOptions indentOptions = (CommonCodeStyleSettings.IndentOptions)object;
if (OPTION_TAB_CHAR.equals(key)) {
if (TAB_CHAR_TAB.equals(value) || TAB_CHAR_MIXED.equals(value)) {
indentOptions.USE_TAB_CHARACTER = true;
}
else if (TAB_CHAR_SPACE.equals(value)) {
indentOptions.USE_TAB_CHARACTER = false;
}
}
else if (OPTION_CONTINUATION_INDENT.equals(key)) {
indentOptions.CONTINUATION_INDENT_SIZE = indentOptions.TAB_SIZE * valueToInt(value);
}
else if (OPTION_TAB_SIZE.equals(key)) {
int newTabSize = valueToInt(value);
int continuationTabs = indentOptions.TAB_SIZE > 0 ? indentOptions.CONTINUATION_INDENT_SIZE / indentOptions.TAB_SIZE : -1;
indentOptions.TAB_SIZE = newTabSize;
if (continuationTabs >= 0) {
indentOptions.CONTINUATION_INDENT_SIZE = continuationTabs * newTabSize;
catch (IOException e) {
//
}
}
}
}
private static boolean setAlignmentAndWrappingOptions(@NotNull CommonCodeStyleSettings settings,
@NotNull String key,
@NotNull String value) {
int encodedValue = Integer.parseInt(value);
AlignmentAndWrapValueDecoder decoder = new AlignmentAndWrapValueDecoder(encodedValue);
if (OPTION_ALIGN_ARGS_IN_ANNOTATION.equals(key)) {
settings.FIELD_ANNOTATION_WRAP =
settings.METHOD_ANNOTATION_WRAP =
settings.PARAMETER_ANNOTATION_WRAP =
settings.VARIABLE_ANNOTATION_WRAP =
settings.CLASS_ANNOTATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_EXPR_IN_ARRAY_INITIALIZER.equals(key)) {
settings.ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION = decoder.isAlignmentOn();
settings.ARRAY_INITIALIZER_WRAP = decoder.getWrapType();
settings.ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_ARGS_IN_METHOD_INVOCATION.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS_IN_CALLS = decoder.isAlignmentOn();
settings.CALL_PARAMETERS_WRAP = decoder.getWrapType();
settings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_INTERFACES_IN_TYPE_DECL.equals(key)) {
settings.ALIGN_MULTILINE_EXTENDS_LIST = decoder.isAlignmentOn();
settings.EXTENDS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.EXTENDS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_ASSIGNMENT.equals(key)) {
settings.ALIGN_MULTILINE_ASSIGNMENT = decoder.isAlignmentOn();
settings.ASSIGNMENT_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_METHOD_DECL_PARAMETERS.equals(key)) {
settings.ALIGN_MULTILINE_PARAMETERS = decoder.isAlignmentOn();
settings.METHOD_PARAMETERS_WRAP = decoder.getWrapType();
settings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_BINARY_EXPR.equals(key)) {
settings.ALIGN_MULTILINE_BINARY_OPERATION = decoder.isAlignmentOn();
settings.BINARY_OPERATION_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_THROWS_IN_METHOD_DECL.equals(key)) {
settings.ALIGN_MULTILINE_THROWS_LIST = decoder.isAlignmentOn();
settings.THROWS_KEYWORD_WRAP = decoder.getFirstElementWrapType();
settings.THROWS_LIST_WRAP = decoder.getWrapType();
return true;
}
else if (OPTION_ALIGN_RESOURCES_IN_TRY.equals(key)) {
settings.ALIGN_MULTILINE_RESOURCES = decoder.isAlignmentOn();
settings.RESOURCE_LIST_WRAP = decoder.getWrapType();
settings.RESOURCE_LIST_LPAREN_ON_NEXT_LINE = decoder.isFirstElementWrapped();
return true;
}
else if (OPTION_ALIGN_CHAINED_CALLS.equals(key)) {
settings.METHOD_CALL_CHAIN_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_CHAINED_METHODS = decoder.isAlignmentOn();
}
else if (OPTION_ALIGN_CONDITIONALS.equals(key)) {
settings.TERNARY_OPERATION_WRAP = decoder.getWrapType();
settings.ALIGN_MULTILINE_TERNARY_OPERATION = decoder.isAlignmentOn();
}
return false;
}
}
@@ -7,7 +7,7 @@ import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.PlatformTestCase;
import org.jetbrains.idea.eclipse.importer.EclipseCodeStyleSchemeImporter;
import org.jetbrains.idea.eclipse.importer.EclipseCodeStyleImportWorker;
import java.io.File;
import java.io.FileInputStream;
@@ -24,7 +24,6 @@ public class EclipseSettingsImportTest extends PlatformTestCase {
public void testImportCodeStyleSettingsFromXmlProfile() throws Exception {
File input = new File(getTestDataPath() + "eclipse_exported.xml");
EclipseCodeStyleSchemeImporter codeStyleSchemeImporter = new EclipseCodeStyleSchemeImporter();
CodeStyleSchemes schemes = CodeStyleSchemes.getInstance();
CodeStyleScheme scheme = schemes.createNewScheme(getTestName(false), null);
CodeStyleSettings settings = scheme.getCodeStyleSettings();
@@ -147,7 +146,7 @@ public class EclipseSettingsImportTest extends PlatformTestCase {
InputStream inputStream = new FileInputStream(input);
try {
codeStyleSchemeImporter.importScheme(inputStream, null, scheme);
new EclipseCodeStyleImportWorker().importScheme(inputStream, null, scheme);
assertTrue(javaSettings.SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS);
assertTrue(javaSettings.SPACE_WITHIN_ARRAY_INITIALIZER_BRACES);