From a2a4c7f433f22888e9236aba529f7cae7bfbddab Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Thu, 7 Apr 2016 18:37:53 +0300 Subject: [PATCH] Eclipse color theme importer, initial implementation --- .../editor/colors/impl/EmptyColorScheme.java | 10 +- .../ManageCodeStyleSchemesDialog.java | 30 +-- .../options/colors/ColorAndFontOptions.java | 19 +- .../options/colors/SchemesPanel.java | 54 +++++ .../openapi/options/SchemeImportUtil.java | 62 ++++++ plugins/eclipse/resources/META-INF/plugin.xml | 4 + .../colors/EclipseColorSchemeImporter.java | 193 ++++++++++++++++++ .../colors/EclipseColorThemeElements.java | 73 +++++++ .../colors/EclipseThemeOptionHandler.java | 166 +++++++++++++++ .../importer/colors/EclipseThemeReader.java | 179 ++++++++++++++++ 10 files changed, 761 insertions(+), 29 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/options/SchemeImportUtil.java create mode 100644 plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorSchemeImporter.java create mode 100644 plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorThemeElements.java create mode 100644 plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeOptionHandler.java create mode 100644 plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeReader.java diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EmptyColorScheme.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EmptyColorScheme.java index 655524f305a2..6a18cc5a9fb0 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EmptyColorScheme.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/colors/impl/EmptyColorScheme.java @@ -32,13 +32,21 @@ public class EmptyColorScheme extends DefaultColorsScheme { public final static String NAME = "Empty"; public final static EmptyColorScheme INSTANCE = new EmptyColorScheme(); - private final static TextAttributes EMPTY_TEXT = new TextAttributes(Color.BLACK, Color.white, null, EffectType.BOXED, Font.PLAIN); + private final static TextAttributes EMPTY_TEXT = new TextAttributes(Color.BLACK, Color.white, null, EffectType.BOXED, Font.PLAIN); + private final static TextAttributes DEFAULT_ATTRS = new TextAttributes(Color.GRAY, null, null, EffectType.BOXED, Font.PLAIN); private EmptyColorScheme() { myAttributesMap.put(HighlighterColors.TEXT, EMPTY_TEXT); initFonts(); } + @Nullable + @Override + public TextAttributes getAttributes(TextAttributesKey key) { + TextAttributes attributes = super.getAttributes(key); + return attributes == null ? DEFAULT_ATTRS : attributes; + } + @Nullable @Override protected TextAttributes getKeyDefaults(@NotNull TextAttributesKey key) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java index 1571caf04958..ca28996573e2 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java @@ -19,9 +19,6 @@ import com.intellij.application.options.ImportSourceChooserDialog; import com.intellij.application.options.SaveSchemeDialog; import com.intellij.application.options.SchemesToImportPopup; import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.fileChooser.FileChooserDialog; -import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.options.*; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.DialogWrapper; @@ -44,7 +41,8 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import java.awt.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -154,7 +152,8 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper { @Nullable private CodeStyleScheme importExternalCodeStyle(final SchemeImporter importer) throws SchemeImportException { - final VirtualFile selectedFile = selectImportSource(importer.getSourceExtensions()); + final VirtualFile selectedFile = SchemeImportUtil + .selectImportSource(importer.getSourceExtensions(), myContentPane, CodeStyleSchemesUIConfiguration.Util.getRecentImportFile()); if (selectedFile != null) { CodeStyleSchemesUIConfiguration.Util.setRecentImportFile(selectedFile); final SchemeCreator schemeCreator = new SchemeCreator(); @@ -169,27 +168,6 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper { return null; } - @Nullable - private VirtualFile selectImportSource(final String[] sourceExtensions) { - final Set extensions = new HashSet(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() { // there is a possibility that nothing will be selected in a table. So we just need to corresponding disable actions final CodeStyleScheme selectedScheme = getSelectedInTableScheme(); diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java index 1a75c1c4ff91..badceac06155 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/ColorAndFontOptions.java @@ -57,8 +57,6 @@ import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.psi.search.scope.packageSet.PackageSet; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.HashMap; -import com.intellij.util.diff.FilesTooBigForDiffException; import com.intellij.util.ui.UIUtil; import gnu.trove.THashMap; import gnu.trove.THashSet; @@ -137,6 +135,23 @@ public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract private MyColorScheme getScheme(String name) { return mySchemes.get(name); } + + @NotNull + public String getUniqueName(@NotNull String preferredName) { + String name; + if (mySchemes.containsKey(preferredName)) { + for (int i = 1; ; i++) { + name = preferredName + " (" + i + ")"; + if (!mySchemes.containsKey(name)) { + break; + } + } + } + else { + name = preferredName; + } + return name; + } public EditorColorsScheme getSelectedScheme() { return mySelectedScheme; diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java index bf4f94e8281a..f875ce44f767 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/SchemesPanel.java @@ -16,11 +16,20 @@ package com.intellij.application.options.colors; +import com.intellij.application.options.ImportSourceChooserDialog; import com.intellij.application.options.SaveSchemeDialog; import com.intellij.application.options.SkipSelfSearchComponent; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.impl.EditorColorsSchemeImpl; +import com.intellij.openapi.editor.colors.impl.EmptyColorScheme; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.options.SchemeImportException; +import com.intellij.openapi.options.SchemeImportUtil; +import com.intellij.openapi.options.SchemeImporter; +import com.intellij.openapi.options.SchemeImporterEP; +import com.intellij.openapi.project.DefaultProjectFactory; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.EventDispatcher; import com.intellij.util.containers.ContainerUtil; @@ -39,6 +48,7 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent { private JComboBox mySchemeComboBox; private JButton myDeleteButton; + private JButton myImportButton; private JLabel myHintLabel; private final EventDispatcher myDispatcher = EventDispatcher.create(ColorAndFontSettingsListener.class); @@ -114,6 +124,16 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent { panel.add(myDeleteButton, new GridBagConstraints(gridx++, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new JBInsets(0, 0, 5, 5), 0, 0)); + myImportButton = new JButton("Import..."); + myImportButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + chooseAndImport(); + } + }); + panel.add(myImportButton, + new GridBagConstraints(gridx++, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new JBInsets(0, 0, 5, 5), 0, + 0)); myHintLabel = new JLabel(ApplicationBundle.message("hint.readonly.scheme.cannot.be.modified")); myHintLabel.setEnabled(false); panel.add(myHintLabel, @@ -196,4 +216,38 @@ public class SchemesPanel extends JPanel implements SkipSelfSearchComponent { public void addListener(ColorAndFontSettingsListener listener) { myDispatcher.addListener(listener); } + + private void chooseAndImport() { + ImportSourceChooserDialog importSourceChooserDialog = + new ImportSourceChooserDialog(this, EditorColorsScheme.class); + if (importSourceChooserDialog.showAndGet()) { + final String selectedImporterName = importSourceChooserDialog.getSelectedSourceName(); + if (selectedImporterName != null) { + final SchemeImporter importer = SchemeImporterEP.getImporter(selectedImporterName, EditorColorsScheme.class); + if (importer != null) { + VirtualFile importSource = SchemeImportUtil.selectImportSource(importer.getSourceExtensions(), this, null); + if (importSource != null) { + try { + EditorColorsScheme imported = + importer.importScheme(DefaultProjectFactory.getInstance().getDefaultProject(), importSource, myOptions.getSelectedScheme(), + name -> { + String newName = myOptions.getUniqueName(name); + EditorColorsScheme newScheme = new EditorColorsSchemeImpl(EmptyColorScheme.INSTANCE); + newScheme.setName(newName); + return newScheme; + }); + if (imported != null) { + myOptions.addImportedScheme(imported); + } + + } + catch (SchemeImportException e) { + e.printStackTrace(); + } + } + } + } + } + } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SchemeImportUtil.java b/platform/platform-impl/src/com/intellij/openapi/options/SchemeImportUtil.java new file mode 100644 index 000000000000..45897f55ae4d --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/options/SchemeImportUtil.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2016 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.openapi.options; + +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileChooser.FileChooserDialog; +import com.intellij.openapi.fileChooser.FileChooserFactory; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class SchemeImportUtil { + @Nullable + public static VirtualFile selectImportSource(@NotNull final String[] sourceExtensions, + @NotNull Component parent, + @Nullable VirtualFile preselect) { + final Set extensions = new HashSet(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, parent); + final VirtualFile[] preselectFiles; + if (preselect != null) { + preselectFiles = new VirtualFile[1]; + preselectFiles[0] = preselect; + } + else { + preselectFiles = new VirtualFile[0]; + } + final VirtualFile[] virtualFiles = fileChooser.choose(null, preselectFiles); + //CodeStyleSchemesUIConfiguration.Util.getRecentImportFile()); + if (virtualFiles.length != 1) return null; + virtualFiles[0].refresh(false, false); + return virtualFiles[0]; + } +} diff --git a/plugins/eclipse/resources/META-INF/plugin.xml b/plugins/eclipse/resources/META-INF/plugin.xml index bd6e50f5e5d1..4db99452cb85 100644 --- a/plugins/eclipse/resources/META-INF/plugin.xml +++ b/plugins/eclipse/resources/META-INF/plugin.xml @@ -29,6 +29,10 @@ name="Eclipse XML Profile" implementationClass="org.jetbrains.idea.eclipse.importer.EclipseCodeStyleSchemeImporter" schemeClass="com.intellij.psi.codeStyle.CodeStyleScheme"/> + diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorSchemeImporter.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorSchemeImporter.java new file mode 100644 index 000000000000..06468197c6cd --- /dev/null +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorSchemeImporter.java @@ -0,0 +1,193 @@ +/* + * Copyright 2000-2016 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.colors; + +import com.intellij.execution.process.ConsoleHighlighter; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.diff.DiffColors; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.openapi.editor.HighlighterColors; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.colors.ex.DefaultColorSchemesManager; +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.SchemeFactory; +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.ui.ColorUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; + +@SuppressWarnings("UseJBColor") +public class EclipseColorSchemeImporter implements SchemeImporter, EclipseColorThemeElements { + + private final static String[] ECLIPSE_THEME_EXTENSIONS = {"xml"}; + + private final static TextAttributesKey[] ATTRIBUTES_TO_COPY = { + HighlighterColors.BAD_CHARACTER, + CodeInsightColors.WRONG_REFERENCES_ATTRIBUTES, + CodeInsightColors.ERRORS_ATTRIBUTES, + CodeInsightColors.WARNINGS_ATTRIBUTES, + CodeInsightColors.GENERIC_SERVER_ERROR_OR_WARNING, + CodeInsightColors.DUPLICATE_FROM_SERVER, + CodeInsightColors.WEAK_WARNING_ATTRIBUTES, + CodeInsightColors.INFORMATION_ATTRIBUTES, + CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES, + CodeInsightColors.DEPRECATED_ATTRIBUTES, + CodeInsightColors.LINE_FULL_COVERAGE, + CodeInsightColors.LINE_PARTIAL_COVERAGE, + CodeInsightColors.LINE_NONE_COVERAGE, + ConsoleViewContentType.NORMAL_OUTPUT_KEY, + ConsoleViewContentType.ERROR_OUTPUT_KEY, + ConsoleViewContentType.USER_INPUT_KEY, + ConsoleViewContentType.SYSTEM_OUTPUT_KEY, + ConsoleViewContentType.LOG_ERROR_OUTPUT_KEY, + ConsoleViewContentType.LOG_WARNING_OUTPUT_KEY, + ConsoleViewContentType.LOG_EXPIRED_ENTRY, + ConsoleHighlighter.BLACK, + ConsoleHighlighter.RED, + ConsoleHighlighter.GREEN, + ConsoleHighlighter.YELLOW, + ConsoleHighlighter.BLUE, + ConsoleHighlighter.MAGENTA, + ConsoleHighlighter.CYAN, + ConsoleHighlighter.GRAY, + ConsoleHighlighter.DARKGRAY, + ConsoleHighlighter.RED_BRIGHT, + ConsoleHighlighter.GREEN_BRIGHT, + ConsoleHighlighter.YELLOW_BRIGHT, + ConsoleHighlighter.BLUE_BRIGHT, + ConsoleHighlighter.MAGENTA_BRIGHT, + ConsoleHighlighter.CYAN_BRIGHT, + ConsoleHighlighter.WHITE, + + DiffColors.DIFF_ABSENT, + DiffColors.DIFF_CONFLICT, + DiffColors.DIFF_DELETED, + DiffColors.DIFF_INSERTED, + DiffColors.DIFF_MODIFIED, + + DefaultLanguageHighlighterColors.INVALID_STRING_ESCAPE + }; + + // + // These attributes are referenced only symbolically since they are located outside this module's dependencies. + // + private final static String[] EXTERNAL_ATTRIBUTES = { + "BREAKPOINT_ATTRIBUTES", + "EXECUTIONPOINT_ATTRIBUTES", + "NOT_TOP_FRAME_ATTRIBUTES", + "DEBUGGER_INLINED_VALUES", + "DEBUGGER_INLINED_VALUES_MODIFIED", + "DEBUGGER_INLINED_VALUES_EXECUTION_LINE" + }; + + + @NotNull + @Override + public String[] getSourceExtensions() { + return ECLIPSE_THEME_EXTENSIONS; + } + + @Nullable + @Override + public EditorColorsScheme importScheme(@NotNull Project project, + @NotNull VirtualFile selectedFile, + @NotNull EditorColorsScheme currentScheme, + @NotNull SchemeFactory schemeFactory) throws SchemeImportException { + String themeName = readSchemeName(selectedFile); + if (themeName != null) { + EditorColorsScheme colorsScheme = schemeFactory.createNewScheme(themeName); + readFromStream(selectedFile, new EclipseThemeOptionHandler(colorsScheme)); + setupMissingColors(colorsScheme); + return colorsScheme; + } + return null; + } + + private static String readSchemeName(@NotNull VirtualFile selectedFile) throws SchemeImportException { + return readFromStream(selectedFile, null); + } + + + private static String readFromStream(@NotNull final VirtualFile file, + @Nullable final EclipseThemeReader.OptionHandler optionHandler) + throws SchemeImportException { + InputStream inputStream = null; + try { + inputStream = file.getInputStream(); + EclipseThemeReader themeReader = new EclipseThemeReader(optionHandler); + themeReader.readSettings(inputStream); + return themeReader.getThemeName(); + } catch (IOException e) { + throw new SchemeImportException(e); + } + finally { + if (inputStream != null) { + try { + inputStream.close(); + } + catch (IOException e) { + // + } + } + } + } + + @Nullable + @Override + public String getAdditionalImportInfo(@NotNull EditorColorsScheme scheme) { + return null; + } + + private static void setupMissingColors(@NotNull EditorColorsScheme scheme) { + Color background= scheme.getDefaultBackground(); + String defaultSchemeName = ColorUtil.isDark(background) ? "Darcula" : EditorColorsScheme.DEFAULT_SCHEME_NAME; + EditorColorsScheme baseScheme = DefaultColorSchemesManager.getInstance().getScheme(defaultSchemeName); + assert baseScheme != null : "Can not find default scheme '" + defaultSchemeName + "'!"; + for (TextAttributesKey attributesKey : ATTRIBUTES_TO_COPY) { + copyAttributes(baseScheme, scheme, attributesKey); + } + for (String keyName : EXTERNAL_ATTRIBUTES) { + TextAttributesKey key = TextAttributesKey.createTextAttributesKey(keyName); + copyAttributes(baseScheme, scheme, key); + } + Color lightForeground = ColorUtil.mix(background, scheme.getDefaultForeground(), 0.5); + scheme.setColor(EditorColors.WHITESPACES_COLOR, lightForeground); + scheme.setColor(EditorColors.INDENT_GUIDE_COLOR, lightForeground); + scheme.setColor(EditorColors.SOFT_WRAP_SIGN_COLOR, lightForeground); + TextAttributes matchedBrace = new TextAttributes(); + matchedBrace.setEffectType(EffectType.BOXED); + matchedBrace.setEffectColor(lightForeground); + scheme.setAttributes(CodeInsightColors.MATCHED_BRACE_ATTRIBUTES, matchedBrace); + TextAttributes unmatchedBrace = matchedBrace.clone(); + unmatchedBrace.setEffectColor(ColorUtil.mix(background, Color.RED, 0.5)); + } + + private static void copyAttributes(@NotNull EditorColorsScheme source, @NotNull EditorColorsScheme target, @NotNull TextAttributesKey key) { + target.setAttributes(key, source.getAttributes(key)); + } + +} diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorThemeElements.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorThemeElements.java new file mode 100644 index 000000000000..96b884fc2be8 --- /dev/null +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseColorThemeElements.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2016 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.colors; + +public interface EclipseColorThemeElements { + String BACKGROUND_SUFFIX = "background"; + + String COLOR_THEME_TAG = "colorTheme"; + String SEARCH_RESULT_TAG = "searchResultIndication"; + String FILTER_SEARCH_RESULT_TAG = "filteredSearchResultIndication"; + String OCCURENCE_TAG = "occurrenceIndication"; + String WRITE_OCCURENCE_TAG = "writeOccurrenceIndication"; + String FIND_SCOPE_TAG = "findScope"; + String DELETION_INDICATION_TAG = "deletionIndication"; + String SOURCE_HOVER_BACKGROUND_TAG = "sourceHoverBackground"; + String SINGLE_LINE_COMMENT_TAG = "singleLineComment"; + String MULTI_LINE_COMMENT_TAG = "multiLineComment"; + String COMMENT_TASK_TAG = "commentTaskTag"; + String JAVADOC_TAG = "javadoc"; + String JAVADOC_LINK_TAG = "javadocLink"; + String JAVADOC_TAG_TAG = "javadocTag"; + String JAVADOC_KEYWORD_TAG = "javadocKeyword"; + String CLASS_TAG = "class"; + String INTERFACE_TAG = "interface"; + String METHOD_TAG = "method"; + String METHOD_DECLARATION = "methodDeclaration"; + String BRACKET = "bracket"; + String NUMBER_TAG = "number"; + String STRING_TAG = "string"; + String OPERATOR_TAG = "operator"; + String KEYWORD_TAG = "keyword"; + String ANNOTATION_TAG = "annotation"; + String STATIC_METHOD_TAG = "staticMethod"; + String LOCAL_VARIABLE_TAG = "localVariable"; + String LOCAL_VARIABLE_DECL_TAG = "localVariableDeclaration"; + String FIELD_TAG = "field"; + String STATIC_FIELD_TAG = "staticField"; + String STATIC_FINAL_FIELD_TAG = "staticFinalField"; + String DEPRECATED_MEMBER_TAG = "deprecatedMember"; + String ENUM_TAG = "enum"; + String INHERITED_METHOD_TAG = "inheritedMethod"; + String ABSTRACT_METHOD_TAG = "abstractMethod"; + String PARAMETER_VAR_TAG = "parameterVariable"; + String TYPE_ARG_TAG = "typeArgument"; + String TYPE_PARAM_TAG = "typeParameter"; + String CONST_TAG = "constant"; + String BACKGROUND_TAG = "background"; + String CURR_LINE_TAG = "currentLine"; + String FOREGROUND_TAG = "foreground"; + String LINE_NUMBER_TAG = "lineNumber"; + String SELECTION_BACKGROUND_TAG = "selectionBackground"; + String SELECTION_FOREGROUND_TAG = "selectionForeground"; + + String NAME_ATTR = "name"; + String COLOR_ATTR = "color"; + String BOLD_ATTR = "bold"; + String ITALIC_ATTR = "italic"; + String UNDERLINE_ATTR = "underline"; + String STRIKETHROUGH_ATTR = "strikethrough"; +} diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeOptionHandler.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeOptionHandler.java new file mode 100644 index 000000000000..93c5e05de91b --- /dev/null +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeOptionHandler.java @@ -0,0 +1,166 @@ +/* + * Copyright 2000-2016 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.colors; + +import com.intellij.ide.highlighter.JavaHighlightingColors; +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors; +import com.intellij.openapi.editor.HighlighterColors; +import com.intellij.openapi.editor.XmlHighlighterColors; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.colors.impl.AbstractColorsScheme; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.Map; + +@SuppressWarnings("UseJBColor") +public class EclipseThemeOptionHandler implements EclipseThemeReader.OptionHandler, EclipseColorThemeElements { + private EditorColorsScheme myColorsScheme; + + private final static Map ECLIPSE_TO_IDEA_ATTR_MAP = new HashMap<>(); + + static { + ECLIPSE_TO_IDEA_ATTR_MAP.put(SINGLE_LINE_COMMENT_TAG, DefaultLanguageHighlighterColors.LINE_COMMENT); + ECLIPSE_TO_IDEA_ATTR_MAP.put(MULTI_LINE_COMMENT_TAG, DefaultLanguageHighlighterColors.BLOCK_COMMENT); + ECLIPSE_TO_IDEA_ATTR_MAP.put(JAVADOC_TAG, DefaultLanguageHighlighterColors.DOC_COMMENT); + ECLIPSE_TO_IDEA_ATTR_MAP.put(JAVADOC_TAG_TAG, DefaultLanguageHighlighterColors.DOC_COMMENT_MARKUP); + ECLIPSE_TO_IDEA_ATTR_MAP.put(JAVADOC_KEYWORD_TAG, DefaultLanguageHighlighterColors.DOC_COMMENT_TAG); + ECLIPSE_TO_IDEA_ATTR_MAP.put(CLASS_TAG, DefaultLanguageHighlighterColors.CLASS_NAME); + ECLIPSE_TO_IDEA_ATTR_MAP.put(INTERFACE_TAG, DefaultLanguageHighlighterColors.INTERFACE_NAME); + ECLIPSE_TO_IDEA_ATTR_MAP.put(METHOD_TAG, DefaultLanguageHighlighterColors.FUNCTION_CALL); + ECLIPSE_TO_IDEA_ATTR_MAP.put(METHOD_DECLARATION, DefaultLanguageHighlighterColors.FUNCTION_DECLARATION); + ECLIPSE_TO_IDEA_ATTR_MAP.put(NUMBER_TAG, DefaultLanguageHighlighterColors.NUMBER); + ECLIPSE_TO_IDEA_ATTR_MAP.put(ANNOTATION_TAG, DefaultLanguageHighlighterColors.METADATA); + ECLIPSE_TO_IDEA_ATTR_MAP.put(STATIC_METHOD_TAG, DefaultLanguageHighlighterColors.STATIC_METHOD); + ECLIPSE_TO_IDEA_ATTR_MAP.put(STATIC_FIELD_TAG, DefaultLanguageHighlighterColors.STATIC_FIELD); + ECLIPSE_TO_IDEA_ATTR_MAP.put(PARAMETER_VAR_TAG, DefaultLanguageHighlighterColors.PARAMETER); + ECLIPSE_TO_IDEA_ATTR_MAP.put(CONST_TAG, DefaultLanguageHighlighterColors.CONSTANT); + ECLIPSE_TO_IDEA_ATTR_MAP.put(COMMENT_TASK_TAG, CodeInsightColors.TODO_DEFAULT_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(TYPE_ARG_TAG, JavaHighlightingColors.TYPE_PARAMETER_NAME_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(ENUM_TAG, JavaHighlightingColors.ENUM_NAME_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(INHERITED_METHOD_TAG, JavaHighlightingColors.INHERITED_METHOD_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(ABSTRACT_METHOD_TAG, JavaHighlightingColors.ABSTRACT_METHOD_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(STATIC_FINAL_FIELD_TAG, JavaHighlightingColors.STATIC_FINAL_FIELD_ATTRIBUTES); + ECLIPSE_TO_IDEA_ATTR_MAP.put(DEPRECATED_MEMBER_TAG, CodeInsightColors.DEPRECATED_ATTRIBUTES); + } + + public EclipseThemeOptionHandler(EditorColorsScheme colorsScheme) { + myColorsScheme = colorsScheme; + } + + @Override + public void handleColorOption(@NotNull String name, @NotNull TextAttributes attributes) { + if (BACKGROUND_TAG.equals(name)) { + updateAttributes(HighlighterColors.TEXT, attributes); + myColorsScheme.setColor(EditorColors.GUTTER_BACKGROUND, attributes.getBackgroundColor()); + } + else if (FOREGROUND_TAG.equals(name)) { + updateAttributes(HighlighterColors.TEXT, attributes); + updateAttributes(DefaultLanguageHighlighterColors.IDENTIFIER, attributes); + } + else if (CURR_LINE_TAG.equals(name)) { + myColorsScheme.setColor(EditorColors.CARET_ROW_COLOR, attributes.getForegroundColor()); + } + else if (SELECTION_BACKGROUND_TAG.equals(name)) { + myColorsScheme.setColor(EditorColors.SELECTION_BACKGROUND_COLOR, attributes.getBackgroundColor()); + } + else if (SELECTION_FOREGROUND_TAG.equals(name)) { + myColorsScheme.setColor(EditorColors.SELECTION_FOREGROUND_COLOR, attributes.getForegroundColor()); + } + else if (BRACKET.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.BRACES, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.BRACKETS, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.PARENTHESES, attributes); + } + else if (OPERATOR_TAG.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.OPERATION_SIGN, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.COMMA, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.SEMICOLON, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.DOT, attributes); + } + else if (LINE_NUMBER_TAG.equals(name)) { + Color lineNumberColor = attributes.getForegroundColor(); + myColorsScheme.setColor(EditorColors.LINE_NUMBERS_COLOR, lineNumberColor); + myColorsScheme.setColor(EditorColors.TEARLINE_COLOR, lineNumberColor); + myColorsScheme.setColor(EditorColors.RIGHT_MARGIN_COLOR, lineNumberColor); + myColorsScheme.setColor(EditorColors.CARET_COLOR, lineNumberColor); + } + else if(LOCAL_VARIABLE_TAG.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.LOCAL_VARIABLE, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.MARKUP_TAG, attributes); + } + else if(LOCAL_VARIABLE_DECL_TAG.equals(name)) { + myColorsScheme.setAttributes(XmlHighlighterColors.HTML_TAG_NAME, attributes); + myColorsScheme.setAttributes(XmlHighlighterColors.XML_TAG_NAME, attributes); + } + else if(FIELD_TAG.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD, attributes); + myColorsScheme.setAttributes(XmlHighlighterColors.XML_ATTRIBUTE_NAME, attributes); + myColorsScheme.setAttributes(XmlHighlighterColors.HTML_ATTRIBUTE_NAME, attributes); + } + else if(OCCURENCE_TAG.equals(name)) { + myColorsScheme.setAttributes(EditorColors.IDENTIFIER_UNDER_CARET_ATTRIBUTES, toBackgroundAttributes(attributes)); + } + else if (WRITE_OCCURENCE_TAG.equals(name)) { + myColorsScheme.setAttributes(EditorColors.WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES, toBackgroundAttributes(attributes)); + } + else if(SEARCH_RESULT_TAG.equals(name)) { + myColorsScheme.setAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES, toBackgroundAttributes(attributes)); + } + else if(FILTER_SEARCH_RESULT_TAG.equals(name)) { + myColorsScheme.setAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES, toBackgroundAttributes(attributes)); + } + else if (STRING_TAG.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.STRING, attributes); + TextAttributes validEscapeAttrs = attributes.clone(); + validEscapeAttrs.setFontType(Font.BOLD); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.VALID_STRING_ESCAPE, validEscapeAttrs); + } + else if (KEYWORD_TAG.equals(name)) { + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.KEYWORD, attributes); + myColorsScheme.setAttributes(DefaultLanguageHighlighterColors.MARKUP_ENTITY, attributes); + } + else { + if (ECLIPSE_TO_IDEA_ATTR_MAP.containsKey(name)) { + myColorsScheme.setAttributes(ECLIPSE_TO_IDEA_ATTR_MAP.get(name), attributes); + } + } + } + + private void updateAttributes(@NotNull TextAttributesKey key, @NotNull TextAttributes attributes) { + if (myColorsScheme instanceof AbstractColorsScheme) { + TextAttributes alreadyDefined = ((AbstractColorsScheme)myColorsScheme).getDirectlyDefinedAttributes(key); + if (alreadyDefined != null) { + if (attributes.getForegroundColor() != null) alreadyDefined.setForegroundColor(attributes.getForegroundColor()); + if (attributes.getBackgroundColor() != null) alreadyDefined.setBackgroundColor(attributes.getBackgroundColor()); + return; + } + } + myColorsScheme.setAttributes(key, attributes); + } + + private static TextAttributes toBackgroundAttributes(@NotNull TextAttributes attributes) { + TextAttributes backgroundAttrs = attributes.clone(); + backgroundAttrs.setBackgroundColor(attributes.getForegroundColor()); + backgroundAttrs.setForegroundColor(null); + return backgroundAttrs; + } +} diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeReader.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeReader.java new file mode 100644 index 000000000000..f0554e7a55f8 --- /dev/null +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/colors/EclipseThemeReader.java @@ -0,0 +1,179 @@ +/* + * Copyright 2000-2016 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.colors; + +import com.intellij.openapi.editor.markup.EffectType; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.options.SchemeImportException; +import com.intellij.util.containers.HashMap; +import org.intellij.lang.annotations.JdkConstants; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.awt.*; +import java.io.InputStream; +import java.util.Map; + +@SuppressWarnings("UseJBColor") +public class EclipseThemeReader extends DefaultHandler implements EclipseColorThemeElements { + private @Nullable OptionHandler myOptionHandler; + private @Nullable String myThemeName; + + private final static Map ECLIPSE_DEFAULT_FONT_STYLES = new HashMap<>(); + static { + ECLIPSE_DEFAULT_FONT_STYLES.put(KEYWORD_TAG, Font.BOLD); + } + + public EclipseThemeReader(@Nullable OptionHandler handler) { + myOptionHandler = handler; + } + + + protected void readSettings(InputStream input) throws SchemeImportException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setValidating(false); + SAXParser parser; + try { + parser = spf.newSAXParser(); + parser.parse(input, this); + } + catch (Exception e) { + if (e.getCause() instanceof NotAnEclipseThemeException) { + throw new SchemeImportException("The input file is not a valid Eclipse theme."); + } + else { + throw new SchemeImportException(e); + } + } + } + + private static class NotAnEclipseThemeException extends Exception { + public NotAnEclipseThemeException(String message) { + super(message); + } + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if (COLOR_THEME_TAG.equals(qName)) { + myThemeName = attributes.getValue(NAME_ATTR); + if (myThemeName == null) { + throw new SAXException(new NotAnEclipseThemeException("'name' attribute of 'colorTheme' is missing.")); + } + } + else { + if (myThemeName != null) { + if (myOptionHandler != null) { + myOptionHandler.handleColorOption(qName, readTextAttributes(qName, attributes, isBackground(qName))); + } + } + else { + throw new SAXException(new NotAnEclipseThemeException("'colorTheme' element is missing.")); + } + } + } + + public interface OptionHandler { + void handleColorOption(@NotNull String name, @NotNull TextAttributes textAttribute); + } + + private static TextAttributes readTextAttributes(@NotNull String tag, Attributes attributes, boolean isBackground) throws SAXException { + TextAttributes textAttributes = new TextAttributes(); + Color color = getColor(attributes); + if (isBackground) { + textAttributes.setBackgroundColor(color); + } + else { + textAttributes.setForegroundColor(color); + } + textAttributes.setFontType(getFontStyle(tag, attributes)); + EffectType effectType = getEffectType(attributes); + if (effectType != null) { + textAttributes.setEffectType(effectType); + textAttributes.setEffectColor(textAttributes.getForegroundColor()); + } + return textAttributes; + } + + private static boolean isBackground(@NotNull String tagName) { + if (tagName.length() >= BACKGROUND_SUFFIX.length()) { + tagName = tagName.substring(tagName.length() - BACKGROUND_SUFFIX.length()); + return tagName.equalsIgnoreCase(BACKGROUND_SUFFIX); + } + return false; + } + + @Nullable + public String getThemeName() { + return myThemeName; + } + + @Nullable + private static Color getColor(Attributes attributes) throws SAXException { + String colorString = attributes.getValue(COLOR_ATTR); + if (colorString != null && colorString.length() > 0) { + try { + int colorValue = Integer.decode(colorString); + return new Color(colorValue); + } + catch (NumberFormatException nfe) { + throw new SAXException("Invalid color value: '" + colorString + "'"); + } + } + return null; + } + + @JdkConstants.FontStyle + private static int getFontStyle(@NotNull String tag, @NotNull Attributes attributes) { + int fontStyle = getDefaultFontStyle(tag); + String boldValue = attributes.getValue(BOLD_ATTR); + if (boldValue != null) { + if (Boolean.parseBoolean(boldValue)) fontStyle |= Font.BOLD; + else fontStyle &= ~Font.BOLD; + } + String italicValue = attributes.getValue(ITALIC_ATTR); + if (italicValue != null) { + if (Boolean.parseBoolean(italicValue)) fontStyle |= Font.ITALIC; + else fontStyle &= ~Font.ITALIC; + } + return fontStyle; + } + + @SuppressWarnings("MagicConstant") + @JdkConstants.FontStyle + private static int getDefaultFontStyle(@NotNull String tag) { + if (ECLIPSE_DEFAULT_FONT_STYLES.containsKey(tag)) return ECLIPSE_DEFAULT_FONT_STYLES.get(tag); + return Font.PLAIN; + } + + @Nullable + private static EffectType getEffectType(@NotNull Attributes attributes) { + String strikeThrough = attributes.getValue(STRIKETHROUGH_ATTR); + if (strikeThrough != null && Boolean.parseBoolean(strikeThrough)) { + return EffectType.STRIKEOUT; + } + String underline = attributes.getValue(UNDERLINE_ATTR); + if (underline != null && Boolean.parseBoolean(underline)) { + return EffectType.LINE_UNDERSCORE; + } + return null; + } +}