Merge branch 'master' into no-reformat-dialog-on-reformat-code-action
authorYaroslav Lepenkin <yaroslav.lepenkin@jetbrains.com>
Wed, 14 Jan 2015 14:57:55 +0000 (16:57 +0200)
committerYaroslav Lepenkin <yaroslav.lepenkin@jetbrains.com>
Wed, 14 Jan 2015 14:57:55 +0000 (16:57 +0200)
Conflicts:
platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
platform/lang-impl/src/com/intellij/codeInsight/actions/RearrangeCodeProcessor.java
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java

37 files changed:
java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_before.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/selectionReformat_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/selectionReformat_before.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_before.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_before.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_before.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/wholeFileReformat_after.java [new file with mode: 0644]
java/java-tests/testData/actions/codeProcessor/wholeFileReformat_before.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessorTest.java
java/java-tests/testSrc/com/intellij/codeInsight/actions/MultiActionCodeProcessorTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/actions/ReformatCodeActionTest.java
platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RearrangeCodeAction.java
platform/lang-impl/src/com/intellij/codeInsight/actions/AbstractLayoutCodeProcessor.java
platform/lang-impl/src/com/intellij/codeInsight/actions/CodeProcessor.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
platform/lang-impl/src/com/intellij/codeInsight/actions/LastRunReformatCodeOptionsProvider.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java
platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeOptions.java
platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeSettingsStorage.java [deleted file]
platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutProjectCodeDialog.java
platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsAction.java
platform/lang-impl/src/com/intellij/codeInsight/actions/OptimizeImportsProcessor.java
platform/lang-impl/src/com/intellij/codeInsight/actions/OptionalReformatActions.java [moved from platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeConstants.java with 54% similarity]
platform/lang-impl/src/com/intellij/codeInsight/actions/RearrangeCodeProcessor.java
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeRunOptions.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFileAction.java [new file with mode: 0644]
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesDialog.java
platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFilesOptions.java
platform/platform-resources/src/idea/Keymap_Default.xml
platform/platform-resources/src/idea/LangActions.xml

diff --git a/java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_after.java b/java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_after.java
new file mode 100644 (file)
index 0000000..edb36d6
--- /dev/null
@@ -0,0 +1,14 @@
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Test {
+
+        public static void main(String[] args) {
+            List<String> list = new ArrayList<String>();
+            int a = 3;
+
+int b = 3;
+        }
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_before.java b/java/java-tests/testData/actions/codeProcessor/selectedTextAndOptimizeImports_before.java
new file mode 100644 (file)
index 0000000..2256d47
--- /dev/null
@@ -0,0 +1,17 @@
+import java.lang.String;
+import java.util.List;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+
+public class Test {
+
+        public static void main(String[] args) {
+<selection>List<String> list = new ArrayList<String>();
+int a = 3;</selection>
+
+int b = 3;
+        }
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/selectionReformat_after.java b/java/java-tests/testData/actions/codeProcessor/selectionReformat_after.java
new file mode 100644 (file)
index 0000000..7e145c3
--- /dev/null
@@ -0,0 +1,11 @@
+public class Test {
+
+    int a = 2;
+    int b = 3;
+
+
+         public void run() {
+               int myFirst = 12;
+            }
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/actions/codeProcessor/selectionReformat_before.java b/java/java-tests/testData/actions/codeProcessor/selectionReformat_before.java
new file mode 100644 (file)
index 0000000..d753fc6
--- /dev/null
@@ -0,0 +1,11 @@
+public class Test {
+
+      <selection>int a = 2;
+           int b = 3;</selection>
+
+
+         public void run() {
+               int myFirst = 12;
+            }
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_after.java b/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_after.java
new file mode 100644 (file)
index 0000000..122700a
--- /dev/null
@@ -0,0 +1,18 @@
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Test {
+
+        public static void main(String[] args) {
+            List<String> list = new ArrayList<String>();
+            int a = 3;
+
+int b = 3;
+        }
+
+
+    public void test() {
+    }
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_before.java b/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformatAndOptimize_before.java
new file mode 100644 (file)
index 0000000..8780318
--- /dev/null
@@ -0,0 +1,22 @@
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+
+
+public class Test {
+
+        public static void main(String[] args) {
+<selection>                                        List<String> list = new ArrayList<String>();
+int a = 3;<caret></selection>
+
+int b = 3;
+        }
+
+
+<selection><caret>
+public void test() {
+}</selection>
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_after.java b/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_after.java
new file mode 100644 (file)
index 0000000..bf2d0b7
--- /dev/null
@@ -0,0 +1,19 @@
+public class Test {
+
+    int a = 3;
+    int b = 12;
+
+long t = 12;
+
+      public void test() {
+
+          int a = 3;
+          int b = 4;
+      }
+
+                int rest = -12;
+
+    public void run() {
+    }
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_before.java b/java/java-tests/testData/actions/codeProcessor/vcsChangedTextReformat_before.java
new file mode 100644 (file)
index 0000000..d837a92
--- /dev/null
@@ -0,0 +1,18 @@
+public class Test {
+
+<selection>          int a = 3;
+        <caret>int b = 12;</selection>
+
+long t = 12;
+
+      public void test() {
+
+<selection>               int a = 3;
+                  <caret>int b = 4;</selection>
+      }
+
+                int rest = -12;
+
+<selection>public void run() {}<caret></selection>
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_after.java b/java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_after.java
new file mode 100644 (file)
index 0000000..b3c3407
--- /dev/null
@@ -0,0 +1,11 @@
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Test {
+
+    public static void main(String[] args) {
+        List<String> list = new ArrayList<String>();
+    }
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_before.java b/java/java-tests/testData/actions/codeProcessor/wholeFileReformatAndOptimize_before.java
new file mode 100644 (file)
index 0000000..a996d55
--- /dev/null
@@ -0,0 +1,14 @@
+import java.lang.String;
+import java.util.List;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.HashSet;
+
+
+public class Test {
+
+        public static void main(String[] args) {
+List<String> list = new ArrayList<String>();
+  }
+
+}
diff --git a/java/java-tests/testData/actions/codeProcessor/wholeFileReformat_after.java b/java/java-tests/testData/actions/codeProcessor/wholeFileReformat_after.java
new file mode 100644 (file)
index 0000000..05460c5
--- /dev/null
@@ -0,0 +1,10 @@
+public class Test {
+
+    public int a = 3;
+
+
+    public void test() {
+        int c = 3;
+    }
+
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/actions/codeProcessor/wholeFileReformat_before.java b/java/java-tests/testData/actions/codeProcessor/wholeFileReformat_before.java
new file mode 100644 (file)
index 0000000..e8d0ad4
--- /dev/null
@@ -0,0 +1,10 @@
+public class Test {
+
+        public int a = 3;
+
+
+            public void test() {
+                       int c = 3;
+                }
+
+}
\ No newline at end of file
index fbd85a3b62a5e0e6653f2586636b6dff4462a932..e170e2a78da87a54cc64e949d24a929cec67987e 100644 (file)
@@ -317,14 +317,9 @@ class AdditionalEventInfo {
   }
 }
 
-class MockReformatFileSettings implements LayoutCodeOptions {
-  private boolean myProcessWholeFile;
-  private boolean myProcessDirectories;
-  private boolean myRearrange;
-  private boolean myIncludeSubdirs;
+class MockReformatFileSettings implements ReformatFilesOptions {
   private boolean myOptimizeImports;
-  private boolean myProcessOnlyChangedText;
-  private boolean myIsOK = true;
+  private boolean myIncludeSubdirs;
 
   @Nullable
   @Override
@@ -339,33 +334,13 @@ class MockReformatFileSettings implements LayoutCodeOptions {
   }
 
   @Override
-  public boolean isProcessWholeFile() {
-    return myProcessWholeFile;
-  }
-
-  MockReformatFileSettings setProcessWholeFile(boolean processWholeFile) {
-    myProcessWholeFile = processWholeFile;
-    return this;
+  public TextRangeType getTextRangeType() {
+    return TextRangeType.WHOLE_FILE;
   }
 
   @Override
-  public boolean isProcessDirectory() {
-    return myProcessDirectories;
-  }
-
-  MockReformatFileSettings setProcessDirectory(boolean processDirectories) {
-    myProcessDirectories = processDirectories;
-    return this;
-  }
-
-  @Override
-  public boolean isRearrangeEntries() {
-    return myRearrange;
-  }
-
-  @Override
-  public boolean isIncludeSubdirectories() {
-    return myIncludeSubdirs;
+  public boolean isRearrangeCode() {
+    return false;
   }
 
   @Override
@@ -379,23 +354,6 @@ class MockReformatFileSettings implements LayoutCodeOptions {
     return this;
   }
 
-  @Override
-  public boolean isProcessOnlyChangedText() {
-    return myProcessOnlyChangedText;
-  }
-
-  @NotNull
-  MockReformatFileSettings setProcessOnlyChangedText(boolean processOnlyChangedText) {
-    myProcessOnlyChangedText = processOnlyChangedText;
-    return this;
-  }
-
-  @NotNull
-  MockReformatFileSettings setRearrange(boolean rearrange) {
-    myRearrange = rearrange;
-    return this;
-  }
-
   @NotNull
   MockReformatFileSettings setIncludeSubdirs(boolean includeSubdirs) {
     myIncludeSubdirs = includeSubdirs;
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/actions/MultiActionCodeProcessorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/actions/MultiActionCodeProcessorTest.java
new file mode 100644 (file)
index 0000000..f457bf7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2014 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.codeInsight.actions;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.CaretModel;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+
+import java.util.List;
+
+import static com.intellij.codeInsight.actions.TextRangeType.*;
+
+public class MultiActionCodeProcessorTest extends LightPlatformCodeInsightFixtureTestCase {
+
+  @Override
+  protected String getTestDataPath() {
+    return JavaTestUtil.getJavaTestDataPath() + "/actions/codeProcessor/";
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    myFixture.getFile().putUserData(FormatChangedTextUtil.CHANGED_RANGES, null);
+    super.tearDown();
+  }
+
+  public void doTest(LayoutCodeOptions options) {
+    myFixture.configureByFile(getTestDataPath() + getTestName(true) + "_before.java");
+    CodeProcessor processor = new CodeProcessor(myFixture.getFile(), myFixture.getEditor(), options);
+
+    if (options.getTextRangeType() == VCS_CHANGED_TEXT) {
+      CaretModel model = myFixture.getEditor().getCaretModel();
+      List<TextRange> ranges = ContainerUtil.mapNotNull(model.getAllCarets(), new Function<Caret, TextRange>() {
+        @Override
+        public TextRange fun(Caret caret) {
+          if (caret.hasSelection()) {
+            return new TextRange(caret.getSelectionStart(), caret.getSelectionEnd());
+          }
+          return null;
+        }
+      });
+      myFixture.getFile().putUserData(FormatChangedTextUtil.CHANGED_RANGES, ranges);
+    }
+
+    processor.processCode();
+    myFixture.checkResultByFile(getTestName(true) + "_after.java");
+  }
+
+  public void testSelectionReformat() {
+    doTest(new ReformatCodeRunOptions(SELECTED_TEXT));
+  }
+
+  public void testWholeFileReformat() {
+    doTest(new ReformatCodeRunOptions(WHOLE_FILE));
+  }
+
+  public void testVcsChangedTextReformat() {
+    doTest(new ReformatCodeRunOptions(VCS_CHANGED_TEXT));
+  }
+
+  public void testWholeFileReformatAndOptimize() {
+    doTest(new ReformatCodeRunOptions(WHOLE_FILE).setOptimizeImports(true));
+  }
+
+  public void testSelectedTextAndOptimizeImports() {
+    doTest(new ReformatCodeRunOptions(SELECTED_TEXT).setOptimizeImports(true));
+  }
+
+  //public void testVcsChangedTextReformatAndOptimize() {
+  //  doTest(new ReformatCodeRunOptions(VCS_CHANGED_TEXT).setOptimizeImports(true));
+  //}
+}
index f2cd858132db21d65c05bdead47a7daefd138746..b4305938925380f2c4e5ee4b886c4d9d3bfa695b 100644 (file)
@@ -34,22 +34,16 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
 
   public void testReformatAndOptimizeMultipleFiles() throws IOException {
     List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
-    injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
+
+    //todo mock this guy
+    //LastRunReformatCodeOptionsProvider provider = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
 
     performReformatActionOnSelectedFiles(files);
     checkFormationAndImportsOptimizationFor(files);
   }
 
-  public void testReformatSingleSelectedFile() throws IOException {
-    List<PsiFile> files = createTestFiles(getTempRootDirectory(), classNames);
-    PsiFile fileToReformat = files.get(0);
-    List<PsiFile> shouldNotBeFormatted = files.subList(1, files.size());
-    injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true));
-
-    performReformatActionOnSelectedFile(fileToReformat);
-
-    checkFormationAndImportsOptimizationFor(Arrays.asList(fileToReformat));
-    checkNoProcessingWasPerformedOn(shouldNotBeFormatted);
+  public void testReformatSingleSelected_FileWithoutEditor() throws IOException {
+    //todo fill
   }
 
   public void testReformatAndOptimizeFileFromEditor() throws IOException {
@@ -77,26 +71,8 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
     checkNoProcessingWasPerformedOn(noProcessing);
   }
 
-  public void testOptimizeAndReformatAllFilesInDirectoryIncludeSubdirs() throws IOException {
-    TestFileStructure fileStructure = getThreeLevelDirectoryStructure();
-    injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true).setProcessDirectory(true).setIncludeSubdirs(true));
-    PsiFile fileInEditor = fileStructure.getFilesAtLevel(2).get(0);
-    List<PsiFile> shouldNotBeFormatted = fileStructure.getFilesAtLevel(1);
-
-    performReformatActionOnFileInEditor(fileInEditor);
-
-    checkFormationAndImportsOptimizationFor(fileStructure.getFilesAtLevel(2), fileStructure.getFilesAtLevel(3));
-    checkNoProcessingWasPerformedOn(shouldNotBeFormatted);
-  }
-
-  public void testOptimizeAndReformatAllFilesInDirectoryExcludeSubdirs() throws IOException {
-    TestFileStructure fileStructure = getThreeLevelDirectoryStructure();
-    injectMockDialogFlags(new MockReformatFileSettings().setOptimizeImports(true).setIncludeSubdirs(false));
-
-    performReformatActionOnSelectedFiles(fileStructure.getFilesAtLevel(2));
-
-    checkFormationAndImportsOptimizationFor(fileStructure.getFilesAtLevel(2));
-    checkNoProcessingWasPerformedOn(fileStructure.getFilesAtLevel(1), fileStructure.getFilesAtLevel(3));
+  public void testOptimizeAndReformat_AllFilesInDirectoryIncludeSubdirs() throws IOException {
+    //todo create tests for AbstractLayoutCodeProcessor
   }
 
   public void testOptimizeAndReformatInModule() throws IOException {
@@ -110,25 +86,9 @@ public class ReformatCodeActionTest extends AbstractLayoutCodeProcessorTest {
     checkFormationAndImportsOptimizationFor(files);
   }
 
-  private TestFileStructure getThreeLevelDirectoryStructure() throws IOException {
-    TestFileStructure fileStructure = new TestFileStructure(getModule(), getTempRootDirectory());
 
-    fileStructure.createDirectoryAndMakeItCurrent("dir");
-    addFilesToCurrentDirectory(fileStructure);
 
-    fileStructure.createDirectoryAndMakeItCurrent("innerDir");
-    addFilesToCurrentDirectory(fileStructure);
 
-    fileStructure.createDirectoryAndMakeItCurrent("innerInnerDir");
-    addFilesToCurrentDirectory(fileStructure);
 
-    return fileStructure;
-  }
 
-  private void addFilesToCurrentDirectory(TestFileStructure fileStructure) throws IOException {
-    for (int i = 0; i < 5; i++) {
-      String className = "Test" + i;
-      fileStructure.addTestFile("Test" + i + ".java", getUntouchedJavaSourceForTotalProcessing(className));
-    }
-  }
 }
index 843f8880d713122fa330e37e99bcb79a08acec4a..959bcf75e7d21c86432d76462f949595348e5883 100644 (file)
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
 import com.intellij.openapi.actionSystem.CommonDataKeys;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.SelectionModel;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiFile;
@@ -61,6 +62,13 @@ public class RearrangeCodeAction extends AnAction {
     if (file == null) {
       return;
     }
-    new RearrangeCodeProcessor(project, file, editor.getSelectionModel()).run();
+
+    SelectionModel model = editor.getSelectionModel();
+    if (model.hasSelection()) {
+      new RearrangeCodeProcessor(file, model).run();
+    }
+    else {
+      new RearrangeCodeProcessor(file).run();
+    }
   }
 }
index 5fd44fe874ac96aa4d23e1b23b73cb59c382a546..37ad0423e6a8b13623028fcfb65d0b38aa6243ac 100644 (file)
@@ -18,11 +18,15 @@ package com.intellij.codeInsight.actions;
 
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.lang.LanguageFormatting;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.ApplicationBundle;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.application.ModalityState;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.SelectionModel;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.progress.ProcessCanceledException;
@@ -35,6 +39,7 @@ import com.intellij.openapi.project.ProjectCoreUtil;
 import com.intellij.openapi.roots.GeneratedSourcesFilter;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.ui.ex.MessagesEx;
+import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.PsiBundle;
 import com.intellij.psi.PsiDirectory;
@@ -43,11 +48,14 @@ import com.intellij.psi.PsiFile;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.SequentialModalProgressTask;
 import com.intellij.util.SequentialTask;
+import com.intellij.util.SmartList;
 import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.diff.FilesTooBigForDiffException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -67,7 +75,7 @@ public abstract class AbstractLayoutCodeProcessor {
 
   private final String myProgressText;
   private final String myCommandName;
-  private final Runnable myPostRunnable;
+  private Runnable myPostRunnable;
   private boolean myProcessChangedTextOnly;
 
   protected AbstractLayoutCodeProcessor myPreviousCodeProcessor;
@@ -169,6 +177,10 @@ public abstract class AbstractLayoutCodeProcessor {
     return list;
   }
 
+  public void setPostRunnable(Runnable postRunnable) {
+    myPostRunnable = postRunnable;
+  }
+
   @Nullable
   private FutureTask<Boolean> getPreviousProcessorTask(@NotNull PsiFile file, boolean processChangedTextOnly) {
     return myPreviousCodeProcessor != null ? myPreviousCodeProcessor.preprocessFile(file, processChangedTextOnly)
@@ -568,4 +580,32 @@ public abstract class AbstractLayoutCodeProcessor {
 
     return true;
   }
+
+  protected static List<TextRange> getSelectedRanges(@NotNull SelectionModel selectionModel) {
+    final List<TextRange> ranges = new SmartList<TextRange>();
+    if (selectionModel.hasSelection()) {
+      TextRange range = TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
+      ranges.add(range);
+    }
+    else if (selectionModel.hasBlockSelection()) {
+      int[] starts = selectionModel.getBlockSelectionStarts();
+      int[] ends = selectionModel.getBlockSelectionEnds();
+      for (int i = 0; i < starts.length; i++) {
+        ranges.add(TextRange.create(starts[i], ends[i]));
+      }
+    }
+
+    return ranges;
+  }
+
+  protected void handleFileTooBigException(Logger logger, FilesTooBigForDiffException e, @NotNull PsiFile file) {
+    logger.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
+    if (!ApplicationManager.getApplication().isUnitTestMode()) {
+      Notification notification = new Notification(ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
+                                                   ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
+                                                   ApplicationBundle.message("reformat.changed.text.file.too.big.notification.text", file.getName()),
+                                                   NotificationType.INFORMATION);
+      notification.notify(file.getProject());
+    }
+  }
 }
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/CodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/CodeProcessor.java
new file mode 100644 (file)
index 0000000..088f9d7
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2000-2014 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.codeInsight.actions;
+
+import com.intellij.codeInsight.hint.HintManager;
+import com.intellij.codeInsight.hint.HintManagerImpl;
+import com.intellij.codeInsight.hint.HintUtil;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.ui.LightweightHint;
+import com.intellij.util.diff.FilesTooBigForDiffException;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.List;
+
+import static com.intellij.codeInsight.actions.TextRangeType.*;
+
+class CodeProcessor {
+  private final Editor myEditor;
+
+  private final boolean myShouldOptimizeImports;
+  private final boolean myShouldRearrangeCode;
+  private final boolean myProcessSelectedText;
+  private final boolean myProcessChangesTextOnly;
+  private final boolean myShouldNotify;
+
+  private final Project myProject;
+  private final PsiFile myFile;
+  private final TextRangeType myProcessingType;
+
+  public CodeProcessor(PsiFile file,
+                       Editor editor,
+                       LayoutCodeOptions runOptions)
+  {
+    myFile = file;
+    myProject = file.getProject();
+    myEditor = editor;
+
+    myProcessingType = runOptions.getTextRangeType();
+
+    myShouldOptimizeImports = runOptions.isOptimizeImports();
+    myShouldRearrangeCode = runOptions.isRearrangeCode();
+    myProcessSelectedText = myEditor != null && runOptions.getTextRangeType() == SELECTED_TEXT;
+    myProcessChangesTextOnly = runOptions.getTextRangeType() == VCS_CHANGED_TEXT;
+
+    myShouldNotify = myEditor != null && !myProcessSelectedText;
+  }
+
+  public void processCode() {
+    AbstractLayoutCodeProcessor processor = null;
+    if (myShouldOptimizeImports) {
+      processor = new OptimizeImportsProcessor(myProject, myFile);
+    }
+
+    if (processor != null) {
+      if (myProcessSelectedText) {
+        processor = new ReformatCodeProcessor(processor, myEditor.getSelectionModel());
+      }
+      else {
+        processor = new ReformatCodeProcessor(processor, myProcessChangesTextOnly);
+      }
+    }
+    else {
+      if (myProcessSelectedText) {
+        processor = new ReformatCodeProcessor(myFile, myEditor.getSelectionModel());
+      }
+      else {
+        processor = new ReformatCodeProcessor(myFile, myProcessChangesTextOnly);
+      }
+    }
+
+    if (myShouldRearrangeCode) {
+      if (myProcessSelectedText) {
+        processor = new RearrangeCodeProcessor(processor, myEditor.getSelectionModel());
+      }
+      else {
+        processor = new RearrangeCodeProcessor(processor);
+      }
+    }
+
+    if (myShouldNotify) {
+      Document document = PsiDocumentManager.getInstance(myProject).getDocument(myFile);
+      if (document != null) {
+        processor.setPostRunnable(getNotificationCallBack(document));
+      }
+    }
+
+    processor.run();
+  }
+
+  private Runnable getNotificationCallBack(@NotNull final Document document) {
+    final CharSequence textBeforeChange = document.getImmutableCharSequence();
+    final Runnable calculateChangesAndNotify = new Runnable() {
+      @Override
+      public void run() {
+        final String info = prepareMessage(document, textBeforeChange);
+        ApplicationManager.getApplication().invokeLater(new Runnable() {
+          @Override
+          public void run() {
+            if (!myEditor.isDisposed() && myEditor.getComponent().isShowing()) {
+              showHint(myEditor, info);
+            }
+          }
+        });
+      }
+    };
+
+    return new Runnable() {
+      @Override
+      public void run() {
+        ApplicationManager.getApplication().executeOnPooledThread(calculateChangesAndNotify);
+      }
+    };
+  }
+
+  private static int getProcessedLinesNumber(final Document document, final CharSequence before) {
+    int totalLinesProcessed = 0;
+    try {
+      List<TextRange> ranges = FormatChangedTextUtil.calculateChangedTextRanges(document, before);
+      for (TextRange range : ranges) {
+        int lineStartNumber = document.getLineNumber(range.getStartOffset());
+        int lineEndNumber = document.getLineNumber(range.getEndOffset());
+
+        totalLinesProcessed += lineEndNumber - lineStartNumber + 1;
+      }
+    }
+    catch (FilesTooBigForDiffException e) {
+      return -1;
+    }
+    return totalLinesProcessed;
+  }
+
+  @NotNull
+  private String prepareMessage(@NotNull Document document, @NotNull CharSequence textBeforeChange) {
+    int totalLinesProcessed = getProcessedLinesNumber(document, textBeforeChange);
+
+    String linesInfo = "";
+    if (totalLinesProcessed >= 0) {
+      linesInfo = "Changed " + totalLinesProcessed + " lines";
+    }
+
+    String scopeInfo = myProcessingType == VCS_CHANGED_TEXT ? ", processed only changed lines since last revision" : null;
+    String actionsInfo = "Performed: formatting";
+    if (myShouldOptimizeImports) {
+      actionsInfo += ", import optimization";
+    }
+    if (myShouldRearrangeCode) {
+      actionsInfo += " and code rearrangement";
+    }
+
+    String shortcutInfo = "Show reformat dialog: " + KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction("ReformatFile"));
+
+    String info = linesInfo;
+    if (scopeInfo != null) {
+      info += scopeInfo;
+    }
+    info += "\n";
+    info += actionsInfo + "\n";
+    info += shortcutInfo;
+
+    return info;
+  }
+
+  private static void showHint(@NotNull Editor editor, @NotNull String info) {
+    JComponent component = HintUtil.createInformationLabel(info);
+    LightweightHint hint = new LightweightHint(component);
+    HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, HintManager.UNDER,
+                                                     HintManager.HIDE_BY_ANY_KEY |
+                                                     HintManager.HIDE_BY_TEXT_CHANGE |
+                                                     HintManager.HIDE_BY_SCROLLING,
+                                                     0, false);
+  }
+}
index 03691d0749e05c971ee0980557e0d95dd58d8152..1a38026975af9dcc26318067786783dab0d92ef0 100644 (file)
@@ -56,6 +56,8 @@ import java.util.*;
 public class FormatChangedTextUtil {
   public static final Key<String> TEST_REVISION_CONTENT = Key.create("test.revision.content");
   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.FormatChangedTextUtil");
+  protected static final Key<List<TextRange>> CHANGED_RANGES = Key.create("changed.ranges.since.last.revision");
+
 
   private FormatChangedTextUtil() {
   }
@@ -71,26 +73,9 @@ public class FormatChangedTextUtil {
     final VirtualFile virtualFile = file.getVirtualFile();
     if (virtualFile != null) {
       final Change change = ChangeListManager.getInstance(project).getChange(virtualFile);
-      if (change != null && change.getType() == Change.Type.NEW) {
-        return true;
-      }
+      return change != null;
     }
-
-    final LineStatusTrackerManagerI manager = LineStatusTrackerManager.getInstance(project);
-    if (manager == null) {
-      return false;
-    }
-    
-    final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
-    if (document == null) {
-      return false;
-    }
-    final LineStatusTracker lineStatusTracker = manager.getLineStatusTracker(document);
-    if (lineStatusTracker == null) {
-      return false;
-    }
-    final List<Range> ranges = lineStatusTracker.getRanges();
-    return !ranges.isEmpty();
+    return false;
   }
 
   /**
@@ -270,17 +255,12 @@ public class FormatChangedTextUtil {
     }
 
     String contentFromVcs = getRevisionedContentFrom(change);
-    return contentFromVcs != null ? calculateChangedTextRanges(project, file, contentFromVcs)
+    return contentFromVcs != null ? calculateChangedTextRanges(document, contentFromVcs)
                                   : ContainerUtil.<TextRange>emptyList();
   }
 
   @Nullable
-  private static List<TextRange> getCachedChangedLines(@NotNull Project project, @NotNull PsiFile file) {
-    Document document = PsiDocumentManager.getInstance(project).getDocument(file);
-    if (document == null) {
-      return ContainerUtil.emptyList();
-    }
-
+  private static List<TextRange> getCachedChangedLines(@NotNull Project project, @NotNull Document document) {
     LineStatusTracker tracker = LineStatusTrackerManager.getInstance(project).getLineStatusTracker(document);
     if (tracker != null) {
       List<Range> ranges = tracker.getRanges();
@@ -307,17 +287,10 @@ public class FormatChangedTextUtil {
   }
 
   @NotNull
-  private static List<TextRange> calculateChangedTextRanges(@NotNull Project project, 
-                                                            @NotNull PsiFile file, 
-                                                            @NotNull String contentFromVcs) throws FilesTooBigForDiffException 
+  protected static List<TextRange> calculateChangedTextRanges(@NotNull Document document,
+                                                              @NotNull CharSequence contentFromVcs) throws FilesTooBigForDiffException
   {
     Document documentFromVcs = ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(contentFromVcs, true, false);
-    Document document = PsiDocumentManager.getInstance(project).getDocument(file);
-
-    if (document == null) {
-      return ContainerUtil.emptyList();
-    }
-
     List<Range> changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
     return getChangedTextRanges(document, changedRanges);
   }
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LastRunReformatCodeOptionsProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LastRunReformatCodeOptionsProvider.java
new file mode 100644 (file)
index 0000000..9ba882f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 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.codeInsight.actions;
+
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.lang.Language;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+public class LastRunReformatCodeOptionsProvider {
+
+  private static final String OPTIMIZE_IMPORTS_KEY     = "LayoutCode.optimizeImports";
+  private static final String REARRANGE_ENTRIES_KEY    = "LayoutCode.rearrangeEntries";
+  private static final String PROCESS_CHANGED_TEXT_KEY = "LayoutCode.processChangedText";
+
+  private final PropertiesComponent myPropertiesComponent;
+
+  public LastRunReformatCodeOptionsProvider(@NotNull PropertiesComponent propertiesComponent) {
+    myPropertiesComponent = propertiesComponent;
+  }
+
+  public ReformatCodeRunOptions getLastRunOptions(@NotNull PsiFile file) {
+    Language language = file.getLanguage();
+
+    ReformatCodeRunOptions settings = new ReformatCodeRunOptions(getLastTextRangeType());
+    settings.setOptimizeImports(getLastOptimizeImports());
+    settings.setRearrangeCode(isRearrangeCode(language));
+
+    return settings;
+  }
+
+  public void saveRearrangeState(@NotNull Language language, boolean value) {
+    String key = getRearrangeCodeKeyFor(language);
+    myPropertiesComponent.setValue(key, Boolean.toString(value));
+  }
+
+  public void saveOptimizeImportsState(boolean value) {
+    String optimizeImports = Boolean.toString(value);
+    myPropertiesComponent.setValue(OPTIMIZE_IMPORTS_KEY, optimizeImports);
+  }
+
+  public boolean getLastOptimizeImports() {
+    return myPropertiesComponent.getBoolean(OPTIMIZE_IMPORTS_KEY, false);
+  }
+
+  public TextRangeType getLastTextRangeType() {
+    return myPropertiesComponent.getBoolean(PROCESS_CHANGED_TEXT_KEY, false) ? TextRangeType.VCS_CHANGED_TEXT : TextRangeType.WHOLE_FILE;
+  }
+
+  public void saveProcessVcsChangedTextState(boolean value) {
+    String processOnlyVcsChangedText = Boolean.toString(value);
+    myPropertiesComponent.setValue(PROCESS_CHANGED_TEXT_KEY, processOnlyVcsChangedText);
+  }
+
+  public void saveRearrangeCodeState(boolean value) {
+    myPropertiesComponent.setValue(REARRANGE_ENTRIES_KEY, Boolean.toString(value));
+  }
+
+  public boolean getLastRearrangeCode() {
+    return myPropertiesComponent.getBoolean(REARRANGE_ENTRIES_KEY, false);
+  }
+
+  public boolean isRearrangeCode(@NotNull Language language) {
+    String key = getRearrangeCodeKeyFor(language);
+    return myPropertiesComponent.getBoolean(key, false);
+  }
+
+  private static String getRearrangeCodeKeyFor(@NotNull Language language) {
+    return REARRANGE_ENTRIES_KEY + language.getDisplayName();
+  }
+
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.form
new file mode 100644 (file)
index 0000000..b6e07f4
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.codeInsight.actions.LayoutCodeDialog">
+  <grid id="27dc6" binding="myButtonsPanel" layout-manager="GridLayoutManager" row-count="3" column-count="5" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+    <margin top="0" left="0" bottom="0" right="0"/>
+    <constraints>
+      <xy x="20" y="20" width="472" height="400"/>
+    </constraints>
+    <properties/>
+    <border type="none"/>
+    <children>
+      <vspacer id="52898">
+        <constraints>
+          <grid row="2" column="3" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+        </constraints>
+      </vspacer>
+      <component id="8ca39" class="com.intellij.openapi.ui.Splitter">
+        <constraints>
+          <grid row="1" column="4" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+      </component>
+      <grid id="91e0a" binding="myActionsPanel" 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="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+        </constraints>
+        <properties/>
+        <border type="none"/>
+        <children>
+          <component id="9d93" class="javax.swing.JCheckBox" binding="myOptimizeImportsCb" default-binding="true">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <margin top="0" left="0" bottom="0" right="0"/>
+              <text value="&amp;Optimize imports"/>
+            </properties>
+          </component>
+          <vspacer id="2d364">
+            <constraints>
+              <grid row="2" 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>
+          <component id="a291" class="javax.swing.JCheckBox" binding="myRearrangeCodeCb" default-binding="true">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <margin top="0" left="0" bottom="0" right="0"/>
+              <text value="Rearra&amp;nge code"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <grid id="b1a5c" binding="myScopePanel" layout-manager="GridLayoutManager" row-count="4" 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>
+          <grid row="1" 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/>
+        <border type="none"/>
+        <children>
+          <component id="cea7f" class="javax.swing.JRadioButton" binding="myOnlyVCSChangedTextRb" default-binding="true">
+            <constraints>
+              <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <margin top="0" left="0" bottom="0" right="0"/>
+              <text value="Only &amp;VCS changed text"/>
+            </properties>
+          </component>
+          <hspacer id="6a094">
+            <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>
+          <vspacer id="467fa">
+            <constraints>
+              <grid row="3" 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>
+          <component id="27301" class="javax.swing.JRadioButton" binding="mySelectedTextRadioButton" default-binding="true">
+            <constraints>
+              <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <margin top="0" left="0" bottom="0" right="0"/>
+              <text value="&amp;Selected text"/>
+            </properties>
+          </component>
+          <component id="2eea6" class="javax.swing.JRadioButton" binding="myWholeFileRadioButton" default-binding="true">
+            <constraints>
+              <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+            </constraints>
+            <properties>
+              <margin top="0" left="0" bottom="0" right="0"/>
+              <text value="&amp;Whole file"/>
+            </properties>
+          </component>
+        </children>
+      </grid>
+      <component id="38fdd" class="javax.swing.JLabel">
+        <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="Scope:"/>
+        </properties>
+      </component>
+      <component id="1fda7" class="javax.swing.JLabel">
+        <constraints>
+          <grid row="0" column="1" 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="Optional:"/>
+        </properties>
+      </component>
+      <hspacer id="b6b1d">
+        <constraints>
+          <grid row="1" column="2" 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>
+  <buttonGroups>
+    <group name="myGroup1">
+      <member id="e5942"/>
+      <member id="4a767"/>
+      <member id="2b374"/>
+      <member id="27301"/>
+      <member id="2eea6"/>
+      <member id="cea7f"/>
+    </group>
+  </buttonGroups>
+</form>
index 716d2f88484499fa3d2c21da773b1a58a1497209..6dc2971b800cdb0fc58226e805cc58e986803ac6 100644 (file)
 
 package com.intellij.codeInsight.actions;
 
-import com.intellij.CommonBundle;
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.lang.LanguageImportStatements;
-import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
 import com.intellij.openapi.help.HelpManager;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.psi.PsiDirectory;
 import com.intellij.psi.PsiFile;
-import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
-import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
 import com.intellij.psi.codeStyle.arrangement.Rearranger;
-import com.intellij.psi.search.SearchScope;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.vcsUtil.VcsUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 
-public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions {
+public class LayoutCodeDialog extends DialogWrapper {
   @NotNull  private final Project myProject;
-  @Nullable private final PsiFile myFile;
-  @Nullable private final PsiDirectory myDirectory;
-  private final Boolean myTextSelected;
-
-  private JRadioButton myRbFile;
-  private JRadioButton myRbSelectedText;
-  private JRadioButton myRbDirectory;
-  private JCheckBox    myCbIncludeSubdirs;
-  private JCheckBox    myCbOptimizeImports;
-  private JCheckBox    myCbArrangeEntries;
-  private JCheckBox    myCbOnlyVcsChangedRegions;
-  private JCheckBox    myDoNotAskMeCheckBox;
+  @NotNull private final PsiFile myFile;
+
+  private final boolean myTextSelected;
 
   private final String myHelpId;
-  @Nullable private CommonCodeStyleSettings myCommonSettings;
-  private boolean myRearrangeAlwaysEnabled;
+  private final LastRunReformatCodeOptionsProvider myLastRunOptions;
+
+  private JPanel myButtonsPanel;
 
-  private final boolean myOptimizeImportProcessorsForFileLanguageExists;
-  private final boolean myRearrangerProcessorsForFileLanguageExists;
-  private final boolean myFileHasChanges;
+  private JCheckBox myOptimizeImportsCb;
+  private JCheckBox myRearrangeCodeCb;
 
-  private boolean myOptimizeImportsSelected;
-  private boolean myFormatOnlyVCSChangedRegionsSelected;
-  private boolean myDoNotShowDialogSelected;
-  private boolean myRearrangeEntriesSelected;
+  private JRadioButton myOnlyVCSChangedTextRb;
+  private JRadioButton mySelectedTextRadioButton;
+  private JRadioButton myWholeFileRadioButton;
 
+  private JPanel myActionsPanel;
+  private JPanel myScopePanel;
 
-  public  LayoutCodeDialog(@NotNull Project project,
-                          @NotNull String title,
-                          @Nullable PsiFile file,
-                          @Nullable PsiDirectory directory,
-                          Boolean isTextSelected,
+  private LayoutCodeOptions myRunOptions;
+
+  public LayoutCodeDialog(@NotNull Project project,
+                          @NotNull PsiFile file,
+                          boolean textSelected,
                           final String helpId) {
     super(project, true);
     myFile = file;
     myProject = project;
-    myDirectory = directory;
-    myTextSelected = isTextSelected;
-
-    myOptimizeImportProcessorsForFileLanguageExists = myFile != null && !LanguageImportStatements.INSTANCE.forFile(myFile).isEmpty();
-    myRearrangerProcessorsForFileLanguageExists = myFile != null && Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null;
-    myFileHasChanges = myFile != null && FormatChangedTextUtil.hasChanges(myFile);
+    myTextSelected = textSelected;
+    myHelpId = helpId;
 
-    if (myFile != null) myCommonSettings = CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(myFile.getLanguage());
-    myRearrangeAlwaysEnabled = myCommonSettings != null
-                               && myCommonSettings.isForceArrangeMenuAvailable()
-                               && myCommonSettings.FORCE_REARRANGE_MODE == CommonCodeStyleSettings.REARRANGE_ALWAYS;
+    myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
+    myRunOptions = createOptionsBundledOnDialog();
 
     setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
-    setTitle(title);
+    setTitle("Reformat File: " + file.getName());
+
     init();
-    myHelpId = helpId;
   }
 
-  @Override
   protected void init() {
     super.init();
 
-    loadCbsStates();
-    setUpInitialSelection();
+    setUpActions();
+    setUpTextRangeMode();
+  }
 
-    myRbFile.addActionListener(new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        saveEnabledCbsSelectedState();
-        setUpCbsStateForFileFormatting();
-      }
-    });
 
-    myRbDirectory.addActionListener(new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        saveEnabledCbsSelectedState();
-        setUpCbsStatesForDirectoryFormatting();
-      }
-    });
+  private void setUpTextRangeMode() {
+    mySelectedTextRadioButton.setEnabled(myTextSelected);
+    if (!myTextSelected) {
+      mySelectedTextRadioButton.setToolTipText("No text selected in editor");
+    }
 
-    myRbSelectedText.addActionListener(new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        saveEnabledCbsSelectedState();
-        setUpCbsStatesForSelectedTextFormatting();
+    final boolean fileHasChanges = FormatChangedTextUtil.hasChanges(myFile);
+    if (myFile.getVirtualFile() instanceof LightVirtualFile) {
+      myOnlyVCSChangedTextRb.setVisible(false);
+    }
+    else {
+      myOnlyVCSChangedTextRb.setEnabled(fileHasChanges);
+      if (!fileHasChanges) {
+        String hint = getChangesNotAvailableHint();
+        if (hint != null) myOnlyVCSChangedTextRb.setToolTipText(hint);
       }
-    });
-  }
+    }
 
-  private void setUpInitialSelection() {
-    if (myTextSelected == Boolean.TRUE) {
-      myRbSelectedText.setSelected(true);
-      setUpCbsStatesForSelectedTextFormatting();
+    myWholeFileRadioButton.setEnabled(true);
+
+    if (myTextSelected) {
+      mySelectedTextRadioButton.setSelected(true);
     }
     else {
-      if (myFile != null) {
-        myRbFile.setSelected(true);
-        setUpCbsStateForFileFormatting();
+      boolean lastRunProcessedChangedText = myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
+      if (lastRunProcessedChangedText && fileHasChanges) {
+        myOnlyVCSChangedTextRb.setSelected(true);
       }
       else {
-        myRbDirectory.setSelected(true);
-        setUpCbsStatesForDirectoryFormatting();
+        myWholeFileRadioButton.setSelected(true);
       }
     }
-    myCbIncludeSubdirs.setSelected(true);
-  }
-
-  private void loadCbsStates() {
-    myOptimizeImportsSelected = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false);
-    myRearrangeEntriesSelected = myRearrangeAlwaysEnabled || ReformatCodeAction.getLastSavedRearrangeCbState(myProject, myFile);
-    myFormatOnlyVCSChangedRegionsSelected = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false);
   }
 
-  private void saveEnabledCbsSelectedState() {
-    if (myCbArrangeEntries.isEnabled()) {
-      myRearrangeEntriesSelected = myCbArrangeEntries.isSelected();
-    }
-    if (myCbOptimizeImports.isEnabled()) {
-      myOptimizeImportsSelected = myCbOptimizeImports.isSelected();
-    }
-    if (myCbOnlyVcsChangedRegions.isEnabled()) {
-      myFormatOnlyVCSChangedRegionsSelected = myCbOnlyVcsChangedRegions.isSelected();
-    }
-    if (myDoNotAskMeCheckBox.isEnabled()) {
-      myDoNotShowDialogSelected = myDoNotAskMeCheckBox.isSelected();
+  private void setUpActions() {
+    boolean canOptimizeImports = !LanguageImportStatements.INSTANCE.forFile(myFile).isEmpty();
+    myOptimizeImportsCb.setVisible(canOptimizeImports);
+    if (canOptimizeImports) {
+      myOptimizeImportsCb.setSelected(myLastRunOptions.getLastOptimizeImports());
     }
-  }
-
-  private void setUpCbsStateForFileFormatting() {
-    myCbOptimizeImports.setEnabled(myOptimizeImportProcessorsForFileLanguageExists);
-    myCbOptimizeImports.setSelected(myOptimizeImportProcessorsForFileLanguageExists && myOptimizeImportsSelected);
-
-    myCbArrangeEntries.setEnabled(myRearrangerProcessorsForFileLanguageExists);
-    myCbArrangeEntries.setSelected(myRearrangerProcessorsForFileLanguageExists && myRearrangeEntriesSelected);
-
-    myCbOnlyVcsChangedRegions.setEnabled(myFileHasChanges);
-    myCbOnlyVcsChangedRegions.setSelected(myFileHasChanges && myFormatOnlyVCSChangedRegionsSelected);
-
-    myDoNotAskMeCheckBox.setEnabled(true);
-    myDoNotAskMeCheckBox.setSelected(myDoNotShowDialogSelected);
-
-    myCbIncludeSubdirs.setEnabled(false);
-  }
-
-  private void setUpCbsStatesForDirectoryFormatting() {
-    myCbOptimizeImports.setEnabled(true);
-    myCbOptimizeImports.setSelected(myOptimizeImportsSelected);
-
-    myCbArrangeEntries.setEnabled(true);
-    myCbArrangeEntries.setSelected(myRearrangeEntriesSelected);
-
-    myCbOnlyVcsChangedRegions.setEnabled(myDirectory != null && FormatChangedTextUtil.hasChanges(myDirectory));
-    myCbOnlyVcsChangedRegions.setSelected(false);
-
-    myDoNotAskMeCheckBox.setEnabled(false);
-    myDoNotAskMeCheckBox.setSelected(false);
-
-    myCbIncludeSubdirs.setEnabled(true);
-  }
 
-  private void setUpCbsStatesForSelectedTextFormatting() {
-    myCbOptimizeImports.setEnabled(false);
-    myCbOptimizeImports.setSelected(false);
-
-    myCbArrangeEntries.setEnabled(true);
-    myCbArrangeEntries.setSelected(myRearrangeEntriesSelected);
-
-    myCbOnlyVcsChangedRegions.setEnabled(false);
-    myCbOnlyVcsChangedRegions.setSelected(false);
-
-    myDoNotAskMeCheckBox.setEnabled(true);
-    myDoNotAskMeCheckBox.setSelected(myDoNotShowDialogSelected);
-
-    myCbIncludeSubdirs.setEnabled(false);
+    boolean canRearrangeCode = Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null;
+    myRearrangeCodeCb.setVisible(canRearrangeCode);
+    if (canRearrangeCode) {
+      myRearrangeCodeCb.setSelected(myLastRunOptions.isRearrangeCode(myFile.getLanguage()));
+    }
   }
 
-  @Override
-  protected JComponent createCenterPanel() {
-    JPanel panel = new JPanel(new GridBagLayout());
-    panel.setBorder(BorderFactory.createEmptyBorder(4, 8, 8, 0));
-    GridBagConstraints gbConstraints = new GridBagConstraints();
-    gbConstraints.gridy = 0;
-    gbConstraints.gridx = 0;
-    gbConstraints.gridwidth = 3;
-    gbConstraints.gridheight = 1;
-    gbConstraints.weightx = 1;
-
-    gbConstraints.fill = GridBagConstraints.BOTH;
-    gbConstraints.insets = new Insets(0, 0, 0, 0);
-
-    myRbFile = new JRadioButton(CodeInsightBundle.message("process.scope.file",
-                                                          (myFile != null ? "'" + myFile.getVirtualFile().getPresentableUrl() + "'" : "")));
-    panel.add(myRbFile, gbConstraints);
-
-    myRbSelectedText = new JRadioButton(CodeInsightBundle.message("reformat.option.selected.text"));
-    if (myTextSelected != null) {
-      gbConstraints.gridy++;
-      gbConstraints.insets = new Insets(0, 0, 0, 0);
-      panel.add(myRbSelectedText, gbConstraints);
+  @Nullable
+  private String getChangesNotAvailableHint() {
+    if (!VcsUtil.isFileUnderVcs(myProject, VcsUtil.getFilePath(myFile.getVirtualFile()))) {
+      return "File not under VCS root";
     }
-
-    myRbDirectory = new JRadioButton();
-    myCbIncludeSubdirs = new JCheckBox(CodeInsightBundle.message("reformat.option.include.subdirectories"));
-    if (myDirectory != null) {
-      myRbDirectory.setText(CodeInsightBundle.message("reformat.option.all.files.in.directory",
-                                                      myDirectory.getVirtualFile().getPresentableUrl()));
-      gbConstraints.gridy++;
-      gbConstraints.insets = new Insets(0, 0, 0, 0);
-      panel.add(myRbDirectory, gbConstraints);
-
-      if (myDirectory.getSubdirectories().length > 0) {
-        gbConstraints.gridy++;
-        gbConstraints.insets = new Insets(0, 20, 0, 0);
-        panel.add(myCbIncludeSubdirs, gbConstraints);
-      }
+    else if (!FormatChangedTextUtil.hasChanges(myFile)) {
+      return "File was not changed since last revision";
     }
+    return null;
+  }
 
-    myCbOptimizeImports = new JCheckBox(CodeInsightBundle.message("reformat.option.optimize.imports"));
-    if (myTextSelected != null && LanguageImportStatements.INSTANCE.hasAnyExtensions()) {
-      gbConstraints.gridy++;
-      gbConstraints.insets = new Insets(0, 0, 0, 0);
-      panel.add(myCbOptimizeImports, gbConstraints);
+  private void saveCurrentConfiguration() {
+    if (myOptimizeImportsCb.isEnabled()) {
+      myLastRunOptions.saveOptimizeImportsState(myRunOptions.isOptimizeImports());
     }
-
-    myCbArrangeEntries = new JCheckBox(CodeInsightBundle.message("reformat.option.rearrange.entries"));
-    if (myDirectory != null || myFile != null && Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null)
-    {
-      gbConstraints.gridy++;
-      gbConstraints.insets = new Insets(0, 0, 0, 0);
-      panel.add(myCbArrangeEntries, gbConstraints);
+    if (myRearrangeCodeCb.isEnabled()) {
+      myLastRunOptions.saveRearrangeState(myFile.getLanguage(), myRunOptions.isRearrangeCode());
     }
 
-    myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region"));
-    gbConstraints.gridy++;
-    panel.add(myCbOnlyVcsChangedRegions, gbConstraints);
+    if (!mySelectedTextRadioButton.isSelected()) {
+      myLastRunOptions.saveProcessVcsChangedTextState(myOnlyVCSChangedTextRb.isSelected());
+    }
+  }
 
-    ButtonGroup buttonGroup = new ButtonGroup();
-    buttonGroup.add(myRbFile);
-    buttonGroup.add(myRbSelectedText);
-    buttonGroup.add(myRbDirectory);
+  @NotNull
+  private LayoutCodeOptions createOptionsBundledOnDialog() {
+    return new LayoutCodeOptions() {
+      @Override
+      public TextRangeType getTextRangeType() {
+        if (myOnlyVCSChangedTextRb.isSelected()) {
+          return TextRangeType.VCS_CHANGED_TEXT;
+        }
+        if (mySelectedTextRadioButton.isSelected()) {
+          return TextRangeType.SELECTED_TEXT;
+        }
+        return TextRangeType.WHOLE_FILE;
+      }
 
-    myRbFile.setEnabled(myFile != null);
-    myRbSelectedText.setEnabled(myTextSelected == Boolean.TRUE);
+      @Override
+      public boolean isRearrangeCode() {
+        return myRearrangeCodeCb.isEnabled() && myRearrangeCodeCb.isSelected();
+      }
 
-    return panel;
+      @Override
+      public boolean isOptimizeImports() {
+        return myOptimizeImportsCb.isEnabled() && myOptimizeImportsCb.isSelected();
+      }
+    };
   }
 
+  @Nullable
   @Override
-  protected JComponent createSouthPanel() {
-    JComponent southPanel = super.createSouthPanel();
-    myDoNotAskMeCheckBox = new JCheckBox(CommonBundle.message("dialog.options.do.not.show"));
-    return DialogWrapper.addDoNotShowCheckBox(southPanel, myDoNotAskMeCheckBox);
+  protected JComponent createCenterPanel() {
+    return myButtonsPanel;
   }
 
   @NotNull
@@ -302,81 +196,14 @@ public class LayoutCodeDialog extends DialogWrapper implements LayoutCodeOptions
     HelpManager.getInstance().invokeHelp(myHelpId);
   }
 
-  @Override
-  public boolean isProcessWholeFile() {
-    return myRbFile.isSelected();
-  }
-
-  @Override
-  public boolean isProcessDirectory() {
-    return myRbDirectory.isSelected();
-  }
-
-  @Override
-  public boolean isIncludeSubdirectories() {
-    return myCbIncludeSubdirs.isSelected();
-  }
-
-  @Override
-  public boolean isOptimizeImports() {
-    return myCbOptimizeImports.isSelected();
-  }
-
-  @Override
-  public boolean isRearrangeEntries() {
-    return myCbArrangeEntries.isSelected();
-  }
-
-  @Nullable
-  @Override
-  public String getFileTypeMask() {
-    return null;
-  }
-
-  @Nullable
-  @Override
-  public SearchScope getSearchScope() {
-    return null;
-  }
-
-  @Override
-  public boolean isProcessOnlyChangedText() {
-    return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
-  }
-
-  public boolean isDoNotAskMe() {
-    if (myDoNotAskMeCheckBox.isEnabled()) {
-      return myDoNotAskMeCheckBox.isSelected();
-    }
-    else {
-      return !EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG;
-    }
-  }
-
   @Override
   protected void doOKAction() {
     super.doOKAction();
-    persistEnabledCbsStates();
+    saveCurrentConfiguration();
   }
 
-  private void persistEnabledCbsStates() {
-    if (myCbOptimizeImports.isEnabled()) {
-      String optimizeImports = Boolean.toString(myCbOptimizeImports.isSelected());
-      PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, optimizeImports);
-    }
-    if (myCbOnlyVcsChangedRegions.isEnabled()) {
-      String formatVcsChangedRegions = Boolean.toString(myCbOnlyVcsChangedRegions.isSelected());
-      PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, formatVcsChangedRegions);
-    }
-    if (myCbArrangeEntries.isEnabled()) {
-      saveRearrangeCbState(myCbArrangeEntries.isSelected());
-    }
+  public LayoutCodeOptions getRunOptions() {
+    return myRunOptions;
   }
 
-  private void saveRearrangeCbState(boolean isSelected) {
-    if (myFile != null)
-      LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, myFile.getLanguage(), isSelected);
-    else
-      LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isSelected);
-  }
 }
index 5a05a9ac13abcfac4e97536dda2e072d3de3a54e..2400e3b628af9d9e8c2e66ecfec364cfaa030166 100644 (file)
  */
 package com.intellij.codeInsight.actions;
 
-public interface LayoutCodeOptions extends DirectoryFormattingOptions {
+public interface LayoutCodeOptions extends OptionalReformatActions {
 
-  boolean isProcessWholeFile();
+  TextRangeType getTextRangeType();
 
-  boolean isProcessDirectory();
+}
 
+enum TextRangeType {
+  VCS_CHANGED_TEXT,
+  SELECTED_TEXT,
+  WHOLE_FILE
 }
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeSettingsStorage.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeSettingsStorage.java
deleted file mode 100644 (file)
index 5175cf5..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2000-2013 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.codeInsight.actions;
-
-import com.intellij.ide.util.PropertiesComponent;
-import com.intellij.lang.Language;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-public class LayoutCodeSettingsStorage {
-
-  private LayoutCodeSettingsStorage() {
-  }
-
-  public static void saveRearrangeEntriesOptionFor(@NotNull Project project, @NotNull Language language, boolean value) {
-    String key = getRearrangeEntriesKeyForLanguage(language);
-    PropertiesComponent.getInstance(project).setValue(key, Boolean.toString(value));
-  }
-
-  public static void saveRearrangeEntriesOptionFor(@NotNull Project project, boolean value) {
-    PropertiesComponent.getInstance(project).setValue(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, Boolean.toString(value));
-  }
-
-  public static boolean getLastSavedRearrangeEntriesCbStateFor(@NotNull Project project) {
-    return PropertiesComponent.getInstance(project).getBoolean(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, false);
-  }
-
-  public static boolean getLastSavedRearrangeEntriesCbStateFor(@NotNull Project project, @NotNull Language language) {
-    String key = getRearrangeEntriesKeyForLanguage(language);
-    return PropertiesComponent.getInstance(project).getBoolean(key, false);
-  }
-
-  private static String getRearrangeEntriesKeyForLanguage(@NotNull Language language) {
-    return LayoutCodeConstants.REARRANGE_ENTRIES_KEY + language.getDisplayName();
-  }
-
-}
index 7f76f1b012a5879164d1e25a0632b1aef734a05a..7690e09339f8a05bdcf87cd5dc3d75ec172b56c7 100644 (file)
@@ -47,6 +47,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
   private final Project myProject;
   private final String  myText;
   private final boolean myEnableOnlyVCSChangedTextCb;
+  private final LastRunReformatCodeOptionsProvider myLastRunOptions;
 
   private JLabel myTitle;
   protected JCheckBox myIncludeSubdirsCb;
@@ -75,6 +76,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
     myText = text;
     myProject = project;
     myEnableOnlyVCSChangedTextCb = enableOnlyVCSChangedTextCb;
+    myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
 
     setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
     setTitle(title);
@@ -100,11 +102,11 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
   }
 
   private void restoreCbsStates() {
-    myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
-    myCbRearrangeEntries.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
+    myCbOptimizeImports.setSelected(myLastRunOptions.getLastOptimizeImports());
+    myCbRearrangeEntries.setSelected(myLastRunOptions.getLastRearrangeCode());
     myCbOnlyVcsChangedRegions.setEnabled(myEnableOnlyVCSChangedTextCb);
     myCbOnlyVcsChangedRegions.setSelected(
-      myEnableOnlyVCSChangedTextCb && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
+      myEnableOnlyVCSChangedTextCb && myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT
     );
   }
 
@@ -177,7 +179,7 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
   }
 
   @Override
-  public boolean isRearrangeEntries() {
+  public boolean isRearrangeCode() {
     return myCbRearrangeEntries.isSelected();
   }
 
@@ -189,10 +191,10 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
   @Override
   protected void doOKAction() {
     super.doOKAction();
-    PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports()));
-    LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
+    myLastRunOptions.saveOptimizeImportsState(isOptimizeImports());
+    myLastRunOptions.saveRearrangeCodeState(isRearrangeCode());
     if (myEnableOnlyVCSChangedTextCb) {
-      PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myCbOnlyVcsChangedRegions.isSelected()));
+      myLastRunOptions.saveProcessVcsChangedTextState(getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT);
     }
   }
 
@@ -200,10 +202,6 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
     return myCbOptimizeImports.isSelected();
   }
 
-  public boolean isProcessOnlyChangedText() {
-    return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
-  }
-
   @Nullable
   public String getFileTypeMask() {
     if (myEnableFileNameFilterCb.isSelected()) {
@@ -232,4 +230,10 @@ public class LayoutProjectCodeDialog extends DialogWrapper implements ReformatFi
     return false;
   }
 
+  @Override
+  public TextRangeType getTextRangeType() {
+    return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected()
+           ? TextRangeType.VCS_CHANGED_TEXT
+           : TextRangeType.WHOLE_FILE;
+  }
 }
index bc18a4241360e013879ff5dbd92af3f16f3180ab..8045e9f2b063796dca2123411174739bbdb755cf 100644 (file)
 package com.intellij.codeInsight.actions;
 
 import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.lang.LanguageImportStatements;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.DialogWrapper;
@@ -72,13 +72,16 @@ public class OptimizeImportsAction extends AnAction {
 
       if (projectContext != null || moduleContext != null) {
         final String text;
+        final boolean hasChanges;
         if (moduleContext != null) {
           text = CodeInsightBundle.message("process.scope.module", moduleContext.getName());
+          hasChanges = FormatChangedTextUtil.hasChanges(moduleContext);
         }
         else {
           text = CodeInsightBundle.message("process.scope.project", projectContext.getPresentableUrl());
+          hasChanges = FormatChangedTextUtil.hasChanges(projectContext);
         }
-        DialogWrapper dialog = new OptimizeOnModuleDialog(project, text);
+        DialogWrapper dialog = new OptimizeImportsDialog(project, text, hasChanges);
         if (!dialog.showAndGet()) {
           return;
         }
@@ -106,29 +109,21 @@ public class OptimizeImportsAction extends AnAction {
       }
     }
 
-    boolean processDirectory;
-    boolean includeSubdirectories;
-
-    if (ApplicationManager.getApplication().isUnitTestMode()) {
-      includeSubdirectories = processDirectory = false;
-    }
-    else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG && file != null) {
-      includeSubdirectories = processDirectory = false;
-    }
-    else {
-      final LayoutCodeDialog dialog =
-        new LayoutCodeDialog(project, CodeInsightBundle.message("process.optimize.imports"), file, dir, null, HELP_ID);
-      if (!dialog.showAndGet()) {
+    boolean processDirectory = false;
+    boolean processOnlyVcsChangedFiles = false;
+    if (!ApplicationManager.getApplication().isUnitTestMode() && file == null && dir != null) {
+      String message = CodeInsightBundle.message("process.scope.directory", dir.getName());
+      OptimizeImportsDialog dialog = new OptimizeImportsDialog(project, message, FormatChangedTextUtil.hasChanges(dir));
+      dialog.show();
+      if (!dialog.isOK()) {
         return;
       }
-      EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG = !dialog.isDoNotAskMe();
-      ReformatCodeAction.updateShowDialogSetting(dialog, "\"Optimize Imports\" dialog disabled");
-      processDirectory = dialog.isProcessDirectory();
-      includeSubdirectories = dialog.isIncludeSubdirectories();
+      processDirectory = true;
+      processOnlyVcsChangedFiles = dialog.isProcessOnlyVcsChangedFiles();
     }
 
     if (processDirectory){
-      new OptimizeImportsProcessor(project, dir, includeSubdirectories).run();
+      new OptimizeImportsProcessor(project, dir, true, processOnlyVcsChangedFiles).run();
     }
     else{
       new OptimizeImportsProcessor(project, file).run();
@@ -204,21 +199,44 @@ public class OptimizeImportsAction extends AnAction {
     return !LanguageImportStatements.INSTANCE.forFile(file).isEmpty();
   }
 
-  private static class OptimizeOnModuleDialog extends DialogWrapper {
+  private static class OptimizeImportsDialog extends DialogWrapper {
+    private final boolean myContextHasChanges;
+
     private final String myText;
+    private JCheckBox myOnlyVcsCheckBox;
+    private final LastRunReformatCodeOptionsProvider myLastRunOptions;
 
-    OptimizeOnModuleDialog(Project project, String text) {
+    OptimizeImportsDialog(Project project, String text, boolean hasChanges) {
       super(project, false);
       myText = text;
+      myContextHasChanges = hasChanges;
+      myLastRunOptions = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
       setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
       setTitle(CodeInsightBundle.message("process.optimize.imports"));
       init();
     }
 
+    public boolean isProcessOnlyVcsChangedFiles() {
+      return myOnlyVcsCheckBox.isSelected();
+    }
+
     @Nullable
     @Override
     protected JComponent createCenterPanel() {
-      return new JLabel(myText);
+      JPanel panel = new JPanel();
+      BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
+      panel.setLayout(layout);
+
+      panel.add(new JLabel(myText));
+      myOnlyVcsCheckBox = new JCheckBox("only VCS changed files");
+
+      boolean lastRunVcsChangedTextEnabled = myLastRunOptions.getLastTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
+
+      myOnlyVcsCheckBox.setEnabled(myContextHasChanges);
+      myOnlyVcsCheckBox.setSelected(myContextHasChanges && lastRunVcsChangedTextEnabled);
+
+      panel.add(myOnlyVcsCheckBox);
+      return panel;
     }
   }
 }
index 6cdb063c04349d738b5306790dc2af7c2c884f96..b693fb782ad71b6254b49b80ab6ee48531d1b1ec 100644 (file)
@@ -48,6 +48,10 @@ public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
     super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, false);
   }
 
+  public OptimizeImportsProcessor(Project project, PsiDirectory directory, boolean includeSubdirs, boolean processOnlyVcsChangedFiles) {
+    super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, processOnlyVcsChangedFiles);
+  }
+
   public OptimizeImportsProcessor(Project project, PsiFile file) {
     super(project, file, PROGRESS_TEXT, COMMAND_NAME, false);
   }
similarity index 54%
rename from platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeConstants.java
rename to platform/lang-impl/src/com/intellij/codeInsight/actions/OptionalReformatActions.java
index 84de47d7f4579a2b35f3443a97f90ca826b4313c..e71f5c116ad50ab4ae1c6e9e263a749008b30442 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 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.
  */
 package com.intellij.codeInsight.actions;
 
-import org.jetbrains.annotations.NonNls;
+public interface OptionalReformatActions {
 
-/**
- * @author Denis Zhdanov
- * @since 12/16/11 6:10 PM
- */
-public class LayoutCodeConstants {
+  boolean isOptimizeImports();
 
-  @NonNls public static final String OPTIMIZE_IMPORTS_KEY     = "LayoutCode.optimizeImports";
-  @NonNls public static final String REARRANGE_ENTRIES_KEY    = "LayoutCode.rearrangeEntries";
-  @NonNls public static final String PROCESS_CHANGED_TEXT_KEY = "LayoutCode.processChangedText";
+  boolean isRearrangeCode();
 
-  private LayoutCodeConstants() {
-  }
 }
index 4867d85abbd7e94f5afa105e24a5446890e9277a..f8ae0ac7869eced95d406cdda8f5dce9a97be29f 100644 (file)
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.actions;
 
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.SelectionModel;
 import com.intellij.openapi.project.Project;
@@ -25,12 +26,12 @@ import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiFile;
 import com.intellij.psi.codeStyle.arrangement.Rearranger;
 import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine;
-import com.intellij.util.SmartList;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.diff.FilesTooBigForDiffException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collection;
-import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.FutureTask;
 
@@ -39,12 +40,23 @@ public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
   public static final String COMMAND_NAME = "Rearrange code";
   public static final String PROGRESS_TEXT = "Rearranging code...";
 
-  @Nullable private SelectionModel mySelectionModel;
+  private static final Logger LOG = Logger.getInstance(RearrangeCodeProcessor.class);
+  private SelectionModel mySelectionModel;
 
   public RearrangeCodeProcessor(@NotNull AbstractLayoutCodeProcessor previousProcessor) {
     super(previousProcessor, COMMAND_NAME, PROGRESS_TEXT);
   }
 
+  public RearrangeCodeProcessor(@NotNull AbstractLayoutCodeProcessor previousProcessor, @NotNull SelectionModel model) {
+    super(previousProcessor, COMMAND_NAME, PROGRESS_TEXT);
+    mySelectionModel = model;
+  }
+
+  public RearrangeCodeProcessor(@NotNull PsiFile file,
+                                @NotNull SelectionModel selectionModel)
+  {
+    super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, false);
+
   public RearrangeCodeProcessor(@NotNull AbstractLayoutCodeProcessor previousProcessor, @NotNull SelectionModel selectionModel) {
     super(previousProcessor, COMMAND_NAME, PROGRESS_TEXT);
     mySelectionModel = selectionModel;
@@ -57,6 +69,10 @@ public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
     mySelectionModel = selectionModel;
   }
 
+  public RearrangeCodeProcessor(@NotNull PsiFile file) {
+    super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, false);
+  }
+
   public RearrangeCodeProcessor(@NotNull Project project,
                                 @NotNull PsiFile[] files,
                                 @NotNull String commandName,
@@ -70,27 +86,32 @@ public class RearrangeCodeProcessor extends AbstractLayoutCodeProcessor {
     return new FutureTask<Boolean>(new Callable<Boolean>() {
       @Override
       public Boolean call() throws Exception {
-        Collection<TextRange> ranges = processChangedTextOnly ? FormatChangedTextUtil.getChangedTextRanges(myProject, file)
-                                                              : getRangesToFormat(file);
-
-        RearrangeCommand rearranger = new RearrangeCommand(myProject, file, COMMAND_NAME, ranges);
-        if (rearranger.couldRearrange()) {
-          rearranger.run();
+        try {
+          Collection<TextRange> ranges = getRangesToFormat(file, processChangedTextOnly);
+          RearrangeCommand rearranger = new RearrangeCommand(myProject, file, COMMAND_NAME, ranges);
+          if (rearranger.couldRearrange()) {
+            rearranger.run();
+          }
+          return true;
+        }
+        catch (FilesTooBigForDiffException e) {
+          handleFileTooBigException(LOG, e, file);
+          return false;
         }
-        return true;
       }
     });
   }
 
-  public Collection<TextRange> getRangesToFormat(@NotNull PsiFile file) {
-    final List<TextRange> ranges = new SmartList<TextRange>();
-    if (mySelectionModel != null && mySelectionModel.hasSelection()) {
-      ranges.add(TextRange.create(mySelectionModel.getSelectionStart(), mySelectionModel.getSelectionEnd()));
+  public Collection<TextRange> getRangesToFormat(@NotNull PsiFile file, boolean processChangedTextOnly) throws FilesTooBigForDiffException {
+    if (mySelectionModel != null) {
+      return getSelectedRanges(mySelectionModel);
     }
-    else {
-      ranges.add(TextRange.create(0, file.getTextLength()));
+
+    if (processChangedTextOnly) {
+      return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
     }
-    return ranges;
+
+    return ContainerUtil.newSmartList(file.getTextRange());
   }
 }
 
index 78c6b9a6cff67c4d78088bb8e1672c602689036d..f983511275aed2828d663bed7340ea119cd2de80 100644 (file)
 
 package com.intellij.codeInsight.actions;
 
-import com.intellij.application.options.editor.EditorOptions;
 import com.intellij.codeInsight.CodeInsightBundle;
 import com.intellij.find.impl.FindInProjectUtil;
 import com.intellij.formatting.FormattingModelBuilder;
 import com.intellij.ide.util.PropertiesComponent;
 import com.intellij.lang.LanguageFormatting;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationListener;
-import com.intellij.notification.NotificationType;
-import com.intellij.notification.Notifications;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
 import com.intellij.openapi.module.Module;
-import com.intellij.openapi.options.ShowSettingsUtil;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.openapi.project.DumbService;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
 import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.IdeFrame;
-import com.intellij.openapi.wm.ex.WindowManagerEx;
 import com.intellij.psi.*;
 import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.search.LocalSearchScope;
@@ -53,8 +43,6 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
 
-import javax.swing.*;
-import javax.swing.event.HyperlinkEvent;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -95,14 +83,14 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
         if (selectedFlags == null)
           return;
 
-        final boolean processOnlyChangedText = selectedFlags.isProcessOnlyChangedText();
+        final boolean processOnlyChangedText = selectedFlags.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
         final boolean shouldOptimizeImports = selectedFlags.isOptimizeImports() && !DumbService.getInstance(project).isDumb();
 
         AbstractLayoutCodeProcessor processor = new ReformatCodeProcessor(project, convertToPsiFiles(files, project), null, processOnlyChangedText);
         if (shouldOptimizeImports) {
           processor = new OptimizeImportsProcessor(processor);
         }
-        if (selectedFlags.isRearrangeEntries()) {
+        if (selectedFlags.isRearrangeCode()) {
           processor = new RearrangeCodeProcessor(processor);
         }
 
@@ -137,15 +125,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
       }
     }
 
-    boolean optimizeImports = ReformatFilesDialog.isOptmizeImportsOptionOn();
-    boolean processWholeFile = false;
-    boolean processChangedTextOnly = PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false);
-    boolean rearrangeEntries = getLastSavedRearrangeCbState(project, file);
-
-    final boolean showDialog = EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG;
-
-    if (file == null && dir == null) return;
-    if (file == null) {
+    if (file == null && dir != null) {
       DirectoryFormattingOptions options = getDirectoryFormattingOptions(project, dir);
       if (options != null) {
         reformatDirectory(project, dir, options);
@@ -153,57 +133,29 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
       return;
     }
 
-    if (showDialog) {
-      LayoutCodeOptions selectedFlags = getLayoutCodeOptions(project, file, dir, hasSelection);
-      if (selectedFlags == null)
-        return;
+    if (file == null || editor == null) return;
 
-      optimizeImports = selectedFlags.isOptimizeImports();
-      rearrangeEntries = selectedFlags.isRearrangeEntries();
-      processWholeFile = selectedFlags.isProcessWholeFile();
-      processChangedTextOnly = selectedFlags.isProcessOnlyChangedText();
-
-      if (selectedFlags.isProcessDirectory()) {
-        assert dir != null : "File = " + file + ", Element = " + CommonDataKeys.PSI_ELEMENT.getData(dataContext);
-        reformatDirectory(project, dir, selectedFlags);
-        return;
-      }
-    }
-
-    if (!showDialog && processChangedTextOnly && isChangeNotTrackedForFile(project, file)) {
-      processChangedTextOnly = false;
-    }
+    LastRunReformatCodeOptionsProvider provider = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
+    ReformatCodeRunOptions currentRunOptions = provider.getLastRunOptions(file);
 
-    final TextRange range;
-    final boolean processSelectedText = !processWholeFile && hasSelection;
-    if (processSelectedText) {
-      range = TextRange.create(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
+    TextRangeType processingScope = currentRunOptions.getTextRangeType();
+    if (hasSelection) {
+      processingScope = TextRangeType.SELECTED_TEXT;
     }
-    else{
-      range = null;
-    }
-
-    AbstractLayoutCodeProcessor processor;
-    if (optimizeImports && range == null) {
-      processor = new OptimizeImportsProcessor(project, file);
-      processor = new ReformatCodeProcessor(processor, processChangedTextOnly);
+    else if (processingScope == TextRangeType.VCS_CHANGED_TEXT) {
+      if (isChangeNotTrackedForFile(project, file)) {
+        processingScope = TextRangeType.WHOLE_FILE;
+      }
     }
     else {
-      processor = new ReformatCodeProcessor(project, file, range, !processSelectedText && processChangedTextOnly);
-    }
-
-    if (rearrangeEntries) {
-      if (processSelectedText && editor != null) {
-        processor = new RearrangeCodeProcessor(processor, editor.getSelectionModel());
-      }
-      else {
-        processor = new RearrangeCodeProcessor(processor);
-      }
+      processingScope = TextRangeType.WHOLE_FILE;
     }
 
-    processor.run();
+    currentRunOptions.setProcessingScope(processingScope);
+    new CodeProcessor(file, editor, currentRunOptions).processCode();
   }
 
+
   private static boolean isChangeNotTrackedForFile(@NotNull Project project, @NotNull PsiFile file) {
     boolean isUnderVcs = VcsUtil.isFileUnderVcs(project, VcsUtil.getFilePath(file.getVirtualFile()));
     if (!isUnderVcs) return true;
@@ -241,10 +193,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
                                         @NotNull DirectoryFormattingOptions options)
   {
     AbstractLayoutCodeProcessor processor = new ReformatCodeProcessor(
-      project,
-      dir,
-      options.isIncludeSubdirectories(),
-      options.isProcessOnlyChangedText()
+      project, dir, options.isIncludeSubdirectories(), options.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT
     );
 
     registerScopeFilter(processor, options.getSearchScope());
@@ -253,7 +202,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
     if (options.isOptimizeImports()) {
       processor = new OptimizeImportsProcessor(processor);
     }
-    if (options.isRearrangeEntries()) {
+    if (options.isRearrangeCode()) {
       processor = new RearrangeCodeProcessor(processor);
     }
 
@@ -265,7 +214,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
                                      @NotNull ReformatFilesOptions selectedFlags)
   {
     boolean shouldOptimizeImports = selectedFlags.isOptimizeImports() && !DumbService.getInstance(project).isDumb();
-    boolean processOnlyChangedText = selectedFlags.isProcessOnlyChangedText();
+    boolean processOnlyChangedText = selectedFlags.getTextRangeType() == TextRangeType.VCS_CHANGED_TEXT;
 
     AbstractLayoutCodeProcessor processor;
     if (moduleContext != null)
@@ -280,7 +229,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
       processor = new OptimizeImportsProcessor(processor);
     }
 
-    if (selectedFlags.isRearrangeEntries()) {
+    if (selectedFlags.isRearrangeCode()) {
       processor = new RearrangeCodeProcessor(processor);
     }
 
@@ -332,23 +281,6 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
     }
   }
 
-  public static void updateShowDialogSetting(LayoutCodeDialog dialog, String title) {
-    if (dialog.isDoNotAskMe()) {
-      Notifications.Bus.notify(new Notification("Reformat Code", title,
-                                                "<html>You can re-enable the dialog on the <a href=''>IDE Settings -> Editor</a> pane</html>",
-                                                NotificationType.INFORMATION, new NotificationListener() {
-          @Override
-          public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
-            if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
-              final ShowSettingsUtil util = ShowSettingsUtil.getInstance();
-              IdeFrame ideFrame = WindowManagerEx.getInstanceEx().findFrameFor(null);
-              util.editConfigurable((JFrame)ideFrame, new EditorOptions());
-            }
-          }
-        }));
-    }
-  }
-
   public static PsiFile[] convertToPsiFiles(final VirtualFile[] files,Project project) {
     final PsiManager manager = PsiManager.getInstance(project);
     final ArrayList<PsiFile> result = new ArrayList<PsiFile>();
@@ -460,31 +392,6 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
     return dialog;
   }
 
-  @Nullable
-  private static LayoutCodeOptions getLayoutCodeOptions(@NotNull Project project,
-                                                 @Nullable PsiFile file,
-                                                 @Nullable PsiDirectory dir,
-                                                 boolean hasSelection) {
-    if (ApplicationManager.getApplication().isUnitTestMode()) {
-      return (LayoutCodeOptions)myTestOptions;
-    }
-    LayoutCodeDialog dialog = new LayoutCodeDialog(project, CodeInsightBundle.message("process.reformat.code"),
-                                                   file, dir, hasSelection ? Boolean.TRUE : Boolean.FALSE, HELP_ID);
-    if (!dialog.showAndGet()) {
-      return null;
-    }
-    EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG = !dialog.isDoNotAskMe();
-    updateShowDialogSetting(dialog, "\"Reformat Code\" dialog disabled");
-    return dialog;
-  }
-
-  public static boolean getLastSavedRearrangeCbState(@NotNull Project project, @Nullable PsiFile file) {
-    if (file != null) {
-      return LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(project, file.getLanguage());
-    }
-    return LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(project);
-  }
-
   @TestOnly
   protected static void setTestOptions(ReformatFilesOptions options) {
     myTestOptions = options;
index 4ebe9274c1ca00202fce12e59f1ca2837e621b23..c86255295a2af4b9c2a091e12aaab68a22292005 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.notification.NotificationType;
 import com.intellij.openapi.application.ApplicationBundle;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.SelectionModel;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.TextRange;
@@ -46,13 +47,24 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
   
   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.ReformatCodeProcessor");
 
-  private final Collection<TextRange> myRanges = new ArrayList<TextRange>();
   private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text");
+  private final Collection<TextRange> myRanges = new ArrayList<TextRange>();
+  private SelectionModel mySelectionModel;
 
   public ReformatCodeProcessor(Project project, boolean processChangedTextOnly) {
     super(project, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
   }
 
+  public ReformatCodeProcessor(@NotNull PsiFile file, @NotNull SelectionModel selectionModel) {
+    super(file.getProject(), COMMAND_NAME, PROGRESS_TEXT, false);
+    mySelectionModel = selectionModel;
+  }
+
+  public ReformatCodeProcessor(AbstractLayoutCodeProcessor processor, @NotNull SelectionModel selectionModel) {
+    super(processor, COMMAND_NAME, PROGRESS_TEXT);
+    mySelectionModel = selectionModel;
+  }
+
   public ReformatCodeProcessor(AbstractLayoutCodeProcessor processor, boolean processChangedTextOnly) {
     super(processor, COMMAND_NAME, PROGRESS_TEXT);
     setProcessChangedTextOnly(processChangedTextOnly);
@@ -73,6 +85,10 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
     }
   }
 
+  public ReformatCodeProcessor(@NotNull PsiFile file, boolean processChangedTextOnly) {
+    super(file.getProject(), file, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
+  }
+
   public ReformatCodeProcessor(Project project, PsiFile[] files, @Nullable Runnable postRunnable, boolean processChangedTextOnly) {
     this(project, files, COMMAND_NAME, postRunnable, processChangedTextOnly);
   }
@@ -101,14 +117,7 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
           return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
         }
         catch (FilesTooBigForDiffException e) {
-          LOG.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
-          if (!ApplicationManager.getApplication().isUnitTestMode()) {
-            Notification notification = new Notification(ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
-                                                         ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
-                                                         ApplicationBundle.message("reformat.changed.text.file.too.big.notification.text", file.getName()),
-                                                         NotificationType.INFORMATION);
-            notification.notify(file.getProject());
-          }
+          handleFileTooBigException(LOG, e, file);
           return false;
         } 
         catch (IncorrectOperationException e) {
@@ -124,6 +133,10 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
 
   @NotNull
   private Collection<TextRange> getRangesToFormat(boolean processChangedTextOnly, PsiFile file) throws FilesTooBigForDiffException {
+    if (mySelectionModel != null) {
+      return getSelectedRanges(mySelectionModel);
+    }
+
     if (processChangedTextOnly) {
       return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
     }
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeRunOptions.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeRunOptions.java
new file mode 100644 (file)
index 0000000..67d20e2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2014 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.codeInsight.actions;
+
+public class ReformatCodeRunOptions implements LayoutCodeOptions {
+
+  private boolean myRearrangeCode;
+  private boolean myOptimizeImports;
+  private TextRangeType myProcessingScope;
+
+  public ReformatCodeRunOptions(TextRangeType processingScope) {
+    myProcessingScope = processingScope;
+  }
+
+  public void setProcessingScope(TextRangeType processingScope) {
+    myProcessingScope = processingScope;
+  }
+
+  @Override
+  public boolean isOptimizeImports() {
+    return myOptimizeImports;
+  }
+
+  @Override
+  public boolean isRearrangeCode() {
+    return myRearrangeCode;
+  }
+
+  public ReformatCodeRunOptions setRearrangeCode(boolean rearrangeCode) {
+    myRearrangeCode = rearrangeCode;
+    return this;
+  }
+
+  public ReformatCodeRunOptions setOptimizeImports(boolean optimizeImports) {
+    myOptimizeImports = optimizeImports;
+    return this;
+  }
+
+  @Override
+  public TextRangeType getTextRangeType() {
+    return myProcessingScope;
+  }
+
+}
+
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFileAction.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatFileAction.java
new file mode 100644 (file)
index 0000000..aace328
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2014 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.codeInsight.actions;
+
+import com.intellij.lang.LanguageFormatting;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NonNls;
+
+public class ReformatFileAction extends AnAction implements DumbAware {
+  private static final @NonNls String HELP_ID = "editing.codeReformatting";
+
+  @Override
+  public void update(AnActionEvent event) {
+    Presentation presentation = event.getPresentation();
+    DataContext dataContext = event.getDataContext();
+    Project project = CommonDataKeys.PROJECT.getData(dataContext);
+    Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+    if (project == null || editor == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+    if (file == null || file.getVirtualFile() == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    if (LanguageFormatting.INSTANCE.forContext(file) != null) {
+      presentation.setEnabled(true);
+    }
+  }
+
+  @Override
+  public void actionPerformed(AnActionEvent event) {
+    Presentation presentation = event.getPresentation();
+    DataContext dataContext = event.getDataContext();
+    Project project = CommonDataKeys.PROJECT.getData(dataContext);
+    Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+    if (project == null || editor == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+    if (file == null || file.getVirtualFile() == null) {
+      presentation.setEnabled(false);
+      return;
+    }
+
+    boolean hasSelection = editor.getSelectionModel().hasSelection();
+    LayoutCodeDialog dialog = new LayoutCodeDialog(project, file, hasSelection, HELP_ID);
+    dialog.show();
+
+    if (dialog.isOK()) {
+      new CodeProcessor(file, editor, dialog.getRunOptions()).processCode();
+    }
+  }
+}
index d364857352e6110b8ea67dcfdb0c7d7e89b9a2b9..a7651cd34cb595f62889d727d9baee9ef9fe6d45 100644 (file)
@@ -27,25 +27,27 @@ import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
 
+import static com.intellij.codeInsight.actions.TextRangeType.*;
+
 public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesOptions {
-  @NotNull private Project myProject;
   private JPanel myPanel;
   private JCheckBox myOptimizeImports;
   private JCheckBox myOnlyChangedText;
   private JCheckBox myRearrangeEntriesCb;
 
+  private final LastRunReformatCodeOptionsProvider myLastRunSettings;
+
   public ReformatFilesDialog(@NotNull Project project, @NotNull VirtualFile[] files) {
     super(project, true);
-    myProject = project;
-    setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
-    myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
+    myLastRunSettings = new LastRunReformatCodeOptionsProvider(PropertiesComponent.getInstance());
+
     boolean canTargetVcsChanges = FormatChangedTextUtil.hasChanges(files, project);
     myOnlyChangedText.setEnabled(canTargetVcsChanges);
-    myOnlyChangedText.setSelected(
-      canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
-    ); 
-    myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
-    myRearrangeEntriesCb.setSelected(LayoutCodeSettingsStorage.getLastSavedRearrangeEntriesCbStateFor(myProject));
+    myOnlyChangedText.setSelected(canTargetVcsChanges && myLastRunSettings.getLastTextRangeType() == VCS_CHANGED_TEXT);
+    myOptimizeImports.setSelected(myLastRunSettings.getLastOptimizeImports());
+    myRearrangeEntriesCb.setSelected(myLastRunSettings.getLastRearrangeCode());
+
+    setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
     init();
   }
 
@@ -60,25 +62,25 @@ public class ReformatFilesDialog extends DialogWrapper implements ReformatFilesO
   }
 
   @Override
-  public boolean isProcessOnlyChangedText() {
-    return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected();
+  public TextRangeType getTextRangeType() {
+    return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected()
+           ? VCS_CHANGED_TEXT
+           : WHOLE_FILE;
   }
 
   @Override
-  public boolean isRearrangeEntries() {
+  public boolean isRearrangeCode() {
     return myRearrangeEntriesCb.isSelected();
   }
 
   @Override
   protected void doOKAction() {
     super.doOKAction();
-    PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myOptimizeImports.isSelected()));
-    PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myOnlyChangedText.isSelected()));
-    LayoutCodeSettingsStorage.saveRearrangeEntriesOptionFor(myProject, isRearrangeEntries());
-  }
-
-  static boolean isOptmizeImportsOptionOn() {
-    return PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false);
+    myLastRunSettings.saveOptimizeImportsState(isOptimizeImports());
+    myLastRunSettings.saveRearrangeCodeState(isRearrangeCode());
+    if (myOnlyChangedText.isEnabled()) {
+      myLastRunSettings.saveProcessVcsChangedTextState(getTextRangeType() == VCS_CHANGED_TEXT);
+    }
   }
 
   @Nullable
index bb958e77b2fe729834b30395233ee718fbf3e388..f1075794032495cb8ad2e9c07458da1865a8ad2c 100644 (file)
@@ -18,13 +18,7 @@ package com.intellij.codeInsight.actions;
 import com.intellij.psi.search.SearchScope;
 import org.jetbrains.annotations.Nullable;
 
-public interface ReformatFilesOptions {
-
-  boolean isOptimizeImports();
-
-  boolean isProcessOnlyChangedText();
-
-  boolean isRearrangeEntries();
+public interface ReformatFilesOptions extends LayoutCodeOptions {
 
   @Nullable
   String getFileTypeMask();
index 8cd7594ebaaa6923687088437ee6c611d692e4fc..107cfd8b76a69be588841e24c60e974b60e9f577 100644 (file)
@@ -87,6 +87,9 @@
   <action id="ReformatCode">
     <keyboard-shortcut first-keystroke="control alt L"/>
   </action>
+  <action id="ReformatFile">
+    <keyboard-shortcut first-keystroke="control shift alt L"/>
+  </action>
   <action id="Generate">
     <keyboard-shortcut first-keystroke="alt INSERT"/>
   </action>
index a513c018a241e4e3f3f9bbe9d5b5bf0ffe20bfee..2b641e189aa1f6d614b9ecad96532f8a170720d7 100644 (file)
       <reference ref="Arrangement.Rule.Group.Condition.Move.Down"/>
     </group>
 
+    <action id="ReformatFile" class="com.intellij.codeInsight.actions.ReformatFileAction"/>
+
   </actions>
 </component>