diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index dbf1ae9d7258..ed4656825714 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -88,7 +88,7 @@ public class CompilerManagerImpl extends CompilerManager { addCompilableFileType(StdFileTypes.JAVA); final File projectGeneratedSrcRoot = CompilerPaths.getGeneratedDataDirectory(project); - FileUtil.createIfDoesntExist(projectGeneratedSrcRoot); + projectGeneratedSrcRoot.mkdirs(); final LocalFileSystem lfs = LocalFileSystem.getInstance(); myWatchRoots = lfs.addRootsToWatch(Collections.singletonList(FileUtil.toCanonicalPath(projectGeneratedSrcRoot.getPath())), true); Disposer.register(project, new Disposable() { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java index e216c7cd2ea4..b7bdd9134769 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/ExpressionEvaluationDialog.java @@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.components.JBLabel; import com.intellij.util.ui.UIUtil; import javax.swing.*; @@ -82,13 +83,13 @@ public class ExpressionEvaluationDialog extends EvaluationDialog { protected JComponent createCenterPanel() { final JPanel panel = new JPanel(new BorderLayout()); - final JPanel exprPanel = new JPanel(new BorderLayout()); + final JPanel exprPanel = new JPanel(new BorderLayout(UIUtil.DEFAULT_HGAP, 0)); exprPanel.add(new JLabel(DebuggerBundle.message("label.evaluate.dialog.expression")), BorderLayout.WEST); exprPanel.add(getExpressionCombo(), BorderLayout.CENTER); - final JLabel help = new JLabel("Press Enter to Evaluate or Control+Enter to evaluate and add to the Watches", SwingConstants.RIGHT); + final JBLabel help = new JBLabel("Press Enter to Evaluate or Control+Enter to evaluate and add to the Watches", SwingConstants.RIGHT); help.setBorder(IdeBorderFactory.createEmptyBorder(2,0,6,0)); - UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, help); - help.setForeground(UIUtil.getInactiveTextColor()); + help.setComponentStyle(UIUtil.ComponentStyle.SMALL); + help.setFontColor(UIUtil.FontColor.BRIGHTER); exprPanel.add(help, BorderLayout.SOUTH); diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java index aae5ed814941..5ce8aaa763bf 100644 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java +++ b/java/java-impl/src/com/intellij/application/options/CodeStyleImportsPanel.java @@ -52,9 +52,6 @@ public class CodeStyleImportsPanel extends JPanel { private final PackageEntryTable myPackageList = new PackageEntryTable(); private JBTable myImportLayoutTable; - private JButton myMoveUpButton; - private JButton myMoveDownButton; - private JButton myRemovePackageFromImportLayoutButton; private JBTable myPackageTable; private final CodeStyleSettings mySettings; private JRadioButton myJspImportCommaSeparated; diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseMoveInitializerToMethodAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseMoveInitializerToMethodAction.java new file mode 100644 index 000000000000..a656448f7ce2 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/BaseMoveInitializerToMethodAction.java @@ -0,0 +1,205 @@ +/* + * 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.codeInsight.intention.impl; + +import com.intellij.codeInsight.CodeInsightUtilBase; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils; +import com.intellij.codeInsight.highlighting.HighlightManager; +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.jsp.jspJava.JspClass; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.util.PsiTreeUtil; +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.List; + +/** + * refactored from {@link com.intellij.codeInsight.intention.impl.MoveInitializerToConstructorAction} + * + * @author Danila Ponomarenko + */ +public abstract class BaseMoveInitializerToMethodAction extends PsiElementBaseIntentionAction { + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + if (element instanceof PsiCompiledElement) return false; + final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class, false, PsiMember.class, PsiCodeBlock.class, PsiDocComment.class); + if (field == null || hasUnsuitableModifiers(field)) return false; + if (!field.hasInitializer()) return false; + PsiClass psiClass = field.getContainingClass(); + + return psiClass != null && !psiClass.isInterface() && !(psiClass instanceof PsiAnonymousClass) && !(psiClass instanceof JspClass); + } + + private boolean hasUnsuitableModifiers(@NotNull PsiField field) { + for (@PsiModifier.ModifierConstant String modifier : getUnsuitableModifiers()) { + if (field.hasModifierProperty(modifier)) { + return true; + } + } + return false; + } + + @NotNull + protected abstract Collection getUnsuitableModifiers(); + + @Override + public final void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; + + final PsiField field = getFieldAtCaret(editor, file); + assert field != null; + final PsiClass aClass = field.getContainingClass(); + if (aClass == null) return; + + final Collection methodsToAddInitialization = getOrCreateMethods(project, editor, file, aClass); + + + final List assignments = addFieldAssignments(field, methodsToAddInitialization); + field.getInitializer().delete(); + + if (!assignments.isEmpty()) { + highlightRExpression((PsiAssignmentExpression)assignments.get(0).getExpression(), project, editor); + } + } + + private static void highlightRExpression(@NotNull PsiAssignmentExpression assignment, @NotNull Project project, Editor editor) { + final EditorColorsManager manager = EditorColorsManager.getInstance(); + final TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + final PsiExpression expression = assignment.getRExpression(); + + HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[]{expression}, attributes, false, null); + } + + @NotNull + private static List addFieldAssignments(@NotNull PsiField field, @NotNull Collection methods) { + final List assignments = new ArrayList(); + for (PsiMethod method : methods) { + assignments.add(addAssignment(getOrCreateMethodBody(method), field)); + } + return assignments; + } + + @NotNull + private static PsiCodeBlock getOrCreateMethodBody(@NotNull PsiMethod method) { + PsiCodeBlock codeBlock = method.getBody(); + if (codeBlock == null) { + CreateFromUsageUtils.setupMethodBody(method); + codeBlock = method.getBody(); + } + return codeBlock; + } + + @NotNull + protected abstract Collection getOrCreateMethods(@NotNull Project project, @NotNull Editor editor, PsiFile file, @NotNull PsiClass aClass); + + @Nullable + private static PsiField getFieldAtCaret(@NotNull Editor editor, @NotNull PsiFile file) { + final int offset = editor.getCaretModel().getOffset(); + return PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiField.class); + } + + @NotNull + private static PsiExpressionStatement addAssignment(@NotNull PsiCodeBlock codeBlock, @NotNull PsiField field) throws IncorrectOperationException { + final PsiElementFactory factory = JavaPsiFacade.getInstance(codeBlock.getProject()).getElementFactory(); + + final PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(field.getName() + " = y;", codeBlock); + + PsiExpression initializer = field.getInitializer(); + if (initializer instanceof PsiArrayInitializerExpression) { + initializer = arrayInitializerToNewExpression((PsiArrayInitializerExpression)initializer, factory, codeBlock); + } + + final PsiAssignmentExpression expression = (PsiAssignmentExpression)statement.getExpression(); + expression.getRExpression().replace(initializer); + + final PsiElement newStatement = codeBlock.addBefore(statement, findFirstFieldUsage(codeBlock.getStatements(), field)); + replaceWithQualifiedReferences(newStatement, newStatement, factory); + return (PsiExpressionStatement)newStatement; + } + + @Nullable + private static PsiElement findFirstFieldUsage(@NotNull PsiStatement[] statements, @NotNull PsiField field) { + for (PsiStatement blockStatement : statements) { + if (!isSuperOrThisMethodCall(blockStatement) && containsReference(blockStatement, field)) { + return blockStatement; + } + } + return null; + } + + private static boolean isSuperOrThisMethodCall(@NotNull PsiStatement statement) { + if (statement instanceof PsiExpressionStatement) { + final PsiElement expression = ((PsiExpressionStatement)statement).getExpression(); + if (HighlightUtil.isSuperOrThisMethodCall(expression)) { + return true; + } + } + return false; + } + + private static PsiExpression arrayInitializerToNewExpression(@NotNull PsiArrayInitializerExpression initializer, + @NotNull PsiElementFactory factory, + @NotNull PsiElement context) { + final PsiType type = initializer.getType(); + final PsiNewExpression newExpression = (PsiNewExpression)factory.createExpressionFromText("new " + type.getCanonicalText() + "{}", context); + newExpression.getArrayInitializer().replace(initializer); + return newExpression; + } + + private static boolean containsReference(final @NotNull PsiElement element, + final @NotNull PsiField field) { + final Ref result = new Ref(Boolean.FALSE); + element.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (expression.resolve() == field) { + result.set(Boolean.TRUE); + } + super.visitReferenceExpression(expression); + } + }); + return result.get().booleanValue(); + } + + private static void replaceWithQualifiedReferences(@NotNull PsiElement expression, @NotNull PsiElement root, @NotNull PsiElementFactory factory) throws IncorrectOperationException { + final PsiReference reference = expression.getReference(); + if (reference == null) { + for (PsiElement child : expression.getChildren()) { + replaceWithQualifiedReferences(child, root, factory); + } + return; + } + + final PsiElement resolved = reference.resolve(); + if (resolved instanceof PsiVariable && !(resolved instanceof PsiField) && !PsiTreeUtil.isAncestor(root, resolved, false)) { + final PsiVariable variable = (PsiVariable)resolved; + PsiElement qualifiedExpr = factory.createExpressionFromText("this." + variable.getName(), expression); + expression.replace(qualifiedExpr); + } + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java index 82deb5925d89..19f3322cc9eb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/MoveInitializerToConstructorAction.java @@ -16,25 +16,15 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; -import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils; -import com.intellij.codeInsight.highlighting.HighlightManager; import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; import com.intellij.codeInsight.intention.QuickFixFactory; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.jsp.jspJava.JspClass; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -42,7 +32,7 @@ import java.util.*; /** * @author cdr */ -public class MoveInitializerToConstructorAction extends PsiElementBaseIntentionAction { +public class MoveInitializerToConstructorAction extends BaseMoveInitializerToMethodAction { @Override @NotNull public String getFamilyName() { @@ -55,124 +45,48 @@ public class MoveInitializerToConstructorAction extends PsiElementBaseIntentionA return CodeInsightBundle.message("intention.move.initializer.to.constructor"); } + @NotNull @Override - public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { - if (element instanceof PsiCompiledElement) return false; - final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class, false, PsiMember.class, PsiCodeBlock.class, PsiDocComment.class); - if (field == null || field.hasModifierProperty(PsiModifier.STATIC)) return false; - if (!field.hasInitializer()) return false; - PsiClass psiClass = field.getContainingClass(); - - return psiClass != null && !psiClass.isInterface() && !(psiClass instanceof PsiAnonymousClass) && !(psiClass instanceof JspClass); + protected Collection getUnsuitableModifiers() { + return Arrays.asList(PsiModifier.STATIC); } + @NotNull @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; - - int offset = editor.getCaretModel().getOffset(); - - PsiElement element = file.findElementAt(offset); - final PsiField field = PsiTreeUtil.getParentOfType(element, PsiField.class); - - assert field != null; - PsiClass aClass = field.getContainingClass(); - PsiMethod[] constructors = aClass.getConstructors(); - Collection constructorsToAddInitialization; - if (constructors.length == 0) { - IntentionAction addDefaultConstructorFix = QuickFixFactory.getInstance().createAddDefaultConstructorFix(aClass); - addDefaultConstructorFix.invoke(project, editor, file); - editor.getCaretModel().moveToOffset(offset); //restore caret - constructorsToAddInitialization = Arrays.asList(aClass.getConstructors()); - } - else { - constructorsToAddInitialization = new ArrayList(Arrays.asList(constructors)); - for (Iterator iterator = constructorsToAddInitialization.iterator(); iterator.hasNext();) { - PsiMethod ctr = iterator.next(); - List chained = HighlightControlFlowUtil.getChainedConstructors(ctr); - if (chained != null) { - iterator.remove(); - } - } + protected Collection getOrCreateMethods(@NotNull Project project, @NotNull Editor editor, PsiFile file, @NotNull PsiClass aClass) { + final Collection constructors = Arrays.asList(aClass.getConstructors()); + if (constructors.isEmpty()) { + return createConstructor(project, editor, file, aClass); } - PsiExpressionStatement toMove = null; - for (PsiMethod constructor : constructorsToAddInitialization) { - PsiCodeBlock codeBlock = constructor.getBody(); - if (codeBlock == null) { - CreateFromUsageUtils.setupMethodBody(constructor); - codeBlock = constructor.getBody(); - } - PsiExpressionStatement added = addAssignment(codeBlock, field); - if (toMove == null) toMove = added; - } - field.getInitializer().delete(); - if (toMove != null) { - PsiAssignmentExpression assignment = (PsiAssignmentExpression)toMove.getExpression(); - PsiExpression expression = assignment.getRExpression(); - EditorColorsManager manager = EditorColorsManager.getInstance(); - TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[] {expression}, attributes, false,null); - } + return removeChainedConstructors(constructors); } - private static PsiExpressionStatement addAssignment(@NotNull PsiCodeBlock codeBlock, @NotNull PsiField field) throws IncorrectOperationException { - PsiElementFactory factory = JavaPsiFacade.getInstance(codeBlock.getProject()).getElementFactory(); - PsiExpressionStatement statement = (PsiExpressionStatement)factory.createStatementFromText(field.getName()+" = y;", codeBlock); - PsiAssignmentExpression expression = (PsiAssignmentExpression)statement.getExpression(); - PsiExpression initializer = field.getInitializer(); - if (initializer instanceof PsiArrayInitializerExpression) { - PsiType type = initializer.getType(); - PsiNewExpression newExpression = (PsiNewExpression)factory.createExpressionFromText("new " + type.getCanonicalText() + "{}", codeBlock); - newExpression.getArrayInitializer().replace(initializer); - initializer = newExpression; - } - expression.getRExpression().replace(initializer); - PsiStatement[] statements = codeBlock.getStatements(); - PsiElement anchor = null; - for (PsiStatement blockStatement : statements) { - if (blockStatement instanceof PsiExpressionStatement && - HighlightUtil.isSuperOrThisMethodCall(((PsiExpressionStatement)blockStatement).getExpression())) { - continue; - } - if (containsReference(blockStatement, field)) { - anchor = blockStatement; - break; + @NotNull + private static Collection removeChainedConstructors(@NotNull Collection constructors) { + final List result = new ArrayList(constructors); + + final Iterator iterator = result.iterator(); + //noinspection ForLoopThatDoesntUseLoopVariable + for (PsiMethod constructor = iterator.next(); iterator.hasNext(); constructor = iterator.next()) { + final List chained = HighlightControlFlowUtil.getChainedConstructors(constructor); + if (chained != null) { + iterator.remove(); } } - PsiElement newStatement = codeBlock.addBefore(statement,anchor); - replaceWithQualifiedReferences(newStatement, newStatement); - return (PsiExpressionStatement)newStatement; + + return result; } - private static boolean containsReference(final PsiElement element, final PsiField field) { - final Ref result = new Ref(Boolean.FALSE); - element.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { - if (expression.resolve() == field) { - result.set(Boolean.TRUE); - } - super.visitReferenceExpression(expression); - } - }); - return result.get().booleanValue(); + @NotNull + private static Collection createConstructor(@NotNull Project project, + @NotNull Editor editor, + PsiFile file, + @NotNull PsiClass aClass) { + final IntentionAction addDefaultConstructorFix = QuickFixFactory.getInstance().createAddDefaultConstructorFix(aClass); + final int offset = editor.getCaretModel().getOffset(); + addDefaultConstructorFix.invoke(project, editor, file); + editor.getCaretModel().moveToOffset(offset); //restore caret + return Arrays.asList(aClass.getConstructors()); } - - private static void replaceWithQualifiedReferences(final PsiElement expression, PsiElement root) throws IncorrectOperationException { - PsiReference reference = expression.getReference(); - if (reference != null) { - PsiElement resolved = reference.resolve(); - if (resolved instanceof PsiVariable && !(resolved instanceof PsiField) && !PsiTreeUtil.isAncestor(root, resolved, false)) { - PsiVariable variable = (PsiVariable)resolved; - PsiElementFactory factory = JavaPsiFacade.getInstance(resolved.getProject()).getElementFactory(); - PsiElement qualifiedExpr = factory.createExpressionFromText("this." + variable.getName(), expression); - expression.replace(qualifiedExpr); - } - } - else { - for (PsiElement child : expression.getChildren()) { - replaceWithQualifiedReferences(child, root); - } - } - } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java index 51974730e346..6b9d7c583910 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/BaseExpressionToFieldHandler.java @@ -58,6 +58,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.IntroduceHandlerBase; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer; import com.intellij.refactoring.introduceVariable.IntroduceVariableBase; import com.intellij.refactoring.rename.RenameJavaVariableProcessor; import com.intellij.refactoring.util.CommonRefactoringUtil; @@ -123,7 +124,10 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase if (psiField != null && psiField.getParent() == aClass) break; aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true); } - if (classes.size() == 1 || editor == null || ApplicationManager.getApplication().isUnitTestMode()) { + final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + final boolean shouldSuggestDialog = activeIntroducer instanceof InplaceIntroduceConstantPopup && + activeIntroducer.startsOnTheSameElement(selectedExpr, null); + if (classes.size() == 1 || editor == null || ApplicationManager.getApplication().isUnitTestMode() || shouldSuggestDialog) { return !convertExpressionToField(selectedExpr, editor, file, project, tempType); } else { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java index a991d6e519aa..1f9661d1c5e0 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/LocalToFieldHandler.java @@ -32,6 +32,7 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.EnumConstantsUtil; import com.intellij.refactoring.util.RefactoringUtil; @@ -80,7 +81,10 @@ public abstract class LocalToFieldHandler { } if (classes.isEmpty()) return false; - if (classes.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { + final AbstractInplaceIntroducer activeIntroducer = AbstractInplaceIntroducer.getActiveIntroducer(editor); + final boolean shouldSuggestDialog = activeIntroducer instanceof InplaceIntroduceConstantPopup && + activeIntroducer.startsOnTheSameElement(null, local); + if (classes.size() == 1 || ApplicationManager.getApplication().isUnitTestMode() || shouldSuggestDialog) { if (convertLocalToField(local, classes.get(getChosenClassIndex(classes)), editor, tempIsStatic)) return false; } else { final boolean isStatic = tempIsStatic; diff --git a/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java b/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java index ea6605c01e7a..d1cb70528867 100644 --- a/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java +++ b/java/java-impl/src/com/intellij/testIntegration/BaseGenerateTestSupportMethodAction.java @@ -65,7 +65,7 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction { @Override protected boolean isValidForClass(PsiClass targetClass) { - List frameworks = findSuitableFrameworks(targetClass); + List frameworks = TestIntegrationUtils.findSuitableFrameworks(targetClass); if (frameworks.isEmpty()) return false; for (TestFramework each : frameworks) { @@ -78,22 +78,6 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction { return true; } - private static List findSuitableFrameworks(PsiClass targetClass) { - TestFramework[] frameworks = Extensions.getExtensions(TestFramework.EXTENSION_NAME); - for (TestFramework each : frameworks) { - if (each.isTestClass(targetClass)) { - return Collections.singletonList(each); - } - } - - List result = new SmartList(); - for (TestFramework each : frameworks) { - if (each.isPotentialTestClass(targetClass)) { - result.add(each); - } - } - return result; - } private static class MyHandler implements CodeInsightActionHandler { private TestIntegrationUtils.MethodKind myMethodKind; @@ -104,7 +88,7 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction { public void invoke(@NotNull Project project, @NotNull final Editor editor, @NotNull final PsiFile file) { final PsiClass targetClass = findTargetClass(editor, file); - final List frameworks = findSuitableFrameworks(targetClass); + final List frameworks = TestIntegrationUtils.findSuitableFrameworks(targetClass); if (frameworks.isEmpty()) return; if (frameworks.size() == 1) { diff --git a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java index ef291f961544..e61ecbfbe45d 100644 --- a/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java +++ b/java/java-impl/src/com/intellij/testIntegration/TestIntegrationUtils.java @@ -29,17 +29,20 @@ import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.util.classMembers.MemberInfo; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Properties; @@ -234,4 +237,24 @@ public class TestIntegrationUtils { PsiElementFactory f = JavaPsiFacade.getInstance(project).getElementFactory(); return f.createMethod("dummy", PsiType.VOID); } + + public static List findSuitableFrameworks(PsiClass targetClass) { + TestFramework[] frameworks = Extensions.getExtensions(TestFramework.EXTENSION_NAME); + for (TestFramework each : frameworks) { + if (each.isTestClass(targetClass)) { + return Collections.singletonList(each); + } + } + + List result = new SmartList(); + for (TestFramework each : frameworks) { + if (each.isPotentialTestClass(targetClass)) { + result.add(each); + } + } + return result; + } + + private TestIntegrationUtils() { + } } diff --git a/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java b/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java new file mode 100644 index 000000000000..7d8f852942a8 --- /dev/null +++ b/java/java-impl/src/com/intellij/testIntegration/intention/MoveInitializerToSetUpMethodAction.java @@ -0,0 +1,64 @@ +/* + * 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.testIntegration.intention; + +import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.codeInsight.TestFrameworks; +import com.intellij.codeInsight.intention.impl.BaseMoveInitializerToMethodAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.testIntegration.TestIntegrationUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * @author cdr + */ +public class MoveInitializerToSetUpMethodAction extends BaseMoveInitializerToMethodAction { + @Override + @NotNull + public String getFamilyName() { + return getText(); + } + + @Override + @NotNull + public String getText() { + return CodeInsightBundle.message("intention.move.initializer.to.set.up"); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + return super.isAvailable(project, editor, element) && TestIntegrationUtils.isTest(element); + } + + @NotNull + @Override + protected Collection getUnsuitableModifiers() { + return Arrays.asList(PsiModifier.STATIC, PsiModifier.FINAL); + } + + @NotNull + @Override + protected Collection getOrCreateMethods(@NotNull Project project, @NotNull Editor editor, PsiFile file, @NotNull PsiClass aClass) { + final PsiMethod setUpMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(aClass); + return setUpMethod == null ? Collections.emptyList() : Arrays.asList(setUpMethod); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit3.java new file mode 100644 index 000000000000..045691648e20 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterJUnit3.java @@ -0,0 +1,15 @@ +// "Move initializer to setUp method" "true" +package junit.framework; + +public class X extends TestCase { + int i; + + public void setUp() throws Exception { + super.setUp(); + i = 7; + } +} + +//HACK: making test possible without attaching jUnit +public abstract class TestCase { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterTestNG.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterTestNG.java new file mode 100644 index 000000000000..7bfbf5594472 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterTestNG.java @@ -0,0 +1,13 @@ +// "Move initializer to setUp method" "true" +public class X { + int i; + + @org.testng.annotations.BeforeMethod + public void setUp() throws Exception { + i = 7; + } + + @org.testng.annotations.Test + public void test() { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterjUnit4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterjUnit4.java new file mode 100644 index 000000000000..a5288ff2319b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/afterjUnit4.java @@ -0,0 +1,13 @@ +// "Move initializer to setUp method" "true" +public class X { + int i; + + @org.junit.Before + public void setUp() throws Exception { + i = 7; + } + + @org.junit.Test + public void test() { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit3.java new file mode 100644 index 000000000000..931598db8f0f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeJUnit3.java @@ -0,0 +1,10 @@ +// "Move initializer to setUp method" "true" +package junit.framework; + +public class X extends TestCase { + int i = 7; +} + +//HACK: making test possible without attaching jUnit +public abstract class TestCase { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeNotTest.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeNotTest.java new file mode 100644 index 000000000000..ca76098bf11a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeNotTest.java @@ -0,0 +1,4 @@ +// "Move initializer to setUp method" "false" +public class X { + int i = 7; +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeTestNG.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeTestNG.java new file mode 100644 index 000000000000..e10228b207f1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforeTestNG.java @@ -0,0 +1,8 @@ +// "Move initializer to setUp method" "true" +public class X { + int i = 7; + + @org.testng.annotations.Test + public void test() { + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforejUnit4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforejUnit4.java new file mode 100644 index 000000000000..75ca6a7b4354 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp/beforejUnit4.java @@ -0,0 +1,8 @@ +// "Move initializer to setUp method" "true" +public class X { + int i = 7; + + @org.junit.Test + public void test() { + } +} diff --git a/platform/platform-impl/src/com/intellij/platform/DirectoryProjectGeneratorProductAware.java b/java/java-tests/testSrc/com/intellij/codeInsight/intention/MoveInitializerToSetUpMethodActionTest.java similarity index 60% rename from platform/platform-impl/src/com/intellij/platform/DirectoryProjectGeneratorProductAware.java rename to java/java-tests/testSrc/com/intellij/codeInsight/intention/MoveInitializerToSetUpMethodActionTest.java index fbd7de87468c..9cc98f529e13 100644 --- a/platform/platform-impl/src/com/intellij/platform/DirectoryProjectGeneratorProductAware.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/intention/MoveInitializerToSetUpMethodActionTest.java @@ -13,17 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.platform; +package com.intellij.codeInsight.intention; -import org.jetbrains.annotations.NotNull; +import com.intellij.codeInsight.daemon.LightIntentionActionTestCase; /** - * Inheritors of {@link DirectoryProjectGenerator} should implement this interface to be filtered out in some IDE. - * - * @author Sergey Simonchik + * @author ven */ -public interface DirectoryProjectGeneratorProductAware { +public class MoveInitializerToSetUpMethodActionTest extends LightIntentionActionTestCase { + public void test() throws Exception { doAllTests(); } - boolean isSuitableForProduct(@NotNull String productName); + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/moveInitializerToSetUp"; + } } diff --git a/java/openapi/src/com/intellij/codeInsight/AnnotationUtil.java b/java/openapi/src/com/intellij/codeInsight/AnnotationUtil.java index 5907116b7ea3..d3c819519540 100644 --- a/java/openapi/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/openapi/src/com/intellij/codeInsight/AnnotationUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -284,9 +285,10 @@ public class AnnotationUtil { return false; } - public static boolean isAnnotatingApplicable(PsiElement elt) { + public static boolean isAnnotatingApplicable(@NotNull PsiElement elt) { + final Project project = elt.getProject(); return PsiUtil.isLanguageLevel5OrHigher(elt) && - JavaPsiFacade.getInstance(elt.getProject()).findClass(NULLABLE, elt.getResolveScope()) != null; + JavaPsiFacade.getInstance(project).findClass(NullableNotNullManager.getInstance(project).getDefaultNullable(), elt.getResolveScope()) != null; } public static boolean isJetbrainsAnnotation(@NonNls final String simpleName) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuildListener.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuildListener.java new file mode 100644 index 000000000000..41889ae61518 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuildListener.java @@ -0,0 +1,18 @@ +package org.jetbrains.jps.incremental; + +import com.intellij.openapi.util.Pair; + +import java.util.Collection; +import java.util.EventListener; + +/** + * @author Eugene Zhuravlev + * Date: 5/21/12 + */ +public interface BuildListener extends EventListener{ + + /** + * @param paths collection of pairs [output root->relative path to generated file] + */ + void filesGenerated(Collection> paths); +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java index aa154c937595..90bc8c3660a4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/Builder.java @@ -10,4 +10,10 @@ public abstract class Builder { public abstract String getName(); public abstract String getDescription(); + + public void buildStarted(CompileContext compileContext) { + } + + public void buildFinished(CompileContext compileContext) { + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java index 7573f0b1fd79..829950b6ce85 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/BuilderRegistry.java @@ -56,7 +56,7 @@ public class BuilderRegistry { return Collections.unmodifiableList(myModuleLevelBuilders.get(category)); // todo } - public List getAllModuleLevelBuilders() { + public List getModuleLevelBuilders() { return ContainerUtil.concat(myModuleLevelBuilders.values()); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index 178c70d6513d..d5140ce06b0c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -2,6 +2,7 @@ package org.jetbrains.jps.incremental; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.util.EventDispatcher; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.ether.dependencyView.Mappings; @@ -9,6 +10,7 @@ import org.jetbrains.jps.*; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.incremental.fs.RootDescriptor; import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.FileGeneratedEvent; import org.jetbrains.jps.incremental.messages.ProgressMessage; import org.jetbrains.jps.incremental.messages.UptoDateFilesSavedEvent; import org.jetbrains.jps.incremental.storage.BuildDataManager; @@ -43,6 +45,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler private final Map myBuilderParams; private final CanceledStatus myCancelStatus; private float myDone = -1.0f; + private EventDispatcher myListeners = EventDispatcher.create(BuildListener.class); public CompileContext(CompileScope scope, ProjectDescriptor pd, boolean isMake, @@ -92,6 +95,14 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myBuilderParams.get(paramName); } + public void addBuildListener(BuildListener listener) { + myListeners.addListener(listener); + } + + public void removeBuildListener(BuildListener listener) { + myListeners.removeListener(listener); + } + public void markDirty(final File file) throws IOException { final RootDescriptor descriptor = getModuleAndRoot(file); if (descriptor != null) { @@ -290,6 +301,12 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler ((ProgressMessage)msg).setDone(myDone); } myDelegateMessageHandler.processMessage(msg); + if (msg instanceof FileGeneratedEvent) { + final Collection> paths = ((FileGeneratedEvent)msg).getPaths(); + if (!paths.isEmpty()) { + myListeners.getMulticaster().filesGenerated(paths); + } + } } public boolean errorsDetected() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompilerEncodingConfiguration.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompilerEncodingConfiguration.java index 8a10c1a2f14e..c8e699634dd0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompilerEncodingConfiguration.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompilerEncodingConfiguration.java @@ -34,7 +34,7 @@ public class CompilerEncodingConfiguration { private Map> computeModuleCharsetMap() { final Map> map = new THashMap>(); - final List builders = BuilderRegistry.getInstance().getAllModuleLevelBuilders(); + final List builders = BuilderRegistry.getInstance().getModuleLevelBuilders(); for (Map.Entry entry : myFilePathToCharset.entrySet()) { final String filePath = entry.getKey(); final String charset = entry.getValue(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 0d84546cf4f3..8f3b8491ed95 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -10,7 +10,6 @@ import com.intellij.util.io.MappingFailedException; import com.intellij.util.io.PersistentEnumerator; import org.jetbrains.annotations.Nullable; import org.jetbrains.ether.dependencyView.Callbacks; -import org.jetbrains.ether.dependencyView.Mappings; import org.jetbrains.jps.*; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.api.GlobalOptions; @@ -29,9 +28,11 @@ import org.jetbrains.jps.incremental.storage.SourceToOutputMapping; import org.jetbrains.jps.incremental.storage.Timestamps; import org.jetbrains.jps.server.ProjectDescriptor; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.lang.reflect.Field; -import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -193,35 +194,47 @@ public class IncProjectBuilder { private void runBuild(CompileContext context, boolean forceCleanCaches) throws ProjectBuildException { context.setDone(0.0f); - LOG.info("Building project '" + - context.getProject().getProjectName() + - "'; isRebuild:" + - context.isProjectRebuild() + - "; isMake:" + - context.isMake()); + LOG.info("Building project '" + context.getProject().getProjectName() + "'; isRebuild:" + context.isProjectRebuild() + "; isMake:" + context.isMake()); - if (context.isProjectRebuild() || forceCleanCaches) { - cleanOutputRoots(context); + for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) { + builder.buildStarted(context); + } + for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) { + builder.buildStarted(context); } - context.processMessage(new ProgressMessage("Running 'before' tasks")); - runTasks(context, myBuilderRegistry.getBeforeTasks()); + try { + if (context.isProjectRebuild() || forceCleanCaches) { + cleanOutputRoots(context); + } - context.setCompilingTests(false); - context.processMessage(new ProgressMessage("Checking production sources")); - buildChunks(context, myProductionChunks); + context.processMessage(new ProgressMessage("Running 'before' tasks")); + runTasks(context, myBuilderRegistry.getBeforeTasks()); - context.setCompilingTests(true); - context.processMessage(new ProgressMessage("Checking test sources")); - buildChunks(context, myTestChunks); + context.setCompilingTests(false); + context.processMessage(new ProgressMessage("Checking production sources")); + buildChunks(context, myProductionChunks); - context.processMessage(new ProgressMessage("Building project")); - runProjectLevelBuilders(context); + context.setCompilingTests(true); + context.processMessage(new ProgressMessage("Checking test sources")); + buildChunks(context, myTestChunks); - context.processMessage(new ProgressMessage("Running 'after' tasks")); - runTasks(context, myBuilderRegistry.getAfterTasks()); + context.processMessage(new ProgressMessage("Building project")); + runProjectLevelBuilders(context); + + context.processMessage(new ProgressMessage("Running 'after' tasks")); + runTasks(context, myBuilderRegistry.getAfterTasks()); + } + finally { + for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) { + builder.buildFinished(context); + } + for (ModuleLevelBuilder builder : myBuilderRegistry.getModuleLevelBuilders()) { + builder.buildFinished(context); + } + context.processMessage(new ProgressMessage("Finished, saving caches...")); + } - context.processMessage(new ProgressMessage("Finished, saving caches...")); } private CompileContext createContext(CompileScope scope, boolean isMake, final boolean isProjectRebuild) throws ProjectBuildException { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/FileGeneratedEvent.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/FileGeneratedEvent.java index 4b9091d3fdd5..dd052c2c898a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/FileGeneratedEvent.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/FileGeneratedEvent.java @@ -11,7 +11,7 @@ import java.util.Collection; */ public class FileGeneratedEvent extends BuildMessage { - private Collection> myPaths = new ArrayList>(); + private final Collection> myPaths = new ArrayList>(); public FileGeneratedEvent() { super("", Kind.INFO); diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index 386f6abf0b4e..be62585412c8 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -655,6 +655,10 @@ public class Mappings { } void affectAll(final int className, final Collection affectedFiles) { + affectAll(className, affectedFiles, null); + } + + void affectAll(final int className, final Collection affectedFiles, final DependentFilesFilter filter) { final TIntHashSet dependants = myClassToClassDependency.get(className); if (dependants != null) { @@ -665,7 +669,11 @@ public class Mappings { public boolean execute(int depClass) { final int depFile = myClassToSourceFile.get(depClass); if (depFile > 0 && depFile != sourceFile) { - affectedFiles.add(new File(myContext.getValue(depFile))); + final File theFile = new File(myContext.getValue(depFile)); + + if (filter == null || filter.accept(theFile)) { + affectedFiles.add(theFile); + } } return true; } @@ -934,7 +942,7 @@ public class Mappings { if (classes != null) { for (ClassRepr c : classes) { debug("Affecting usages of removed class ", c.name); - u.affectAll(c.name, affectedFiles); + u.affectAll(c.name, affectedFiles, filter); } } } diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java index 4df4ce644252..eb43306a8f80 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/CoreJarHandler.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. @@ -16,6 +16,7 @@ package com.intellij.openapi.vfs.impl.jar; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -35,13 +36,20 @@ public class CoreJarHandler extends JarHandlerBase { Map entries = new HashMap(); - for (EntryInfo info : getEntriesMap().values()) { - getOrCreateFile(info, entries); - } + final Map entriesMap = getEntriesMap(); + if (entriesMap != null) { + for (EntryInfo info : entriesMap.values()) { + getOrCreateFile(info, entries); + } - myRoot = getOrCreateFile(getEntryInfo(""), entries); + myRoot = getOrCreateFile(getEntryInfo(""), entries); + } + else { + myRoot = null; + } } + @NotNull private CoreJarVirtualFile getOrCreateFile(EntryInfo info, Map entries) { CoreJarVirtualFile answer = entries.get(info); if (answer == null) { diff --git a/platform/lang-api/src/com/intellij/ui/FileColorManager.java b/platform/lang-api/src/com/intellij/ui/FileColorManager.java index 4f60564760ab..a51549060430 100644 --- a/platform/lang-api/src/com/intellij/ui/FileColorManager.java +++ b/platform/lang-api/src/com/intellij/ui/FileColorManager.java @@ -42,6 +42,8 @@ public abstract class FileColorManager { public abstract boolean isEnabledForProjectView(); + public abstract Project getProject(); + @SuppressWarnings({"MethodMayBeStatic"}) @Nullable public abstract Color getColor(@NotNull String name); diff --git a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java index 7c67954ae2ae..29d6d25e52d9 100644 --- a/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/TabbedLanguageCodeStylePanel.java @@ -512,7 +512,7 @@ public abstract class TabbedLanguageCodeStylePanel extends CodeStyleAbstractPane super(settings); myProvider = provider; myTopPanel = new JPanel(); - myTopPanel.setLayout(new BorderLayout()); + myTopPanel.setLayout(new BorderLayout(8, 0)); myLeftPanel = new JPanel(new BorderLayout()); myTopPanel.add(myLeftPanel, BorderLayout.WEST); myRightPanel = new JPanel(); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java index 028af62d9e17..69910417c7f3 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java @@ -207,9 +207,7 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr } protected static JPanel createPreviewPanel() { - JPanel panel = new JPanel(new BorderLayout()); - panel.setPreferredSize(new Dimension(200, 0)); - return panel; + return new JPanel(new BorderLayout()); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java index 12cc00f51182..4719872ddb7e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java @@ -75,16 +75,19 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle initTables(); myTreeTable = createOptionsTree(getSettings()); - JBScrollPane scrollPane = new JBScrollPane(myTreeTable); - scrollPane.setPreferredSize(new Dimension(400, -1)); - scrollPane.setMinimumSize(new Dimension(400, -1)); + JBScrollPane scrollPane = new JBScrollPane(myTreeTable) { + @Override + public Dimension getMinimumSize() { + return super.getPreferredSize(); + } + }; myPanel.add(scrollPane - , new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 5), 0, 0)); + , new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, + new Insets(0, 0, 0, 8), 0, 0)); final JPanel previewPanel = createPreviewPanel(); myPanel.add(previewPanel, - new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, + new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); installPreviewPanel(previewPanel); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTreeWithPreviewPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTreeWithPreviewPanel.java index 7f6bb64b0fe8..a53a19ea4d7a 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTreeWithPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTreeWithPreviewPanel.java @@ -20,7 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.CustomCodeStyleSettings; -import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.UIUtil; @@ -69,17 +69,20 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA myOptionsTree = createOptionsTree(); myOptionsTree.setCellRenderer(new MyTreeCellRenderer()); - JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myOptionsTree); - scrollPane.setPreferredSize(new Dimension(350, -1)); - scrollPane.setMinimumSize(new Dimension(350, -1)); + JScrollPane scrollPane = new JBScrollPane(myOptionsTree) { + @Override + public Dimension getMinimumSize() { + return super.getPreferredSize(); + } + }; myPanel.add(scrollPane, - new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 5), 0, 0)); + new GridBagConstraints(0, 0, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, + new Insets(0, 0, 0, 8), 0, 0)); JPanel previewPanel = createPreviewPanel(); myPanel.add(previewPanel, - new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, + new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); installPreviewPanel(previewPanel); @@ -421,6 +424,7 @@ public abstract class OptionTreeWithPreviewPanel extends MultilanguageCodeStyleA else { myLabel.setText(value.toString()); myLabel.setFont(myLabel.getFont().deriveFont(Font.BOLD)); + myLabel.setOpaque(true); if (isSelected) { myLabel.setForeground(UIUtil.getTreeSelectionForeground()); diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationAction.java index c88e23c72cd2..91fe8164e25b 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationAction.java @@ -451,10 +451,10 @@ public class ChooseRunConfigurationAction extends AnAction { final RunnerAndConfigurationSettings selectedConfiguration = manager.getSelectedConfiguration(); final Map wrappedExisting = new LinkedHashMap(); - final ConfigurationType[] factories = manager.getConfigurationFactories(); - for (final ConfigurationType factory : factories) { - if (!(factory instanceof UnknownConfigurationType)) { - final RunnerAndConfigurationSettings[] configurations = manager.getConfigurationSettings(factory); + final ConfigurationType[] types = manager.getConfigurationFactories(); + for (final ConfigurationType type : types) { + if (!(type instanceof UnknownConfigurationType)) { + final RunnerAndConfigurationSettings[] configurations = manager.getConfigurationSettings(type); for (final RunnerAndConfigurationSettings configuration : configurations) { final ItemWrapper wrapped = ItemWrapper.wrap(project, configuration); if (configuration == selectedConfiguration) { diff --git a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationAction.java b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationAction.java index 862790d02294..006f4060141b 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationAction.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationAction.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.util.ArrayList; public class RunConfigurationAction extends ComboBoxAction implements DumbAware { private static final Logger LOG = Logger.getInstance("#com.intellij.execution.actions.RunConfigurationAction"); @@ -153,7 +154,16 @@ public class RunConfigurationAction extends ComboBoxAction implements DumbAware for (ConfigurationType type : types) { final DefaultActionGroup actionGroup = new DefaultActionGroup(); final RunnerAndConfigurationSettings[] configurations = runManager.getConfigurationSettings(type); - for (final RunnerAndConfigurationSettings configuration : configurations) { + ArrayList configurationSettingsList = new ArrayList(); + int i = 0; + for (RunnerAndConfigurationSettings configuration : configurations) { + if (configuration.isTemporary()) { + configurationSettingsList.add(configuration); + } else { + configurationSettingsList.add(i++, configuration); + } + } + for (final RunnerAndConfigurationSettings configuration : configurationSettingsList) { //if (runManager.canRunConfiguration(configuration)) { final MenuAction action = new MenuAction(configuration, project); actionGroup.add(action); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java index 484cb35ac961..ccabac77a2d4 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ExecutionManagerImpl.java @@ -106,6 +106,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom if (!activeTasks.isEmpty()) { ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + /** @noinspection SSBasedInspection*/ public void run() { for (BeforeRunTask task : activeTasks) { BeforeRunTaskProvider provider = BeforeRunTaskProvider.getProvider(myProject, task.getProviderId()); @@ -116,7 +117,16 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom return; } } - DumbService.getInstance(myProject).smartInvokeLater(startRunnable); + // important! Do not use DumbService.smartInvokelater here because it depends on modality state + // and execution of startRunnable could be skipped if modality state check fails + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (!myProject.isDisposed()) { + DumbService.getInstance(myProject).runWhenSmart(startRunnable); + } + } + }); } }); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java index 81395baa3f15..6f798533f6ff 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java @@ -236,7 +236,7 @@ class RunConfigurable extends BaseConfigurable { ConfigurationFactory[] factories = type.getConfigurationFactories(); if (factories.length == 1) { final ConfigurationFactory factory = factories[0]; - showTemplateConfigurabel(factory); + showTemplateConfigurable(factory); } else { drawPressAddButtonMessage((ConfigurationType)userObject); @@ -244,7 +244,7 @@ class RunConfigurable extends BaseConfigurable { } } else if (userObject instanceof ConfigurationFactory) { - showTemplateConfigurabel((ConfigurationFactory)userObject); + showTemplateConfigurable((ConfigurationFactory)userObject); } } } @@ -290,7 +290,7 @@ class RunConfigurable extends BaseConfigurable { ((DefaultTreeModel)myTree.getModel()).reload(); } - private void showTemplateConfigurabel(ConfigurationFactory factory) { + private void showTemplateConfigurable(ConfigurationFactory factory) { Configurable configurable = myStoredComponents.get(factory); if (configurable == null){ configurable = new TemplateConfigurable(RunManagerImpl.getInstanceImpl(myProject).getConfigurationTemplate(factory)); @@ -1123,16 +1123,36 @@ class RunConfigurable extends BaseConfigurable { final TreePath selectionPath = myTree.getSelectionPath(); if (selectionPath != null) { final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)selectionPath.getLastPathComponent(); - if (!(treeNode.getUserObject() instanceof ConfigurationType)) { + if (!(treeNode.getUserObject() instanceof ConfigurationType) && !(treeNode.getUserObject() instanceof String)) { + RunnerAndConfigurationSettings selectedSettings = getSettings(treeNode); + if (selectedSettings == null) + return; + RunnerAndConfigurationSettings siblingSettings = null; if (myDirection < 0) { - presentation.setEnabled(treeNode.getPreviousSibling() != null); + siblingSettings = getSettings(treeNode.getPreviousSibling()); + } else { + siblingSettings = getSettings(treeNode.getNextSibling()); } - else { - presentation.setEnabled(treeNode.getNextSibling() != null); + if (siblingSettings != null) { + presentation.setEnabled(siblingSettings.isTemporary() == selectedSettings.isTemporary()); } } } } + + @Nullable + private RunnerAndConfigurationSettings getSettings(DefaultMutableTreeNode treeNode) { + if (treeNode == null) + return null; + RunnerAndConfigurationSettings settings = null; + if (treeNode.getUserObject() instanceof SingleConfigurationConfigurable) { + settings = (RunnerAndConfigurationSettings)((SingleConfigurationConfigurable)treeNode.getUserObject()).getSettings(); + } + if (treeNode.getUserObject() instanceof RunnerAndConfigurationSettings) { + settings = (RunnerAndConfigurationSettings)treeNode.getUserObject(); + } + return settings; + } } private static class RunConfigurationBean { diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java index 2b9637df0b3e..6fbf4652024e 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java @@ -213,16 +213,17 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, /** * Template configuration is not included */ + @NotNull public RunnerAndConfigurationSettings[] getConfigurationSettings(@NotNull final ConfigurationType type) { - final LinkedHashSet array = new LinkedHashSet(); + final LinkedHashSet set = new LinkedHashSet(); for (RunnerAndConfigurationSettings configuration : getSortedConfigurations()) { final ConfigurationType configurationType = configuration.getType(); if (configurationType != null && type.getId().equals(configurationType.getId())) { - array.add(configuration); + set.add(configuration); } } - return array.toArray(new RunnerAndConfigurationSettings[array.size()]); + return set.toArray(new RunnerAndConfigurationSettings[set.size()]); } public RunnerAndConfigurationSettings getConfigurationTemplate(final ConfigurationFactory factory) { @@ -257,6 +258,8 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, mySharedConfigurations.put(newId, shared); setBeforeRunTasks(configuration, tasks, addEnabledTemplateTasksIfAbsent); + saveOrder(); + myOrdered = false; if (existingSettings == settings) { myDispatcher.getMulticaster().runConfigurationChanged(settings); @@ -354,7 +357,13 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, Collections.sort(order, new Comparator>() { @Override public int compare(Pair o1, Pair o2) { - return o1.first.compareTo(o2.first); + boolean temporary1 = o1.getSecond().isTemporary(); + boolean temporary2 = o2.getSecond().isTemporary(); + if (temporary1 == temporary2) { + return o1.first.compareTo(o2.first); + } else { + return temporary1 ? 1 : -1; + } } }); } @@ -362,7 +371,13 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, Collections.sort(order, new Comparator>() { @Override public int compare(Pair o1, Pair o2) { - return myOrder.indexOf(o1.first) - myOrder.indexOf(o2.first); + boolean temporary1 = o1.getSecond().isTemporary(); + boolean temporary2 = o2.getSecond().isTemporary(); + if (temporary1 == temporary2) { + return myOrder.indexOf(o1.first) - myOrder.indexOf(o2.first); + } else { + return temporary1 ? 1 : -1; + } } }); } @@ -923,11 +938,13 @@ public class RunManagerImpl extends RunManagerEx implements JDOMExternalizable, } public void fireRunConfigurationChanged(@NotNull RunnerAndConfigurationSettings settings) { + myOrdered = false; invalidateConfigurationIcon(settings); myDispatcher.getMulticaster().runConfigurationChanged(settings); } private void fireRunConfigurationsRemoved(@NotNull List removed) { + myOrdered = false; for (RunnerAndConfigurationSettings settings : removed) { myDispatcher.getMulticaster().runConfigurationRemoved(settings); } diff --git a/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java b/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java index bfe3145039dc..41c51522bf43 100644 --- a/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java +++ b/platform/lang-impl/src/com/intellij/ide/bookmarks/BookmarkItem.java @@ -105,6 +105,7 @@ public class BookmarkItem implements ItemWrapper { } public void execute(Project project, JBPopup popup) { + popup.cancel(); myBookmark.navigate(); } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java index 6d2cef1cf7a6..70ed0e4ab00e 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/AllFileTemplatesConfigurable.java @@ -534,21 +534,20 @@ public class AllFileTemplatesConfigurable implements SearchableConfigurable, Con if (myEditor != null) { myModified = false; fireListChanged(); - reset(); } } public void reset() { myEditor.reset(); initLists(); - final PropertiesComponent component = PropertiesComponent.getInstance(); - final String tabName = component.getValue(CURRENT_TAB); + final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(); + final String tabName = propertiesComponent.getValue(CURRENT_TAB); int idx = 0; for (FileTemplateTab tab : myTabs) { if (Comparing.strEqual(tab.getTitle(), tabName)) { myCurrentTab = tab; myTabbedPane.setSelectedIndex(idx); - final String selectedTemplateName = component.getValue(SELECTED_TEMPLATE); + final String selectedTemplateName = propertiesComponent.getValue(SELECTED_TEMPLATE); final FileTemplate[] templates = myCurrentTab.getTemplates(); for (FileTemplate template : templates) { if (Comparing.strEqual(template.getName(), selectedTemplateName)) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index c3c45db3336f..37a1d1b304d5 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -204,7 +204,7 @@ public class FileStructurePopup implements Disposable { }; //myAbstractTreeBuilder.getUi().setPassthroughMode(true); - myAbstractTreeBuilder.getUi().getUpdater().setDelay(1); + myAbstractTreeBuilder.getUi().getUpdater().setDelay(0); myInitialPsiElement = getCurrentElement(getPsiFile(myProject)); //myAbstractTreeBuilder.setCanYieldUpdate(true); Disposer.register(this, myAbstractTreeBuilder); diff --git a/platform/lang-impl/src/com/intellij/ide/util/projectWizard/WebModuleGenerationStep.java b/platform/lang-impl/src/com/intellij/ide/util/projectWizard/WebModuleGenerationStep.java new file mode 100644 index 000000000000..e30bd321aa89 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/util/projectWizard/WebModuleGenerationStep.java @@ -0,0 +1,266 @@ +/* + * 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.ide.util.projectWizard; + +import com.google.common.collect.Maps; +import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.platform.DirectoryProjectGenerator; +import com.intellij.platform.WebProjectGenerator; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.io.File; +import java.util.Map; + +/** + * @author Sergey Simonchik + */ +public class WebModuleGenerationStep extends ModuleWizardStep { + + private final ModuleBuilder myModuleBuilder; + private final Icon myIcon; + private final String myHelpId; + private final Map myGeneratorPeers = Maps.newHashMap(); + private JComponent myRootComponent; + private WebProjectGenerator myCurrentGenerator; + private JPanel myRightPanel; + + public WebModuleGenerationStep(ModuleBuilder moduleBuilder, @NotNull Icon icon, @NotNull String helpId) { + myModuleBuilder = moduleBuilder; + myIcon = icon; + myHelpId = helpId; + } + + @Override + public JComponent getComponent() { + if (myRootComponent == null) { + myRootComponent = createComponent(); + } + return myRootComponent; + } + + @NotNull + private JComponent createComponent() { + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + final JList generatorList = new JBList(); + + DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME); + DefaultListModel listModel = new DefaultListModel(); + + EmptyProjectGenerator emptyProjectGenerator = new EmptyProjectGenerator(); + listModel.addElement(emptyProjectGenerator); + for (DirectoryProjectGenerator generator : generators) { + if (generator instanceof WebProjectGenerator) { + listModel.addElement(generator); + } + } + generatorList.setModel(listModel); + generatorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + generatorList.setCellRenderer(new ListCellRendererWrapper(generatorList.getCellRenderer()) { + @Override + public void customize(JList list, + DirectoryProjectGenerator value, + int index, + boolean selected, + boolean hasFocus) { + setText(" " + value.getName()); + } + }); + generatorList.addListSelectionListener(new ListSelectionListener() { + @SuppressWarnings({"HardCodedStringLiteral"}) + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + @SuppressWarnings("unchecked") + WebProjectGenerator selectedGenerator = + (WebProjectGenerator) generatorList.getSelectedValue(); + myCurrentGenerator = selectedGenerator; + showGenerator(selectedGenerator); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + generatorList.requestFocusInWindow(); + } + }); + } + }); + + JPanel leftPanel = createLeftPanel(generatorList); + splitPane.setLeftComponent(leftPanel); + myRightPanel = new JPanel(new CardLayout()); + splitPane.setRightComponent(myRightPanel); + + generatorList.setSelectedValue(emptyProjectGenerator, true); + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + generatorList.requestFocusInWindow(); + } + }, ModalityState.any()); + return splitPane; + } + + private void showGenerator(@NotNull WebProjectGenerator generator) { + WebProjectGenerator.GeneratorPeer peer = myGeneratorPeers.get(generator); + if (peer == null) { + peer = generator.createPeer(); + JComponent component = peer.getComponent(); + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 25)); + panel.add(component); + myRightPanel.add(panel, generator.getName()); + myRightPanel.revalidate(); + myRightPanel.repaint(); + myGeneratorPeers.put(generator, peer); + } + CardLayout cardLayout = (CardLayout) myRightPanel.getLayout(); + cardLayout.show(myRightPanel, generator.getName()); + } + + @NotNull + private static JPanel createLeftPanel(@NotNull JList generatorList) { + JPanel panel = new JPanel(); + LayoutManager boxLayoutManager = new BoxLayout(panel, BoxLayout.Y_AXIS); + panel.setLayout(boxLayoutManager); + JLabel label = new JLabel("Select Web Module Type:"); + panel.add(label, Component.LEFT_ALIGNMENT); + label.setAlignmentX(Component.LEFT_ALIGNMENT); + panel.add(Box.createVerticalStrut(5)); + JBScrollPane scrollPane = new JBScrollPane( + generatorList, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED + ); + Dimension listPrefSize = calcTypeListPreferredSize(generatorList); + scrollPane.setPreferredSize(listPrefSize); + panel.add(scrollPane, Component.LEFT_ALIGNMENT); + scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT); + return panel; + } + + @NotNull + private static Dimension calcTypeListPreferredSize(@NotNull JList list) { + FontMetrics fontMetrics = list.getFontMetrics(list.getFont()); + int fontHeight = fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent(); + int width = 0; + int height = 0; + ListModel listModel = list.getModel(); + int size = listModel.getSize(); + for (int i = 0; i < size; i++) { + DirectoryProjectGenerator generator = (DirectoryProjectGenerator) listModel.getElementAt(i); + height += fontHeight + 6; + width = Math.max(width, fontMetrics.stringWidth(generator.getName())); + } + return new Dimension(width, height); + } + + @Override + public boolean validate() throws ConfigurationException { + if (myCurrentGenerator == null) { + throw new RuntimeException("Current generator should be not-null"); + } + WebProjectGenerator.GeneratorPeer peer = myGeneratorPeers.get(myCurrentGenerator); + if (peer == null) { + throw new ConfigurationException("Peer should be not-null for " + myCurrentGenerator.getName()); + } + return peer.validate() == null; + } + + @SuppressWarnings("unchecked") + @Override + public void updateDataModel() { + WebProjectGenerator generator = myCurrentGenerator; + if (generator == null) { + throw new RuntimeException("Current generator should be not-null"); + } + WebProjectGenerator.GeneratorPeer peer = myGeneratorPeers.get(myCurrentGenerator); + if (peer == null) { + throw new RuntimeException("Peer should be not-null for " + myCurrentGenerator.getName()); + } + Object settings = peer.getSettings(); + File dir = new File(myModuleBuilder.getModuleFileDirectory()); + VirtualFile moduleDir = LocalFileSystem.getInstance().findFileByIoFile(dir); + if (moduleDir == null || !moduleDir.isValid()) { + moduleDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir); + } + if (moduleDir != null && moduleDir.isValid()) { + generator.generateProject(null, moduleDir, settings, null); + } + } + + public Icon getIcon() { + return myIcon; + } + + @Override + public String getHelpId() { + return myHelpId; + } + + private static class EmptyProjectGenerator extends WebProjectGenerator { + @Nls + @Override + public String getName() { + return "Empty module"; + } + + @Override + public void generateProject(Project project, VirtualFile baseDir, Object settings, Module module) {} + + @NotNull + @Override + public WebProjectGenerator.GeneratorPeer createPeer() { + return new WebProjectGenerator.GeneratorPeer() { + + @NotNull + @Override + public JComponent getComponent() { + return new JLabel("No extra files will be created."); + } + + @NotNull + @Override + public Object getSettings() { + return new Object(); + } + + @Override + @Nullable + public ValidationInfo validate() { + return null; + } + + @Override + public void addSettingsStateListener(@NotNull WebProjectGenerator.SettingsStateListener listener) {} + }; + } + } + +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java index e485a409421e..f74567aa4221 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java +++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java @@ -19,7 +19,6 @@ import com.intellij.ide.DataManager; import com.intellij.ide.IdeBundle; import com.intellij.ide.favoritesTreeView.FavoritesManager; import com.intellij.ide.projectView.impl.AbstractUrl; -import com.intellij.ide.ui.ListCellRendererWrapper; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -46,6 +45,8 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.ComboboxWithBrowseButton; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.TitledSeparator; import com.intellij.usages.Usage; import com.intellij.usages.UsageView; import com.intellij.usages.UsageViewManager; @@ -102,12 +103,7 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo myValidationManager.addScopeListener(myScopeListener); addActionListener(createScopeChooserListener()); - combo.setRenderer(new ListCellRendererWrapper(combo.getRenderer()) { - @Override - public void customize(final JList list, final ScopeDescriptor value, final int index, final boolean selected, final boolean hasFocus) { - if (value != null) setText(value.getDisplay()); - } - }); + combo.setRenderer(new ScopeDescriptionWithDelimiterRenderer()); rebuildModel(); @@ -166,20 +162,39 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo DefaultComboBoxModel model = new DefaultComboBoxModel(); createPredefinedScopeDescriptors(model); + boolean firstInGroup = true; List changeLists = ChangeListsScopesProvider.getInstance(myProject).getCustomScopes(); for (NamedScope changeListScope : changeLists) { - model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, changeListScope))); + model.addElement(new ScopeDescriptionWithDelimiter(GlobalSearchScopes.filterScope(myProject, changeListScope), firstInGroup ? "VCS" : null)); + firstInGroup = false; } + + firstInGroup = true; final NamedScopesHolder[] holders = NamedScopesHolder.getAllNamedScopeHolders(myProject); for (NamedScopesHolder holder : holders) { NamedScope[] scopes = holder.getEditableScopes(); //predefined scopes already included for (NamedScope scope : scopes) { - model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, scope))); + model.addElement(new ScopeDescriptionWithDelimiter(GlobalSearchScopes.filterScope(myProject, scope), firstInGroup ? "Custom scopes" : null)); + firstInGroup = false; } } return model; } + + private static class ScopeDescriptionWithDelimiter extends ScopeDescriptor { + + private String mySeparatorAbove; + + public ScopeDescriptionWithDelimiter(SearchScope scope, String separatorAbove) { + super(scope); + mySeparatorAbove = separatorAbove; + } + + public String getSeparatorAbove() { + return mySeparatorAbove; + } + } @Override public Dimension getPreferredSize() { @@ -416,4 +431,27 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo if (idx < 0) return null; return ((ScopeDescriptor)combo.getSelectedItem()).getDisplay(); } + + private static class ScopeDescriptionWithDelimiterRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + final JComponent component = (JComponent)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setText(((ScopeDescriptor)value).getDisplay()); + + if (value instanceof ScopeDescriptionWithDelimiter && index >= 0) { + final String separatorAbove = ((ScopeDescriptionWithDelimiter)value).getSeparatorAbove(); + if (separatorAbove != null) { + JPanel panel = new JPanel(new BorderLayout()); + final TitledSeparator comp = new TitledSeparator(separatorAbove); + panel.add(comp, BorderLayout.NORTH); + component.setBorder(IdeBorderFactory.createEmptyBorder(0, 2, 0, 0)); + panel.add(component, BorderLayout.CENTER); + return panel; + } + } + setBorder(IdeBorderFactory.createEmptyBorder(0, 2, 0, 0)); + + return component; + } + } } diff --git a/platform/lang-impl/src/com/intellij/openapi/module/WebModuleType.java b/platform/lang-impl/src/com/intellij/openapi/module/WebModuleType.java index f53bfa74482f..426686827d0e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/WebModuleType.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/WebModuleType.java @@ -1,8 +1,12 @@ package com.intellij.openapi.module; import com.intellij.ide.util.projectWizard.ModuleBuilder; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.WebModuleGenerationStep; +import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import org.jetbrains.annotations.NotNull; /** @@ -14,6 +18,16 @@ public class WebModuleType extends WebModuleTypeBase { return (WebModuleType)ModuleTypeManager.getInstance().findByID(WEB_MODULE); } + @Override + public ModuleWizardStep[] createWizardSteps(WizardContext wizardContext, ModuleBuilder moduleBuilder, ModulesProvider modulesProvider) { + WebModuleGenerationStep generationStep = new WebModuleGenerationStep( + moduleBuilder, + wizardContext.getStepIcon(), + "reference.dialogs.new.project.fromScratch.webModuleGeneration" + ); + return new ModuleWizardStep[]{generationStep}; + } + public ModuleBuilder createModuleBuilder() { return new ModuleBuilder() { @Override diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/actions/DependenciesHandlerBase.java b/platform/lang-impl/src/com/intellij/packageDependencies/actions/DependenciesHandlerBase.java index 91ae54a9da02..5c443d98eedc 100644 --- a/platform/lang-impl/src/com/intellij/packageDependencies/actions/DependenciesHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/packageDependencies/actions/DependenciesHandlerBase.java @@ -50,9 +50,6 @@ public abstract class DependenciesHandlerBase { public void analyze() { final List builders = new ArrayList(); - for (AnalysisScope scope : myScopes) { - builders.add(createDependenciesBuilder(scope)); - } final Task task; if (canStartInBackground()) { @@ -95,7 +92,10 @@ public abstract class DependenciesHandlerBase { protected abstract DependenciesBuilder createDependenciesBuilder(AnalysisScope scope); - private static void perform(List builders) { + private void perform(List builders) { + for (AnalysisScope scope : myScopes) { + builders.add(createDependenciesBuilder(scope)); + } for (DependenciesBuilder builder : builders) { builder.analyze(); } diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java index 79dd21586975..112b70c17b3b 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.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. @@ -20,12 +20,14 @@ import com.intellij.notification.impl.ui.StickyButton; import com.intellij.notification.impl.ui.StickyButtonUI; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; import com.intellij.ui.ColorChooser; import com.intellij.ui.ColorUtil; +import com.intellij.ui.FileColorManager; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; @@ -46,12 +48,12 @@ import java.util.List; public class FileColorConfigurationEditDialog extends DialogWrapper { private FileColorConfiguration myConfiguration; private JComboBox myScopeComboBox; - private final FileColorManagerImpl myManager; + private final FileColorManager myManager; private HashMap myColorToButtonMap; private static final String CUSTOM_COLOR_NAME = "Custom"; private final Map myScopeNames = new HashMap(); - public FileColorConfigurationEditDialog(@NotNull final FileColorManagerImpl manager, @Nullable final FileColorConfiguration configuration) { + public FileColorConfigurationEditDialog(@NotNull final FileColorManager manager, @Nullable final FileColorConfiguration configuration) { super(true); setTitle(configuration == null ? "Add color label" : "Edit color label"); @@ -62,9 +64,16 @@ public class FileColorConfigurationEditDialog extends DialogWrapper { init(); updateCustomButton(); + if (myConfiguration != null && !StringUtil.isEmpty(myConfiguration.getScopeName())) { + myScopeComboBox.setSelectedItem(myConfiguration.getScopeName()); + } updateOKButton(); } + public JComboBox getScopeComboBox() { + return myScopeComboBox; + } + @Override protected JComponent createNorthPanel() { final JPanel result = new JPanel(); diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorSettingsTable.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorSettingsTable.java index 98e2083d496b..f984c4d09ccd 100644 --- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorSettingsTable.java +++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorSettingsTable.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. @@ -31,6 +31,7 @@ import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import java.awt.*; import java.util.ArrayList; +import java.util.EventObject; import java.util.List; /** @@ -42,9 +43,11 @@ public abstract class FileColorSettingsTable extends JBTable { private static final int COLOR_COLUMN = 1; private final List myOriginal; + @NotNull private final FileColorManager myManager; public FileColorSettingsTable(@NotNull final FileColorManager manager, @NotNull final List configurations) { super(new ModelAdapter(manager, copy(configurations))); + myManager = manager; setStriped(true); myOriginal = configurations; @@ -78,6 +81,20 @@ public abstract class FileColorSettingsTable extends JBTable { return (ModelAdapter) super.getModel(); } + @Override + public boolean editCellAt(int row, int column, EventObject e) { + final Object at = getModel().getValueAt(row, column); + final FileColorConfigurationEditDialog dialog = new FileColorConfigurationEditDialog(myManager, ((FileColorConfiguration)at)); + dialog.getScopeComboBox().setEnabled(false); + dialog.show(); + return false; + } + + @Override + public boolean isCellEditable(int row, int column) { + return column == 1; + } + public boolean isModified() { final List current = getModel().getConfigurations(); diff --git a/platform/platform-api/src/com/intellij/ui/table/TableView.java b/platform/platform-api/src/com/intellij/ui/table/TableView.java index 3bc11c1f33c4..4e3767db2567 100644 --- a/platform/platform-api/src/com/intellij/ui/table/TableView.java +++ b/platform/platform-api/src/com/intellij/ui/table/TableView.java @@ -90,6 +90,13 @@ public class TableView extends BaseTableView implements ItemsProvider, Sel final RowSorter sorter = getRowSorter(); final List current = sorter == null ? null : sorter.getSortKeys(); ColumnInfo[] columns = getListTableModel().getColumnInfos(); + int[] sizeMode = new int[columns.length]; + int[] widths = new int[columns.length]; + int fixedWidth = 0; + int varWidth = 0; + int varCount = 0; + + // calculate for (int i = 0; i < columns.length; i++) { final ColumnInfo columnInfo = columns[i]; final TableColumn column = getColumnModel().getColumn(i); @@ -108,21 +115,51 @@ public class TableView extends BaseTableView implements ItemsProvider, Sel final String maxStringValue; final String preferredValue; if (columnInfo.getWidth(this) > 0) { + sizeMode[i] = 0; int width = columnInfo.getWidth(this); - column.setMaxWidth(width); - column.setPreferredWidth(width); - column.setMinWidth(width); + widths[i] = width; } else if ((maxStringValue = columnInfo.getMaxStringValue(this)) != null) { + sizeMode[i] = 1; int width = getFontMetrics(getFont()).stringWidth(maxStringValue) + columnInfo.getAdditionalWidth(); width = Math.max(width, headerSize.width); + widths[i] = width; + varCount ++; + } + else if ((preferredValue = columnInfo.getPreferredStringValue()) != null) { + sizeMode[i] = 2; + int width = getFontMetrics(getFont()).stringWidth(preferredValue) + columnInfo.getAdditionalWidth(); + width = Math.max(width, headerSize.width); + widths[i] = width; + varCount ++; + } + if (sizeMode[i] == 0) { + fixedWidth += widths[i]; + } + else { + varWidth += widths[i]; + } + } + + // apply + int viewWidth = getParent() != null? getParent().getWidth() : getWidth(); + int addendum = varCount > 0 && viewWidth > fixedWidth + varWidth? (viewWidth - fixedWidth - varWidth) / varCount : 0; + for (int i=0 ; i 'Add Module...' -> 'Web Module') + * and to small IDE (PhpStorm, WebStorm etc. available via File -> 'New Project...'). + * + * @author Sergey Simonchik + */ +public abstract class WebProjectGenerator implements DirectoryProjectGenerator { + + @Nls + @Override + public abstract String getName(); + + @Override + @Nullable + public final T showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException { + GeneratorPeer peer = createPeer(); + DialogWrapper dialog = new MyDialogWrapper(peer); + dialog.show(); + if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { + throw new ProcessCanceledException(); + } + return peer.getSettings(); + } + + @Override + public abstract void generateProject(Project project, VirtualFile baseDir, T settings, Module module); + + /** + * Always returns {@link ValidationResult#OK}. + * Real validation should be done in {@link WebProjectGenerator.GeneratorPeer#validate()}. + */ + @NotNull + @Override + public final ValidationResult validate(@NotNull String baseDirPath) { + return ValidationResult.OK; + } + + @NotNull + public abstract GeneratorPeer createPeer(); + + public interface GeneratorPeer { + @NotNull + JComponent getComponent(); + + @NotNull + T getSettings(); + + @Nullable + ValidationInfo validate(); + + void addSettingsStateListener(@NotNull SettingsStateListener listener); + } + + public interface SettingsStateListener { + void stateChanged(boolean validSettings); + } + + private class MyDialogWrapper extends DialogWrapper { + + private final GeneratorPeer myPeer; + private final JComponent myCenterComponent; + + protected MyDialogWrapper(@NotNull GeneratorPeer peer) { + super(true); + myPeer = peer; + myCenterComponent = peer.getComponent(); + getOKAction().setEnabled(peer.validate() == null); + peer.addSettingsStateListener(new SettingsStateListener() { + @Override + public void stateChanged(boolean validSettings) { + getOKAction().setEnabled(validSettings); + } + }); + setTitle(WebProjectGenerator.this.getName()); + init(); + } + + @Override + protected ValidationInfo doValidate() { + return myPeer.validate(); + } + + @Override + protected JComponent createCenterPanel() { + return myCenterComponent; + } + } + +} diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 44959f82bda1..701d9da115bc 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -390,6 +390,7 @@ inspection.i18n.option.ignore.comment.title=Non-Nls comment pattern inspection.i18n.option.ignore.assigned.to.constants=Ignore literals assigned to constants inspection.i18n.option.ignore.tostring=Ignore contents of toString() method intention.move.initializer.to.constructor=Move initializer to constructor +intention.move.initializer.to.set.up=Move initializer to setUp method intention.move.field.assignment.to.declaration=Move assignment to field declaration i18nize.jsp.error=Please select JSP text to I18nize.\nMake sure you have not selected any scriptlets, custom tags or other foreign languages elements.\nAlso, HTML tags inside selection must be balanced. i18nize.error.title=Cannot I18nize Selection diff --git a/platform/testFramework/src/com/intellij/mock/MockRunManager.java b/platform/testFramework/src/com/intellij/mock/MockRunManager.java index 481ef662723b..450d8b68ba4f 100644 --- a/platform/testFramework/src/com/intellij/mock/MockRunManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockRunManager.java @@ -67,6 +67,7 @@ public class MockRunManager extends RunManagerEx { } @Override + @NotNull public RunnerAndConfigurationSettings[] getConfigurationSettings(@NotNull ConfigurationType type) { return new RunnerAndConfigurationSettings[0]; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java index af8df2800988..59fb55db18a5 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java +++ b/plugins/android-designer/src/com/intellij/android/designer/componentTree/AndroidTreeDecorator.java @@ -75,7 +75,9 @@ public final class AndroidTreeDecorator extends TreeComponentDecorator { } } - renderer.append(fullTitle.toString()); + if (fullTitle.length() > 0) { + renderer.append(fullTitle.toString()); + } if (full) { renderer.setIcon(metaModel.getIcon()); diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index ef29c4f42c0d..f1d5ed58e131 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -442,7 +442,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { public RadComponent create() throws Exception { RadViewComponent component = ModelParser.createComponent(null, paletteItem.getMetaModel()); if (component instanceof IConfigurableComponent) { - ((IConfigurableComponent)component).configure(getModule()); + ((IConfigurableComponent)component).configure(myRootComponent); } return component; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java index 9ec0fb74ed12..fbde0ea1ede3 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/IConfigurableComponent.java @@ -15,11 +15,11 @@ */ package com.intellij.android.designer.model; -import com.intellij.openapi.module.Module; +import com.intellij.designer.model.RadComponent; /** * @author Alexander Lobas */ public interface IConfigurableComponent { - void configure(Module module) throws Exception; + void configure(RadComponent rootComponent) throws Exception; } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/IdManager.java b/plugins/android-designer/src/com/intellij/android/designer/model/IdManager.java index 24230a323810..8cc797b8ee94 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/IdManager.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/IdManager.java @@ -55,9 +55,9 @@ public class IdManager { } public void removeComponent(RadViewComponent component, boolean withChildren) { - String id = component.getId(); - if (id != null) { - myIdList.remove(id); + String idValue = parseIdValue(component.getId()); + if (idValue != null) { + myIdList.remove(idValue); } if (withChildren) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java index b1740fe9f251..c0312cdf44ac 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java @@ -93,7 +93,7 @@ public class ModelParser extends XmlRecursiveElementVisitor { try { MetaModel metaModel = myMetaManager.getModelByTag(tag.getName()); if (metaModel == null) { - metaModel = myMetaManager.getModelByTag(""); + metaModel = myMetaManager.getModelByTag("view"); } RadViewComponent component = createComponent(tag, metaModel); @@ -199,7 +199,7 @@ public class ModelParser extends XmlRecursiveElementVisitor { for (XmlTag tag : parentComponent.getTag().getSubTags()) { MetaModel metaModel = metaManager.getModelByTag(tag.getName()); if (metaModel == null) { - metaModel = metaManager.getModelByTag(""); + metaModel = metaManager.getModelByTag("view"); } RadViewComponent component = createComponent(tag, metaModel); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java index 839ca8aca0de..8566e60491c2 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -76,7 +76,7 @@ public class PropertyParser { } public void load(RadViewComponent component) throws Exception { - MetaModel model = component.getMetaModel(); + MetaModel model = component.getMetaModelForProperties(); String target = model.getTarget(); if (target == null) { ViewInfo info = component.getViewInfo(); @@ -106,7 +106,7 @@ public class PropertyParser { if (layoutParams != null) { MetaModel[] models = new MetaModel[layoutParams.length]; - models[0] = parent.getMetaModel(); + models[0] = parent.getMetaModelForProperties(); for (int i = 1; i < layoutParams.length; i++) { if (models[i - 1] == null) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadCustomViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadCustomViewComponent.java new file mode 100644 index 000000000000..6ce1ff5a0ced --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadCustomViewComponent.java @@ -0,0 +1,138 @@ +/* + * 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.android.designer.model; + +import com.intellij.android.designer.propertyTable.CustomViewProperty; +import com.intellij.android.designer.propertyTable.editors.ChooseClassDialog; +import com.intellij.designer.model.IComponentDecorator; +import com.intellij.designer.model.MetaManager; +import com.intellij.designer.model.MetaModel; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiClass; +import com.intellij.psi.xml.XmlTag; +import com.intellij.ui.SimpleColoredComponent; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class RadCustomViewComponent extends RadViewComponent implements IConfigurableComponent, IComponentDecorator { + private static final String NAME_KEY = "view.name"; + public static final String MODEL_KEY = "view.model"; + private static final Property CLASS_PROPERTY = new CustomViewProperty(); + + @Override + public String getCreationXml() { + return ""; + } + + @Override + public MetaModel getMetaModelForProperties() throws Exception { + MetaModel metaModel = getClientProperty(MODEL_KEY); + + if (metaModel == null) { + Module module = getRoot().getClientProperty(ModelParser.MODULE_KEY); + MetaManager metaManager = ViewsMetaManager.getInstance(module.getProject()); + PsiClass viewClass = ChooseClassDialog.findClass(module, getViewClass()); + + while (viewClass != null) { + metaModel = metaManager.getModelByTarget(viewClass.getQualifiedName()); + if (metaModel != null) { + break; + } + viewClass = viewClass.getSuperClass(); + } + if (metaModel == null) { + metaModel = myMetaModel; + } + + setClientProperty(MODEL_KEY, metaModel); + } + + return metaModel; + } + + @Override + public void configure(RadComponent rootComponent) throws Exception { + String view = chooseView(rootComponent); + if (view != null) { + setClientProperty(NAME_KEY, view); + } + else { + throw new Exception(); + } + } + + @Nullable + public static String chooseView(RadComponent rootComponent) { + Module module = rootComponent.getClientProperty(ModelParser.MODULE_KEY); + ChooseClassDialog dialog = + new ChooseClassDialog(module, "View Dialog", false, "android.view.View"); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + return dialog.getClassName(); + } + + return null; + } + + @Nullable + public String getViewClass() { + XmlTag tag = getTag(); + + String classAttribute = tag.getAttributeValue("class"); + if (!StringUtil.isEmpty(classAttribute)) { + return classAttribute; + } + + String tagName = tag.getName(); + if (!StringUtil.isEmpty(tagName) && !tagName.equals("view")) { + return tagName; + } + + return null; + } + + @Override + public void decorateTree(SimpleColoredComponent renderer) { + String viewClass = getViewClass(); + if (viewClass != null) { + renderer.append(" - " + viewClass); + } + } + + @Override + public void setProperties(List properties) { + List oldProperties = getProperties(); + if (!properties.isEmpty() && (oldProperties == null || oldProperties.isEmpty())) { + properties = new ArrayList(properties); + properties.add(0, CLASS_PROPERTY); + } + super.setProperties(properties); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java index 967359d37b3c..6d36f90020b5 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadFragment.java @@ -17,13 +17,15 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.propertyTable.FragmentProperty; import com.intellij.android.designer.propertyTable.IdProperty; -import com.intellij.android.designer.propertyTable.editors.FragmentDialog; +import com.intellij.android.designer.propertyTable.editors.ChooseClassDialog; import com.intellij.android.designer.propertyTable.editors.ResourceEditor; +import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.Property; import com.intellij.designer.propertyTable.editors.TextEditor; import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.DialogWrapper; import org.jetbrains.android.dom.attrs.AttributeFormat; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; @@ -37,12 +39,10 @@ public class RadFragment extends RadViewComponent implements IConfigurableCompon new FragmentProperty("name", new ResourceEditor(null, Collections.emptySet(), null) { @Override protected void showDialog() { - Module module = myRootComponent.getClientProperty(ModelParser.MODULE_KEY); - FragmentDialog dialog = new FragmentDialog(module); - dialog.show(); + String fragment = chooseFragment(myRootComponent); - if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - setValue(dialog.getFragmentName()); + if (fragment != null) { + setValue(fragment); } } }); @@ -59,18 +59,30 @@ public class RadFragment extends RadViewComponent implements IConfigurableCompon } @Override - public void configure(Module module) throws Exception { - FragmentDialog dialog = new FragmentDialog(module); - dialog.show(); - - if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - setClientProperty(NAME_KEY, dialog.getFragmentName()); + public void configure(RadComponent rootComponent) throws Exception { + String fragment = chooseFragment(rootComponent); + if (fragment != null) { + setClientProperty(NAME_KEY, fragment); } else { throw new Exception(); } } + @Nullable + private static String chooseFragment(RadComponent rootComponent) { + Module module = rootComponent.getClientProperty(ModelParser.MODULE_KEY); + ChooseClassDialog dialog = + new ChooseClassDialog(module, "Fragment Dialog", true, "android.app.Fragment", "android.support.v4.app.Fragment"); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + return dialog.getClassName(); + } + + return null; + } + @Override public void setProperties(List properties) { if (!properties.isEmpty()) { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java index fb4649c4348f..2f1b1b402fcf 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java @@ -18,6 +18,7 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.propertyTable.IdProperty; import com.intellij.android.designer.propertyTable.IncludeLayoutProperty; import com.intellij.android.designer.propertyTable.editors.ResourceDialog; +import com.intellij.designer.model.RadComponent; import com.intellij.designer.propertyTable.Property; import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.DialogWrapper; @@ -38,7 +39,8 @@ public class RadIncludeLayout extends RadViewComponent implements IConfigurableC "\"/>"; } - public void configure(Module module) throws Exception { + public void configure(RadComponent rootComponent) throws Exception { + Module module = rootComponent.getClientProperty(ModelParser.MODULE_KEY); ResourceDialog dialog = new ResourceDialog(module, IncludeLayoutProperty.TYPES); dialog.show(); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index fad2d11dc357..815dac81094a 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -39,23 +39,17 @@ tooltip="A Fragment is a piece of an application's user interface or behavior that can be placed in an Activity."/> - - + + - - - - + - @@ -1411,6 +1405,7 @@ + diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java new file mode 100644 index 000000000000..954de1ccbfa1 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/CustomViewProperty.java @@ -0,0 +1,122 @@ +/* + * 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.android.designer.propertyTable; + +import com.intellij.android.designer.model.PropertyParser; +import com.intellij.android.designer.model.RadCustomViewComponent; +import com.intellij.android.designer.propertyTable.editors.ResourceEditor; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.android.dom.attrs.AttributeFormat; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class CustomViewProperty extends Property { + private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null); + private final PropertyEditor myEditor = new ResourceEditor(null, Collections.emptySet(), null) { + @Override + protected void showDialog() { + String view = RadCustomViewComponent.chooseView(myRootComponent); + if (view != null) { + setValue(view); + } + } + }; + + public CustomViewProperty() { + super(null, "view:class"); + setImportant(true); + } + + @Override + public Property createForNewPresentation(@Nullable Property parent, @NotNull String name) { + return null; + } + + @Override + public Object getValue(RadCustomViewComponent component) throws Exception { + String viewClass = component.getViewClass(); + return viewClass == null ? "" : viewClass; + } + + @Override + public void setValue(final RadCustomViewComponent component, final Object value) throws Exception { + if (StringUtil.isEmpty((String)value)) { + return; + } + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + XmlTag tag = component.getTag(); + if ("view".equals(tag.getName())) { + tag.setAttribute("class", (String)value); + } + else { + tag.setName((String)value); + } + } + }); + + component.extractClientProperty(RadCustomViewComponent.MODEL_KEY); + component.setProperties(Collections.emptyList()); + + PropertyParser propertyParser = component.getRoot().getClientProperty(PropertyParser.KEY); + propertyParser.load(component); + } + + @Override + public boolean isDefaultValue(RadCustomViewComponent component) throws Exception { + return false; + } + + @Override + public void setDefaultValue(RadCustomViewComponent component) throws Exception { + } + + @Override + public boolean availableFor(List components) { + return false; + } + + @Override + public boolean needRefreshPropertyList() { + return true; + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return myEditor; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ChooseClassDialog.java similarity index 70% rename from plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java rename to plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ChooseClassDialog.java index 77d3db00a049..e66cf795ae79 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/FragmentDialog.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ChooseClassDialog.java @@ -24,6 +24,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.ui.ListSpeedSearch; import com.intellij.ui.ScrollPaneFactory; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; @@ -37,12 +38,12 @@ import java.util.Collections; /** * @author Alexander Lobas */ -public class FragmentDialog extends DialogWrapper implements ListSelectionListener { +public class ChooseClassDialog extends DialogWrapper implements ListSelectionListener { private final JList myList = new JList(); private final JScrollPane myComponent = ScrollPaneFactory.createScrollPane(myList); - private String myResultFragmentName; + private String myResultClassName; - public FragmentDialog(Module module) { + public ChooseClassDialog(Module module, String title, boolean includeAll, String... classes) { super(module.getProject()); myList.setPreferredSize(new Dimension(500, 400)); @@ -56,11 +57,10 @@ public class FragmentDialog extends DialogWrapper implements ListSelectionListen }); DefaultListModel model = new DefaultListModel(); - for (PsiClass psiClass : findInheritors(module, "android.app.Fragment")) { - model.addElement(psiClass.getQualifiedName()); - } - for (PsiClass psiClass : findInheritors(module, "android.support.v4.app.Fragment")) { - model.addElement(psiClass.getQualifiedName()); + for (String className : classes) { + for (PsiClass psiClass : findInheritors(module, className, includeAll)) { + model.addElement(psiClass.getQualifiedName()); + } } myList.setModel(model); @@ -70,22 +70,29 @@ public class FragmentDialog extends DialogWrapper implements ListSelectionListen new ListSpeedSearch(myList); - setTitle("Fragment Dialog"); + setTitle(title); getOKAction().setEnabled(false); init(); } - private static Collection findInheritors(Module module, String name) { - Project project = module.getProject(); - PsiClass base = JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project)); + private static Collection findInheritors(Module module, String name, boolean includeAll) { + PsiClass base = findClass(module, name); if (base != null) { - GlobalSearchScope scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false); + GlobalSearchScope scope = includeAll ? + GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, false) : + GlobalSearchScope.moduleScope(module); return ClassInheritorsSearch.search(base, scope, true).findAll(); } return Collections.emptyList(); } + @Nullable + public static PsiClass findClass(Module module, String name) { + Project project = module.getProject(); + return JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project)); + } + @Override public JComponent getPreferredFocusedComponent() { return myList; @@ -96,13 +103,13 @@ public class FragmentDialog extends DialogWrapper implements ListSelectionListen return myComponent; } - public String getFragmentName() { - return myResultFragmentName; + public String getClassName() { + return myResultClassName; } @Override public void valueChanged(ListSelectionEvent e) { - myResultFragmentName = (String)myList.getSelectedValue(); - getOKAction().setEnabled(myResultFragmentName != null); + myResultClassName = (String)myList.getSelectedValue(); + getOKAction().setEnabled(myResultClassName != null); } } \ No newline at end of file diff --git a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java index 5cf3bca40dc2..4fa0175b31a0 100644 --- a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java +++ b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApkBuilder.java @@ -27,10 +27,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import com.intellij.util.text.DateFormatUtil; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidCompilerMessageKind; -import org.jetbrains.android.util.AndroidExecutionUtil; -import org.jetbrains.android.util.AndroidNativeLibData; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -261,7 +258,7 @@ public class AndroidApkBuilder { } fos = new FileOutputStream(outputApk); - builder = new SignedJarBuilder(fos, key, certificate); + builder = new SafeSignedJarBuilder(fos, key, certificate, outputApk); FileInputStream fis = new FileInputStream(apkPath); try { diff --git a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApt.java b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApt.java index c2ee5c64c8b8..bd93289d3094 100644 --- a/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApt.java +++ b/plugins/android/common/src/org/jetbrains/android/compiler/tools/AndroidApt.java @@ -27,7 +27,9 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -127,26 +129,12 @@ public final class AndroidApt { private static void makeFieldsNotFinal(@NotNull File[] libRJavaFiles) throws IOException { for (File file : libRJavaFiles) { if (file.isFile()) { - final String fileContent = readFile(file); + final String fileContent = AndroidCommonUtils.readFile(file); FileUtil.writeToFile(file, fileContent.replace("public static final int ", "public static int ")); } } } - @NotNull - private static String readFile(@NotNull File file) throws IOException { - final InputStream is = new BufferedInputStream(new FileInputStream(file)); - try { - final byte[] data = new byte[is.available()]; - //noinspection ResultOfMethodCallIgnored - is.read(data); - return new String(data); - } - finally { - is.close(); - } - } - private static Map> doCompile(@NotNull IAndroidTarget target, @NotNull String manifestFileOsPath, @NotNull String outDirOsPath, @@ -240,6 +228,24 @@ public final class AndroidApt { boolean debugMode, int versionCode, FileFilter assetsFilter) throws IOException { + for (String resDirPath : resPaths) { + if (FileUtil.isAncestor(resDirPath, outputPath, false)) { + throw new IOException("Resource directory " + + FileUtil.toSystemDependentName(resDirPath) + + " contains output " + + FileUtil.toSystemDependentName(outputPath)); + } + } + + for (String assetsDirPath : osAssetDirPaths) { + if (FileUtil.isAncestor(assetsDirPath, outputPath, false)) { + throw new IOException("Assets directory " + + FileUtil.toSystemDependentName(assetsDirPath) + + " contains output " + + FileUtil.toSystemDependentName(outputPath)); + } + } + final ArrayList args = new ArrayList(); //noinspection deprecation diff --git a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java index 2dab42af9725..11b219a2037e 100644 --- a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -434,4 +434,22 @@ public class AndroidCommonUtils { } return revisionNumber > 0 ? revisionNumber : -1; } + + @NotNull + public static String readFile(@NotNull File file) throws IOException { + final InputStream is = new BufferedInputStream(new FileInputStream(file)); + try { + final byte[] data = new byte[is.available()]; + //noinspection ResultOfMethodCallIgnored + is.read(data); + return new String(data); + } + finally { + is.close(); + } + } + + public static boolean contains2Identifiers(String packageName) { + return packageName.split("\\.").length >= 2; + } } diff --git a/plugins/android/common/src/org/jetbrains/android/util/SafeSignedJarBuilder.java b/plugins/android/common/src/org/jetbrains/android/util/SafeSignedJarBuilder.java new file mode 100644 index 000000000000..ee1a106f6919 --- /dev/null +++ b/plugins/android/common/src/org/jetbrains/android/util/SafeSignedJarBuilder.java @@ -0,0 +1,32 @@ +package org.jetbrains.android.util; + +import com.android.jarutils.SignedJarBuilder; +import com.intellij.openapi.util.io.FileUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +/** + * @author Eugene.Kudelevsky + */ +public class SafeSignedJarBuilder extends SignedJarBuilder { + private final String myOutFilePath; + + public SafeSignedJarBuilder(FileOutputStream outputStream, PrivateKey key, X509Certificate certificate, String outFilePath) + throws IOException, NoSuchAlgorithmException { + super(outputStream, key, certificate); + myOutFilePath = FileUtil.toSystemDependentName(outFilePath); + } + + @Override + public void writeFile(File inputFile, String jarPath) throws IOException { + if (FileUtil.pathsEqual(inputFile.getPath(), myOutFilePath)) { + throw new IOException("Cannot pack file " + myOutFilePath + " into itself"); + } + super.writeFile(inputFile, jarPath); + } +} diff --git a/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties b/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties index becdaa2aa6ed..baa5947ccfa5 100644 --- a/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties +++ b/plugins/android/jps-plugin/src/messages/AndroidJpsBundle.properties @@ -1,19 +1,26 @@ -android.jps.progress.dex=Executing DEX for module {0} -android.jps.errors.sdk.not.specified=Android SDK is not specified for module {0} -android.jps.errors.sdk.invalid=Android SDK is invalid or not specified for module {0} -android.jps.errors.output.dir.not.specified=Output directory is not specified for module {0} -android.jps.warnings.dex.no.compiled.files=Dex won't be launched for module {0} because it doesn't contain compiled files -android.jps.errors.cannot.delete.file=Cannot delete file {0} +android.jps.progress.dex=Executing DEX [{0}] +android.jps.errors.sdk.not.specified=[{0}] Android SDK is not specified +android.jps.errors.sdk.invalid=[{0}] Android SDK is invalid or not specified +android.jps.errors.output.dir.not.specified=[{0}] Output directory is not specified +android.jps.warnings.dex.no.compiled.files=[{0}] Dex won't be launched because it doesn't contain compiled files +android.jps.cannot.delete.file=Cannot delete file {0} android.jps.progress.aidl=Processing AIDL files -android.jps.progress.renderscript=Processing AIDL files +android.jps.progress.renderscript=Processing RenderScript files android.jps.errors.cannot.compute.package=Cannot compute package for file {0} -android.jps.progress.aapt=Generating R.java and Manifest.java files for module {0} -android.jps.progress.build.config=Generating BuildConfig.java file for module {0} -android.jps.errors.manifest.not.found=AndroidManifest.xml file not found in the module {0} -android.jps.errors.package.not.specified=Package is not specified in AndroidManifest.xml for module {0} -android.jps.progress.library.packaging=Packaging Android libraries for module {0} -android.jps.errors.main.content.root.not.found=Cannot find main content root for module {0} -android.jps.progress.proguard=Executing ProGuard for module {0} -android.jps.progress.res.caching=Caching resources for module {0} +android.jps.progress.aapt=Generating R.java and Manifest.java files [{0}] +android.jps.progress.build.config=Generating BuildConfig.java files [{0}] +android.jps.errors.manifest.not.found=[{0}] AndroidManifest.xml file not found +android.jps.errors.package.not.specified=[{0}] Package is not specified in AndroidManifest.xml +android.jps.progress.library.packaging=Packaging Android libraries [{0}] +android.jps.errors.main.content.root.not.found=[{0}] Cannot find main content root +android.jps.progress.proguard=Executing ProGuard [{0}] +android.jps.progress.res.caching=Caching resources [{0}] android.jps.progress.packaging=Packaging {0} -android.jps.progress.packaging.resources=Packaging resources for module {0} \ No newline at end of file +android.jps.progress.packaging.resources=Packaging resources [{0}] +android.jps.errors.incorrect.package.name=[{0}] Package name must contain at least 2 segments +android.jps.internal.error=Internal error +android.jps.cannot.create.directory=Cannot create directory {0} +android.jps.cannot.delete=Cannot delete {0} +android.jps.errors.cannot.find.proguard.cfg=[{0}] Cannot find proguard config file +android.jps.cannot.find.file=Cannot find file {0} +android.jps.errors.cannot.compute.output.apk=[{0}] Cannot compute output path for APK \ No newline at end of file diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java index 53c02b440316..1c9698795948 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidDexBuilder.java @@ -135,8 +135,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { else if (facet.isRunProguard()) { final File proguardCfgFile = facet.getProguardConfigFile(); if (proguardCfgFile == null) { - context.processMessage( - new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot find proguard config file for module " + module.getName())); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.errors.cannot.find.proguard.cfg", module.getName()))); success = false; continue; } @@ -199,7 +199,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.dex", module.getName()))); - if (!runDex(platform, dexOutputDir.getPath(), files, context)) { + if (!runDex(platform, dexOutputDir.getPath(), files, context, module.getName())) { success = false; dexStateStorage.update(module.getName(), null); } @@ -228,13 +228,15 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { private static boolean runDex(@NotNull AndroidPlatform platform, @NotNull String outputDir, @NotNull String[] compileTargets, - @NotNull CompileContext context) throws IOException { + @NotNull CompileContext context, + @NotNull String moduleName) throws IOException { @SuppressWarnings("deprecation") final String dxJarPath = FileUtil.toSystemDependentName(platform.getTarget().getPath(IAndroidTarget.DX_JAR)); final File dxJar = new File(dxJarPath); if (!dxJar.isFile()) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot find file " + dxJarPath)); + context.processMessage( + new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.cannot.find.file", dxJarPath))); return false; } @@ -253,7 +255,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { final File outFile = new File(outFilePath); if (outFile.exists() && !outFile.delete()) { context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.WARNING, - AndroidJpsBundle.message("android.jps.errors.cannot.delete.file", outFilePath))); + AndroidJpsBundle.message("android.jps.cannot.delete.file", outFilePath))); } // todo: pass additional vm params and max heap size from settings @@ -273,7 +275,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { AndroidCommonUtils.handleDexCompilationResult(process, outFilePath, messages); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, moduleName); return messages.get(AndroidCompilerMessageKind.ERROR).size() == 0; } @@ -291,7 +293,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { final File proguardCfgFile = new File(proguardCfgPath); if (!proguardCfgFile.exists()) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot find file " + proguardCfgPath)); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.cannot.find.file", proguardCfgPath))); return false; } @@ -341,7 +344,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { final File logsDir = new File(logsDirOsPath); if (!logsDir.exists()) { if (!logsDir.mkdirs()) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + logsDirOsPath)); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.cannot.create.directory", logsDirOsPath))); return false; } } @@ -352,7 +356,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder { AndroidCommonUtils.launchProguard(platform.getTarget(), platform.getSdkToolsRevision(), platform.getSdk().getSdkPath(), proguardCfgPath, includeSystemProguardCfg, inputJarOsPath, externalJarOsPaths, outputJarPath, logsDirOsPath); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, module.getName()); final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty(); proguardStateStorage.update(module.getName(), success ? newState : null); diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy index ba64de3f7dc4..d7d04ba87dab 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy @@ -78,7 +78,7 @@ class AndroidFacet extends Facet { } private File findFileByRelativeModulePath(String relativePath, boolean lookInContentRoot) { - if (relativePath == null) { + if (relativePath == null || relativePath.length() == 0) { return null } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy index a7e5bf8634e0..8d793b97bcf9 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy @@ -35,9 +35,8 @@ class AndroidFacetType extends FacetTypeService { final targetFileName = nativeLibItem.get("@" + AndroidCommonUtils.TARGET_FILE_NAME_ATTRIBUTE) if (architecture != null && url != null && targetFileName != null) { - facet.additionalNativeLibs.add(new AndroidNativeLibData((String)architecture, - IdeaProjectLoadingUtil.pathFromUrl((String)url), - (String)targetFileName)) + final path = macroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl((String)url)) + facet.additionalNativeLibs.add(new AndroidNativeLibData((String)architecture, path, (String)targetFileName)) } } } @@ -76,7 +75,7 @@ class AndroidFacetType extends FacetTypeService { facet.apkRelativePath = value break case "CUSTOM_DEBUG_KEYSTORE_PATH": - facet.customDebugKeyStorePath = IdeaProjectLoadingUtil.pathFromUrl(value) + facet.customDebugKeyStorePath = macroExpander.expandMacros(IdeaProjectLoadingUtil.pathFromUrl(value)) break case "LIBS_FOLDER_RELATIVE_PATH": facet.nativeLibsFolderRelativePath = value diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java index 09c0597fa926..c2eeff28008a 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidJpsUtil.java @@ -86,7 +86,8 @@ class AndroidJpsUtil { public static void addMessages(@NotNull CompileContext context, @NotNull Map> messages, - @NotNull String builderName) { + @NotNull String builderName, + @NotNull String moduleName) { for (Map.Entry> entry : messages.entrySet()) { for (String message : entry.getValue()) { String filePath = null; @@ -99,7 +100,8 @@ class AndroidJpsUtil { } final BuildMessage.Kind category = toBuildMessageKind(entry.getKey()); if (category != null) { - context.processMessage(new CompilerMessage(builderName, category, message, filePath, -1L, -1L, -1L, line, -1L)); + context.processMessage( + new CompilerMessage(builderName, category, '[' + moduleName + "] " + message, filePath, -1L, -1L, -1L, line, -1L)); } } } diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java index a2af3d4916c2..2192dc9b932a 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidPackagingBuilder.java @@ -170,7 +170,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { if (context.isProjectRebuild() && resCacheDir.exists()) { if (!FileUtil.delete(resCacheDir)) { context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, - "Cannot delete directory " + resCacheDir.getPath())); + AndroidJpsBundle.message("android.jps.cannot.create.directory", resCacheDir.getPath()))); return false; } } @@ -178,7 +178,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { if (!resCacheDir.exists()) { if (!resCacheDir.mkdirs()) { context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, - "Cannot create directory " + resCacheDir.getPath())); + AndroidJpsBundle.message("android.jps.cannot.create.directory", resCacheDir.getPath()))); return false; } } @@ -188,7 +188,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { final Map> messages = AndroidApt.crunch(target, Collections.singletonList(resourceDir.getPath()), resCacheDir.getPath()); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, module.getName()); final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty(); storage.update(module.getName(), success ? state : null); @@ -353,8 +353,8 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { final String sdkPath = platform.getSdk().getSdkPath(); final String outputPath = AndroidJpsUtil.getApkPath(facet, outputDir); if (outputPath == null) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, - "Cannot compute output path for file " + AndroidJpsUtil.getApkName(module))); + context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle + .message("android.jps.errors.cannot.compute.output.apk", module.getName()))); return false; } final String customKeyStorePath = FileUtil.toSystemDependentName(facet.getCustomDebugKeyStorePath()); @@ -365,7 +365,6 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { final String classesDexFilePath = classesDexFile.getPath(); final String[] externalJars = ArrayUtil.toStringArray(externalJarsSet); - // currently including native libraries through pom.xml doesn't work when jps compilation is used, MAVEN_REPOSITORY url macros needed final List additionalNativeLibs = facet.getAdditionalNativeLibs(); final AndroidFileSetState currentFileSetState = @@ -391,7 +390,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { .execute(resPackagePath, classesDexFilePath, sourceRoots, externalJars, nativeLibDirs, additionalNativeLibs, outputApkPath, release, sdkPath, customKeyStorePath, new MyExcludedSourcesFilter(context.getProject())); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, module.getName()); final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty(); apkFileSetStorage.update(module.getName(), success ? currentFileSetState : null); @@ -492,7 +491,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { final String[] resourceDirPaths = AndroidJpsUtil.collectResourceDirsForCompilation(facet, true, context); return doPackageResources(context, manifestFile, target, resourceDirPaths, ArrayUtil.toStringArray(assetsDirPaths), outputFilePath, - AndroidJpsUtil.isReleaseBuild(context)); + AndroidJpsUtil.isReleaseBuild(context), module.getName()); } catch (IOException e) { AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); @@ -506,7 +505,8 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { @NotNull String[] resourceDirPaths, @NotNull String[] assetsDirPaths, @NotNull String outputFilePath, - boolean releasePackage) { + boolean releasePackage, + @NotNull String moduleName) { try { final String outputPath = releasePackage ? outputFilePath + RELEASE_SUFFIX @@ -523,7 +523,7 @@ public class AndroidPackagingBuilder extends ProjectLevelBuilder { } }); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, moduleName); return messages.get(AndroidCompilerMessageKind.ERROR).size() == 0; } catch (final IOException e) { diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java index a153b7fa1e12..ca20576e2201 100644 --- a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java +++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java @@ -39,7 +39,13 @@ import java.util.*; public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.android.AndroidSourceGeneratingBuilder"); + @NonNls private static final String ANDROID_VALIDATOR = "android-validator"; + @NonNls private static final String ANDROID_IDL_COMPILER = "android-idl-compiler"; + @NonNls private static final String ANDROID_RENDERSCRIPT_COMPILER = "android-renderscript-compiler"; + @NonNls private static final String ANDROID_BUILD_CONFIG_GENERATOR = "android-buildconfig-generator"; + @NonNls private static final String ANDROID_APT_COMPILER = "android-apt-compiler"; @NonNls private static final String BUILDER_NAME = "android-source-generator"; + @NonNls private static final String AIDL_EXTENSION = "aidl"; @NonNls private static final String RENDERSCRIPT_EXTENSION = "rs"; @NonNls private static final String MANIFEST_TAG = "manifest"; @@ -114,13 +120,13 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { for (Module module : moduleDataMap.keySet()) { final File generatedSourcesStorage = AndroidJpsUtil.getGeneratedSourcesStorage(module); if (generatedSourcesStorage.exists() && - !deleteAndMarkRecursively(generatedSourcesStorage, context)) { + !deleteAndMarkRecursively(generatedSourcesStorage, context, BUILDER_NAME)) { success = false; } final File generatedResourcesStorage = AndroidJpsUtil.getGeneratedResourcesStorage(module); if (generatedResourcesStorage.exists() && - !deleteAndMarkRecursively(generatedResourcesStorage, context)) { + !deleteAndMarkRecursively(generatedResourcesStorage, context, BUILDER_NAME)) { success = false; } } @@ -177,7 +183,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { "] Incompatible version of Android SDK Platform-tools package. Min version is " + MIN_PLATFORM_TOOLS_REVISION + ". Please, update it though SDK manager"; - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message)); + context.processMessage(new CompilerMessage(ANDROID_VALIDATOR, BuildMessage.Kind.ERROR, message)); success = false; } @@ -188,7 +194,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { "] Incompatible version of Android SDK Tools package. Min version is " + MIN_SDK_TOOLS_REVISION + ". Please, update it though SDK manager"; - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message)); + context.processMessage(new CompilerMessage(ANDROID_VALIDATOR, BuildMessage.Kind.ERROR, message)); success = false; } @@ -225,7 +231,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { message += "change packaging type of module " + depModule.getName() + " to 'apklib' in pom.xml file or "; } message += "change dependency scope to 'Provided'."; - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.WARNING, message)); + context.processMessage(new CompilerMessage(ANDROID_VALIDATOR, BuildMessage.Kind.WARNING, message)); } } } @@ -247,7 +253,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { try { if (facet == null || isLibraryWithBadCircularDependency(facet)) { - if (!clearDirectoryIfNotEmpty(outputDirectory, context)) { + if (!clearDirectoryIfNotEmpty(outputDirectory, context, ANDROID_BUILD_CONFIG_GENERATOR)) { success = false; } continue; @@ -266,17 +272,17 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } } + context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.build.config", module.getName()))); + // clear directory, because it may contain obsolete files (ex. if package name was changed) - if (!clearDirectory(outputDirectory, context)) { + if (!clearDirectory(outputDirectory, context, ANDROID_BUILD_CONFIG_GENERATOR)) { success = false; continue; } - context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.build.config", module.getName()))); - if (doBuildConfigGeneration(packageName, libPackages, debug, outputDirectory, context)) { storage.update(module.getName(), newState); - markDirtyRecursively(outputDirectory, context); + markDirtyRecursively(outputDirectory, context, ANDROID_BUILD_CONFIG_GENERATOR); } else { storage.update(module.getName(), null); @@ -284,7 +290,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } } catch (IOException e) { - AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, null, e, ANDROID_BUILD_CONFIG_GENERATOR); success = false; } } @@ -318,7 +324,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { return true; } catch (IOException e) { - AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, null, e, ANDROID_BUILD_CONFIG_GENERATOR); return false; } } @@ -340,7 +346,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final MyModuleData moduleData = moduleDataMap.get(module); if (!LOG.assertTrue(moduleData != null)) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error")); + context.processMessage(new CompilerMessage(ANDROID_IDL_COMPILER, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.internal.error"))); success = false; continue; } @@ -349,7 +355,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { if (!aidlOutputDirectory.exists() && !aidlOutputDirectory.mkdirs()) { context.processMessage( - new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + aidlOutputDirectory.getPath())); + new CompilerMessage(ANDROID_IDL_COMPILER, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.cannot.create.directory", aidlOutputDirectory.getPath()))); success = false; continue; } @@ -362,7 +368,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final String packageName = computePackageForFile(context, file); if (packageName == null) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, + context.processMessage(new CompilerMessage(ANDROID_IDL_COMPILER, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.errors.cannot.compute.package", filePath))); success = false; continue; @@ -374,7 +380,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final Map> messages = AndroidIdl.execute(target, filePath, outputFilePath, sourceRootPaths); - addMessages(context, messages, filePath, BUILDER_NAME); + addMessages(context, messages, filePath, ANDROID_IDL_COMPILER); if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) { success = false; @@ -386,7 +392,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } } catch (final IOException e) { - AndroidJpsUtil.reportExceptionError(context, filePath, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, filePath, e, ANDROID_IDL_COMPILER); success = false; } } @@ -408,7 +414,8 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final MyModuleData moduleData = moduleDataMap.get(module); if (!LOG.assertTrue(moduleData != null)) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error")); + context.processMessage(new CompilerMessage(ANDROID_RENDERSCRIPT_COMPILER, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.internal.error"))); success = false; continue; } @@ -416,8 +423,8 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final File generatedSourcesDir = AndroidJpsUtil.getGeneratedSourcesStorage(module); final File rsOutputDirectory = new File(generatedSourcesDir, AndroidJpsUtil.RENDERSCRIPT_GENERATED_SOURCE_ROOT_NAME); if (!rsOutputDirectory.exists() && !rsOutputDirectory.mkdirs()) { - context.processMessage( - new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + rsOutputDirectory.getPath())); + context.processMessage(new CompilerMessage(ANDROID_RENDERSCRIPT_COMPILER, BuildMessage.Kind.ERROR, AndroidJpsBundle + .message("android.jps.cannot.create.directory", rsOutputDirectory.getPath()))); success = false; continue; } @@ -426,7 +433,8 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final File rawDir = new File(generatedResourcesDir, "raw"); if (!rawDir.exists() && !rawDir.mkdirs()) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + rawDir.getPath())); + context.processMessage(new CompilerMessage(ANDROID_RENDERSCRIPT_COMPILER, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.cannot.create.directory", rawDir.getPath()))); success = false; continue; } @@ -445,7 +453,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final Map> messages = AndroidRenderscript.execute(sdkLocation, target, filePath, tmpOutputDirectory.getPath(), depFolderPath, rawDir.getPath()); - addMessages(context, messages, filePath, BUILDER_NAME); + addMessages(context, messages, filePath, ANDROID_RENDERSCRIPT_COMPILER); if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) { success = false; @@ -469,7 +477,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } } catch (IOException e) { - AndroidJpsUtil.reportExceptionError(context, filePath, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, filePath, e, ANDROID_RENDERSCRIPT_COMPILER); success = false; } finally { @@ -497,7 +505,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { try { if (!needToRunAaptCompilation(facet)) { - if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context)) { + if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context, ANDROID_APT_COMPILER)) { success = false; } continue; @@ -506,7 +514,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final String[] resPaths = AndroidJpsUtil.collectResourceDirsForCompilation(facet, false, context); if (resPaths.length == 0) { // there is no resources in the module - if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context)) { + if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context, ANDROID_APT_COMPILER)) { success = false; } continue; @@ -515,7 +523,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { final File manifestFile = moduleData.getManifestFileForCompiler(); if (isLibraryWithBadCircularDependency(facet)) { - if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context)) { + if (!clearDirectoryIfNotEmpty(aptOutputDirectory, context, ANDROID_APT_COMPILER)) { success = false; } continue; @@ -532,7 +540,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { "' won't be final, because of circular dependency on module '" + circularDepLibWithSamePackage.getName() + "'"; - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.WARNING, message)); + context.processMessage(new CompilerMessage(ANDROID_APT_COMPILER, BuildMessage.Kind.WARNING, message)); } final boolean generateNonFinalFields = facet.isLibrary() || circularDepLibWithSamePackage != null; @@ -550,20 +558,19 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { continue; } } + context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.aapt", module.getName()))); // clear directory, because it may contain obsolete files (ex. if package name was changed) - if (!clearDirectory(aptOutputDirectory, context)) { + if (!clearDirectory(aptOutputDirectory, context, ANDROID_APT_COMPILER)) { success = false; - continue; + continue; } - context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.aapt", module.getName()))); - final Map> messages = AndroidApt.compile(target, -1, manifestFile.getPath(), packageName, aptOutputDirectory.getPath(), resPaths, ArrayUtil.toStringArray(depLibPackagesSet), generateNonFinalFields); - AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME); + AndroidJpsUtil.addMessages(context, messages, ANDROID_APT_COMPILER, module.getName()); if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) { success = false; @@ -571,35 +578,35 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { } else { storage.update(module.getName(), newState); - markDirtyRecursively(aptOutputDirectory, context); + markDirtyRecursively(aptOutputDirectory, context, ANDROID_APT_COMPILER); } } catch (IOException e) { - AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, null, e, ANDROID_APT_COMPILER); success = false; } } return success; } - private static boolean clearDirectory(File dir, CompileContext context) throws IOException { - if (!deleteAndMarkRecursively(dir, context)) { + private static boolean clearDirectory(File dir, CompileContext context, String compilerName) throws IOException { + if (!deleteAndMarkRecursively(dir, context, compilerName)) { return false; } if (!dir.mkdirs()) { - context.processMessage( - new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot create directory " + dir.getPath())); + context.processMessage(new CompilerMessage(compilerName, BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.cannot.create.directory", dir.getPath()))); return false; } return true; } - private static boolean clearDirectoryIfNotEmpty(@NotNull File dir, @NotNull CompileContext context) throws IOException { + private static boolean clearDirectoryIfNotEmpty(@NotNull File dir, @NotNull CompileContext context, String compilerName) throws IOException { if (dir.isDirectory()) { final String[] list = dir.list(); if (list != null && list.length > 0) { - return clearDirectory(dir, context); + return clearDirectory(dir, context, compilerName); } } return true; @@ -610,11 +617,13 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { !AndroidJpsUtil.isMavenizedModule(facet.getModule()); } - private static boolean deleteAndMarkRecursively(@NotNull File dir, @NotNull CompileContext context) throws IOException { + private static boolean deleteAndMarkRecursively(@NotNull File dir, @NotNull CompileContext context, @NotNull String compilerName) + throws IOException { if (dir.exists()) { final List filesToDelete = collectJavaFilesRecursively(dir); if (!FileUtil.delete(dir)) { - context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot delete " + dir.getPath())); + context.processMessage( + new CompilerMessage(compilerName, BuildMessage.Kind.ERROR, AndroidJpsBundle.message("android.jps.cannot.delete", dir.getPath()))); return false; } @@ -625,7 +634,9 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { return true; } - private static boolean markDirtyRecursively(@NotNull File dir, @NotNull final CompileContext context) { + private static boolean markDirtyRecursively(@NotNull File dir, + @NotNull final CompileContext context, + @NotNull final String compilerName) { final Ref success = Ref.create(true); FileUtil.processFilesRecursively(dir, new Processor() { @@ -636,7 +647,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { context.markDirty(file); } catch (IOException e) { - AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); + AndroidJpsUtil.reportExceptionError(context, null, e, compilerName); success.set(false); return false; } @@ -873,6 +884,13 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder { continue; } + if (!AndroidCommonUtils.contains2Identifiers(packageName)) { + context.processMessage(new CompilerMessage(BUILDER_NAME, facet.isLibrary() ? BuildMessage.Kind.WARNING : BuildMessage.Kind.ERROR, + AndroidJpsBundle.message("android.jps.errors.incorrect.package.name", module.getName()))); + success = false; + continue; + } + moduleDataMap.put(module, new MyModuleData(platform, facet, manifestFile, packageName)); } diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index f781c20b8954..31228d4d4850 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -22,7 +22,7 @@ select.compatible.avd.error=Please select compatible AVD cant.remove.avd.error=Cannot remove AVD. Please close the emulator cant.load.avds.error=Cannot reload AVD list. Please check SDK build.android.module.process.title=Create Android main package -package.name.must.contain.2.ids.error=A package name must contain 2 identifiers (i.e. com.example) +package.name.must.contain.2.ids.error=A package name must contain 2 segments (i.e. com.example) specify.platform.error=Please specify Android SDK specify.main.package.error=Android main package in module {0} not specified android.module.type.name=Android Module diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index 3e56484c6e81..1cd6304f0d25 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -41,6 +41,7 @@ import org.jetbrains.annotations.Nullable; import java.io.DataInput; import java.io.DataOutput; +import java.io.File; import java.io.IOException; import java.util.*; @@ -82,6 +83,24 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } private static GenerationItem[] doGenerate(final CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { + if (items == null || items.length == 0) { + return EMPTY_GENERATION_ITEM_ARRAY; + } + + // we have one item per module there, so clear output directory + final String genRootPath = FileUtil.toSystemDependentName(outputRootDirectory.getPath()); + final File genRootDir = new File(genRootPath); + if (genRootDir.exists()) { + if (!FileUtil.delete(genRootDir)) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot delete directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + if (!genRootDir.mkdir()) { + context.addMessage(CompilerMessageCategory.ERROR, "Cannot create directory " + genRootPath, null, -1, -1); + return EMPTY_GENERATION_ITEM_ARRAY; + } + } + List results = new ArrayList(items.length); boolean toRefresh = false; @@ -258,6 +277,13 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { -1, -1); continue; } + + if (!AndroidCommonUtils.contains2Identifiers(packageName)) { + final String message = "[" + module.getName() + "] Package name must contain at least 2 segments"; + myContext.addMessage(facet.getConfiguration().LIBRARY_PROJECT ? CompilerMessageCategory.WARNING : CompilerMessageCategory.ERROR, + message, manifestFile.getUrl(), -1, -1); + continue; + } final String[] libPackages = AndroidCompileUtil.getLibPackages(module, packageName); final Module circularDepLibWithSamePackage = AndroidCompileUtil.findCircularDependencyOnLibraryWithSamePackage(facet); diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/AndroidPackageConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/AndroidPackageConverter.java index 3d457a59a508..165f1fe1c21e 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/AndroidPackageConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/AndroidPackageConverter.java @@ -34,9 +34,6 @@ public class AndroidPackageConverter extends Converter implements Custom @Override public String fromString(@Nullable @NonNls String s, ConvertContext context) { - /*if (s == null) return null; - final JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject()); - return facade.findPackage(s) == null ? null : s;*/ return s; } diff --git a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java index 526d43d4d8a2..06547b1bd90b 100644 --- a/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java +++ b/plugins/android/src/org/jetbrains/android/exportSignedPackage/ApkStep.java @@ -58,6 +58,7 @@ import org.jetbrains.android.facet.AndroidRootUtil; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.util.AndroidBundle; import org.jetbrains.android.util.AndroidCommonUtils; +import org.jetbrains.android.util.SafeSignedJarBuilder; import org.jetbrains.android.util.SaveFileListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -282,7 +283,7 @@ class ApkStep extends ExportSignedPackageWizardStep { assert privateKey != null; X509Certificate certificate = myWizard.getCertificate(); assert certificate != null; - SignedJarBuilder builder = new SignedJarBuilder(fos, privateKey, certificate); + SignedJarBuilder builder = new SafeSignedJarBuilder(fos, privateKey, certificate, destFile.getPath()); FileInputStream fis = new FileInputStream(srcApk); try { builder.writeZip(fis, null); diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java index c9b6dfa70b98..c0fdabd8e656 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java @@ -437,10 +437,7 @@ public class AndroidFacetEditorTab extends FacetEditorTab { myConfiguration.RES_FOLDER_RELATIVE_PATH = '/' + getAndCheckRelativePath(absResPath, false); String absAssetsPath = myAssetsFolderField.getText().trim(); - if (absResPath.length() == 0) { - throw new ConfigurationException("Assets folder not specified"); - } - myConfiguration.ASSETS_FOLDER_RELATIVE_PATH = '/' + getAndCheckRelativePath(absAssetsPath, false); + myConfiguration.ASSETS_FOLDER_RELATIVE_PATH = absAssetsPath.length() > 0 ? '/' + getAndCheckRelativePath(absAssetsPath, false) : ""; String absApkPath = (String)myApkPathCombo.getComboBox().getEditor().getItem(); if (absApkPath.length() == 0) { @@ -451,10 +448,7 @@ public class AndroidFacetEditorTab extends FacetEditorTab { } String absLibsPath = myNativeLibsFolder.getText().trim(); - if (absLibsPath.length() == 0) { - throw new ConfigurationException("Native libs folder not specified"); - } - myConfiguration.LIBS_FOLDER_RELATIVE_PATH = '/' + getAndCheckRelativePath(absLibsPath, false); + myConfiguration.LIBS_FOLDER_RELATIVE_PATH = absLibsPath.length() > 0 ? '/' + getAndCheckRelativePath(absLibsPath, false) : ""; if (myConfiguration.LIBRARY_PROJECT != myIsLibraryProjectCheckbox.isSelected()) { runApt = true; @@ -633,6 +627,12 @@ public class AndroidFacetEditorTab extends FacetEditorTab { @Nullable private String toAbsolutePath(String genRelativePath) { + if (genRelativePath == null) { + return null; + } + if (genRelativePath.length() == 0) { + return ""; + } String moduleDirPath = AndroidRootUtil.getModuleDirPath(myContext.getModule()); if (moduleDirPath == null) return null; try { diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java index 04f021c92d83..c24eed85f9a6 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java @@ -117,6 +117,10 @@ public class AndroidRootUtil { @Nullable public static VirtualFile getFileByRelativeModulePath(Module module, String relativePath, boolean lookInContentRoot) { + if (relativePath == null || relativePath.length() == 0) { + return null; + } + VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); String moduleDirPath = new File(module.getModuleFilePath()).getParent(); diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java index ee4249762d5d..698b7319a208 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java @@ -24,6 +24,7 @@ import com.intellij.psi.JavaTokenType; import com.intellij.ui.DocumentAdapter; import com.intellij.util.ui.UIUtil; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -83,7 +84,7 @@ public class AndroidAppPropertiesEditor { if (!isValidPackageName(candidate)) { return AndroidBundle.message("not.valid.package.name.error", candidate); } - if (!contains2Identifiers(candidate)) { + if (!AndroidCommonUtils.contains2Identifiers(candidate)) { return AndroidBundle.message("package.name.must.contain.2.ids.error"); } return ""; @@ -157,8 +158,4 @@ public class AndroidAppPropertiesEditor { public JPanel getActivtiyPanel() { return myActivtiyPanel; } - - private static boolean contains2Identifiers(String packageName) { - return packageName.split("\\.").length >= 2; - } } diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java index 95ce23f5bf97..9be9195012cf 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java @@ -20,6 +20,7 @@ import com.android.AndroidConstants; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.intellij.CommonBundle; +import com.intellij.codeInsight.actions.ReformatCodeProcessor; import com.intellij.execution.RunManagerEx; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.configurations.GeneralCommandLine; @@ -374,6 +375,8 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { } } }); + + new ReformatCodeProcessor(project, module, false).run(); } }); } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/MessageNode.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/MessageNode.java index 42502723d1b8..0b584a55400d 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/MessageNode.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/MessageNode.java @@ -31,6 +31,7 @@ import javax.swing.tree.DefaultMutableTreeNode; final class MessageNode extends DefaultMutableTreeNode { private String[] myText; private AntMessage myMessage; + @Nullable private RangeMarker myRangeMarker; private Document myEditorDocument; private boolean myAllowToShowPosition; @@ -105,5 +106,13 @@ final class MessageNode extends DefaultMutableTreeNode { public int getPriority() { return myMessage.getPriority(); } + + public void clearRangeMarker() { + final RangeMarker rangeMarker = myRangeMarker; + if (rangeMarker != null) { + myRangeMarker = null; + rangeMarker.dispose(); + } + } } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java index acac4b46ec69..0bf420d2f77e 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java @@ -325,6 +325,10 @@ public final class TreeView implements AntOutputView, OccurenceNavigator { } public void clearAllMessages() { + for (MessageNode messageItem : myMessageItems) { + messageItem.clearRangeMarker(); + } + myMessageItems.clear(); myStatusNode = null; createModel(); myTree.setModel(myTreeModel); diff --git a/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/after.groovy.template b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/after.groovy.template new file mode 100644 index 000000000000..7b645b07a8f2 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/after.groovy.template @@ -0,0 +1,5 @@ +def foo(char c) { + ... +} + +foo('a' as char) \ No newline at end of file diff --git a/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/before.groovy.template b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/before.groovy.template new file mode 100644 index 000000000000..2472ed425e62 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/before.groovy.template @@ -0,0 +1,5 @@ +def foo(char c) { + ... +} + +foo('a') \ No newline at end of file diff --git a/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/description.html b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/description.html new file mode 100644 index 000000000000..b9439c2f48dd --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/GrConvertStringToCharIntention/description.html @@ -0,0 +1,5 @@ + + +Creates explicit cast to character literal. + + \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 78dfd1164efe..df1c77c38197 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -901,6 +901,11 @@ intention.category.groovy/intention.category.conversions org.jetbrains.plugins.groovy.intentions.conversions.ConvertGStringToStringIntention + + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle + intention.category.groovy/intention.category.conversions + org.jetbrains.plugins.groovy.intentions.conversions.GrConvertStringToCharIntention + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle intention.category.groovy/intention.category.conversions diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GrCastFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GrCastFix.java index 2f7240528272..e4cd6be74c27 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GrCastFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GrCastFix.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.codeInspection.assignment; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -32,25 +33,31 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; * @author Maxim.Medvedev */ public class GrCastFix extends GroovyFix implements LocalQuickFix { - private GrExpression myExpression; private PsiType myExpectedType; - public GrCastFix(GrExpression expression, PsiType expectedType) { - myExpression = expression; + public GrCastFix(PsiType expectedType) { myExpectedType = expectedType; } @Override protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { - if (!myExpression.isValid() || !myExpectedType.isValid()) return; + doCast(project, myExpectedType, descriptor.getPsiElement()); + } + + static void doCast(Project project, PsiType type, PsiElement element) { + if (!type.isValid()) return; + + if (!(element instanceof GrExpression)) return; + + final GrExpression expr = (GrExpression)element; final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project); final GrSafeCastExpression cast = (GrSafeCastExpression)factory.createExpressionFromText("foo as String"); - final GrTypeElement typeElement = factory.createTypeElement(myExpectedType); - cast.getOperand().replace(myExpression); + final GrTypeElement typeElement = factory.createTypeElement(type); + cast.getOperand().replaceWithExpression(expr, true); cast.getCastTypeElement().replace(typeElement); - final GrExpression replaced = myExpression.replaceWithExpression(cast, true); + final GrExpression replaced = expr.replaceWithExpression(cast, true); GrReferenceAdjuster.shortenReferences(replaced); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 0f4fd7d7ba04..ff68bf774825 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -19,9 +19,11 @@ package org.jetbrains.plugins.groovy.codeInspection.assignment; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Function; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +43,8 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; +import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; +import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; @@ -67,6 +71,8 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.MixinMemberContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -110,16 +116,16 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { } private static class MyVisitor extends BaseInspectionVisitor { - private void checkAssignability(@NotNull PsiType expectedType, @NotNull GrExpression expression, GroovyPsiElement element) { + private void checkAssignability(@NotNull PsiType expectedType, @NotNull GrExpression expression) { if (PsiUtil.isRawClassMemberAccess(expression)) return; //GRVY-2197 - if (checkForImplicitEnumAssigning(expectedType, expression, element)) return; + if (checkForImplicitEnumAssigning(expectedType, expression, expression)) return; final PsiType rType = expression.getType(); if (rType == null || rType == PsiType.VOID) return; - if (!TypesUtil.isAssignable(expectedType, rType, element)) { - final LocalQuickFix[] fixes = {new GrCastFix(expression, expectedType)}; + if (!TypesUtil.isAssignable(expectedType, rType, expression)) { + final LocalQuickFix[] fixes = {new GrCastFix(expectedType)}; final String message = GroovyBundle.message("cannot.assign", rType.getPresentableText(), expectedType.getPresentableText()); - registerError(element, message, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + registerError(expression, message, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } } @@ -166,7 +172,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (returnValue != null && !(returnValue.getParent() instanceof GrReturnStatement) && !isNewInstanceInitialingByTuple(returnValue)) { - checkAssignability(expectedType, returnValue, returnValue); + checkAssignability(expectedType, returnValue); } return true; } @@ -185,7 +191,11 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { final PsiType expectedType = method.getReturnType(); if (value == null || expectedType == null) return; - checkAssignability(expectedType, value, returnStatement); + + //don't check if the return type is void. the check is done inside annotator, because it's a compilation error + if (expectedType == PsiType.VOID) return; + + checkAssignability(expectedType, value); } @Override @@ -211,7 +221,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (clazz != null && CommonClassNames.JAVA_UTIL_LIST.equals(clazz.getQualifiedName())) { final PsiType[] types = pct.getParameters(); if (types.length == 1 && types[0] != null && rType != null) { - checkAssignability(types[0], rValue, rValue); + checkAssignability(types[0], rValue); } } return; @@ -227,7 +237,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { } if (lType != null && rType != null) { - checkAssignability(lType, rValue, rValue); + checkAssignability(lType, rValue); } } @@ -245,7 +255,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { return; } - checkAssignability(varType, initializer, initializer); + checkAssignability(varType, initializer); } private static boolean isNewInstanceInitialingByTuple(GrExpression initializer) { @@ -359,8 +369,8 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { final GrExpression exception = throwStatement.getException(); if (exception != null) { - checkAssignability(PsiType.getJavaLangThrowable(throwStatement.getManager(), throwStatement.getResolveScope()), exception, - exception); + checkAssignability(PsiType.getJavaLangThrowable(throwStatement.getManager(), throwStatement.getResolveScope()), exception + ); } } @@ -538,7 +548,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { } private void highlightInapplicableMethodUsage(GroovyResolveResult methodResolveResult, - PsiElement place, + GroovyPsiElement place, PsiMethod method, PsiType[] argumentTypes) { final PsiClass containingClass = @@ -559,9 +569,32 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { else { message = GroovyBundle.message("cannot.apply.method1", method.getName(), canonicalText, typesString); } - registerError(getElementToHighlight(place, PsiUtil.getArgumentsList(place)), message); + + registerError(getElementToHighlight(place, PsiUtil.getArgumentsList(place)), message, + genCastFixes(GrClosureSignatureUtil.createSignature(methodResolveResult), argumentTypes, place), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } + private static LocalQuickFix[] genCastFixes(GrSignature signature, PsiType[] argumentTypes, GroovyPsiElement context) { + + final List signatures = GrClosureSignatureUtil.generateSimpleSignature(signature); + + List> errors = new ArrayList>(); + for (GrClosureSignature closureSignature : signatures) { + final GrClosureSignatureUtil.MapResultWithError map = + GrClosureSignatureUtil.mapSimpleSignatureWithErrors(closureSignature, argumentTypes, Function.ID, context, 1); + if (map != null) { + errors.addAll(map.getErrors()); + } + } + + final ArrayList fixes = new ArrayList(); + for (Pair error : errors) { + fixes.add(new ParameterCastFix(error.first, error.second)); + } + + return fixes.toArray(new LocalQuickFix[fixes.size()]); + } private boolean checkCallApplicability(PsiType type, GroovyPsiElement invokedExpr, boolean checkUnknownArgs) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/ParameterCastFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/ParameterCastFix.java new file mode 100644 index 000000000000..7714be1f6756 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/ParameterCastFix.java @@ -0,0 +1,84 @@ +/* + * 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 org.jetbrains.plugins.groovy.codeInspection.assignment; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.codeInspection.GroovyFix; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +/** + * @author Max Medvedev + */ +public class ParameterCastFix extends GroovyFix { + private final int param; + private final PsiType myType; + private String myName; + + public ParameterCastFix(int param, PsiType type) { + this.param = param; + myType = type; + + StringBuilder builder = new StringBuilder(); + builder.append("Cast "); + + builder.append(param + 1); + switch (param + 1) { + case 1: + builder.append("st"); + break; + case 2: + builder.append("nd"); + break; + case 3: + builder.append("rd"); + break; + default: + builder.append("th"); + break; + } + builder.append(" parameter to ").append(type.getCanonicalText()); + + + myName = builder.toString(); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + final GrArgumentList list = element instanceof GrArgumentList ? (GrArgumentList)element :PsiUtil.getArgumentsList(element); + if (list == null) return; + + final GrExpression[] arguments = list.getExpressionArguments(); + + final int p = list.getNamedArguments().length > 0 ? param - 1 : param; + if (arguments.length <= p) return; + + GrCastFix.doCast(project, myType, arguments[p]); + } + + @NotNull + @Override + public String getName() { + return myName; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties index f10fee212f67..d6ad7e92ace5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties @@ -154,4 +154,6 @@ remove.parameter.0=Remove parameter ''{0}'' remove.unused.parameter=Remove unused parameter remove.exception=Remove exception remove.catch.block=Remove catch block -try.catch.fix=Try-catch fix \ No newline at end of file +try.catch.fix=Try-catch fix +gr.convert.string.to.char.intention.name=Cast to char +gr.convert.string.to.char.intention.family.name=Cast to char diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/GrConvertStringToCharIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/GrConvertStringToCharIntention.java new file mode 100644 index 000000000000..516336a29009 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/GrConvertStringToCharIntention.java @@ -0,0 +1,55 @@ +/* + * 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 org.jetbrains.plugins.groovy.intentions.conversions; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.intentions.base.Intention; +import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSafeCastExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; + +/** + * @author Max Medvedev + */ +public class GrConvertStringToCharIntention extends Intention { + @Override + protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException { + final GrExpression cast = GroovyPsiElementFactory.getInstance(project).createExpressionFromText("a as char"); + ((GrSafeCastExpression)cast).getOperand().replaceWithExpression((GrExpression)element, true); + + ((GrExpression)element).replaceWithExpression(cast, true); + } + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new PsiElementPredicate() { + @Override + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof GrLiteral)) return false; + + final Object value = ((GrLiteral)element).getValue(); + return value instanceof String && ((String)value).length() == 1; + } + }; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java index b2d1341f3b6c..3e22c2ebb6be 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/signatures/GrClosureSignatureUtil.java @@ -847,4 +847,94 @@ public class GrClosureSignatureUtil { return null; } + + + public static class MapResultWithError { + private final ArgInfo[] mapping; + private final List> errorsAndExpectedType; + + public MapResultWithError(ArgInfo[] mapping, List> errorsAndExpectedType) { + this.mapping = mapping; + this.errorsAndExpectedType = errorsAndExpectedType; + } + + public ArgInfo[] getMapping() { + return mapping; + } + + public List> getErrors() { + return errorsAndExpectedType; + } + } + + @Nullable + public static MapResultWithError mapSimpleSignatureWithErrors(@NotNull GrClosureSignature signature, + @NotNull Arg[] args, + @NotNull Function typeComputer, + @NotNull GroovyPsiElement context, + int maxErrorCount) { + final GrClosureParameter[] params = signature.getParameters(); + if (args.length < params.length) return null; + + if (args.length > params.length && !signature.isVarargs()) return null; + + int optional = getOptionalParamCount(params, false); + assert optional == 0; + + int errorCount = 0; + ArgInfo[] map = new ArgInfo[params.length]; + + List> errors = new ArrayList>(maxErrorCount); + + for (int i = 0; i < params.length; i++) { + if (isAssignableByConversion(params[i].getType(), typeComputer.fun(args[i]), context)) { + map[i] = new ArgInfo(args[i]); + } + else if (params[i].getType() instanceof PsiArrayType && i == params.length - 1) { + if (i + 1 == args.length) { + errors.add(new Pair(i, params[i].getType())); + } + final PsiType ellipsis = ((PsiArrayType)params[i].getType()).getComponentType(); + for (int j = i; j < args.length; j++) { + if (!isAssignableByConversion(ellipsis, typeComputer.fun(args[j]), context)) { + errorCount++; + if (errorCount > maxErrorCount) return null; + errors.add(new Pair(i, ellipsis)); + } + map[i] = new ArgInfo(args[i]); + } + } + else { + errorCount++; + if (errorCount > maxErrorCount) return null; + errors.add(new Pair(i, params[i].getType())); + } + } + return new MapResultWithError(map, errors); + } + + public static List generateSimpleSignature(GrSignature signature) { + final List result = new ArrayList(); + signature.accept(new GrRecursiveSignatureVisitor() { + @Override + public void visitClosureSignature(GrClosureSignature signature) { + final GrClosureParameter[] original = signature.getParameters(); + final ArrayList parameters = new ArrayList(original.length); + + for (GrClosureParameter parameter : original) { + parameters.add(new GrClosureParameterImpl(parameter.getType(), false, null)); + } + + final int pcount = signature.isVarargs() ? signature.getParameterCount() - 2 : signature.getParameterCount() - 1; + for (int i = pcount; i >= 0; i--) { + if (original[i].isOptional()) { + result.add(new GrClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); + parameters.remove(i); + } + } + result.add(new GrClosureSignatureImpl(parameters.toArray(new GrClosureParameter[parameters.size()]), signature.getReturnType(), signature.isVarargs(), false)); + } + }); + return result; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ArgumentCastTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ArgumentCastTest.groovy new file mode 100644 index 000000000000..df598c39c8c5 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ArgumentCastTest.groovy @@ -0,0 +1,59 @@ +/* + * 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 org.jetbrains.plugins.groovy.intentions + +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection + +/** + * @author Max Medvedev + */ +class ArgumentCastTest extends GrIntentionTestCase { + void test0() { + doTextTest('''\ +def foo(char c) {} +foo('a') +''', "Cast 1st parameter to char", '''\ +def foo(char c) {} +foo('a' as char) +''', GroovyAssignabilityCheckInspection) + } + + void test1() { + doTextTest('''\ +def foo(char c, int x) {} +foo('a', 2) +''', "Cast 1st parameter to char", '''\ +def foo(char c, int x) {} +foo('a' as char, 2) +''', GroovyAssignabilityCheckInspection) + } + + void test2() { + doAntiTest('''\ +def foo(char c, int x) {} + +foo('a', 2, 3) +''', "Cast 1st parameter to char", GroovyAssignabilityCheckInspection) + } + + void test3() { + doAntiTest('''\ +def foo(char c, int x) {} + +foo('a', 'a') +''', "Cast 1st parameter to char", GroovyAssignabilityCheckInspection) + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.groovy index 1534b0179da6..becb31f9c61e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/GrIntentionTestCase.groovy @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.intentions; import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInspection.LocalInspectionTool import com.intellij.psi.impl.source.PostprocessReformattingAspect import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase @@ -44,16 +45,18 @@ public abstract class GrIntentionTestCase extends LightCodeInsightFixtureTestCas } } - protected void doTextTest(String before, String hint, String after) { + protected void doTextTest(String before, String hint, String after, Class... inspections) { myFixture.configureByText("a.groovy", before); + myFixture.enableInspections(inspections) final List list = myFixture.filterAvailableIntentions(hint); myFixture.launchAction(assertOneElement(list)); PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); myFixture.checkResult(after); } - protected void doAntiTest(String before, String hint) { + protected void doAntiTest(String before, String hint, Class... inspections) { myFixture.configureByText("a.groovy", before); + myFixture.enableInspections(inspections) assertEmpty(myFixture.filterAvailableIntentions(hint)); } } diff --git a/plugins/groovy/testdata/highlighting/IncompatibleTypesAssignments.groovy b/plugins/groovy/testdata/highlighting/IncompatibleTypesAssignments.groovy index ec3ab80efe0d..43eec020a3ac 100644 --- a/plugins/groovy/testdata/highlighting/IncompatibleTypesAssignments.groovy +++ b/plugins/groovy/testdata/highlighting/IncompatibleTypesAssignments.groovy @@ -1,6 +1,6 @@ class X{ int method1(Date date) { - return date; + return date; } int method2(Date date) { diff --git a/plugins/groovy/testdata/highlighting/ReturnAssignability.groovy b/plugins/groovy/testdata/highlighting/ReturnAssignability.groovy index 7a8991cc01ad..d4f2e02df3f6 100644 --- a/plugins/groovy/testdata/highlighting/ReturnAssignability.groovy +++ b/plugins/groovy/testdata/highlighting/ReturnAssignability.groovy @@ -3,7 +3,7 @@ File foo() { if (ints.empty) { print {return 42} for (x in ints) { - return 43 + return 43 } } 67 diff --git a/plugins/properties/src/META-INF/plugin.xml b/plugins/properties/src/META-INF/plugin.xml index 6e8de1a88fbc..b5053ce9440b 100644 --- a/plugins/properties/src/META-INF/plugin.xml +++ b/plugins/properties/src/META-INF/plugin.xml @@ -10,6 +10,8 @@ + diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertiesRefactoringSettings.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertiesRefactoringSettings.java new file mode 100644 index 000000000000..650f2ac0555c --- /dev/null +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/PropertiesRefactoringSettings.java @@ -0,0 +1,44 @@ +/* + * 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.lang.properties.refactoring; + +import com.intellij.openapi.components.*; +import com.intellij.util.xmlb.XmlSerializerUtil; + +@State( + name = "PropertiesRefactoringSettings", + storages = { + @Storage( + file = StoragePathMacros.APP_CONFIG + "/other.xml" + )} +) +public class PropertiesRefactoringSettings implements PersistentStateComponent { + + + public boolean RENAME_SEARCH_IN_COMMENTS = false; + + public static PropertiesRefactoringSettings getInstance() { + return ServiceManager.getService(PropertiesRefactoringSettings.class); + } + + public PropertiesRefactoringSettings getState() { + return this; + } + + public void loadState(PropertiesRefactoringSettings state) { + XmlSerializerUtil.copyBean(state, this); + } +} \ No newline at end of file diff --git a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java b/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java index 4119c3dc287f..6bdaa0957133 100644 --- a/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java +++ b/plugins/properties/src/com/intellij/lang/properties/refactoring/RenamePropertyProcessor.java @@ -61,4 +61,14 @@ public class RenamePropertyProcessor extends RenamePsiElementProcessor { } } } + + @Override + public boolean isToSearchInComments(PsiElement element) { + return PropertiesRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS; + } + + @Override + public void setToSearchInComments(PsiElement element, boolean enabled) { + PropertiesRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS = enabled; + } } diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy b/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy index 59fa4bf07e44..47f437e26fda 100644 --- a/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy +++ b/plugins/rearranger/test/src/com/wrq/rearranger/RearrangerTest.groovy @@ -43,6 +43,7 @@ class RearrangerTest extends LightCodeInsightFixtureTestCase { private JavaFieldRuleBuilder fieldRule private JavaMethodRuleBuilder methodRule private CommentRuleBuilder commentRule + private JavaSpacingRule spacingRule @Override protected String getBasePath() { @@ -65,6 +66,7 @@ class RearrangerTest extends LightCodeInsightFixtureTestCase { fieldRule = new JavaFieldRuleBuilder(settings: mySettings) methodRule = new JavaMethodRuleBuilder(settings: mySettings) commentRule = new CommentRuleBuilder(settings: mySettings) + spacingRule = new JavaSpacingRule(settings: mySettings) } public final void testNoRearrangement() throws Exception { @@ -507,306 +509,155 @@ class RearrangerTest extends LightCodeInsightFixtureTestCase { methodRule.create { sort( SortType.BY_NAME ) } } } -// public final void testKeepOverloadsTogetherOriginalOrder() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); -// rs.setKeepOverloadedMethodsTogether(true); -// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_RETAIN_ORIGINAL); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19A.java"); -// } -// -// public final void testKeepOverloadsTogetherAscendingOrder() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); -// rs.setKeepOverloadedMethodsTogether(true); -// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19B.java"); -// } -// -// public final void testKeepOverloadsTogetherDescendingOrder() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest19.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getExtractedMethodsSettings().setMoveExtractedMethods(false); -// rs.setKeepOverloadedMethodsTogether(true); -// rs.setOverloadedOrder(RearrangerSettings.OVERLOADED_ORDER_DESCENDING_PARAMETERS); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult19C.java"); -// } -// -// public final void testInnerClassReferenceToChild() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest20.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getExtractedMethodsSettings().setMoveExtractedMethods(true); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult20.java"); -// } -// -// public final void testMultipleFieldDecl() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest21.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// FieldAttributes fa = new FieldAttributes(); -// fa.getSortAttr().setByName(true); -// rs.addItem(fa, 0); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult21.java"); -// } -// -// public final void testRemoveBlankLines() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest1.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getAfterClassLBrace().setForce(true); -// rs.getAfterClassLBrace().setnBlankLines(0); -// rs.getAfterMethodLBrace().setForce(true); -// rs.getAfterMethodLBrace().setnBlankLines(0); -// rs.getBeforeMethodRBrace().setForce(true); -// rs.getBeforeMethodRBrace().setnBlankLines(0); -// rs.getAfterMethodRBrace().setForce(true); -// rs.getAfterMethodRBrace().setnBlankLines(0); -// rs.getBeforeClassRBrace().setForce(true); -// rs.getBeforeClassRBrace().setnBlankLines(0); -// rs.getAfterClassRBrace().setForce(true); -// rs.getAfterClassRBrace().setnBlankLines(0); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(1); -// rs.setRemoveBlanksInsideCodeBlocks(true); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult1.java"); -// } -// -// public final void testAddBlankLines() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest2.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getAfterClassLBrace().setForce(true); -// rs.getAfterClassLBrace().setnBlankLines(2); -// rs.getAfterMethodLBrace().setForce(true); -// rs.getAfterMethodLBrace().setnBlankLines(3); -// rs.getBeforeMethodRBrace().setForce(true); -// rs.getBeforeMethodRBrace().setnBlankLines(2); -// rs.getAfterMethodRBrace().setForce(true); -// rs.getAfterMethodRBrace().setnBlankLines(1); -// rs.getBeforeClassRBrace().setForce(true); -// rs.getBeforeClassRBrace().setnBlankLines(3); -// rs.getAfterClassRBrace().setForce(true); -// rs.getAfterClassRBrace().setnBlankLines(4); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(1); -// rs.setRemoveBlanksInsideCodeBlocks(true); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult2.java"); -// } -// -// public final void testInnerClassBlankLines() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest4.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rs.getAfterClassLBrace().setForce(true); -// rs.getAfterClassLBrace().setnBlankLines(0); -// rs.getAfterMethodLBrace().setForce(true); -// rs.getAfterMethodLBrace().setnBlankLines(0); -// rs.getBeforeMethodRBrace().setForce(true); -// rs.getBeforeMethodRBrace().setnBlankLines(0); -// rs.getAfterMethodRBrace().setForce(true); -// rs.getAfterMethodRBrace().setnBlankLines(1); -// rs.getBeforeClassRBrace().setForce(true); -// rs.getBeforeClassRBrace().setnBlankLines(1); -// rs.getAfterClassRBrace().setForce(true); -// rs.getAfterClassRBrace().setnBlankLines(1); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(1); -// rs.setRemoveBlanksInsideCodeBlocks(true); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult4.java"); -// } -// -// public void testInnerClassSpacing() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest5.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final File physFile = new File(InteractiveTest.DEFAULT_CONFIGURATION); -// rs = RearrangerSettings.getSettingsFromFile(physFile); -// rs.setAskBeforeRearranging(false); -// rs.getAfterClassRBrace().setnBlankLines(2); -// rs.getAfterClassRBrace().setForce(true); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(3); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult5.java"); -// } -// -// public void testNoRearrangementInnerClass() throws Exception { -// configureByFile("/com/wrq/rearranger/NoRearrangeInnerClassTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final File settingsFile = new File(InteractiveTest.DEFAULT_CONFIGURATION_ROOT + -// "/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml"); -// rs = RearrangerSettings.getSettingsFromFile(settingsFile); -// rs.setAskBeforeRearranging(false); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/NoRearrangeInnerClassResult.java"); -// } -// -// public void testSpacingWithTrailingWhitespace() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest6.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); -// rs.setAskBeforeRearranging(false); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(1); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult6.java"); -// } -// -// public void testSpacingJoinLineBug() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest7.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// File settingsFile = new File(InteractiveTest.DEFAULT_CONFIGURATION_ROOT + -// "/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml"); -// rs = RearrangerSettings.getSettingsFromFile(settingsFile); -// rs.setAskBeforeRearranging(false); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult7.java"); -// } -// -// /** -// * Submitted by Brian Buckley. -// * -// * @throws Exception test exception -// */ -// public void testSpacingConflictingSettingBug() throws Exception { -// configureByFile("/com/wrq/rearranger/SpaceTest8.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// rs = RearrangerSettings.getSettingsFromFile(new File(InteractiveTest.DEFAULT_CONFIGURATION)); -// rs.setAskBeforeRearranging(false); -// rs.getAfterClassLBrace().setForce(true); -// rs.getAfterClassLBrace().setnBlankLines(0); -// rs.getBeforeMethodLBrace().setForce(true); -// rs.getBeforeMethodLBrace().setnBlankLines(1); -// rs.getNewlinesAtEOF().setForce(true); -// rs.getNewlinesAtEOF().setnBlankLines(1); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/SpaceResult8.java"); -// } -// -// public void testGetPrefixImmaterial() throws Exception { -// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_IMMATERIAL); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/GetPrefixImmaterialResult.java"); -// } -// -// public void testGetPrefixReturns() throws Exception { -// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/GetPrefixReturnsResult.java"); -// } -// -// public void testGetPrefixReturnsField() throws Exception { -// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/GetPrefixReturnsFieldResult.java"); -// } -// -// public void testGetFieldReturns() throws Exception { -// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/GetFieldReturnsResult.java"); -// } -// -// public void testGetFieldReturnsField() throws Exception { -// configureByFile("/com/wrq/rearranger/GetterDefinitionTest.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/GetFieldReturnsFieldResult.java"); -// } -// -// public void testSpecialGS() throws Exception { -// configureByFile("/com/wrq/rearranger/RearrangementTest22.java"); -// final PsiFile file = getFile(); -// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file); -// final RearrangerActionHandler rah = new RearrangerActionHandler(); -// MethodAttributes ma = new MethodAttributes(); -// GetterSetterDefinition gsd = ma.getGetterSetterDefinition(); -// rs.addItem(ma, 0); -// ma.setGetterSetterMethodType(true); -// gsd.setGetterNameCriterion(GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX); -// gsd.setGetterBodyCriterion(GetterSetterDefinition.GETTER_BODY_RETURNS); -// gsd.setSetterBodyCriterion(GetterSetterDefinition.SETTER_BODY_IMMATERIAL); -// gsd.setSetterNameCriterion(GetterSetterDefinition.SETTER_NAME_CORRECT_PREFIX); -// rs.setKeepGettersSettersTogether(true); -// rah.rearrangeDocument(getProject(), file, rs, doc); -// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult22.java"); -// } -// + public final void testKeepOverloadsTogetherOriginalOrder() throws Exception { + doTest('RearrangementTest19', 'RearrangementResult19A') { + mySettings.extractedMethodsSettings.moveExtractedMethods = false + mySettings.keepOverloadedMethodsTogether = true + mySettings.overloadedOrder = RearrangerSettings.OVERLOADED_ORDER_RETAIN_ORIGINAL + } } + + public final void testKeepOverloadsTogetherAscendingOrder() throws Exception { + doTest('RearrangementTest19', 'RearrangementResult19B') { + mySettings.extractedMethodsSettings.moveExtractedMethods = false + mySettings.keepOverloadedMethodsTogether = true + mySettings.overloadedOrder = RearrangerSettings.OVERLOADED_ORDER_ASCENDING_PARAMETERS + } } + + public final void testKeepOverloadsTogetherDescendingOrder() throws Exception { + doTest('RearrangementTest19', 'RearrangementResult19C') { + mySettings.extractedMethodsSettings.moveExtractedMethods = false + mySettings.keepOverloadedMethodsTogether = true + mySettings.overloadedOrder = RearrangerSettings.OVERLOADED_ORDER_DESCENDING_PARAMETERS + } } + + public final void testInnerClassReferenceToChild() throws Exception { + doTest('RearrangementTest20', 'RearrangementResult20') { + mySettings.extractedMethodsSettings.moveExtractedMethods = true + } } + + public final void testMultipleFieldDecl() throws Exception { + doTest('RearrangementTest21', 'RearrangementResult21') { + fieldRule.create { sort( SortType.BY_NAME ) } + } } + + public final void testRemoveBlankLines() throws Exception { + doTest('SpaceTest1', 'SpaceResult1') { + spacingRule.create { + spacing(anchor: [ SpacingAnchor.AFTER_CLASS_LBRACE, SpacingAnchor.AFTER_METHOD_LBRACE, SpacingAnchor.BEFORE_METHOD_RBRACE, + SpacingAnchor.BEFORE_CLASS_RBRACE, SpacingAnchor.AFTER_CLASS_RBRACE ], + lines: 0) + } + spacingRule.create { + spacing( anchor: SpacingAnchor.EOF, lines: 1 ) + } + mySettings.removeBlanksInsideCodeBlocks = true + } } + + public final void testAddBlankLines() throws Exception { + doTest('SpaceTest2', 'SpaceResult2') { + spacingRule.create { + spacing( anchor: [ SpacingAnchor.AFTER_METHOD_RBRACE, SpacingAnchor.EOF ], lines: 1) + spacing(anchor: [ SpacingAnchor.AFTER_CLASS_LBRACE, SpacingAnchor.AFTER_METHOD_LBRACE ], lines: 2) + spacing( anchor: SpacingAnchor.AFTER_CLASS_RBRACE, lines: 4) + } + mySettings.removeBlanksInsideCodeBlocks = true + } } + + public final void testInnerClassBlankLines() throws Exception { + doTest('SpaceTest4', 'SpaceResult4') { + spacingRule.create { + spacing(anchor: [ SpacingAnchor.AFTER_CLASS_LBRACE, SpacingAnchor.AFTER_METHOD_LBRACE, SpacingAnchor.BEFORE_METHOD_RBRACE ], + lines: 0) + spacing(anchor: [ SpacingAnchor.AFTER_METHOD_RBRACE, SpacingAnchor.EOF ], + lines: 1) + } + mySettings.removeBlanksInsideCodeBlocks = true + } } + + public void testInnerClassSpacing() throws Exception { + doTest('SpaceTest5', 'SpaceResult5') { + spacingRule.create { + spacing( anchor: SpacingAnchor.AFTER_CLASS_RBRACE, lines: 2 ) + spacing( anchor: SpacingAnchor.EOF, lines: 3 ) + } } } + + public void testSpacingWithTrailingWhitespace() throws Exception { + doTest('SpaceTest6', 'SpaceResult6') { + spacingRule.create { spacing( anchor: SpacingAnchor.EOF, lines: 1 ) } + } } + + /** + * Submitted by Brian Buckley. + * + * @throws Exception test exception + */ + public void testSpacingConflictingSettingBug() throws Exception { + doTest('SpaceTest8', 'SpaceResult8') { + spacingRule.create { spacing( anchor: SpacingAnchor.AFTER_CLASS_LBRACE, lines: 0) } + spacingRule.create { + spacing( anchor: [ SpacingAnchor.BEFORE_METHOD_LBRACE, SpacingAnchor.EOF ], lines: 1) + } } } + + public void testGetPrefixImmaterial() throws Exception { + doTest('GetterDefinitionTest', 'GetPrefixImmaterialResult') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX, + body: GetterSetterDefinition.GETTER_BODY_IMMATERIAL + ) } } } + + public void testGetPrefixReturns() throws Exception { + doTest('GetterDefinitionTest', 'GetPrefixReturnsResult') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX, + body: GetterSetterDefinition.GETTER_BODY_RETURNS + ) } } } + + public void testGetPrefixReturnsField() throws Exception { + doTest('GetterDefinitionTest', 'GetPrefixReturnsFieldResult') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX, + body: GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD + ) } } } + + public void testGetFieldReturns() throws Exception { + doTest('GetterDefinitionTest', 'GetFieldReturnsResult') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD, + body: GetterSetterDefinition.GETTER_BODY_RETURNS + ) } } } + + public void testGetFieldReturnsField() throws Exception { + doTest('GetterDefinitionTest', 'GetFieldReturnsFieldResult') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_MATCHES_FIELD, + body: GetterSetterDefinition.GETTER_BODY_RETURNS_FIELD + ) } } } + + public void testSpecialGS() throws Exception { + doTest('RearrangementTest22', 'RearrangementResult22') { + methodRule.create { + target( MethodType.GETTER_OR_SETTER ) + getterCriteria( + name: GetterSetterDefinition.GETTER_NAME_CORRECT_PREFIX, + body: GetterSetterDefinition.GETTER_BODY_RETURNS + ) + setterCriteria( + name: GetterSetterDefinition.SETTER_NAME_CORRECT_PREFIX, + body: GetterSetterDefinition.SETTER_BODY_IMMATERIAL + ) } + mySettings.keepGettersSettersTogether = true + } } + // public void testInterfaceNoNameNotAlphabeticalNoExcludeMethodAlphabetical() throws Exception { // configureByFile("/com/wrq/rearranger/RearrangementTest23.java"); // final PsiFile file = getFile(); diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/util/AbstractRuleBuilder.groovy b/plugins/rearranger/test/src/com/wrq/rearranger/util/AbstractRuleBuilder.groovy index 58ef7a75e831..2b3452f0fe91 100644 --- a/plugins/rearranger/test/src/com/wrq/rearranger/util/AbstractRuleBuilder.groovy +++ b/plugins/rearranger/test/src/com/wrq/rearranger/util/AbstractRuleBuilder.groovy @@ -5,6 +5,7 @@ import com.wrq.rearranger.settings.RearrangerSettings import com.wrq.rearranger.settings.atomicAttributes.AndNotAttribute import com.wrq.rearranger.settings.attributeGroups.Rule import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable import org.junit.Assert /** @@ -31,7 +32,7 @@ public abstract class AbstractRuleBuilder extends BuilderSupport { @Override protected void nodeCompleted(Object parent, Object node) { - if (!parent) { + if (!parent && node) { registerRule(settings, node as T) } } @@ -72,7 +73,7 @@ public abstract class AbstractRuleBuilder extends BuilderSupport { getCurrent() } - @NotNull + @Nullable protected abstract T createRule() protected abstract void registerRule(@NotNull RearrangerSettings settings, @NotNull T rule) diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/util/RearrangerTestDsl.java b/plugins/rearranger/test/src/com/wrq/rearranger/util/RearrangerTestDsl.java index 41888a50535d..c6a46cbeb636 100644 --- a/plugins/rearranger/test/src/com/wrq/rearranger/util/RearrangerTestDsl.java +++ b/plugins/rearranger/test/src/com/wrq/rearranger/util/RearrangerTestDsl.java @@ -22,6 +22,7 @@ public enum RearrangerTestDsl { COMMENT, GETTER_CRITERIA("getterCriteria"), SETTER_CRITERIA("setterCriteria"), + SPACING, // Attributes INVERT, @@ -30,7 +31,9 @@ public enum RearrangerTestDsl { ALL_PRECEDING("allPreceding"), SUBSEQUENT_RULES_TO_MATCH("subsequentRulesToMatch"), PRECEDING_RULES_TO_MATCH("precedingRulesToMatch"), - BODY; + BODY, + ANCHOR, + BLANK_LINES("lines"); @NotNull private final String myValue; diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/util/java/JavaSpacingRule.groovy b/plugins/rearranger/test/src/com/wrq/rearranger/util/java/JavaSpacingRule.groovy new file mode 100644 index 000000000000..559df6d97ae8 --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/util/java/JavaSpacingRule.groovy @@ -0,0 +1,41 @@ +package com.wrq.rearranger.util.java + +import com.wrq.rearranger.util.AbstractRuleBuilder +import com.wrq.rearranger.settings.RearrangerSettings +import com.wrq.rearranger.util.RearrangerTestDsl + +/** + * @author Denis Zhdanov + * @since 5/21/12 12:54 PM + */ +class JavaSpacingRule extends AbstractRuleBuilder { + + { + def spacingAnchorToProperty = [ + (SpacingAnchor.AFTER_CLASS_LBRACE) : 'afterClassLBrace', + (SpacingAnchor.BEFORE_CLASS_RBRACE) : 'beforeClassRBrace', + (SpacingAnchor.AFTER_CLASS_RBRACE) : 'afterClassRBrace', + (SpacingAnchor.AFTER_METHOD_LBRACE) : 'afterMethodLBrace', + (SpacingAnchor.AFTER_METHOD_RBRACE) : 'afterMethodRBrace', + (SpacingAnchor.BEFORE_METHOD_LBRACE) : 'beforeMethodLBrace', + (SpacingAnchor.BEFORE_METHOD_RBRACE) : 'beforeMethodRBrace', + (SpacingAnchor.EOF) : 'newLinesAtEOF' + ] + registerHandler(RearrangerTestDsl.SPACING, {value, attributes, rule -> + for (i in attributes[RearrangerTestDsl.ANCHOR.value]) { + def s = settings."${spacingAnchorToProperty[i]}" + s.force = true + s.nBlankLines = attributes[RearrangerTestDsl.BLANK_LINES.value] + } + }) + } + + @Override + protected Void createRule() { + null + } + + @Override + protected void registerRule(RearrangerSettings settings, Void rule) { + } +} diff --git a/plugins/rearranger/test/src/com/wrq/rearranger/util/java/SpacingAnchor.java b/plugins/rearranger/test/src/com/wrq/rearranger/util/java/SpacingAnchor.java new file mode 100644 index 000000000000..3e54ae204a2e --- /dev/null +++ b/plugins/rearranger/test/src/com/wrq/rearranger/util/java/SpacingAnchor.java @@ -0,0 +1,10 @@ +package com.wrq.rearranger.util.java; + +/** + * @author Denis Zhdanov + * @since 5/21/12 10:11 AM + */ +public enum SpacingAnchor { + EOF, AFTER_CLASS_LBRACE, BEFORE_CLASS_RBRACE, AFTER_CLASS_RBRACE, AFTER_METHOD_LBRACE, AFTER_METHOD_RBRACE, + BEFORE_METHOD_LBRACE, BEFORE_METHOD_RBRACE +} diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java index a0f03cfacfab..1c5de8b2d482 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsFieldResult.java @@ -1,9 +1,9 @@ public class GetterDefinitionTest { + /** name: matches field; body: returns field */ public int getField2() { return field2; } - int dummyField; int field; int field2; diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java index a0f03cfacfab..1c5de8b2d482 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetFieldReturnsResult.java @@ -1,9 +1,9 @@ public class GetterDefinitionTest { + /** name: matches field; body: returns field */ public int getField2() { return field2; } - int dummyField; int field; int field2; diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java index 4e4b1508b8b1..c1d02458afd7 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixImmaterialResult.java @@ -1,4 +1,5 @@ public class GetterDefinitionTest { + /** name: correct prefix; body: immaterial */ public int getY() { dummyField++; @@ -24,9 +25,9 @@ public class GetterDefinitionTest { public int getField2() { return field2; } - int dummyField; int field; int field2; + int dummyField2; } \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java index a0f03cfacfab..1c5de8b2d482 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsFieldResult.java @@ -1,9 +1,9 @@ public class GetterDefinitionTest { + /** name: matches field; body: returns field */ public int getField2() { return field2; } - int dummyField; int field; int field2; diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java index 07e95ab15c4f..542e5d8b7d6a 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/GetPrefixReturnsResult.java @@ -1,4 +1,5 @@ public class GetterDefinitionTest { + /** name: correct prefix; body: returns */ public int getX() { return field + 1; @@ -18,7 +19,6 @@ public class GetterDefinitionTest { public int getField2() { return field2; } - int dummyField; int field; int field2; diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml deleted file mode 100644 index 06765c372a62..000000000000 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/NoRearrangementInnerClassCfg.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\ \ - //\ -----\ Constructor(s)\ --------------------------------------------------------------------------------------------\n - - - - - - - - - - - - - - - - - - - - - - - \n\ \ //-----\ Interface\ %IF%\ \ ----------------------------------\n - - - - - - - \n\ \ - //\ -----\ Public\ API\ ------------------------------------------------------------------------------------------------\n - - - - - - - - - - - - - - - - - - - \n\ \ - //\ -----\ Package\ API\ -----------------------------------------------------------------------------------------------\n - - - - - - - - - - - - - - - - - - - \n\ \ - //\ -----\ Helper\ method(s)\ ------------------------------------------------------------------------------------------\n - - - - - - - - - - - - - - - - - - - \n\ \ - //\ -----\ Helper\ class(es)\ ------------------------------------------------------------------------------------------\n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java index 9231cd2e03f6..b41fe65fc69f 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult19C.java @@ -5,7 +5,6 @@ public class RearrangementTest19 { RearrangementTest19(int oneParam) { } - RearrangementTest19() { } diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java index cb18ad6e24db..9364871a16e6 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult20.java @@ -12,7 +12,6 @@ public class RearrangementTest20 { } }; } - private static void ChildA(final Object event) { } } diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java index d7c2e1347fbd..927dca0a31d5 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/RearrangementResult22.java @@ -1,4 +1,5 @@ public class RearrangementTest22 { + public int getMyValue() { return 0; } @@ -6,6 +7,5 @@ public class RearrangementTest22 { public void setMyValue(int x) { // does nothing } - int i; } \ No newline at end of file diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java index 7bce95f3b2d6..9e43629b6b79 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult5.java @@ -21,7 +21,6 @@ final class SpaceTest5 { this.privateField5 = privateField1; } -// -------------------------- INNER CLASSES -------------------------- class inner1 { // test class @@ -31,6 +30,8 @@ final class SpaceTest5 { class inner2 { // test class } + + } diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java index 43a50907c1a5..86871ec6db2f 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult6.java @@ -27,6 +27,7 @@ final class TestClass2 { // test class } + class inner2 { // test class } diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java index 363ec5485017..264a24700814 100644 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java +++ b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceResult8.java @@ -1,5 +1,4 @@ public class Tester { -// -------------------------- OTHER METHODS -------------------------- void test() { X x = new X() { diff --git a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml b/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml deleted file mode 100644 index d46de5f9e532..000000000000 --- a/plugins/rearranger/test/testData/com/wrq/rearranger/SpaceTest7cfg.xml +++ /dev/null @@ -1,325 +0,0 @@ - - - - \n - - - ****************************** FIELDS ****************************** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n - - - ****************************** CONSTRUCTORS ****************************** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n - - - ****************************** METHODS ****************************** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n - - - - - - - - - - - - - - - - - \n - - - ****************************** INNER CLASSES ****************************** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/svn4idea/lib/sqljet.jar b/plugins/svn4idea/lib/sqljet.jar index 7fa3785c52ee..41f9548a0e64 100644 Binary files a/plugins/svn4idea/lib/sqljet.jar and b/plugins/svn4idea/lib/sqljet.jar differ diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java index ad8ae4a82460..eef6ec71b071 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java @@ -50,7 +50,7 @@ public class SvnRecursiveStatusWalker { } public void go(final FilePath rootPath, final SVNDepth depth) throws SVNException { - final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), false); + final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), true); myQueue.add(root); while (! myQueue.isEmpty()) { @@ -181,13 +181,25 @@ public class SvnRecursiveStatusWalker { if (statusInner == null) return; final SVNStatusType status = statusInner.getNodeStatus(); - if (SVNStatusType.OBSTRUCTED.equals(status) || SVNStatusType.STATUS_IGNORED.equals(status) || - SVNStatusType.STATUS_NONE.equals(status) || SVNStatusType.STATUS_UNVERSIONED.equals(status) || - SVNStatusType.UNKNOWN.equals(status)) { + final VirtualFile vf = myCurrentItem.getPath().getVirtualFile(); + if (SVNStatusType.STATUS_IGNORED.equals(status)) { + if (vf != null) { + myReceiver.processIgnored(vf); + } return; } - if (myCurrentItem.getPath().getVirtualFile() != null) { - myReceiver.processCopyRoot(myCurrentItem.getPath().getVirtualFile(), statusInner.getURL(), + if (SVNStatusType.STATUS_UNVERSIONED.equals(status) || SVNStatusType.UNKNOWN.equals(status)) { + if (vf != null) { + myReceiver.processUnversioned(vf); + processRecursively(vf, myCurrentItem.getDepth()); + } + return; + } + if (SVNStatusType.OBSTRUCTED.equals(status) || SVNStatusType.STATUS_NONE.equals(status)) { + return; + } + if (vf != null) { + myReceiver.processCopyRoot(vf, statusInner.getURL(), WorkingCopyFormat.getInstance(statusInner.getWorkingCopyFormat())); } } @@ -198,11 +210,7 @@ public class SvnRecursiveStatusWalker { final File ioFile = status.getFile(); checkIfCopyRootWasReported(); - final LocalFileSystem lfs = LocalFileSystem.getInstance(); - VirtualFile vFile = lfs.findFileByIoFile(ioFile); - if (vFile == null) { - vFile = lfs.refreshAndFindFileByIoFile(ioFile); - } + final VirtualFile vFile = getVirtualFile(ioFile); if ((vFile != null) && myPartner.isExcluded(vFile)) return; if ((vFile != null) && (SvnVcs.svnStatusIsUnversioned(status))) { @@ -224,4 +232,13 @@ public class SvnRecursiveStatusWalker { } } } + + private VirtualFile getVirtualFile(File ioFile) { + final LocalFileSystem lfs = LocalFileSystem.getInstance(); + VirtualFile vFile = lfs.findFileByIoFile(ioFile); + if (vFile == null) { + vFile = lfs.refreshAndFindFileByIoFile(ioFile); + } + return vFile; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/FirstInBranch.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/FirstInBranch.java index 6a82be732bbb..4e03b8a87246 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/FirstInBranch.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/FirstInBranch.java @@ -15,7 +15,9 @@ */ package org.jetbrains.idea.svn.history; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.ConcurrentTasks; import com.intellij.util.Consumer; @@ -75,7 +77,12 @@ public class FirstInBranch implements Runnable { private Consumer> createTask(final SVNURL branchURL) { return new Consumer>() { public void consume(final Consumer copyDataConsumer) { - final SVNLogClient logClient = myVcs.createLogClient(); + final SVNLogClient logClient = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public SVNLogClient compute() { + return myVcs.createLogClient(); + } + }); final long start1 = getStart(logClient, branchURL); if (start1 > 0) { final SVNRevision start1Rev = SVNRevision.create(start1); diff --git a/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml index bfdf2f712844..0530b8a816cc 100644 --- a/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml +++ b/plugins/ui-designer/ui-designer-new/src/META-INF/plugin.xml @@ -14,4 +14,14 @@ + + + + + + + + + + diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java index 66dd737b0511..bf2844ab6226 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java @@ -18,8 +18,9 @@ package com.intellij.designer.componentTree; import com.intellij.designer.actions.DesignerActionPanel; import com.intellij.designer.designSurface.FeedbackTreeLayer; import com.intellij.designer.model.RadComponent; -import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.*; import com.intellij.ui.ColoredTreeCellRenderer; +import com.intellij.ui.PopupHandler; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; @@ -55,7 +56,9 @@ public final class ComponentTree extends Tree implements DataProvider { // Install convenient keyboard navigation TreeUtil.installActions(this); - // TODO: Popup menu + PopupHandler + .installPopupHandler(this, (ActionGroup)ActionManager.getInstance().getAction("UIDesigner.ComponentTreePopupMenu"), + ActionPlaces.GUI_DESIGNER_COMPONENT_TREE_POPUP, ActionManager.getInstance()); // TODO: F2 should start inplace editing } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java index 247f230c24b1..749bbb16d2b3 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java @@ -51,6 +51,10 @@ public abstract class RadComponent { return myMetaModel; } + public MetaModel getMetaModelForProperties() throws Exception { + return myMetaModel; + } + public void setMetaModel(MetaModel metaModel) { myMetaModel = metaModel; } diff --git a/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/after.java.template b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/after.java.template new file mode 100644 index 000000000000..388865d2301c --- /dev/null +++ b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/after.java.template @@ -0,0 +1,8 @@ +public class X extends TestCase{ + int field; + + @Override + public void setUp() throws Exception { + field = 0; + } +} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/before.java.template b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/before.java.template new file mode 100644 index 000000000000..3b61194df421 --- /dev/null +++ b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/before.java.template @@ -0,0 +1,7 @@ +public class X extends TestCase{ + int field = 0; + + @Override + public void setUp() throws Exception { + } +} \ No newline at end of file diff --git a/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/description.html b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/description.html new file mode 100644 index 000000000000..cdbc04a0e6e7 --- /dev/null +++ b/resources-en/src/intentionDescriptions/MoveInitializerToSetUpMethodAction/description.html @@ -0,0 +1,6 @@ + + + +This intention moves field initialization into suitable setUp method. + + diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 897d7a0d05d4..233461687c9d 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -615,6 +615,10 @@ com.intellij.codeInsight.intention.impl.MoveInitializerToConstructorAction Declaration + + com.intellij.testIntegration.intention.MoveInitializerToSetUpMethodAction + Declaration + com.intellij.codeInsight.intention.impl.MoveFieldAssignmentToInitializerAction Declaration