PY-18792 Add dedicated page for Optimize Imports in Python code style settings
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 25 May 2016 19:30:44 +0000 (22:30 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 15 Jun 2016 16:34:11 +0000 (19:34 +0300)
python/src/com/jetbrains/python/codeInsight/imports/PyImportOptimizer.java
python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java
python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java
python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.form [new file with mode: 0644]
python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.java [new file with mode: 0644]
python/src/com/jetbrains/python/formatter/PyOtherCodeStylePanel.form [moved from python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form with 98% similarity]
python/src/com/jetbrains/python/formatter/PyOtherCodeStylePanel.java [moved from python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java with 97% similarity]

index 86c456a38a75729daa6cf8643b4df98dfd9dc1db..314a1dd235678eb6288c803b55e23028cfa128b2 100644 (file)
@@ -18,12 +18,13 @@ package com.jetbrains.python.codeInsight.imports;
 import com.google.common.collect.Ordering;
 import com.intellij.codeInspection.LocalInspectionToolSession;
 import com.intellij.lang.ImportOptimizer;
-import com.intellij.openapi.util.Condition;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
 import com.intellij.util.containers.ContainerUtil;
 import com.jetbrains.python.codeInsight.imports.AddImportHelper.ImportPriority;
 import com.jetbrains.python.formatter.PyBlock;
+import com.jetbrains.python.formatter.PyCodeStyleSettings;
 import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
 import com.jetbrains.python.psi.*;
 import org.jetbrains.annotations.NotNull;
@@ -34,7 +35,6 @@ import java.util.*;
  * @author yole
  */
 public class PyImportOptimizer implements ImportOptimizer {
-  private static final boolean SORT_IMPORTS = true;
 
   @Override
   public boolean supports(PsiFile file) {
@@ -68,13 +68,15 @@ public class PyImportOptimizer implements ImportOptimizer {
     private final PyFile myFile;
     private final List<PyImportStatementBase> myImportBlock;
     private final Map<ImportPriority, List<PyImportStatementBase>> myGroups;
+    private final PyCodeStyleSettings myPySettings;
 
     private ImportSorter(@NotNull PyFile file) {
       myFile = file;
+      myPySettings = CodeStyleSettingsManager.getSettings(myFile.getProject()).getCustomSettings(PyCodeStyleSettings.class);
       myImportBlock = myFile.getImportBlock();
-      myGroups = new EnumMap<ImportPriority, List<PyImportStatementBase>>(ImportPriority.class);
+      myGroups = new EnumMap<>(ImportPriority.class);
       for (ImportPriority priority : ImportPriority.values()) {
-        myGroups.put(priority, new ArrayList<PyImportStatementBase>());
+        myGroups.put(priority, new ArrayList<>());
       }
     }
 
@@ -106,7 +108,7 @@ public class PyImportOptimizer implements ImportOptimizer {
 
     private boolean groupsNotSorted() {
       final Ordering<PyImportStatementBase> importOrdering = Ordering.from(AddImportHelper.IMPORT_TYPE_THEN_NAME_COMPARATOR);
-      return SORT_IMPORTS && ContainerUtil.exists(myGroups.values(), imports -> !importOrdering.isOrdered(imports));
+      return ContainerUtil.exists(myGroups.values(), imports -> !importOrdering.isOrdered(imports));
     }
 
     private boolean needBlankLinesBetweenGroups() {
@@ -120,7 +122,7 @@ public class PyImportOptimizer implements ImportOptimizer {
     }
 
     private void applyResults() {
-      if (SORT_IMPORTS) {
+      if (myPySettings.OPTIMIZE_IMPORTS_SORT_ALPHABETICALLY) {
         for (ImportPriority priority : myGroups.keySet()) {
           final List<PyImportStatementBase> imports = myGroups.get(priority);
           Collections.sort(imports, AddImportHelper.IMPORT_TYPE_THEN_NAME_COMPARATOR);
index b48315f9004f3a2c82bc75040643b97645259009..9960c5cdfb53b530bc231973c4a41bc5d4606776 100644 (file)
@@ -30,6 +30,7 @@ public class PyCodeStyleMainPanel extends TabbedLanguageCodeStylePanel {
   @Override
   protected void initTabs(CodeStyleSettings settings) {
     super.initTabs(settings);
-    addTab(new PyCodeStylePanel(settings));
+    addTab(new PyImportsCodeStylePanel(settings));
+    addTab(new PyOtherCodeStylePanel(settings));
   }
 }
index 4ae389a76f2761002a87e0c87327c53c7e4b1215..dddc37d6bbc145720c3559c674d2d77180a6da09 100644 (file)
@@ -88,6 +88,10 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings {
    */
   public boolean USE_CONTINUATION_INDENT_FOR_ARGUMENTS = false;
 
+  public boolean OPTIMIZE_IMPORTS_SORT_ALPHABETICALLY = true;
+  public boolean OPTIMIZE_IMPORTS_SORT_NAMES_IN_FROM_IMPORTS = false;
+  public boolean OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE = false;
+
   public PyCodeStyleSettings(CodeStyleSettings container) {
     super("Python", container);
   }
diff --git a/python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.form b/python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.form
new file mode 100644 (file)
index 0000000..e4395d2
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.formatter.PyImportsCodeStylePanel">
+  <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="10" bottom="10" right="10"/>
+    <constraints>
+      <xy x="20" y="20" width="500" height="400"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <vspacer id="acc">
+        <constraints>
+          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <grid id="ee1fb" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+        <margin top="0" left="0" bottom="0" right="0"/>
+        <constraints>
+          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <clientProperties>
+          <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
+        </clientProperties>
+        <border type="none" title="Optimize Imports"/>
+        <children>
+          <component id="e4d2f" class="com.intellij.ui.components.JBCheckBox" binding="mySortImportsAlphabetically" default-binding="true">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="Sort import statements alphabetically"/>
+            </properties>
+          </component>
+          <component id="fdf9d" class="com.intellij.ui.components.JBCheckBox" binding="mySortNamesInFromImports" default-binding="true">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="Sort names in &quot;from ... import ...&quot; imports"/>
+            </properties>
+          </component>
+          <component id="a7a3a" class="com.intellij.ui.components.JBCheckBox" binding="myJoinFromImportsWithSameSource" default-binding="true">
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <text value="Join &quot;from ... import ...&quot; from the same source"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <hspacer id="25073">
+        <constraints>
+          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </hspacer>
+    </children>
+  </grid>
+</form>
diff --git a/python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.java b/python/src/com/jetbrains/python/formatter/PyImportsCodeStylePanel.java
new file mode 100644 (file)
index 0000000..1c1173f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.jetbrains.python.formatter;
+
+import com.intellij.application.options.CodeStyleAbstractPanel;
+import com.intellij.openapi.editor.colors.EditorColorsScheme;
+import com.intellij.openapi.editor.highlighter.EditorHighlighter;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.ui.components.JBCheckBox;
+import com.jetbrains.python.PythonFileType;
+import com.jetbrains.python.PythonLanguage;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * @author Mikhail Golubev
+ */
+public class PyImportsCodeStylePanel extends CodeStyleAbstractPanel {
+  private JBCheckBox mySortImportsAlphabetically;
+  private JBCheckBox mySortNamesInFromImports;
+  private JBCheckBox myJoinFromImportsWithSameSource;
+  private JPanel myRootPanel;
+
+  public PyImportsCodeStylePanel(@NotNull CodeStyleSettings settings) {
+    super(PythonLanguage.getInstance(), null, settings);
+    addPanelToWatch(myRootPanel);
+
+    mySortImportsAlphabetically.addActionListener(e -> mySortNamesInFromImports.setEnabled(mySortImportsAlphabetically.isSelected()));
+  }
+
+  @Override
+  protected String getTabTitle() {
+    return "Imports";
+  }
+
+  @NotNull
+  @Override
+  protected FileType getFileType() {
+    return PythonFileType.INSTANCE;
+  }
+
+  @Nullable
+  @Override
+  protected EditorHighlighter createHighlighter(EditorColorsScheme scheme) {
+    return null;
+  }
+
+  @Nullable
+  @Override
+  protected String getPreviewText() {
+    return null;
+  }
+
+  @Override
+  protected int getRightMargin() {
+    return 0;
+  }
+
+  @Override
+  public void apply(CodeStyleSettings settings) throws ConfigurationException {
+    final PyCodeStyleSettings pySettings = settings.getCustomSettings(PyCodeStyleSettings.class);
+
+    pySettings.OPTIMIZE_IMPORTS_SORT_ALPHABETICALLY = mySortImportsAlphabetically.isSelected();
+    pySettings.OPTIMIZE_IMPORTS_SORT_NAMES_IN_FROM_IMPORTS = mySortNamesInFromImports.isSelected();
+    pySettings.OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE = myJoinFromImportsWithSameSource.isSelected();
+  }
+
+  @Override
+  public boolean isModified(CodeStyleSettings settings) {
+    final PyCodeStyleSettings pySettings = settings.getCustomSettings(PyCodeStyleSettings.class);
+
+    return mySortImportsAlphabetically.isSelected() != pySettings.OPTIMIZE_IMPORTS_SORT_ALPHABETICALLY ||
+           mySortNamesInFromImports.isSelected() != pySettings.OPTIMIZE_IMPORTS_SORT_NAMES_IN_FROM_IMPORTS ||
+           myJoinFromImportsWithSameSource.isSelected() != pySettings.OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE;
+  }
+
+  @Nullable
+  @Override
+  public JComponent getPanel() {
+    return myRootPanel;
+  }
+
+  @Override
+  protected void resetImpl(CodeStyleSettings settings) {
+    final PyCodeStyleSettings pySettings = settings.getCustomSettings(PyCodeStyleSettings.class);
+
+    mySortImportsAlphabetically.setSelected(pySettings.OPTIMIZE_IMPORTS_SORT_ALPHABETICALLY);
+    mySortNamesInFromImports.setSelected(pySettings.OPTIMIZE_IMPORTS_SORT_NAMES_IN_FROM_IMPORTS);
+    mySortNamesInFromImports.setEnabled(mySortImportsAlphabetically.isSelected());
+    myJoinFromImportsWithSameSource.setSelected(pySettings.OPTIMIZE_IMPORTS_JOIN_FROM_IMPORTS_WITH_SAME_SOURCE);
+  }
+}
similarity index 98%
rename from python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form
rename to python/src/com/jetbrains/python/formatter/PyOtherCodeStylePanel.form
index 1bedd0b8863b397b69d0736b82d2f06e06e9534f..d169d353ef02759d856f5a8a7e39a0bf2f21f955 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.formatter.PyCodeStylePanel">
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.formatter.PyOtherCodeStylePanel">
   <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
     <margin top="0" left="0" bottom="0" right="0"/>
     <constraints>
similarity index 97%
rename from python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java
rename to python/src/com/jetbrains/python/formatter/PyOtherCodeStylePanel.java
index 3459765649b4a49b64980cee162936a9b468ce1a..396fc1fae73761c1867e2cba807e6ef936b4c61c 100644 (file)
@@ -39,7 +39,7 @@ import java.awt.event.ItemListener;
 /**
  * @author yole
  */
-public class PyCodeStylePanel extends CodeStyleAbstractPanel {
+public class PyOtherCodeStylePanel extends CodeStyleAbstractPanel {
 
   private JPanel myPanel;
   private JBCheckBox myAddTrailingBlankLineCheckbox;
@@ -47,7 +47,7 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel {
   private ComboBox myDictAlignmentCombo;
   private JPanel myPreviewPanel;
 
-  protected PyCodeStylePanel(CodeStyleSettings settings) {
+  protected PyOtherCodeStylePanel(CodeStyleSettings settings) {
     super(PythonLanguage.getInstance(), null, settings);
     addPanelToWatch(myPanel);
     installPreviewPanel(myPreviewPanel);