diff --git a/java/idea-ui/src/com/intellij/framework/library/FrameworkSupportWithLibrary.java b/java/idea-ui/src/com/intellij/framework/library/FrameworkSupportWithLibrary.java
index dce7da5e3f85..9ca15ad45ee5 100644
--- a/java/idea-ui/src/com/intellij/framework/library/FrameworkSupportWithLibrary.java
+++ b/java/idea-ui/src/com/intellij/framework/library/FrameworkSupportWithLibrary.java
@@ -16,14 +16,14 @@
package com.intellij.framework.library;
import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription;
-import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* @author nik
*/
public interface FrameworkSupportWithLibrary {
- @NotNull
+ @Nullable
CustomLibraryDescription createLibraryDescription();
boolean isLibraryOnly();
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FieldInColumnsPreFormatProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FieldInColumnsPreFormatProcessor.java
new file mode 100644
index 000000000000..72b27ee31286
--- /dev/null
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FieldInColumnsPreFormatProcessor.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2000-2012 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.psi.impl.source.codeStyle;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.psi.impl.source.tree.ElementType;
+import com.intellij.psi.impl.source.tree.JavaJspElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * There is a possible case that the project is configured to keep fields in columns:
+ *
+ * class Test {
+ * int i = 1;
+ * int fieldWithLongName = 2;
+ * }
+ *
+ * Suppose that one of the fields is renamed. We want to reformat the whole fields group then in order to keep that 'field columns'.
+ *
+ * Current extension checks if given range intersects with a field from a field group and expands its boundaries to contain
+ * the whole group.
+ *
+ * Thread-safe.
+ *
+ * @author Denis Zhdanov
+ * @since 5/9/12 4:54 PM
+ */
+public class FieldInColumnsPreFormatProcessor implements PreFormatProcessor {
+
+ @NotNull
+ @Override
+ public TextRange process(@NotNull ASTNode element, @NotNull TextRange range) {
+ //region Checking that everything is ready to expand the range for the 'fields in columns'.
+ final PsiElement psi = element.getPsi();
+ if (psi == null) {
+ return range;
+ }
+
+ final PsiFile file = psi.getContainingFile();
+ if (file == null) {
+ return range;
+ }
+
+ final Project project = psi.getProject();
+ final CommonCodeStyleSettings settings
+ = CodeStyleSettingsManager.getInstance(project).getCurrentSettings().getCommonSettings(JavaLanguage.INSTANCE);
+ if (!settings.ALIGN_GROUP_FIELD_DECLARATIONS) {
+ return range;
+ }
+
+ final PsiElement startElement = file.findElementAt(range.getStartOffset());
+ if (startElement == null) {
+ return range;
+ }
+
+ final PsiField parent = PsiTreeUtil.getParentOfType(startElement, PsiField.class);
+ if (parent == null) {
+ return range;
+ }
+ //endregion
+
+ //region Calculating start offset to use by the start offset of the first sibling white space or field to the left of the current field.
+ int startToUse = range.getStartOffset();
+ for (PsiElement f = parent; f != null; f = f.getPrevSibling()) {
+ final ASTNode node = f.getNode();
+ if (node == null) {
+ break;
+ }
+ if (JavaJspElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType()) || f instanceof PsiField) {
+ startToUse = f.getTextRange().getStartOffset();
+ }
+ else if (!ElementType.JAVA_COMMENT_BIT_SET.contains(node.getElementType())) {
+ break;
+ }
+ }
+ //endregion
+
+ //region Calculating end offset to use by the end offset of the last field in a group located to the right of the current field.
+ int endToUse = range.getEndOffset();
+ for (PsiElement f = parent; f != null; f = f.getPrevSibling()) {
+ final ASTNode node = f.getNode();
+ if (node == null) {
+ break;
+ }
+ if (f instanceof PsiField) {
+ endToUse = f.getTextRange().getEndOffset();
+ }
+ else if (!JavaJspElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType()) &&
+ !ElementType.JAVA_COMMENT_BIT_SET.contains(node.getElementType()))
+ {
+ break;
+ }
+ }
+ //endregion
+
+ return TextRange.from(startToUse, endToUse);
+ }
+}
diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java
index 4efb46a4b4bd..5c80f43240d7 100644
--- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java
+++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/FormatCommentsProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2012 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.
@@ -25,10 +25,12 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.codeStyle.javadoc.CommentFormatter;
import com.intellij.psi.javadoc.PsiDocComment;
+import org.jetbrains.annotations.NotNull;
public class FormatCommentsProcessor implements PreFormatProcessor {
+ @NotNull
@Override
- public TextRange process(final ASTNode element, final TextRange range) {
+ public TextRange process(@NotNull final ASTNode element, @NotNull final TextRange range) {
final Project project = SourceTreeToPsiMap.treeElementToPsi(element).getProject();
if (!CodeStyleSettingsManager.getSettings(project).ENABLE_JAVADOC_FORMATTING ||
element.getPsi().getContainingFile().getLanguage() != StdLanguages.JAVA) {
diff --git a/java/java-tests/testData/refactoring/renameField/afterFieldInColumns.java b/java/java-tests/testData/refactoring/renameField/afterFieldInColumns.java
new file mode 100644
index 000000000000..b2f73979881e
--- /dev/null
+++ b/java/java-tests/testData/refactoring/renameField/afterFieldInColumns.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+class Test {
+ int jj = 1;
+ int fieldWithLongName = 2;
+
+ void test() {
+ jj = 3;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/renameField/beforeFieldInColumns.java b/java/java-tests/testData/refactoring/renameField/beforeFieldInColumns.java
new file mode 100644
index 000000000000..9e214201346c
--- /dev/null
+++ b/java/java-tests/testData/refactoring/renameField/beforeFieldInColumns.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+class Test {
+ int i = 1;
+ int fieldWithLongName = 2;
+
+ void test() {
+ i = 3;
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/refactoring/RenameFieldTest.java b/java/java-tests/testSrc/com/intellij/refactoring/RenameFieldTest.java
index d5d7f02d317e..656156bfde98 100644
--- a/java/java-tests/testSrc/com/intellij/refactoring/RenameFieldTest.java
+++ b/java/java-tests/testSrc/com/intellij/refactoring/RenameFieldTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2000-2012 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.
+ */
+
/*
* Created by IntelliJ IDEA.
* User: dsl
@@ -10,7 +26,9 @@ package com.intellij.refactoring;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.lang.java.JavaLanguage;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.refactoring.rename.RenameProcessor;
import com.intellij.refactoring.rename.RenameWrongRefHandler;
import org.jetbrains.annotations.NonNls;
@@ -66,6 +84,13 @@ public class RenameFieldTest extends LightRefactoringTestCase {
assertFalse(RenameWrongRefHandler.isAvailable(getProject(), getEditor(), getFile()));
}
+ public void testFieldInColumns() throws Exception {
+ // Assuming that test infrastructure setups temp settings (CodeStyleSettingsManager.setTemporarySettings()) and we don't
+ // need to perform explicit clean-up at the test level.
+ CodeStyleSettingsManager.getSettings(getProject()).getCommonSettings(JavaLanguage.INSTANCE).ALIGN_GROUP_FIELD_DECLARATIONS = true;
+ doTest("jj", "java");
+ }
+
protected static void perform(String newName) {
PsiElement element = TargetElementUtilBase.findTargetElement(myEditor, TargetElementUtilBase
.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED);
diff --git a/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java
index 0ecc556d0d3e..4dbbd81a4146 100644
--- a/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java
+++ b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2012 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,22 +27,26 @@ import java.util.List;
/**
* @author Dmitry Avdeev
+ * @author Konstantin Bulenkov
*/
public class GotoRelatedItem {
+ private final String myGroup;
private final int myMnemonic;
private final PsiElement myElement;
+ public static final String DEFAULT_GROUP_NAME = "";
- protected GotoRelatedItem(@Nullable PsiElement element, final int mnemonic) {
+ protected GotoRelatedItem(@Nullable PsiElement element, String group, final int mnemonic) {
myElement = element;
+ myGroup = group;
myMnemonic = mnemonic;
}
- public GotoRelatedItem(@NotNull PsiElement element) {
- this(element, -1);
+ public GotoRelatedItem(@NotNull PsiElement element, String group) {
+ this(element, group, -1);
}
- protected GotoRelatedItem() {
- this(null, -1);
+ public GotoRelatedItem(@NotNull PsiElement element) {
+ this(element, DEFAULT_GROUP_NAME);
}
public void navigate() {
@@ -67,11 +71,14 @@ public class GotoRelatedItem {
public int getMnemonic() {
return myMnemonic;
}
-
public static List createItems(@NotNull Collection extends PsiElement> elements) {
+ return createItems(elements, DEFAULT_GROUP_NAME);
+ }
+
+ public static List createItems(@NotNull Collection extends PsiElement> elements, String group) {
List items = new ArrayList(elements.size());
for (PsiElement element : elements) {
- items.add(new GotoRelatedItem(element));
+ items.add(new GotoRelatedItem(element, group));
}
return items;
}
@@ -88,6 +95,10 @@ public class GotoRelatedItem {
return true;
}
+ public String getGroup() {
+ return myGroup;
+ }
+
@Override
public int hashCode() {
return myElement != null ? myElement.hashCode() : 0;
diff --git a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
index e79d7e17c076..77908a96df12 100644
--- a/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
+++ b/platform/lang-impl/src/com/intellij/formatting/AbstractBlockWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2012 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.
@@ -236,14 +236,15 @@ public abstract class AbstractBlockWrapper {
else {
return childIndent.add(myParent.getChildOffset(this, options, targetBlockStartOffset));
}
- } else if (!getWhiteSpace().containsLineFeeds()) {
- if (isIndentAffectedAlignment(child)) {
- return createAlignmentIndent(childIndent, child);
- }
- else {
- return childIndent.add(myParent.getChildOffset(this, options, targetBlockStartOffset));
- }
- } else {
+ }
+ else if (!getWhiteSpace().containsLineFeeds()) {
+ final IndentData indent = createAlignmentIndent(childIndent, child);
+ if (indent != null) {
+ return indent;
+ }
+ return childIndent.add(myParent.getChildOffset(this, options, targetBlockStartOffset));
+ }
+ else {
if (myParent == null) return childIndent.add(getWhiteSpace());
if (getIndent().isAbsolute()) {
if (myParent.myParent != null) {
@@ -254,12 +255,11 @@ public abstract class AbstractBlockWrapper {
}
}
if ((myFlags & CAN_USE_FIRST_CHILD_INDENT_AS_BLOCK_INDENT) != 0) {
- if (isIndentAffectedAlignment(child)) {
- return createAlignmentIndent(childIndent, child);
- }
- else {
- return childIndent.add(getWhiteSpace());
+ final IndentData indent = createAlignmentIndent(childIndent, child);
+ if (indent != null) {
+ return indent;
}
+ return childIndent.add(getWhiteSpace());
}
else {
return childIndent.add(myParent.getChildOffset(this, options, targetBlockStartOffset));
@@ -343,29 +343,8 @@ public abstract class AbstractBlockWrapper {
}
/**
- * Allows to answer if indent for the given child block should be calculated taking into consideration alignment
- * of the text at current block start.
- *
- * @param child child block to check
- * @return true if indent should be calculated taking into consideration alignment of the text at current
- * block start; false otherwise
- */
- private boolean isIndentAffectedAlignment(AbstractBlockWrapper child) {
- if (!child.getWhiteSpace().containsLineFeeds()) {
- return false;
- }
- AlignmentImpl alignment = getAlignmentAtStartOffset();
- if (alignment == null || alignment == child.getAlignment()) {
- return false;
- }
-
- LeafBlockWrapper anchorOffsetBlock = alignment.getOffsetRespBlockBefore(child);
- return anchorOffsetBlock == null || anchorOffsetBlock.getStartOffset() >= getStartOffset();
- }
-
- /**
- * Allows to construct indent for the block that is affected by aligning rules. E.g. there is a possible case that the user
- * configures method call arguments to be aligned and single parameter expression spans more than one line:
+ * Check if it's possible to construct indent for the block that is affected by aligning rules. E.g. there is a possible case
+ * that the user configures method call arguments to be aligned and single parameter expression spans more than one line:
*
*
* public void test(String s1, String s2) {}
@@ -383,15 +362,41 @@ public abstract class AbstractBlockWrapper {
* sub-blocks that are located on new lines should also be indented to the point of composite block start.
*
* This method takes care about constructing target absolute indent of the given child block assuming that it's parent
- * (referenced by 'this') or it's ancestor that starts at the same offset is aligned. I.e. it assumes
- * that {@link #isIndentAffectedAlignment(AbstractBlockWrapper)} returns true for the given child block.
+ * (referenced by 'this') or it's ancestor that starts at the same offset is aligned.
*
* @param indentFromParent basic indent of given child from the current parent block
* @param child child block of the current aligned composite block
- * @return absolute indent to use for the given child block of the current composite block
+ * @return absolute indent to use for the given child block of the current composite block if alignment-affected
+ * indent should be used for it;
+ * null otherwise
*/
+ @Nullable
private IndentData createAlignmentIndent(IndentData indentFromParent, AbstractBlockWrapper child) {
+ if (!child.getWhiteSpace().containsLineFeeds()) {
+ return null;
+ }
+
+ AlignmentImpl alignment = getAlignmentAtStartOffset();
+ if (alignment == null || alignment == child.getAlignment()) {
+ return null;
+ }
+
AbstractBlockWrapper previous = child.getPreviousBlock();
+ LeafBlockWrapper anchorOffsetBlock = alignment.getOffsetRespBlockBefore(child);
+ if (anchorOffsetBlock != null && anchorOffsetBlock.getStartOffset() != getStartOffset()) {
+ // Located on different lines.
+ boolean onDifferentLines = false;
+ for (LeafBlockWrapper b = anchorOffsetBlock.getNextBlock(); b != null && b.getStartOffset() < getStartOffset(); b = b.getNextBlock()) {
+ if (b.getWhiteSpace().containsLineFeeds()) {
+ onDifferentLines = true;
+ break;
+ }
+ }
+
+ if (!onDifferentLines) {
+ return null;
+ }
+ }
// There is no point in continuing processing if given child is the first block, i.e. there is no alignment-implied
// offset to add to the given 'indent from parent'.
@@ -399,7 +404,13 @@ public abstract class AbstractBlockWrapper {
return indentFromParent;
}
- IndentData symbolsBeforeCurrent = getNumberOfSymbolsBeforeBlock();
+ IndentData symbolsBeforeCurrent;
+ if (anchorOffsetBlock == null) {
+ symbolsBeforeCurrent = getNumberOfSymbolsBeforeBlock();
+ }
+ else {
+ symbolsBeforeCurrent = anchorOffsetBlock.getNumberOfSymbolsBeforeBlock();
+ }
// Result is calculated as a number of symbols between the current composite parent block plus given 'indent from parent'.
int indentSpaces = symbolsBeforeCurrent.getIndentSpaces() + indentFromParent.getSpaces() + indentFromParent.getIndentSpaces();
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java
index 79c9b76eb08e..c6e22e785a23 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2012 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,11 +26,14 @@ import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.ColoredListCellRenderer;
+import com.intellij.ui.SeparatorWithText;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.popup.list.ListPopupImpl;
+import com.intellij.ui.popup.list.PopupListElementRenderer;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -97,6 +100,8 @@ public class GotoRelatedFileAction extends AnAction {
final String title, final Processor