IDEA-51747 Ability to reformat changed lines only

Added ability to define that only changed text should be reformatted
This commit is contained in:
Denis.Zhdanov
2011-12-19 15:42:13 +04:00
parent d5d02c0ca8
commit 8fc7a2c091
17 changed files with 607 additions and 178 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -30,6 +30,8 @@ import com.intellij.util.ThrowableRunnable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
/**
* Service for reformatting code fragments, getting names for elements
* according to the user's code style and working with import statements and full-qualified names.
@@ -123,9 +125,7 @@ public abstract class CodeStyleManager {
boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException;
/**
* Reformats a range of text in the specified file. This method works faster than
* {@link #reformatRange(com.intellij.psi.PsiElement, int, int)} but invalidates the
* PSI structure for the file.
* Delegates to the {@link #reformatText(PsiFile, Collection)} with the single range defined by the given offsets.
*
* @param element the file to reformat.
* @param startOffset the start of the text range to reformat.
@@ -135,7 +135,18 @@ public abstract class CodeStyleManager {
public abstract void reformatText(@NotNull PsiFile element, int startOffset, int endOffset) throws IncorrectOperationException;
/**
* Reformats the specified range of a file, modifying only line indents and leaving
* Re-formats a ranges of text in the specified file. This method works faster than
* {@link #reformatRange(com.intellij.psi.PsiElement, int, int)} but invalidates the
* PSI structure for the file.
*
* @param element the file to reformat
* @param ranges ranges to process
* @throws IncorrectOperationException if the file to reformat is read-only.
*/
public abstract void reformatText(@NotNull PsiFile element, @NotNull Collection<TextRange> ranges) throws IncorrectOperationException;
/**
* Re-formats the specified range of a file, modifying only line indents and leaving
* all other whitespace intact.
*
* @param file the file to reformat.
@@ -66,18 +66,18 @@ public abstract class AbstractLayoutCodeProcessor {
private final String myProgressText;
private final String myCommandName;
private final Runnable myPostRunnable;
private final boolean myProcessChangedTextOnly;
protected AbstractLayoutCodeProcessor(Project project, String commandName, String progressText) {
myProject = project;
myModule = null;
myDirectory = null;
myIncludeSubdirs = true;
myCommandName = commandName;
myProgressText = progressText;
myPostRunnable = null;
protected AbstractLayoutCodeProcessor(Project project, String commandName, String progressText, boolean processChangedTextOnly) {
this(project, (Module)null, commandName, progressText, processChangedTextOnly);
}
protected AbstractLayoutCodeProcessor(Project project, Module module, String commandName, String progressText) {
protected AbstractLayoutCodeProcessor(Project project,
@Nullable Module module,
String commandName,
String progressText,
boolean processChangedTextOnly)
{
myProject = project;
myModule = module;
myDirectory = null;
@@ -85,9 +85,16 @@ public abstract class AbstractLayoutCodeProcessor {
myCommandName = commandName;
myProgressText = progressText;
myPostRunnable = null;
myProcessChangedTextOnly = processChangedTextOnly;
}
protected AbstractLayoutCodeProcessor(Project project, PsiDirectory directory, boolean includeSubdirs, String progressText, String commandName) {
protected AbstractLayoutCodeProcessor(Project project,
PsiDirectory directory,
boolean includeSubdirs,
String progressText,
String commandName,
boolean processChangedTextOnly)
{
myProject = project;
myModule = null;
myDirectory = directory;
@@ -95,24 +102,38 @@ public abstract class AbstractLayoutCodeProcessor {
myProgressText = progressText;
myCommandName = commandName;
myPostRunnable = null;
myProcessChangedTextOnly = processChangedTextOnly;
}
protected AbstractLayoutCodeProcessor(Project project, PsiFile file, String progressText, String commandName) {
protected AbstractLayoutCodeProcessor(Project project,
PsiFile file,
String progressText,
String commandName,
boolean processChangedTextOnly)
{
myProject = project;
myModule = null;
myFile = file;
myProgressText = progressText;
myCommandName = commandName;
myPostRunnable = null;
myProcessChangedTextOnly = processChangedTextOnly;
}
protected AbstractLayoutCodeProcessor(Project project, PsiFile[] files, String progressText, String commandName, Runnable postRunnable) {
protected AbstractLayoutCodeProcessor(Project project,
PsiFile[] files,
String progressText,
String commandName,
@Nullable Runnable postRunnable,
boolean processChangedTextOnly)
{
myProject = project;
myModule = null;
myFiles = filterFiles(files);
myProgressText = progressText;
myCommandName = commandName;
myPostRunnable = postRunnable;
myProcessChangedTextOnly = processChangedTextOnly;
}
private static PsiFile[] filterFiles(PsiFile[] files){
@@ -128,13 +149,15 @@ public abstract class AbstractLayoutCodeProcessor {
/**
* Ensures that given file is ready to reformatting and prepares it if necessary.
*
* @param file file to process
* @param file file to process
* @param processChangedTextOnly flag that defines is only the changed text (in terms of VCS change) should be processed
* @return task that triggers formatting of the given file. Returns value of that task indicates whether formatting
* is finished correctly or not (exception occurred, user cancelled formatting etc)
* @throws IncorrectOperationException if unexpected exception occurred during formatting
*/
@NotNull
protected abstract FutureTask<Boolean> preprocessFile(PsiFile file) throws IncorrectOperationException;
protected abstract FutureTask<Boolean> preprocessFile(@NotNull PsiFile file, boolean processChangedTextOnly)
throws IncorrectOperationException;
public void run() {
if (myDirectory != null){
@@ -154,7 +177,7 @@ public abstract class AbstractLayoutCodeProcessor {
}
}
private void runProcessFile(final PsiFile file) {
private void runProcessFile(@NotNull final PsiFile file) {
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
if (document == null) {
@@ -174,7 +197,7 @@ public abstract class AbstractLayoutCodeProcessor {
public void run() {
if (!checkFileWritable(file)) return;
try{
resultRunnable[0] = preprocessFile(file);
resultRunnable[0] = preprocessFile(file, myProcessChangedTextOnly);
}
catch(IncorrectOperationException e){
LOG.error(e);
@@ -223,7 +246,7 @@ public abstract class AbstractLayoutCodeProcessor {
}
if (file.isWritable()){
try{
tasks.add(preprocessFile(file));
tasks.add(preprocessFile(file, myProcessChangedTextOnly));
}
catch(IncorrectOperationException e){
LOG.error(e);
@@ -487,7 +510,7 @@ public abstract class AbstractLayoutCodeProcessor {
}
public void runWithoutProgress() throws IncorrectOperationException {
final Runnable runnable = preprocessFile(myFile);
final Runnable runnable = preprocessFile(myFile, myProcessChangedTextOnly);
runnable.run();
}
@@ -0,0 +1,211 @@
/*
* Copyright 2000-2011 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.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.ex.LineStatusTracker;
import com.intellij.openapi.vcs.ex.Range;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManager;
import com.intellij.openapi.vcs.impl.LineStatusTrackerManagerI;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* Contains utility methods for 'format only changed text' (in terms of VCS changes).
*
* @author Denis Zhdanov
* @since 12/19/11 10:55 AM
*/
public class FormatChangedTextUtil {
private FormatChangedTextUtil() {
}
/**
* Allows to answer if given file has changes in comparison with VCS.
*
* @param file target file
* @return <code>true</code> if given file has changes; <code>false</code> otherwise
*/
public static boolean hasChanges(@NotNull PsiFile file) {
final Project project = file.getProject();
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;
}
}
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();
if (ranges == null || ranges.isEmpty()) {
return false;
}
for (Range range : ranges) {
if (range.getType() != Range.DELETED) {
return true;
}
}
return false;
}
/**
* Allows to answer if any file below the given directory (any level of nesting) has changes in comparison with VCS.
*
* @param directory target directory to check
* @return <code>true</code> if any file below the given directory has changes in comparison with VCS;
* <code>false</code> otherwise
*/
public static boolean hasChanges(@NotNull PsiDirectory directory) {
return hasChanges(directory.getVirtualFile(), directory.getProject());
}
/**
* Allows to answer if given file or any file below the given directory (any level of nesting) has changes in comparison with VCS.
*
* @param file target directory to check
* @param project target project
* @return <code>true</code> if given file or any file below the given directory has changes in comparison with VCS;
* <code>false</code> otherwise
*/
public static boolean hasChanges(@NotNull VirtualFile file, @NotNull Project project) {
final Collection<Change> changes = ChangeListManager.getInstance(project).getChangesIn(file);
for (Change change : changes) {
if (change.getType() == Change.Type.NEW || change.getType() == Change.Type.MODIFICATION) {
return true;
}
}
return false;
}
/**
* Allows to answer if any file that belongs to the given module has changes in comparison with VCS.
*
* @param module target module to check
* @return <code>true</code> if any file that belongs to the given module has changes in comparison with VCS
* <code>false</code> otherwise
*/
public static boolean hasChanges(@NotNull Module module) {
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
for (VirtualFile root : rootManager.getSourceRoots()) {
if (hasChanges(root, module.getProject())) {
return true;
}
}
return false;
}
/**
* Allows to answer if any file that belongs to the given project has changes in comparison with VCS.
*
* @param project target project to check
* @return <code>true</code> if any file that belongs to the given project has changes in comparison with VCS
* <code>false</code> otherwise
*/
public static boolean hasChanges(@NotNull final Project project) {
final ModifiableModuleModel moduleModel = new ReadAction<ModifiableModuleModel>() {
protected void run(Result<ModifiableModuleModel> result) throws Throwable {
result.setResult(ModuleManager.getInstance(project).getModifiableModel());
}
}.execute().getResultObject();
try {
for (Module module : moduleModel.getModules()) {
if (hasChanges(module)) {
return true;
}
}
return false;
}
finally {
moduleModel.dispose();
}
}
/**
* Allows to ask for the changed text of the given file (in comparison with VCS).
*
* @param file target file
* @return collection of changed regions for the given file
*/
@NotNull
public static Collection<TextRange> getChanges(@NotNull PsiFile file) {
final Set<TextRange> defaultResult = Collections.singleton(file.getTextRange());
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
final Change change = ChangeListManager.getInstance(file.getProject()).getChange(virtualFile);
if (change != null && change.getType() == Change.Type.NEW) {
return defaultResult;
}
}
final LineStatusTrackerManagerI manager = LineStatusTrackerManager.getInstance(file.getProject());
if (manager == null) {
return defaultResult;
}
final Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
if (document == null) {
return defaultResult;
}
final LineStatusTracker lineStatusTracker = manager.getLineStatusTracker(document);
if (lineStatusTracker == null) {
return defaultResult;
}
final List<Range> ranges = lineStatusTracker.getRanges();
if (ranges == null || ranges.isEmpty()) {
return defaultResult;
}
List<TextRange> result = new ArrayList<TextRange>();
for (Range range : ranges) {
if (range.getType() != Range.DELETED) {
final RangeHighlighter highlighter = range.getHighlighter();
if (highlighter != null) {
result.add(new TextRange(highlighter.getStartOffset(), highlighter.getEndOffset()));
}
}
}
return result;
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2011 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 org.jetbrains.annotations.NonNls;
/**
* @author Denis Zhdanov
* @since 12/16/11 6:10 PM
*/
public class LayoutCodeConstants {
public static final @NonNls String OPTIMIZE_IMPORTS_KEY = "LayoutCode.optimizeImports";
public static final @NonNls String PROCESS_CHANGED_TEXT_KEY = "LayoutCode.processChangedText";
private LayoutCodeConstants() {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -26,7 +26,7 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.util.ui.OptionsDialog;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -37,23 +37,23 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class LayoutCodeDialog extends DialogWrapper {
private final PsiFile myFile;
private final PsiFile myFile;
@Nullable private final PsiDirectory myDirectory;
private final Boolean myTextSelected;
private final Boolean myTextSelected;
private JRadioButton myRbFile;
private JRadioButton myRbSelectedText;
private JRadioButton myRbDirectory;
private JCheckBox myCbIncludeSubdirs;
private JCheckBox myCbOptimizeImports;
private JCheckBox myDoNotAskMeCheckBox;
private JCheckBox myCbIncludeSubdirs;
private JCheckBox myCbOptimizeImports;
private JCheckBox myCbOnlyVcsChangedRegions;
private JCheckBox myDoNotAskMeCheckBox;
public static final @NonNls String OPTIMIZE_IMPORTS_KEY = "LayoutCode.optimizeImports";
private final String myHelpId;
public LayoutCodeDialog(Project project,
String title,
PsiFile file,
public LayoutCodeDialog(@NotNull Project project,
@NotNull String title,
@Nullable PsiFile file,
@Nullable PsiDirectory directory,
Boolean isTextSelected,
final String helpId) {
@@ -84,7 +84,7 @@ public class LayoutCodeDialog extends DialogWrapper {
}
myCbIncludeSubdirs.setSelected(true);
myCbOptimizeImports.setSelected(isOptmizeImportsOptionOn());
myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
ItemListener listener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
@@ -99,18 +99,17 @@ public class LayoutCodeDialog extends DialogWrapper {
updateState();
}
private static boolean isOptmizeImportsOptionOn() {
return Boolean.toString(true).equals(PropertiesComponent.getInstance().getValue(OPTIMIZE_IMPORTS_KEY));
}
private static void setOptimizeImportsOption(boolean state) {
PropertiesComponent.getInstance().setValue(OPTIMIZE_IMPORTS_KEY, Boolean.toString(state));
}
private void updateState() {
myCbIncludeSubdirs.setEnabled(myRbDirectory.isSelected());
myCbOptimizeImports.setEnabled(
!myRbSelectedText.isSelected() && !(myFile != null && LanguageImportStatements.INSTANCE.forFile(myFile) == null && myRbFile.isSelected()));
!myRbSelectedText.isSelected() &&
!(myFile != null && LanguageImportStatements.INSTANCE.forFile(myFile) == null && myRbFile.isSelected()));
final boolean canTargetVcsChanges = canTargetVcsRegions();
myCbOnlyVcsChangedRegions.setEnabled(canTargetVcsChanges);
myCbOnlyVcsChangedRegions.setSelected(
canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
);
myDoNotAskMeCheckBox.setEnabled(!myRbDirectory.isSelected());
myRbDirectory.setEnabled(!myDoNotAskMeCheckBox.isSelected());
@@ -163,6 +162,10 @@ public class LayoutCodeDialog extends DialogWrapper {
panel.add(myCbOptimizeImports, gbConstraints);
}
myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region"));
gbConstraints.gridy++;
panel.add(myCbOnlyVcsChangedRegions, gbConstraints);
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(myRbFile);
buttonGroup.add(myRbSelectedText);
@@ -201,7 +204,7 @@ public class LayoutCodeDialog extends DialogWrapper {
public boolean isProcessWholeFile() {
return myRbFile.isSelected();
}
public boolean isProcessDirectory() {
return myRbDirectory.isSelected();
}
@@ -214,12 +217,35 @@ public class LayoutCodeDialog extends DialogWrapper {
return myCbOptimizeImports.isSelected();
}
public boolean isProcessOnlyChangedText() {
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
}
boolean isDoNotAskMe() {
return myDoNotAskMeCheckBox.isSelected();
return myDoNotAskMeCheckBox.isSelected();
}
protected void doOKAction() {
super.doOKAction();
setOptimizeImportsOption(isOptimizeImports());
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports()));
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(isProcessOnlyChangedText()));
}
private boolean canTargetVcsRegions() {
if (isProcessSelectedText()) {
return false;
}
if (isProcessWholeFile()) {
return FormatChangedTextUtil.hasChanges(myFile);
}
if (isProcessDirectory()) {
if (myDirectory == null) {
return false;
}
return FormatChangedTextUtil.hasChanges(myDirectory);
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -19,9 +19,12 @@ package com.intellij.codeInsight.actions;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -30,36 +33,51 @@ import java.awt.*;
* @author max
*/
public class LayoutProjectCodeDialog extends DialogWrapper {
private static @NonNls final String OPTIMIZE_IMPORTS_KEY = "LayoutCode.optimizeImports";
private static @NonNls final String HELP_ID = "editing.codeReformatting";
private final String myText;
private final boolean mySuggestOptmizeImports;
private final String myText;
private final boolean mySuggestOptimizeImports;
private final Project myProject;
private final Module myModule;
private JCheckBox myCbOptimizeImports;
private JCheckBox myCbOnlyVcsChangedRegions;
public LayoutProjectCodeDialog(Project project, String title, String text, boolean suggestOptmizeImports) {
public LayoutProjectCodeDialog(@NotNull Project project,
@Nullable Module module,
String title,
String text,
boolean suggestOptimizeImports)
{
super(project, false);
myText = text;
mySuggestOptmizeImports = suggestOptmizeImports;
mySuggestOptimizeImports = suggestOptimizeImports;
myProject = project;
myModule = module;
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
setTitle(title);
init();
}
protected JComponent createCenterPanel() {
if (!mySuggestOptmizeImports) return new JLabel(myText);
JPanel panel = new JPanel(new GridLayout(2, 1));
if (!mySuggestOptimizeImports) return new JLabel(myText);
JPanel panel = new JPanel(new GridLayout(3, 1));
panel.add(new JLabel(myText));
myCbOptimizeImports = new JCheckBox(CodeInsightBundle.message("reformat.option.optimize.imports"));
panel.add(myCbOptimizeImports);
myCbOptimizeImports.setSelected(Boolean.toString(true).equals(PropertiesComponent.getInstance().getValue(OPTIMIZE_IMPORTS_KEY)));
myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
myCbOnlyVcsChangedRegions = new JCheckBox(CodeInsightBundle.message("reformat.option.vcs.changed.region"));
panel.add(myCbOnlyVcsChangedRegions);
final boolean canTargetVcsRegions = canTargetVcsRegions();
myCbOnlyVcsChangedRegions.setEnabled(canTargetVcsRegions);
myCbOnlyVcsChangedRegions.setSelected(
canTargetVcsRegions && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
);
return panel;
}
private void setOptimizeImportsOption(boolean state) {
PropertiesComponent.getInstance().setValue(OPTIMIZE_IMPORTS_KEY, Boolean.toString(state));
}
protected Action[] createActions() {
return new Action[]{getOKAction(), getCancelAction(), getHelpAction()};
}
@@ -70,12 +88,24 @@ public class LayoutProjectCodeDialog extends DialogWrapper {
protected void doOKAction() {
super.doOKAction();
if (mySuggestOptmizeImports) {
setOptimizeImportsOption(isOptimizeImports());
if (mySuggestOptimizeImports) {
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(isOptimizeImports()));
}
}
public boolean isOptimizeImports() {
return myCbOptimizeImports.isSelected();
}
public boolean isProcessOnlyChangedText() {
return myCbOnlyVcsChangedRegions.isEnabled() && myCbOnlyVcsChangedRegions.isSelected();
}
private boolean canTargetVcsRegions() {
if (myModule != null) {
return FormatChangedTextUtil.hasChanges(myModule);
}
return FormatChangedTextUtil.hasChanges(myProject);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -54,7 +54,7 @@ public class OptimizeImportsAction extends AnAction {
if (file == null) return;
dir = file.getContainingDirectory();
}
else if (ReformatCodeAction.areFiles(files)) {
else if (files != null && ReformatCodeAction.areFiles(files)) {
final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files);
if (!operationStatus.hasReadonlyFiles()) {
new OptimizeImportsProcessor(project, ReformatCodeAction.convertToPsiFiles(files, project), null).run();
@@ -73,7 +73,8 @@ public class OptimizeImportsAction extends AnAction {
else {
text = CodeInsightBundle.message("process.scope.project", projectContext.getPresentableUrl());
}
LayoutProjectCodeDialog dialog = new LayoutProjectCodeDialog(project, CodeInsightBundle.message("process.optimize.imports"), text, false);
LayoutProjectCodeDialog dialog
= new LayoutProjectCodeDialog(project, null, CodeInsightBundle.message("process.optimize.imports"), text, false);
dialog.show();
if (!dialog.isOK()) return;
if (moduleContext != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -34,19 +34,19 @@ public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
private static final String COMMAND_NAME = CodeInsightBundle.message("process.optimize.imports");
public OptimizeImportsProcessor(Project project) {
super(project, COMMAND_NAME, PROGRESS_TEXT);
super(project, COMMAND_NAME, PROGRESS_TEXT, false);
}
public OptimizeImportsProcessor(Project project, Module module) {
super(project, module, COMMAND_NAME, PROGRESS_TEXT);
super(project, module, COMMAND_NAME, PROGRESS_TEXT, false);
}
public OptimizeImportsProcessor(Project project, PsiDirectory directory, boolean includeSubdirs) {
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME);
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, false);
}
public OptimizeImportsProcessor(Project project, PsiFile file) {
super(project, file, PROGRESS_TEXT, COMMAND_NAME);
super(project, file, PROGRESS_TEXT, COMMAND_NAME, false);
}
public OptimizeImportsProcessor(Project project, PsiFile[] files, Runnable postRunnable) {
@@ -54,11 +54,13 @@ public class OptimizeImportsProcessor extends AbstractLayoutCodeProcessor {
}
public OptimizeImportsProcessor(Project project, PsiFile[] files, String commandName, Runnable postRunnable) {
super(project, files, PROGRESS_TEXT, commandName, postRunnable);
super(project, files, PROGRESS_TEXT, commandName, postRunnable, false);
}
@NotNull
protected FutureTask<Boolean> preprocessFile(final PsiFile file) throws IncorrectOperationException {
protected FutureTask<Boolean> preprocessFile(@NotNull final PsiFile file, boolean processChangedTextOnly)
throws IncorrectOperationException
{
final ImportOptimizer optimizer = LanguageImportStatements.INSTANCE.forFile(file);
Runnable runnable = optimizer != null ? optimizer.processFile(file) : EmptyRunnable.getInstance();
return new FutureTask<Boolean>(runnable, true);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -38,40 +38,44 @@ public class ReformatAndOptimizeImportsProcessor extends AbstractLayoutCodeProce
private final OptimizeImportsProcessor myOptimizeImportsProcessor;
private final ReformatCodeProcessor myReformatCodeProcessor;
public ReformatAndOptimizeImportsProcessor(Project project) {
super(project, COMMAND_NAME, PROGRESS_TEXT);
public ReformatAndOptimizeImportsProcessor(Project project, boolean processChangedTextOnly) {
super(project, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
myOptimizeImportsProcessor = new OptimizeImportsProcessor(project);
myReformatCodeProcessor = new ReformatCodeProcessor(project);
myReformatCodeProcessor = new ReformatCodeProcessor(project, processChangedTextOnly);
}
public ReformatAndOptimizeImportsProcessor(Project project, Module module) {
super(project, module, COMMAND_NAME, PROGRESS_TEXT);
public ReformatAndOptimizeImportsProcessor(Project project, Module module, boolean processChangedTextOnly) {
super(project, module, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
myOptimizeImportsProcessor = new OptimizeImportsProcessor(project, module);
myReformatCodeProcessor = new ReformatCodeProcessor(project, module);
myReformatCodeProcessor = new ReformatCodeProcessor(project, module, processChangedTextOnly);
}
public ReformatAndOptimizeImportsProcessor(Project project, PsiFile[] files) {
super(project, files, PROGRESS_TEXT, COMMAND_NAME, null);
public ReformatAndOptimizeImportsProcessor(Project project, PsiFile[] files, boolean processChangedTextOnly) {
super(project, files, PROGRESS_TEXT, COMMAND_NAME, null, processChangedTextOnly);
myOptimizeImportsProcessor = new OptimizeImportsProcessor(project);
myReformatCodeProcessor = new ReformatCodeProcessor(project);
myReformatCodeProcessor = new ReformatCodeProcessor(project, processChangedTextOnly);
}
public ReformatAndOptimizeImportsProcessor(Project project, PsiDirectory directory, boolean includeSubdirs) {
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME);
public ReformatAndOptimizeImportsProcessor(Project project,
PsiDirectory directory,
boolean includeSubdirs,
boolean processChangedTextOnly)
{
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
myOptimizeImportsProcessor = new OptimizeImportsProcessor(project, directory, includeSubdirs);
myReformatCodeProcessor = new ReformatCodeProcessor(project, directory, includeSubdirs);
myReformatCodeProcessor = new ReformatCodeProcessor(project, directory, includeSubdirs, processChangedTextOnly);
}
public ReformatAndOptimizeImportsProcessor(Project project, PsiFile file) {
super(project, file, PROGRESS_TEXT, COMMAND_NAME);
public ReformatAndOptimizeImportsProcessor(Project project, PsiFile file, boolean processChangedTextOnly) {
super(project, file, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
myOptimizeImportsProcessor = new OptimizeImportsProcessor(project, file);
myReformatCodeProcessor = new ReformatCodeProcessor(project, file, null);
myReformatCodeProcessor = new ReformatCodeProcessor(project, file, null, processChangedTextOnly);
}
@NotNull
protected FutureTask<Boolean> preprocessFile(PsiFile file) throws IncorrectOperationException {
final FutureTask<Boolean> reformatTask = myReformatCodeProcessor.preprocessFile(file);
final FutureTask<Boolean> optimizeImportsTask = myOptimizeImportsProcessor.preprocessFile(file);
protected FutureTask<Boolean> preprocessFile(@NotNull PsiFile file, boolean processChangedTextOnly) throws IncorrectOperationException {
final FutureTask<Boolean> reformatTask = myReformatCodeProcessor.preprocessFile(file, processChangedTextOnly);
final FutureTask<Boolean> optimizeImportsTask = myOptimizeImportsProcessor.preprocessFile(file, false);
return new FutureTask<Boolean>(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -75,20 +75,22 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
else if (areFiles(files)) {
final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files);
if (!operationStatus.hasReadonlyFiles()) {
final ReformatFilesDialog reformatFilesDialog = new ReformatFilesDialog(project);
final ReformatFilesDialog reformatFilesDialog = new ReformatFilesDialog(project, files);
reformatFilesDialog.show();
if (!reformatFilesDialog.isOK()) return;
if (reformatFilesDialog.optimizeImports() && !DumbService.getInstance(project).isDumb()) {
new ReformatAndOptimizeImportsProcessor(project, convertToPsiFiles(files, project)).run();
new ReformatAndOptimizeImportsProcessor(
project, convertToPsiFiles(files, project), reformatFilesDialog.isProcessOnlyChangedText()
).run();
}
else {
new ReformatCodeProcessor(project, convertToPsiFiles(files, project), null).run();
new ReformatCodeProcessor(project, convertToPsiFiles(files, project), null, reformatFilesDialog.isProcessOnlyChangedText()).run();
}
}
return;
}
else{
else {
Project projectContext = PlatformDataKeys.PROJECT_CONTEXT.getData(dataContext);
Module moduleContext = LangDataKeys.MODULE_CONTEXT.getData(dataContext);
@@ -98,26 +100,27 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
text = CodeInsightBundle.message("process.scope.module", moduleContext.getModuleFilePath());
}
else {
text = CodeInsightBundle.message("process.scope.project", projectContext.getPresentableUrl());
text = CodeInsightBundle.message("process.scope.project", project.getPresentableUrl());
}
LayoutProjectCodeDialog dialog = new LayoutProjectCodeDialog(project, CodeInsightBundle.message("process.reformat.code"), text, true);
LayoutProjectCodeDialog dialog
= new LayoutProjectCodeDialog(project, moduleContext, CodeInsightBundle.message("process.reformat.code"), text, true);
dialog.show();
if (!dialog.isOK()) return;
if (dialog.isOptimizeImports() && !DumbService.getInstance(project).isDumb()) {
if (moduleContext != null) {
new ReformatAndOptimizeImportsProcessor(project, moduleContext).run();
new ReformatAndOptimizeImportsProcessor(project, moduleContext, dialog.isProcessOnlyChangedText()).run();
}
else {
new ReformatAndOptimizeImportsProcessor(projectContext).run();
new ReformatAndOptimizeImportsProcessor(project, dialog.isProcessOnlyChangedText()).run();
}
}
else {
if (moduleContext != null) {
new ReformatCodeProcessor(project, moduleContext).run();
new ReformatCodeProcessor(project, moduleContext, dialog.isProcessOnlyChangedText()).run();
}
else {
new ReformatCodeProcessor(projectContext).run();
new ReformatCodeProcessor(project, dialog.isProcessOnlyChangedText()).run();
}
}
return;
@@ -140,6 +143,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
boolean optimizeImports = ReformatFilesDialog.isOptmizeImportsOptionOn();
boolean processWholeFile = false;
boolean processChangedTextOnly = false;
if (EditorSettingsExternalizable.getInstance().getOptions().SHOW_REFORMAT_DIALOG || (file == null && dir != null)) {
final LayoutCodeDialog dialog = new LayoutCodeDialog(project, CodeInsightBundle.message("process.reformat.code"), file, dir,
hasSelection ? Boolean.TRUE : Boolean.FALSE, HELP_ID);
@@ -149,12 +153,14 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
updateShowDialogSetting(dialog, "\"Reformat Code\" dialog disabled");
optimizeImports = dialog.isOptimizeImports();
processWholeFile = dialog.isProcessWholeFile();
processChangedTextOnly = dialog.isProcessOnlyChangedText();
if (dialog.isProcessDirectory()){
if (optimizeImports) {
new ReformatAndOptimizeImportsProcessor(project, dir, dialog.isIncludeSubdirectories()).run();
new ReformatAndOptimizeImportsProcessor(project, dir, dialog.isIncludeSubdirectories(), processChangedTextOnly).run();
}
else {
new ReformatCodeProcessor(project, dir, dialog.isIncludeSubdirectories()).run();
new ReformatCodeProcessor(project, dir, dialog.isIncludeSubdirectories(), processChangedTextOnly).run();
}
return;
}
@@ -170,14 +176,14 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
if (optimizeImports && range == null) {
if (file != null || dir == null) {
new ReformatAndOptimizeImportsProcessor(project, file).run();
new ReformatAndOptimizeImportsProcessor(project, file, processChangedTextOnly).run();
}
else {
new ReformatAndOptimizeImportsProcessor(project, dir, true).run();
new ReformatAndOptimizeImportsProcessor(project, dir, true, processChangedTextOnly).run();
}
}
else {
new ReformatCodeProcessor(project, file, range).run();
new ReformatCodeProcessor(project, file, range, processChangedTextOnly).run();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -27,7 +27,10 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
@@ -37,53 +40,66 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.actions.ReformatCodeProcessor");
private final TextRange myRange;
private final Collection<TextRange> myRanges = new ArrayList<TextRange>();
private static final String PROGRESS_TEXT = CodeInsightBundle.message("reformat.progress.common.text");
public ReformatCodeProcessor(Project project) {
super(project, COMMAND_NAME, PROGRESS_TEXT);
myRange = null;
public ReformatCodeProcessor(Project project, boolean processChangedTextOnly) {
super(project, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
}
public ReformatCodeProcessor(Project project, Module module) {
super(project, module, COMMAND_NAME, PROGRESS_TEXT);
myRange = null;
public ReformatCodeProcessor(Project project, Module module, boolean processChangedTextOnly) {
super(project, module, COMMAND_NAME, PROGRESS_TEXT, processChangedTextOnly);
}
public ReformatCodeProcessor(Project project, PsiDirectory directory, boolean includeSubdirs) {
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME);
myRange = null;
public ReformatCodeProcessor(Project project, PsiDirectory directory, boolean includeSubdirs, boolean processChangedTextOnly) {
super(project, directory, includeSubdirs, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
}
public ReformatCodeProcessor(Project project, PsiFile file, TextRange range) {
super(project, file, PROGRESS_TEXT, COMMAND_NAME);
myRange = range;
public ReformatCodeProcessor(Project project, PsiFile file, @Nullable TextRange range, boolean processChangedTextOnly) {
super(project, file, PROGRESS_TEXT, COMMAND_NAME, processChangedTextOnly);
if (range != null) {
myRanges.add(range);
}
}
public ReformatCodeProcessor(Project project, PsiFile[] files, Runnable postRunnable) {
this(project, files, COMMAND_NAME, postRunnable);
public ReformatCodeProcessor(Project project, PsiFile[] files, Runnable postRunnable, boolean processChangedTextOnly) {
this(project, files, COMMAND_NAME, postRunnable, processChangedTextOnly);
}
public ReformatCodeProcessor(Project project, PsiFile[] files, String commandName, Runnable postRunnable) {
super(project, files, PROGRESS_TEXT, commandName, postRunnable);
myRange = null;
public ReformatCodeProcessor(Project project,
PsiFile[] files,
String commandName,
Runnable postRunnable,
boolean processChangedTextOnly)
{
super(project, files, PROGRESS_TEXT, commandName, postRunnable, processChangedTextOnly);
}
@NotNull
protected FutureTask<Boolean> preprocessFile(final PsiFile file) throws IncorrectOperationException {
protected FutureTask<Boolean> preprocessFile(@NotNull final PsiFile file, final boolean processChangedTextOnly)
throws IncorrectOperationException
{
return new FutureTask<Boolean>(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false);
try {
TextRange range = myRange == null ? file.getTextRange() : myRange;
CodeStyleManager.getInstance(myProject).reformatText(file, range.getStartOffset(), range.getEndOffset());
if (myRanges.isEmpty() && processChangedTextOnly) {
myRanges.addAll(FormatChangedTextUtil.getChanges(file));
}
if (myRanges.isEmpty()) {
myRanges.add(file.getTextRange());
}
CodeStyleManager.getInstance(myProject).reformatText(file, myRanges);
return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
}
catch (IncorrectOperationException e) {
LOG.error(e);
return false;
}
finally {
myRanges.clear();
}
}
});
}
@@ -1,27 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.codeInsight.actions.ReformatFilesDialog">
<grid id="59847" binding="myPanel" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="59847" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="4" bottom="0" right="0"/>
<constraints>
<xy x="30" y="17" width="179" height="94"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
<xy x="30" y="17" width="196" height="104"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="e83d0" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="e83d0" layout-manager="GridLayoutManager" row-count="4" 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>
<xy x="4" y="0" width="119" height="94"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="cb57" class="javax.swing.JLabel">
<constraints>
<xy x="0" y="3" width="119" height="14"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0"/>
<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 resource-bundle="messages/CodeInsightBundle" key="dialog.reformat.files.reformat.selected.files.label"/>
@@ -29,8 +26,7 @@
</component>
<component id="4c38e" class="javax.swing.JCheckBox" binding="myOptimizeImports">
<constraints>
<xy x="0" y="25" width="105" height="22"/>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0"/>
<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>
<text resource-bundle="messages/CodeInsightBundle" key="dialog.reformat.files.optimize.imports.checkbox"/>
@@ -38,16 +34,22 @@
</component>
<vspacer id="8d758">
<constraints>
<xy x="54" y="47" width="11" height="47"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2"/>
<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="a0a79" class="javax.swing.JCheckBox" binding="myOnlyChangedText">
<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>
<text resource-bundle="messages/CodeInsightBundle" key="reformat.option.vcs.changed.region"/>
</properties>
</component>
</children>
</grid>
<hspacer id="c7098">
<constraints>
<xy x="123" y="41" width="56" height="11"/>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1"/>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
</children>
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -20,17 +20,34 @@ import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class ReformatFilesDialog extends DialogWrapper {
private JPanel myPanel;
private JCheckBox myOptimizeImports;
private JCheckBox myOnlyChangedText;
private final VirtualFile[] myFiles;
public ReformatFilesDialog(Project project) {
public ReformatFilesDialog(@NotNull Project project, @NotNull VirtualFile[] files) {
super(project, true);
myFiles = files;
setTitle(CodeInsightBundle.message("dialog.reformat.files.title"));
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
boolean canTargetVcsChanges = false;
for (VirtualFile file : files) {
if (FormatChangedTextUtil.hasChanges(file, project)) {
canTargetVcsChanges = true;
break;
}
}
myOnlyChangedText.setEnabled(canTargetVcsChanges);
myOnlyChangedText.setSelected(
canTargetVcsChanges && PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false)
);
myOptimizeImports.setSelected(isOptmizeImportsOptionOn());
init();
}
@@ -42,13 +59,19 @@ public class ReformatFilesDialog extends DialogWrapper {
return myOptimizeImports.isSelected();
}
public boolean isProcessOnlyChangedText() {
return myOnlyChangedText.isEnabled() && myOnlyChangedText.isSelected();
}
protected void doOKAction() {
PropertiesComponent.getInstance().setValue(LayoutCodeDialog.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myOptimizeImports.isSelected()));
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()));
}
static boolean isOptmizeImportsOptionOn() {
return Boolean.valueOf(PropertiesComponent.getInstance().getValue(LayoutCodeDialog.OPTIMIZE_IMPORTS_KEY));
return PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false);
}
}
@@ -84,7 +84,9 @@ public class ReformatBeforeCheckinHandler extends CheckinHandler implements Chec
};
if (reformat(configuration, true)) {
new ReformatCodeProcessor(myProject, BeforeCheckinHandlerUtil.getPsiFiles(myProject, files), COMMAND_NAME, performCheckoutAction).run();
new ReformatCodeProcessor(
myProject, BeforeCheckinHandlerUtil.getPsiFiles(myProject, files), COMMAND_NAME, performCheckoutAction, false
).run();
}
else {
performCheckoutAction.run();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -48,6 +48,10 @@ import org.jetbrains.annotations.NonNls;
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.TimeUnit;
public class CodeStyleManagerImpl extends CodeStyleManager {
@@ -137,6 +141,14 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
@Override
public void reformatText(@NotNull PsiFile file, int startOffset, int endOffset) throws IncorrectOperationException {
reformatText(file, Collections.singleton(new TextRange(startOffset, endOffset)));
}
@Override
public void reformatText(@NotNull PsiFile file, @NotNull Collection<TextRange> ranges) throws IncorrectOperationException {
if (ranges.isEmpty()) {
return;
}
ApplicationManager.getApplication().assertWriteAccessAllowed();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
@@ -150,17 +162,9 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings());
LOG.assertTrue(file.isValid());
final PsiElement start = findElementInTreeWithFormatterEnabled(file, startOffset);
final PsiElement end = findElementInTreeWithFormatterEnabled(file, endOffset);
if (start != null && !start.isValid()) {
LOG.error("start=" + start + "; file=" + file);
}
if (end != null && !end.isValid()) {
LOG.error("end=" + start + "; end=" + file);
}
Editor editor = PsiUtilBase.findEditor(file);
// There is a possible case that cursor is located at the end of the line that contains only white spaces. For example:
// public void foo() {
// <caret>
@@ -168,7 +172,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
// Formatter removes such white spaces, i.e. keeps only line feed symbol. But we want to preserve caret position then.
// So, we check if it should be preserved and restore it after formatting if necessary
int visualColumnToRestore = -1;
if (editor != null) {
Document document = editor.getDocument();
int caretOffset = editor.getCaretModel().getOffset();
@@ -189,23 +193,40 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
visualColumnToRestore = editor.getCaretModel().getVisualPosition().column;
}
}
boolean formatFromStart = startOffset == 0;
boolean formatToEnd = endOffset == file.getTextLength();
final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(getProject());
final SmartPsiElementPointer startPointer = start == null ? null : smartPointerManager.createSmartPsiElementPointer(start);
final SmartPsiElementPointer endPointer = end == null ? null : smartPointerManager.createSmartPsiElementPointer(end);
codeFormatter.processText(file, new FormatTextRanges(new TextRange(startOffset, endOffset), true), true);
final PsiElement startElement = startPointer == null ? null : startPointer.getElement();
final PsiElement endElement = endPointer == null ? null : endPointer.getElement();
if ((startElement != null || formatFromStart) && (endElement != null || formatToEnd)) {
postProcessText(file, new TextRange(formatFromStart ? 0 : startElement.getTextRange().getStartOffset(),
formatToEnd ? file.getTextLength() : endElement.getTextRange().getEndOffset()));
List<RangeFormatInfo> infos = new ArrayList<RangeFormatInfo>();
for (TextRange range : ranges) {
final PsiElement start = findElementInTreeWithFormatterEnabled(file, range.getStartOffset());
final PsiElement end = findElementInTreeWithFormatterEnabled(file, range.getEndOffset());
if (start != null && !start.isValid()) {
LOG.error("start=" + start + "; file=" + file);
}
if (end != null && !end.isValid()) {
LOG.error("end=" + start + "; end=" + file);
}
boolean formatFromStart = range.getStartOffset() == 0;
boolean formatToEnd = range.getEndOffset() == file.getTextLength();
infos.add(new RangeFormatInfo(
start == null ? null : smartPointerManager.createSmartPsiElementPointer(start),
end == null ? null : smartPointerManager.createSmartPsiElementPointer(end),
formatFromStart,
formatToEnd
));
}
FormatTextRanges formatRanges = new FormatTextRanges();
for (TextRange range : ranges) {
formatRanges.add(range, true);
}
codeFormatter.processText(file, formatRanges, true);
for (RangeFormatInfo info : infos) {
final PsiElement startElement = info.startPointer == null ? null : info.startPointer.getElement();
final PsiElement endElement = info.endPointer == null ? null : info.endPointer.getElement();
if ((startElement != null || info.fromStart) && (endElement != null || info.toEnd)) {
postProcessText(file, new TextRange(info.fromStart ? 0 : startElement.getTextRange().getStartOffset(),
info.toEnd ? file.getTextLength() : endElement.getTextRange().getEndOffset()));
}
}
if (visualColumnToRestore < 0) {
@@ -758,5 +779,23 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
}
});
}
private static class RangeFormatInfo{
public final SmartPsiElementPointer startPointer;
public final SmartPsiElementPointer endPointer;
public final boolean fromStart;
public final boolean toEnd;
RangeFormatInfo(@Nullable SmartPsiElementPointer startPointer,
@Nullable SmartPsiElementPointer endPointer,
boolean fromStart,
boolean toEnd)
{
this.startPointer = startPointer;
this.endPointer = endPointer;
this.fromStart = fromStart;
this.toEnd = toEnd;
}
}
}
@@ -12,6 +12,7 @@ reformat.option.selected.text=&Selected text
reformat.option.all.files.in.directory=&All files in directory {0}
reformat.option.include.subdirectories=&Include subdirectories
reformat.option.optimize.imports=&Optimize imports
reformat.option.vcs.changed.region=Only text changed to &VCS
reformat.progress.file.with.known.name.text=Reformatting {0}
reformat.and.optimize.progress.common.text=Preparing imports...
reformat.progress.common.text=Reformatting code...
@@ -1,5 +1,6 @@
/*
* Copyright 2000-2008 JetBrains s.r.o.
* Copyright 2000-2011 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
@@ -169,7 +170,7 @@ public class MvcModuleStructureSynchronizer extends AbstractProjectComponent {
for (VirtualFile virtualFile : files) {
PsiFile psiFile = manager.findFile(virtualFile);
if (psiFile != null) {
new ReformatCodeProcessor(myProject, psiFile, null).run();
new ReformatCodeProcessor(myProject, psiFile, null, false).run();
}
}
}