/* * 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.application.options.editor; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.editorActions.SmartBackspaceMode; import com.intellij.lang.CodeDocumentationAwareCommenter; import com.intellij.lang.Commenter; import com.intellij.lang.Language; import com.intellij.lang.LanguageCommenters; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; import com.intellij.openapi.options.CompositeConfigurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.UnnamedConfigurable; import com.intellij.openapi.options.ex.ConfigurableWrapper; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.util.Collection; import java.util.List; /** * To provide additional options in Editor | Smart Keys section register implementation of {@link com.intellij.openapi.options.UnnamedConfigurable} in the plugin.xml: * <p/> * <extensions defaultExtensionNs="com.intellij"><br> *   <editorSmartKeysConfigurable instance="class-name"/><br> * </extensions> * <p> * A new instance of the specified class will be created each time then the Settings dialog is opened * * @author yole */ public class EditorSmartKeysConfigurable extends CompositeConfigurable<UnnamedConfigurable> implements EditorOptionsProvider { private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.editor.EditorSmartKeysConfigurable"); private static final ExtensionPointName<EditorSmartKeysConfigurableEP> EP_NAME = ExtensionPointName.create("com.intellij.editorSmartKeysConfigurable"); private JCheckBox myCbSmartHome; private JCheckBox myCbSmartEnd; private JCheckBox myCbInsertPairBracket; private JCheckBox myCbInsertPairQuote; private JCheckBox myCbCamelWords; private JCheckBox myCbSmartIndentOnEnter; private JComboBox myReformatOnPasteCombo; private JPanel myRootPanel; private JPanel myAddonPanel; private JCheckBox myCbInsertPairCurlyBraceOnEnter; private JCheckBox myCbInsertJavadocStubOnEnter; private JCheckBox myCbSurroundSelectionOnTyping; private JCheckBox myCbReformatBlockOnTypingRBrace; private JComboBox mySmartBackspaceCombo; private JCheckBox myCbEnableAddingCaretsOnDoubleCtrlArrows; private boolean myAddonsInitialized = false; private static final String NO_REFORMAT = ApplicationBundle.message("combobox.paste.reformat.none"); private static final String INDENT_BLOCK = ApplicationBundle.message("combobox.paste.reformat.indent.block"); private static final String INDENT_EACH_LINE = ApplicationBundle.message("combobox.paste.reformat.indent.each.line"); private static final String REFORMAT_BLOCK = ApplicationBundle.message("combobox.paste.reformat.reformat.block"); private static final String OFF = ApplicationBundle.message("combobox.smart.backspace.off"); private static final String SIMPLE = ApplicationBundle.message("combobox.smart.backspace.simple"); private static final String SMART = ApplicationBundle.message("combobox.smart.backspace.smart"); public EditorSmartKeysConfigurable() { myReformatOnPasteCombo.addItem(NO_REFORMAT); myReformatOnPasteCombo.addItem(INDENT_BLOCK); myReformatOnPasteCombo.addItem(INDENT_EACH_LINE); myReformatOnPasteCombo.addItem(REFORMAT_BLOCK); mySmartBackspaceCombo.addItem(OFF); mySmartBackspaceCombo.addItem(SIMPLE); mySmartBackspaceCombo.addItem(SMART); myCbInsertJavadocStubOnEnter.setVisible(hasAnyDocAwareCommenters()); myCbEnableAddingCaretsOnDoubleCtrlArrows.setText( ApplicationBundle.message("checkbox.enable.double.ctrl", KeyEvent.getKeyText(ModifierKeyDoubleClickHandler.getMultiCaretActionModifier()))); } private static boolean hasAnyDocAwareCommenters() { final Collection<Language> languages = Language.getRegisteredLanguages(); for (Language language : languages) { final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(language); if (commenter instanceof CodeDocumentationAwareCommenter) { final CodeDocumentationAwareCommenter docCommenter = (CodeDocumentationAwareCommenter)commenter; if (docCommenter.getDocumentationCommentLinePrefix() != null) { return true; } } } return false; } @Override protected List<UnnamedConfigurable> createConfigurables() { return ConfigurableWrapper.createConfigurables(EP_NAME); } @Override @Nls public String getDisplayName() { return "Smart Keys"; } @Override public String getHelpTopic() { return "reference.settingsdialog.IDE.editor.smartkey"; } @Override public JComponent createComponent() { if (!myAddonsInitialized) { myAddonsInitialized = true; for (UnnamedConfigurable provider : getConfigurables()) { myAddonPanel .add(provider.createComponent(), new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 15, 0), 0, 0)); } } return myRootPanel; } @Override public void reset() { EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance(); CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); // Paste switch(codeInsightSettings.REFORMAT_ON_PASTE){ case CodeInsightSettings.NO_REFORMAT: myReformatOnPasteCombo.setSelectedItem(NO_REFORMAT); break; case CodeInsightSettings.INDENT_BLOCK: myReformatOnPasteCombo.setSelectedItem(INDENT_BLOCK); break; case CodeInsightSettings.INDENT_EACH_LINE: myReformatOnPasteCombo.setSelectedItem(INDENT_EACH_LINE); break; case CodeInsightSettings.REFORMAT_BLOCK: myReformatOnPasteCombo.setSelectedItem(REFORMAT_BLOCK); break; } myCbSmartHome.setSelected(editorSettings.isSmartHome()); myCbSmartEnd.setSelected(codeInsightSettings.SMART_END_ACTION); myCbSmartIndentOnEnter.setSelected(codeInsightSettings.SMART_INDENT_ON_ENTER); myCbInsertPairCurlyBraceOnEnter.setSelected(codeInsightSettings.INSERT_BRACE_ON_ENTER); myCbInsertJavadocStubOnEnter.setSelected(codeInsightSettings.JAVADOC_STUB_ON_ENTER); myCbInsertPairBracket.setSelected(codeInsightSettings.AUTOINSERT_PAIR_BRACKET); myCbInsertPairQuote.setSelected(codeInsightSettings.AUTOINSERT_PAIR_QUOTE); myCbReformatBlockOnTypingRBrace.setSelected(codeInsightSettings.REFORMAT_BLOCK_ON_RBRACE); myCbCamelWords.setSelected(editorSettings.isCamelWords()); myCbSurroundSelectionOnTyping.setSelected(codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED); myCbEnableAddingCaretsOnDoubleCtrlArrows.setSelected(editorSettings.addCaretsOnDoubleCtrl()); SmartBackspaceMode backspaceMode = codeInsightSettings.getBackspaceMode(); switch (backspaceMode) { case OFF: mySmartBackspaceCombo.setSelectedItem(OFF); break; case INDENT: mySmartBackspaceCombo.setSelectedItem(SIMPLE); break; case AUTOINDENT: mySmartBackspaceCombo.setSelectedItem(SMART); break; default: LOG.error("Unexpected smart backspace mode value: " + backspaceMode); } super.reset(); } @Override public void apply() throws ConfigurationException { EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance(); CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); editorSettings.setSmartHome(myCbSmartHome.isSelected()); codeInsightSettings.SMART_END_ACTION = myCbSmartEnd.isSelected(); codeInsightSettings.SMART_INDENT_ON_ENTER = myCbSmartIndentOnEnter.isSelected(); codeInsightSettings.INSERT_BRACE_ON_ENTER = myCbInsertPairCurlyBraceOnEnter.isSelected(); codeInsightSettings.JAVADOC_STUB_ON_ENTER = myCbInsertJavadocStubOnEnter.isSelected(); codeInsightSettings.AUTOINSERT_PAIR_BRACKET = myCbInsertPairBracket.isSelected(); codeInsightSettings.AUTOINSERT_PAIR_QUOTE = myCbInsertPairQuote.isSelected(); codeInsightSettings.REFORMAT_BLOCK_ON_RBRACE = myCbReformatBlockOnTypingRBrace.isSelected(); codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED = myCbSurroundSelectionOnTyping.isSelected(); editorSettings.setCamelWords(myCbCamelWords.isSelected()); codeInsightSettings.REFORMAT_ON_PASTE = getReformatPastedBlockValue(); codeInsightSettings.setBackspaceMode(getSmartBackspaceModeValue()); editorSettings.setAddCaretsOnDoubleCtrl(myCbEnableAddingCaretsOnDoubleCtrlArrows.isSelected()); super.apply(); } @Override public boolean isModified() { if (super.isModified()) return true; EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance(); CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance(); boolean isModified = getReformatPastedBlockValue() != codeInsightSettings.REFORMAT_ON_PASTE; isModified |= isModified(myCbSmartHome, editorSettings.isSmartHome()); isModified |= isModified(myCbSmartEnd, codeInsightSettings.SMART_END_ACTION); isModified |= isModified(myCbSmartIndentOnEnter, codeInsightSettings.SMART_INDENT_ON_ENTER); isModified |= isModified(myCbInsertPairCurlyBraceOnEnter, codeInsightSettings.INSERT_BRACE_ON_ENTER); isModified |= isModified(myCbInsertJavadocStubOnEnter, codeInsightSettings.JAVADOC_STUB_ON_ENTER); isModified |= isModified(myCbInsertPairBracket, codeInsightSettings.AUTOINSERT_PAIR_BRACKET); isModified |= isModified(myCbInsertPairQuote, codeInsightSettings.AUTOINSERT_PAIR_QUOTE); isModified |= isModified(myCbReformatBlockOnTypingRBrace, codeInsightSettings.REFORMAT_BLOCK_ON_RBRACE); isModified |= isModified(myCbCamelWords, editorSettings.isCamelWords()); isModified |= isModified(myCbSurroundSelectionOnTyping, codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED); isModified |= isModified(myCbEnableAddingCaretsOnDoubleCtrlArrows, editorSettings.addCaretsOnDoubleCtrl()); isModified |= (getSmartBackspaceModeValue() != codeInsightSettings.getBackspaceMode()); return isModified; } @MagicConstant(intValues = {CodeInsightSettings.NO_REFORMAT, CodeInsightSettings.INDENT_BLOCK, CodeInsightSettings.INDENT_EACH_LINE, CodeInsightSettings.REFORMAT_BLOCK}) private int getReformatPastedBlockValue(){ Object selectedItem = myReformatOnPasteCombo.getSelectedItem(); if (NO_REFORMAT.equals(selectedItem)){ return CodeInsightSettings.NO_REFORMAT; } else if (INDENT_BLOCK.equals(selectedItem)){ return CodeInsightSettings.INDENT_BLOCK; } else if (INDENT_EACH_LINE.equals(selectedItem)){ return CodeInsightSettings.INDENT_EACH_LINE; } else if (REFORMAT_BLOCK.equals(selectedItem)){ return CodeInsightSettings.REFORMAT_BLOCK; } else{ LOG.assertTrue(false); return -1; } } private SmartBackspaceMode getSmartBackspaceModeValue() { Object selectedItem = mySmartBackspaceCombo.getSelectedItem(); if (OFF.equals(selectedItem)){ return SmartBackspaceMode.OFF; } else if (SIMPLE.equals(selectedItem)){ return SmartBackspaceMode.INDENT; } else if (SMART.equals(selectedItem)){ return SmartBackspaceMode.AUTOINDENT; } else{ LOG.error("Unexpected smart backspace item value: " + selectedItem); return SmartBackspaceMode.OFF; } } @Override @NotNull public String getId() { return "editor.preferences.smartKeys"; } }