diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java index 99a93876bf4e..bec0848383fb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java @@ -81,7 +81,7 @@ public class DefaultCodeFragmentFactory extends CodeFragmentFactory { if (parameters.getInvocationCount() <= 1 && JavaCompletionUtil.containsMethodCalls(expression)) { final CompletionService service = CompletionService.getCompletionService(); - if (service.getAdvertisementText() == null && parameters.getInvocationCount() == 1) { + if (service.getAdvertisementText() == null && parameters.getInvocationCount() < 2) { service.setAdvertisementText("Invoke completion once more to see runtime type variants"); } return null; diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index a6d238a8688e..aae24ea21e63 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -17,10 +17,11 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.ide.DataManager; import com.intellij.ide.util.projectWizard.ProjectJdkListRenderer; -import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkType; import com.intellij.openapi.roots.ui.configuration.projectRoot.JdkListConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.ui.ComboBoxWithWidePopup; @@ -48,15 +49,20 @@ import java.util.List; public class JdkComboBox extends ComboBoxWithWidePopup { @Nullable - private Condition myFilter; - + private final Condition myFilter; + @Nullable + private final Condition myCreationFilter; + public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) { - this(jdkModel, null); + this(jdkModel, null, null); } - public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, @Nullable Condition filter) { + public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, + @Nullable Condition filter, + @Nullable Condition creationFilter) { super(new JdkComboBoxModel(jdkModel, filter)); myFilter = filter; + myCreationFilter = creationFilter; setRenderer(new ProjectJdkListRenderer(getRenderer()) { @Override public void doCustomize(JList list, Object value, int index, boolean selected, boolean hasFocus) { @@ -137,12 +143,18 @@ public class JdkComboBox extends ComboBoxWithWidePopup { } } } - }); - JBPopupFactory.getInstance() - .createActionGroupPopup(actionGroupTitle, group, - DataManager.getInstance().getDataContext(JdkComboBox.this), JBPopupFactory.ActionSelectionAid.MNEMONICS, - false) - .showUnderneathOf(setUpButton); + }, myCreationFilter); + final DataContext dataContext = DataManager.getInstance().getDataContext(JdkComboBox.this); + if (group.getChildrenCount() > 1) { + JBPopupFactory.getInstance() + .createActionGroupPopup(actionGroupTitle, group, dataContext, JBPopupFactory.ActionSelectionAid.MNEMONICS, false) + .showUnderneathOf(setUpButton); + } + else { + final AnActionEvent event = + new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, new Presentation(""), ActionManager.getInstance(), 0); + group.getChildren(event)[0].actionPerformed(event); + } } }); } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index 7988292deeaa..6933ecdf998f 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -20,7 +20,6 @@ import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleConfigurationEditor; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; @@ -453,22 +452,7 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry orderEntry) { - return select(module.getName(), null, true).doWhenDone(new Runnable() { - public void run() { - final MasterDetailsComponent.MyNode node = ModuleStructureConfigurable.getInstance(myProject).findModuleNode(module); - if (node != null) { - ModuleConfigurable moduleConfigurable = (ModuleConfigurable)node.getConfigurable(); - ModuleEditor moduleEditor = moduleConfigurable.getModuleEditor(); - moduleEditor.selectEditor(ClasspathEditor.NAME); - if (orderEntry != null) { - ModuleConfigurationEditor editor = moduleEditor.getEditor(ClasspathEditor.NAME); - if (editor instanceof ClasspathEditor) { - ((ClasspathEditor)editor).selectOrderEntry(orderEntry); - } - } - } - } - }); + return ModuleStructureConfigurable.getInstance(myProject).selectOrderEntry(module, orderEntry); } public ActionCallback navigateTo(@Nullable final Place place, final boolean requestFocus) { diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java index 1ea708581f52..c1e9408f5c84 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureConfigurable.java @@ -30,10 +30,7 @@ import com.intellij.ide.util.projectWizard.ProjectWizardUtil; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.module.ModifiableModuleModel; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.*; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -43,16 +40,16 @@ import com.intellij.openapi.roots.impl.ClonableOrderEntry; import com.intellij.openapi.roots.impl.ProjectRootManagerImpl; import com.intellij.openapi.roots.impl.RootModelImpl; import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.ui.configuration.ClasspathEditor; import com.intellij.openapi.roots.ui.configuration.ModuleEditor; import com.intellij.openapi.roots.ui.configuration.ModulesConfigurator; +import com.intellij.openapi.roots.ui.configuration.ProjectStructureConfigurable; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.LibraryProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ModuleProjectStructureElement; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureDaemonAnalyzer; import com.intellij.openapi.roots.ui.configuration.projectRoot.daemon.ProjectStructureElement; -import com.intellij.openapi.ui.DialogBuilder; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.ui.*; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.NullableComputable; @@ -429,6 +426,38 @@ public class ModuleStructureConfigurable extends BaseStructureConfigurable imple return "reference.settingsdialog.project.structure.module"; } + public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry orderEntry) { + for (final ModuleStructureExtension extension : ModuleStructureExtension.EP_NAME.getExtensions()) { + final ActionCallback callback = extension.selectOrderEntry(module, orderEntry); + if (callback != null) { + return callback; + } + } + + Place p = new Place(); + p.putPath(ProjectStructureConfigurable.CATEGORY, this); + Runnable r = null; + + final MasterDetailsComponent.MyNode node = findModuleNode(module); + if (node != null) { + p.putPath(TREE_OBJECT, module); + p.putPath(ModuleEditor.SELECTED_EDITOR_NAME, ClasspathEditor.NAME); + r = new Runnable() { + public void run() { + if (orderEntry != null) { + ModuleEditor moduleEditor = ((ModuleConfigurable)node.getConfigurable()).getModuleEditor(); + ModuleConfigurationEditor editor = moduleEditor.getEditor(ClasspathEditor.NAME); + if (editor instanceof ClasspathEditor) { + ((ClasspathEditor)editor).selectOrderEntry(orderEntry); + } + } + } + }; + } + final ActionCallback result = ProjectStructureConfigurable.getInstance(myProject).navigateTo(p, true); + return r != null ? result.doWhenDone(r) : result; + } + public static ModuleStructureConfigurable getInstance(final Project project) { return ServiceManager.getService(project, ModuleStructureConfigurable.class); diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java index e653fcccc923..dd17ab3ac246 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ModuleStructureExtension.java @@ -5,9 +5,12 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.NamedConfigurable; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.NullableComputable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -71,4 +74,12 @@ public abstract class ModuleStructureExtension { public Comparator getNodeComparator() { return null; } + + /** + * @return callback or null if not handled + */ + @Nullable + public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry entry) { + return null; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index cedc14ed900a..ec44f00d15bb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.lookup.*; import com.intellij.codeInsight.template.SmartCompletionContextType; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.getters.ClassLiteralGetter; @@ -67,7 +68,10 @@ public class BasicExpressionCompletionContributor { } if (!AFTER_DOT.accepts(element)) { - CollectionsUtilityMethodsProvider.addCompletions(parameters, result); + new CollectionsUtilityMethodsProvider(parameters.getPosition(), + parameters.getExpectedType(), + parameters.getDefaultType(), result) + .addCompletions(parameters.getParameters().getInvocationCount() > 1 || StringUtil.isNotEmpty(matcher.getPrefix())); ClassLiteralGetter.addCompletions(parameters, result, matcher); final PsiElement position = parameters.getPosition(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java index 5f59dcf6d378..9411f764f8df 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java @@ -30,55 +30,62 @@ import static com.intellij.psi.CommonClassNames.*; */ class CollectionsUtilityMethodsProvider { public static final Key COLLECTION_FACTORY = Key.create("CollectionFactory"); - - public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, - @NotNull final Consumer result) { - final PsiElement element = parameters.getPosition(); + private final PsiElement myElement; + private final PsiType myExpectedType; + private final PsiType myDefaultType; + @NotNull private final Consumer myResult; - final PsiElement parent = element.getParent(); + CollectionsUtilityMethodsProvider(PsiElement position, + PsiType expectedType, + PsiType defaultType, @NotNull final Consumer result) { + myResult = result; + myElement = position; + myExpectedType = expectedType; + myDefaultType = defaultType; + } + + public void addCompletions(boolean showAll) { + final PsiElement parent = myElement.getParent(); if (parent instanceof PsiReferenceExpression && ((PsiReferenceExpression)parent).getQualifierExpression() != null) return; final PsiClass collectionsClass = - JavaPsiFacade.getInstance(element.getProject()).findClass(JAVA_UTIL_COLLECTIONS, element.getResolveScope()); + JavaPsiFacade.getInstance(myElement.getProject()).findClass(JAVA_UTIL_COLLECTIONS, myElement.getResolveScope()); if (collectionsClass == null) return; - final PsiType type = parameters.getExpectedType(); - final PsiType defaultType = parameters.getDefaultType(); final PsiElement pparent = parent.getParent(); - if (parameters.getParameters().getInvocationCount() > 1 || + if (showAll || pparent instanceof PsiReturnStatement || pparent instanceof PsiConditionalExpression && pparent.getParent() instanceof PsiReturnStatement) { - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "emptyList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "emptySet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "emptyMap", collectionsClass, element); + addCollectionMethod(JAVA_UTIL_LIST, "emptyList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "emptySet", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "emptyMap", collectionsClass); } - if (parameters.getParameters().getInvocationCount() > 1) { - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "singletonList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "singleton", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "singletonMap", collectionsClass, element); + if (showAll) { + addCollectionMethod(JAVA_UTIL_LIST, "singletonList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "singleton", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "singletonMap", collectionsClass); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_COLLECTION, "unmodifiableCollection", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_LIST, "unmodifiableList", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_SET, "unmodifiableSet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, JAVA_UTIL_MAP, "unmodifiableMap", collectionsClass, element); - addCollectionMethod(result, type, defaultType, "java.util.SortedSet", "unmodifiableSortedSet", collectionsClass, element); - addCollectionMethod(result, type, defaultType, "java.util.SortedMap", "unmodifiableSortedMap", collectionsClass, element); + addCollectionMethod(JAVA_UTIL_COLLECTION, "unmodifiableCollection", collectionsClass); + addCollectionMethod(JAVA_UTIL_LIST, "unmodifiableList", collectionsClass); + addCollectionMethod(JAVA_UTIL_SET, "unmodifiableSet", collectionsClass); + addCollectionMethod(JAVA_UTIL_MAP, "unmodifiableMap", collectionsClass); + addCollectionMethod("java.util.SortedSet", "unmodifiableSortedSet", collectionsClass); + addCollectionMethod("java.util.SortedMap", "unmodifiableSortedMap", collectionsClass); } } - private static void addCollectionMethod(final Consumer result, final PsiType expectedType, - final PsiType defaultType, final String baseClassName, - @NonNls final String method, @NotNull final PsiClass collectionsClass, PsiElement place) { - if (isClassType(expectedType, baseClassName) || isClassType(expectedType, JAVA_UTIL_COLLECTION)) { - addMethodItem(result, expectedType, method, collectionsClass, place); - } else if (isClassType(defaultType, baseClassName) || isClassType(defaultType, JAVA_UTIL_COLLECTION)) { - addMethodItem(result, defaultType, method, collectionsClass, place); + private void addCollectionMethod(final String baseClassName, + @NonNls final String method, @NotNull final PsiClass collectionsClass) { + if (isClassType(myExpectedType, baseClassName) || isClassType(myExpectedType, JAVA_UTIL_COLLECTION)) { + addMethodItem(myExpectedType, method, collectionsClass); + } else if (isClassType(myDefaultType, baseClassName) || isClassType(myDefaultType, JAVA_UTIL_COLLECTION)) { + addMethodItem(myDefaultType, method, collectionsClass); } } - private static void addMethodItem(Consumer result, PsiType expectedType, String methodName, PsiClass containingClass, PsiElement place) { + private void addMethodItem(PsiType expectedType, String methodName, PsiClass containingClass) { final PsiMethod[] methods = containingClass.findMethodsByName(methodName, false); if (methods.length == 0) { return; @@ -87,9 +94,9 @@ class CollectionsUtilityMethodsProvider { final PsiMethod method = methods[0]; final JavaMethodCallElement item = new JavaMethodCallElement(method, false, false); item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE); - item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, expectedType), place); + item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, expectedType), myElement); item.putUserData(COLLECTION_FACTORY, true); - result.consume(item); + myResult.consume(item); } private static boolean isClassType(final PsiType type, final String className) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index 80df0986a2f3..b68572f1c4af 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -26,6 +26,7 @@ import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; @@ -147,8 +148,16 @@ class ConstructorInsertHandler implements InsertHandler pair = JavaSmartCompletionContributor.getTypeParameterInfo(parameters.getPosition()); + final Pair pair = TypeArgumentCompletionProvider.getTypeParameterInfo(parameters.getPosition()); myTypeParameter = pair == null ? null : pair.first.getTypeParameters()[pair.second.intValue()]; myLocation = new CompletionLocation(myParameters); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 3c5b21d43b46..60a9855b45e9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -30,28 +30,23 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.NullableLazyKey; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.codeStyle.*; -import com.intellij.psi.filters.AndFilter; -import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.element.ExcludeDeclaredFilter; -import com.intellij.psi.filters.element.ExcludeSillyAssignment; import com.intellij.psi.html.HtmlTag; +import com.intellij.psi.impl.FakePsiElement; +import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.scope.BaseScopeProcessor; -import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.NameHint; +import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiFormatUtil; @@ -78,13 +73,7 @@ public class JavaCompletionUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaCompletionUtil"); public static final Key> DYNAMIC_TYPE_EVALUATOR = Key.create("DYNAMIC_TYPE_EVALUATOR"); - static final Key QUALIFIER_TYPE_ATTR = Key.create("qualifierType"); // SmartPsiElementPointer to PsiType of "qualifier" - @NonNls - public static final String GET_PREFIX = "get"; - @NonNls - public static final String SET_PREFIX = "set"; - @NonNls - public static final String IS_PREFIX = "is"; + private static final Key QUALIFIER_TYPE_ATTR = Key.create("qualifierType"); // SmartPsiElementPointer to PsiType of "qualifier" public static final OffsetKey LPAREN_OFFSET = OffsetKey.create("lparen"); public static final OffsetKey RPAREN_OFFSET = OffsetKey.create("rparen"); public static final OffsetKey ARG_LIST_END_OFFSET = OffsetKey.create("argListEnd"); @@ -435,20 +424,26 @@ public class JavaCompletionUtil { boolean checkInitialized = parameters.getInvocationCount() <= 1 && call != null && PsiKeyword.SUPER.equals(call.getMethodExpression().getText()); final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, checkInitialized, filterStaticAfterInstance, nameCondition); + final PsiType plainQualifier = processor.getQualifierType(); + PsiType qualifierType = plainQualifier; + + PsiType runtimeQualifier = getQualifierCastType(javaReference, parameters); + if (runtimeQualifier != null) { + javaReference = (PsiReferenceExpression) JavaPsiFacade.getElementFactory(element.getProject()).createExpressionFromText("xxx.xxx", createContextWithXxxVariable(element, runtimeQualifier)); + qualifierType = runtimeQualifier; + } + javaReference.processVariants(processor); - final Collection plainResults = processor.getResults(); - final PsiType qualifierType = processor.getQualifierType(); - PsiType castedQualifierType = addQualifierCastingVariants(javaReference, processor, set, parameters); - - boolean mayHighlight = qualifierType != null && (castedQualifierType == null || castedQualifierType.equals(qualifierType) || !qualifierType.isAssignableFrom(castedQualifierType)); + final PsiTypeLookupItem castItem = runtimeQualifier == null ? null : PsiTypeLookupItem.createLookupItem(runtimeQualifier, (PsiReferenceExpression)javaReference); final boolean pkgContext = inSomePackage(element); final Set mentioned = new THashSet(); - for (CompletionElement completionElement : plainResults) { - LookupElement item = createLookupElement(completionElement, qualifierType); + for (CompletionElement completionElement : processor.getResults()) { + LookupElement item = createLookupElement(completionElement); if (item != null) { + item.putUserData(QUALIFIER_TYPE_ATTR, qualifierType); final Object o = item.getObject(); if (o instanceof PsiClass && !isSourceLevelAccessible(element, (PsiClass)o, pkgContext)) { continue; @@ -459,7 +454,7 @@ public class JavaCompletionUtil { } mentioned.add((PsiMember)o); } - set.add(mayHighlight ? highlightIfNeeded(qualifierType, item, o) : item); + set.add(highlightIfNeeded(qualifierType, castQualifier(item, castItem, plainQualifier), o)); } } @@ -479,68 +474,63 @@ public class JavaCompletionUtil { } @Nullable - private static PsiType addQualifierCastingVariants(PsiJavaReference javaReference, JavaCompletionProcessor processor, THashSet set, CompletionParameters parameters) { + private static PsiType getQualifierCastType(PsiJavaReference javaReference, CompletionParameters parameters) { if (javaReference instanceof PsiReferenceExpression) { final PsiReferenceExpression refExpr = (PsiReferenceExpression)javaReference; final PsiExpression qualifier = refExpr.getQualifierExpression(); if (qualifier != null) { final Project project = qualifier.getProject(); - final PairFunction evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR); - PsiReferenceExpression context = refExpr; PsiType type = null; + final PairFunction evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR); if (evaluator != null) { type = evaluator.fun(qualifier, parameters); - context = null; } if (type == null) { type = GuessManager.getInstance(project).getControlFlowExpressionType(qualifier); - context = refExpr; - } - if (type != null) { - processor.clear(); - - return addQualifierCastingVariants(processor, refExpr, type, set, context); } + return type; } } return null; } - private static PsiType addQualifierCastingVariants(JavaCompletionProcessor processor, PsiReferenceExpression refExpr, - PsiType castTo, - THashSet set, final PsiReferenceExpression context) { - Project project = refExpr.getProject(); - - PsiExpression qualifier = refExpr.getQualifierExpression(); - assert qualifier != null; - final String newText = "((" + castTo.getCanonicalText() + ") " + qualifier.getText() + ")." + refExpr.getReferenceName(); - final PsiExpression newRef = JavaPsiFacade.getElementFactory(project).createExpressionFromText(newText, context); - ((PsiReferenceExpression)newRef).processVariants(processor); - - final LookupElement castItem = PsiTypeLookupItem.createLookupItem(castTo, refExpr); - - for (CompletionElement completionElement : processor.getResults()) { - final LookupElement item = createLookupElement(completionElement, castTo); - if (item != null) { - LookupElement item1 = castQualifier(project, item, castItem); - set.add(highlightIfNeeded(castTo, item1, item1.getObject())); + @NotNull + private static LookupElement castQualifier(@NotNull LookupElement item, + @Nullable final PsiTypeLookupItem castTypeItem, + @Nullable PsiType plainQualifier) { + if (castTypeItem == null) { + return item; + } + if (plainQualifier != null) { + Object o = item.getObject(); + if (containsMember(plainQualifier, o)) { + if (!(o instanceof PsiMethod)) { + return item; + } + PsiType castType = castTypeItem.getPsiType(); + if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) { + PsiMethod method = (PsiMethod)o; + PsiSubstitutor plainSub = ((PsiClassType)plainQualifier).resolveGenerics().getSubstitutor(); + PsiSubstitutor castSub = ((PsiClassType)castType).resolveGenerics().getSubstitutor(); + if (method.getSignature(plainSub).equals(method.getSignature(castSub)) && + plainSub.substitute(method.getReturnType()).equals(castSub.substitute(method.getReturnType()))) { + return item; + } + } } } - return castTo; - } - private static LookupElementDecorator castQualifier(final Project project, LookupElement item, final LookupElement to) { return LookupElementDecorator.withInsertHandler(item, new InsertHandlerDecorator() { public void handleInsert(InsertionContext context, LookupElementDecorator item) { final Document document = context.getEditor().getDocument(); - PsiDocumentManager.getInstance(project).commitDocument(document); + context.commitDocument(); final PsiFile file = context.getFile(); final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset(file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null) { final PsiElement qualifier = ref.getQualifier(); if (qualifier != null) { - final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project); + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(qualifier.getProject()); final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : ""; document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")"); @@ -551,7 +541,7 @@ public class JavaCompletionUtil { final int exprStart = qualifier.getTextRange().getStartOffset(); document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter); - CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), to); + CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem); context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); } } @@ -562,24 +552,27 @@ public class JavaCompletionUtil { } public static LookupElement highlightIfNeeded(PsiType qualifierType, LookupElement item, Object object) { - if (qualifierType instanceof PsiArrayType) { - if (object instanceof PsiField || object instanceof PsiMethod) { //length and clone() - PsiElement parent = ((PsiElement)object).getParent(); - if (parent instanceof PsiClass && parent.getContainingFile().getVirtualFile() == null) { //yes, they're a bit dummy - return highlight(item); - } + return containsMember(qualifierType, object) ? highlight(item) : item; + } + + public static boolean containsMember(PsiType qualifierType, Object object) { + if (qualifierType instanceof PsiArrayType && object instanceof PsiMember) { //length and clone() + PsiFile file = ((PsiMember)object).getContainingFile(); + if (file == null || file.getVirtualFile() == null) { //yes, they're a bit dummy + return true; } } else if (qualifierType instanceof PsiClassType) { PsiClass qualifierClass = ((PsiClassType)qualifierType).resolve(); - if (object instanceof PsiField || object instanceof PsiMethod || object instanceof PsiClass) { - PsiClass parent = ((PsiMember)object).getContainingClass(); - if (parent != null && parent.equals(qualifierClass)) { - return highlight(item); - } + if (qualifierClass == null) return false; + if (object instanceof PsiMethod && qualifierClass.findMethodBySignature((PsiMethod)object, false) != null) { + return true; + } + if (object instanceof PsiMember) { + return qualifierClass.equals(((PsiMember)object).getContainingClass()); } } - return item; + return false; } private static LookupElement highlight(LookupElement decorator) { @@ -593,7 +586,7 @@ public class JavaCompletionUtil { }), 1); } - private static LookupItem createLookupElement(CompletionElement completionElement, PsiType qualifierType) { + private static LookupElement createLookupElement(CompletionElement completionElement) { Object completion = completionElement.getElement(); assert !(completion instanceof LookupElement); @@ -601,14 +594,12 @@ public class JavaCompletionUtil { LookupElement _ret = LookupItemUtil.objectToLookupItem(completion); if (_ret == null || !(_ret instanceof LookupItem)) return null; - LookupItem ret = (LookupItem)_ret; final PsiSubstitutor substitutor = completionElement.getSubstitutor(); if (substitutor != null) { - ret.setAttribute(LookupItem.SUBSTITUTOR, substitutor); + ((LookupItem)_ret).setAttribute(LookupItem.SUBSTITUTOR, substitutor); } - ret.putUserData(QUALIFIER_TYPE_ATTR, qualifierType); - return ret; + return _ret; } public static boolean hasAccessibleConstructor(PsiType type) { @@ -928,4 +919,21 @@ public class JavaCompletionUtil { context.setAddCompletionChar(false); return true; } + + public static FakePsiElement createContextWithXxxVariable(final PsiElement place, final PsiType varType) { + return new FakePsiElement() { + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement lastParent, + @NotNull PsiElement place) { + return processor.execute(new LightVariableBuilder("xxx", varType, place), ResolveState.initial()); + } + + @Override + public PsiElement getParent() { + return place; + } + }; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 9761c51aca08..1cb0667bd7e8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -15,9 +15,11 @@ */ package com.intellij.codeInsight.completion; +import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.completion.impl.CamelHumpMatcher; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.search.PsiShortNamesCache; @@ -55,9 +57,11 @@ public class JavaNoVariantsDelegator extends CompletionContributor { return true; } - private static void delegate(CompletionParameters parameters, CompletionResultSet result) { + private static void delegate(CompletionParameters parameters, final CompletionResultSet result) { if (parameters.getCompletionType() == CompletionType.BASIC) { PsiElement position = parameters.getPosition(); + suggestCollectionUtilities(parameters, result, position); + if (parameters.getInvocationCount() <= 1 && JavaCompletionContributor.mayStartClassName(result, false) && JavaCompletionContributor.isClassNamePossible(position)) { @@ -73,6 +77,19 @@ public class JavaNoVariantsDelegator extends CompletionContributor { } } + private static void suggestCollectionUtilities(CompletionParameters parameters, final CompletionResultSet result, PsiElement position) { + if (StringUtil.isNotEmpty(result.getPrefixMatcher().getPrefix())) { + for (ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { + new CollectionsUtilityMethodsProvider(position, info.getType(), info.getDefaultType(), new Consumer() { + @Override + public void consume(LookupElement element) { + result.addElement(element); + } + }).addCompletions(true); + } + } + } + private static void suggestChainedCalls(CompletionParameters parameters, CompletionResultSet result, PsiElement position) { PsiElement parent = position.getParent(); if (!(parent instanceof PsiJavaCodeReferenceElement)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index ad08187d2b45..7af1b6edf7c5 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -18,8 +18,8 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.*; import com.intellij.codeInsight.lookup.*; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.psi.*; import com.intellij.psi.filters.ElementExtractorFilter; @@ -34,10 +34,8 @@ import com.intellij.psi.impl.source.PsiLabelReference; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import com.intellij.util.ReflectionCache; @@ -89,6 +87,8 @@ public class JavaSmartCompletionContributor extends CompletionContributor { static final ElementPattern INSIDE_TYPECAST_EXPRESSION = psiElement().withParent( psiElement(PsiReferenceExpression.class).afterLeaf( psiElement().withText(")").withParent(PsiTypeCastExpression.class))); + static final PsiElementPattern.Capture IN_TYPE_ARGS = + psiElement().inside(psiElement(PsiReferenceParameterList.class)); @Nullable private static ElementFilter getReferenceFilter(PsiElement element) { @@ -286,63 +286,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)), - new CompletionProvider() { - - protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { - final PsiElement context = parameters.getPosition(); - - final Pair pair = getTypeParameterInfo(context); - if (pair == null) return; - - final PsiClass referencedClass = pair.first; - final int parameterIndex = pair.second.intValue(); - final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); - final PsiTypeParameter targetParameter = typeParameters[parameterIndex]; - - boolean isLast = parameterIndex == typeParameters.length - 1; - final TailType tail = isLast ? new CharTailType('>') : TailType.COMMA; - - PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); - final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false); - if (psiTypes.length > 0) { - for (PsiType type : psiTypes) { - if (!(type instanceof PsiClassType)) continue; - final PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics(); - final PsiClass typeClass = result.getElement(); - final PsiSubstitutor substitutor = result.getSubstitutor(); - - if (!InheritanceUtil.isInheritorOrSelf(referencedClass, typeClass, true)) continue; - - final PsiSubstitutor currentSubstitutor = - TypeConversionUtil.getClassSubstitutor(typeClass, referencedClass, PsiSubstitutor.EMPTY); - for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(typeClass)) { - final PsiType argSubstitution = substitutor.substitute(parameter); - final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); - final PsiType substitution = resolveHelper - .getSubstitutionForTypeParameter(targetParameter, paramSubstitution, argSubstitution, false, - PsiUtil.getLanguageLevel(context)); - if (substitution != null && substitution != PsiType.NULL) { - final LookupItem item = PsiTypeLookupItem.createLookupItem(substitution, context); - resultSet.addElement(TailTypeDecorator.withTail(item.setInsertHandler(new DefaultInsertHandler()), tail)); - } - } - } - } else { - final List typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(targetParameter)); - JavaInheritorsGetter - .processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer() { - public void consume(final PsiType type) { - final PsiClass psiClass = PsiUtil.resolveClassInType(type); - if (psiClass == null) return; - - resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass), tail)); - } - }); - - } - } - }); + extend(CompletionType.SMART, IN_TYPE_ARGS, new TypeArgumentCompletionProvider(true)); extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE)); @@ -409,42 +353,14 @@ public class JavaSmartCompletionContributor extends CompletionContributor { return new JavaPsiClassReferenceElement(psiClass); } - @Nullable - public static Pair getTypeParameterInfo(PsiElement context) { - final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true); - if (parameterList == null) return null; - - PsiElement parent = parameterList.getParent(); - if (!(parent instanceof PsiJavaCodeReferenceElement)) return null; - - final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent; - final int parameterIndex; - - int index = 0; - final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true); - if(typeElement != null){ - final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements(); - while (index < elements.length) { - final PsiTypeElement element = elements[index++]; - if(element == typeElement) break; - } - } - parameterIndex = index - 1; - - if(parameterIndex < 0) return null; - final PsiElement target = referenceElement.resolve(); - if(!(target instanceof PsiClass)) return null; - - final PsiClass referencedClass = (PsiClass)target; - final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); - if(typeParameters.length <= parameterIndex) return null; - - return Pair.create(referencedClass, parameterIndex); - } - @NotNull public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) { + return getExpectedTypes(parameters, parameters.getCompletionType() == CompletionType.SMART); + } + + @NotNull + public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters, boolean voidable) { final PsiElement position = parameters.getPosition(); if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) { final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory(); @@ -464,7 +380,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { PsiExpression expression = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true); if (expression == null) return ExpectedTypeInfo.EMPTY_ARRAY; - return ExpectedTypesProvider.getExpectedTypes(expression, true, parameters.getCompletionType() == CompletionType.SMART, false); + return ExpectedTypesProvider.getExpectedTypes(expression, true, voidable, false); } static Set completeReference(final PsiElement element, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java index 5899de6213c5..7c1a3b877601 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferLocalVariablesLiteralsAndAnnoMethodsWeigher.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementWeigher; import com.intellij.psi.*; +import com.intellij.psi.filters.getters.MembersGetter; import com.intellij.psi.util.PropertyUtil; import org.jetbrains.annotations.NotNull; @@ -44,8 +45,9 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle qualifiedWithField, qualifiedWithGetter, superMethodParameters, - collectionFactory, normal, + collectionFactory, + expectedTypeMember, nonInitialized, classLiteral, className, @@ -75,7 +77,10 @@ public class PreferLocalVariablesLiteralsAndAnnoMethodsWeigher extends LookupEle if (item.getUserData(CollectionsUtilityMethodsProvider.COLLECTION_FACTORY) != null) { return MyResult.collectionFactory; } - + if (Boolean.TRUE.equals(item.getUserData(MembersGetter.EXPECTED_TYPE_INHERITOR_MEMBER))) { + return MyResult.expectedTypeMember; + } + final JavaChainLookupElement chain = item.as(JavaChainLookupElement.CLASS_CONDITION_KEY); if (chain != null) { Object qualifier = chain.getQualifier().getObject(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index 52da4c0f460f..5033f6a629cd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -33,11 +33,8 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.*; import com.intellij.psi.filters.element.ModifierFilter; import com.intellij.psi.filters.types.AssignableFromFilter; -import com.intellij.psi.impl.FakePsiElement; -import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -445,24 +442,8 @@ public class ReferenceExpressionCompletionContributor { .createExpressionFromText(((PsiClass)qualifierItem.getObject()).getQualifiedName() + ".xxx", place); } - return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", createContextWithXxxVariable(place, qualifierType)); - } - - public static FakePsiElement createContextWithXxxVariable(final PsiElement place, final PsiType varType) { - return new FakePsiElement() { - @Override - public boolean processDeclarations(@NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - PsiElement lastParent, - @NotNull PsiElement place) { - return processor.execute(new LightVariableBuilder("xxx", varType, place), ResolveState.initial()); - } - - @Override - public PsiElement getParent() { - return place; - } - }; + return (PsiReferenceExpression) factory.createExpressionFromText("xxx.xxx", JavaCompletionUtil + .createContextWithXxxVariable(place, qualifierType)); } private static boolean shoudChain(PsiElement element, PsiType qualifierType, PsiType expectedType, LookupElement item) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java new file mode 100644 index 000000000000..ec1b392d96ff --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/TypeArgumentCompletionProvider.java @@ -0,0 +1,251 @@ +/* + * 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.completion; + +import com.intellij.codeInsight.CharTailType; +import com.intellij.codeInsight.ExpectedTypeInfo; +import com.intellij.codeInsight.TailType; +import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementPresentation; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; +import com.intellij.codeInsight.lookup.TailTypeDecorator; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.intellij.patterns.PsiJavaPatterns.psiElement; + +/** +* @author peter +*/ +class TypeArgumentCompletionProvider extends CompletionProvider { + private final boolean mySmart; + + TypeArgumentCompletionProvider(boolean smart) { + mySmart = smart; + } + + protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { + final PsiElement context = parameters.getPosition(); + + final Pair pair = getTypeParameterInfo(context); + if (pair == null) return; + + ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters, false); + if (types.length > 0) { + for (ExpectedTypeInfo info : types) { + PsiType type = info.getType(); + if (type instanceof PsiClassType) { + fillExpectedTypeArgs(resultSet, context, pair.first, pair.second, ((PsiClassType)type).resolveGenerics(), mySmart ? info.getTailType() : TailType.NONE); + } + } + } else if (mySmart) { + addInheritors(parameters, resultSet, pair.first, pair.second); + } + } + + private static void fillExpectedTypeArgs(CompletionResultSet resultSet, + PsiElement context, + final PsiClass actualClass, + final int index, + PsiClassType.ClassResolveResult expectedType, TailType globalTail) { + final PsiClass expectedClass = expectedType.getElement(); + + if (!InheritanceUtil.isInheritorOrSelf(actualClass, expectedClass, true)) return; + assert expectedClass != null; + + final PsiSubstitutor currentSubstitutor = TypeConversionUtil.getClassSubstitutor(expectedClass, actualClass, PsiSubstitutor.EMPTY); + assert currentSubstitutor != null; + + PsiTypeParameter[] params = actualClass.getTypeParameters(); + final List typeItems = new ArrayList(); + for (int i = index; i < params.length; i++) { + PsiType arg = getExpectedTypeArg(context, i, expectedType, currentSubstitutor, params); + if (arg == null) { + arg = getExpectedTypeArg(context, index, expectedType, currentSubstitutor, params); + if (arg != null) { + resultSet.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(arg, context), getTail(index == params.length - 1))); + } + return; + } + typeItems.add(PsiTypeLookupItem.createLookupItem(arg, context)); + } + + resultSet.addElement(new TypeArgsLookupElement(typeItems, globalTail, ConstructorInsertHandler.hasConstructorParameters(actualClass, context))); + } + + @Nullable + private static PsiType getExpectedTypeArg(PsiElement context, + int index, + PsiClassType.ClassResolveResult expectedType, + PsiSubstitutor currentSubstitutor, PsiTypeParameter[] params) { + PsiClass expectedClass = expectedType.getElement(); + assert expectedClass != null; + for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) { + final PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter); + final PsiType paramSubstitution = currentSubstitutor.substitute(parameter); + final PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper() + .getSubstitutionForTypeParameter(params[index], paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context)); + if (substitution != null && substitution != PsiType.NULL) { + return substitution; + } + } + return null; + } + + private static void addInheritors(CompletionParameters parameters, + final CompletionResultSet resultSet, + final PsiClass referencedClass, + final int parameterIndex) { + final List typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure( + referencedClass.getTypeParameters()[parameterIndex])); + JavaInheritorsGetter.processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer() { + public void consume(final PsiType type) { + final PsiClass psiClass = PsiUtil.resolveClassInType(type); + if (psiClass == null) return; + + resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass), + getTail(parameterIndex == referencedClass.getTypeParameters().length - 1))); + } + }); + } + + private static TailType getTail(boolean last) { + return last ? new CharTailType('>') : TailType.COMMA; + } + + @Nullable + static Pair getTypeParameterInfo(PsiElement context) { + final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true); + if (parameterList == null) return null; + + PsiElement parent = parameterList.getParent(); + if (!(parent instanceof PsiJavaCodeReferenceElement)) return null; + + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent; + final int parameterIndex; + + int index = 0; + final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true); + if(typeElement != null){ + final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements(); + while (index < elements.length) { + final PsiTypeElement element = elements[index++]; + if(element == typeElement) break; + } + } + parameterIndex = index - 1; + + if(parameterIndex < 0) return null; + final PsiElement target = referenceElement.resolve(); + if(!(target instanceof PsiClass)) return null; + + final PsiClass referencedClass = (PsiClass)target; + final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters(); + if(typeParameters.length <= parameterIndex) return null; + + return Pair.create(referencedClass, parameterIndex); + } + + private static class TypeArgsLookupElement extends LookupElement { + private String myLookupString; + private final List myTypeItems; + private final TailType myGlobalTail; + private final boolean myHasParameters; + + public TypeArgsLookupElement(List typeItems, TailType globalTail, boolean hasParameters) { + myTypeItems = typeItems; + myGlobalTail = globalTail; + myHasParameters = hasParameters; + myLookupString = StringUtil.join(myTypeItems, new Function() { + @Override + public String fun(PsiTypeLookupItem item) { + return item.getLookupString(); + } + }, ", "); + } + + @NotNull + @Override + public Object getObject() { + return myTypeItems.get(0).getObject(); + } + + @NotNull + @Override + public String getLookupString() { + return myLookupString; + } + + @Override + public void renderElement(LookupElementPresentation presentation) { + myTypeItems.get(0).renderElement(presentation); + presentation.setItemText(getLookupString()); + presentation.setTailText(null); + presentation.setTypeText(null); + } + + @Override + public void handleInsert(InsertionContext context) { + context.getDocument().deleteString(context.getStartOffset(), context.getTailOffset()); + for (int i = 0; i < myTypeItems.size(); i++) { + CompletionUtil.emulateInsertion(context, context.getTailOffset(), myTypeItems.get(i)); + context.setTailOffset(getTail(i == myTypeItems.size() - 1).processTail(context.getEditor(), context.getTailOffset())); + } + context.setAddCompletionChar(false); + + context.commitDocument(); + + PsiElement leaf = context.getFile().findElementAt(context.getTailOffset() - 1); + if (psiElement().withParents(PsiReferenceParameterList.class, PsiJavaCodeReferenceElement.class, PsiNewExpression.class) + .accepts(leaf)) { + ParenthesesInsertHandler.getInstance(myHasParameters).handleInsert(context, this); + myGlobalTail.processTail(context.getEditor(), context.getTailOffset()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TypeArgsLookupElement element = (TypeArgsLookupElement)o; + + if (!myTypeItems.equals(element.myTypeItems)) return false; + + return true; + } + + @Override + public int hashCode() { + return myTypeItems.hashCode(); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 95c74648027a..5723681ecde3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -85,7 +85,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme if (qualifier instanceof PsiSuperExpression) { final PsiJavaCodeReferenceElement qSuper = ((PsiSuperExpression)qualifier).getQualifier(); if (qSuper == null) { - myQualifierClass = JavaResolveUtil.getContextClass(myElement); + myQualifierClass = JavaResolveUtil.getContextClass( myElement); } else { final PsiElement target = qSuper.resolve(); myQualifierClass = target instanceof PsiClass ? (PsiClass)target : null; diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index 75320bf17347..34305ef9bc58 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.folding.impl; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; +import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.lang.ASTNode; import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; @@ -698,7 +699,7 @@ public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAwar } } - return false; + return !OverrideImplementUtil.getMethodSignaturesToImplement(baseClass).isEmpty(); } private static boolean addToFold(List list, PsiElement elementToFold, Document document, boolean allowOneLiners) { diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java index 7d04ecd1275b..b00372cc9552 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java @@ -46,6 +46,7 @@ public class PsiTypeLookupItem extends LookupItem { myBracketsCount = bracketsCount; } + @NotNull public PsiType getPsiType() { Object object = getObject(); PsiType type = object instanceof PsiType ? (PsiType)object : JavaPsiFacade.getElementFactory(((PsiClass) object).getProject()).createType((PsiClass)object); diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java index a6af89daad40..8923ff7ba34a 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java @@ -22,6 +22,7 @@ import com.intellij.codeInsight.completion.StaticMemberProcessor; import com.intellij.codeInsight.lookup.AutoCompletionPolicy; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Key; import com.intellij.psi.*; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.scope.processor.FilterScopeProcessor; @@ -43,6 +44,7 @@ import java.util.Set; * @author peter */ public abstract class MembersGetter { + public static final Key EXPECTED_TYPE_INHERITOR_MEMBER = Key.create("EXPECTED_TYPE_INHERITOR_MEMBER"); public void processMembers(@NotNull final PsiElement context, final Consumer results, @Nullable final PsiClass where, final boolean acceptMethods, boolean searchInheritors, @@ -85,7 +87,7 @@ public abstract class MembersGetter { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); - PsiClassType baseType = JavaPsiFacade.getElementFactory(where.getProject()).createType(where); + final PsiClassType baseType = JavaPsiFacade.getElementFactory(where.getProject()).createType(where); Consumer consumer = new Consumer() { @Override public void consume(PsiType psiType) { @@ -97,7 +99,7 @@ public abstract class MembersGetter { return; } } - processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper, importedStatically); + processClassDeclaredMembers(psiClass, context, acceptMethods, results, resolveHelper, importedStatically, psiType != baseType); } } }; @@ -110,7 +112,7 @@ public abstract class MembersGetter { private void processClassDeclaredMembers(PsiClass where, PsiElement context, boolean acceptMethods, - Consumer results, final PsiResolveHelper resolveHelper, final Set importedStatically) { + Consumer results, final PsiResolveHelper resolveHelper, final Set importedStatically, boolean isInheritor) { final FilterScopeProcessor processor = new FilterScopeProcessor(TrueFilter.INSTANCE); where.processDeclarations(processor, ResolveState.initial(), null, context); @@ -123,6 +125,7 @@ public abstract class MembersGetter { if (result instanceof PsiMethod && acceptMethods) continue; final LookupElement item = result instanceof PsiMethod ? createMethodElement((PsiMethod)result) : createFieldElement((PsiField)result); if (item != null) { + item.putUserData(EXPECTED_TYPE_INHERITOR_MEMBER, isInheritor); results.consume(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(item)); } } diff --git a/java/java-psi-impl/java-psi-impl.iml b/java/java-psi-impl/java-psi-impl.iml index ef7bdab73a0c..ccd2d51410f9 100644 --- a/java/java-psi-impl/java-psi-impl.iml +++ b/java/java-psi-impl/java-psi-impl.iml @@ -12,7 +12,6 @@ - diff --git a/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java b/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java new file mode 100644 index 000000000000..17d30a741d08 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/CastVisually.java @@ -0,0 +1,14 @@ +import java.lang.Object; + +class IFoo { + Object getValue() {} +} + +class Foo extends IFoo { + Foo getValue() {} + void foo(IFoo o) { + if (o instanceof Foo) { + o.getvx + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments.java new file mode 100644 index 000000000000..853b8c08c99b --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments.java @@ -0,0 +1,5 @@ +import java.util.HashMap; + +public class A { + private HashMap m = new HashMap>() +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java new file mode 100644 index 000000000000..e1350895943c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestAllTypeArguments_after.java @@ -0,0 +1,5 @@ +import java.util.HashMap; + +public class A { + private HashMap m = new HashMap() +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java new file mode 100644 index 000000000000..f70f2eaa011d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet.java @@ -0,0 +1,7 @@ +import java.util.Set; + +class Foo { + { + Set s = em + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java new file mode 100644 index 000000000000..a9f9ca9f5fa4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestEmptySet_after.java @@ -0,0 +1,8 @@ +import java.util.Collections; +import java.util.Set; + +class Foo { + { + Set s = Collections.emptySet() + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java b/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java index 2c3c66313e77..c3c03a12bc15 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/ExcessiveTail-out.java @@ -1,5 +1,5 @@ class HashMap {} public class A { - private HashMap m = new HashMap(); + private HashMap m = new HashMap(); } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java new file mode 100644 index 000000000000..d2c7713aa4d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments-out.java @@ -0,0 +1,5 @@ +import java.util.HashMap; + +public class A { + private HashMap m = new HashMap(); +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java new file mode 100644 index 000000000000..31ec5002ce6b --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArguments.java @@ -0,0 +1,5 @@ +import java.util.HashMap; + +public class A { + private HashMap m = new HashMap<>(); +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java new file mode 100644 index 000000000000..0a148ef74763 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown-out.java @@ -0,0 +1,3 @@ +class AAAAA{ + AAAAA asd = new AAAAA +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java new file mode 100644 index 000000000000..915b39d94441 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/smartType/SeveralTypeArgumentsSomeUnknown.java @@ -0,0 +1,3 @@ +class AAAAA{ + AAAAA asd = new AAAAA< +} diff --git a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java index 052d2656908d..9a81b52d85c8 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after12.java @@ -1,4 +1,4 @@ class Test { - Test test = new Test + Test test = new Test(); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java index 4ffffb2667f1..5d8f893473e0 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/afterNew/after13.java @@ -1,3 +1,3 @@ class AAAAA{ - AAAAA asd = new AAAAA + AAAAA asd = new AAAAA(); } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java index 2770782a68bc..0b6920c6ed53 100644 --- a/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java +++ b/java/java-tests/testData/codeInsight/completion/smartTypeSorting/PreferCollectionsEmptyList.java @@ -1,8 +1,12 @@ +import java.util.List; + public class Aaaaaaa { + List locMethod() {} + { - java.util.List local = null; - java.util.List l = + List local = null; + List l = } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 383ca96325ae..fc87669f19bb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1300,4 +1300,28 @@ public class ListUtils { checkResult() } + public void testCastVisually() { + configure() + def p = LookupElementPresentation.renderElement(myFixture.lookupElements[0]) + assert p.itemText == 'getValue' + assert p.itemTextBold + assert p.typeText == 'Foo' + } + + public void testSuggestEmptySet() { + configure() + assert 'emptySet' == myFixture.lookupElementStrings[0] + type '\n' + checkResult() + } + + public void testSuggestAllTypeArguments() { + configure() + assert 'String, String' == lookup.items[1].lookupString + lookup.currentItem = lookup.items[1] + type '\n' + checkResult() + + } + } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy index 2480cc6bca78..0c853406a0ab 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionOrderingTest.groovy @@ -291,9 +291,9 @@ public class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase { myFixture.addClass("package foo; public class FList implements java.util.List { public static FList emptyList() {} }"); configureNoCompletion(getTestName(false) + ".java"); myFixture.complete(CompletionType.SMART, 2); - assertPreferredItems(0, "local", "local.subList", "emptyList", "singletonList", "unmodifiableList"); - assert 'Collections.emptyList' in lookup.items[2].allLookupStrings - assert 'FList.emptyList' in lookup.items[5].allLookupStrings + assertPreferredItems(0, "local", "local.subList", "locMethod", "locMethod().subList", "emptyList", "singletonList", "unmodifiableList", "emptyList"); + assert 'Collections.emptyList' in lookup.items[4].allLookupStrings + assert 'FList.emptyList' in lookup.items[7].allLookupStrings } public void testDispreferGetterInSetterCall() { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java index 323952086592..408c85d3bbe3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java @@ -909,9 +909,9 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase { doTest(); } - public void testExcessiveTail() throws Exception { - doTest(); - } + public void testExcessiveTail() throws Exception { doTest(); } + public void testSeveralTypeArguments() throws Exception { doTest(); } + public void testSeveralTypeArgumentsSomeUnknown() throws Exception { doTest(); } public void testExtendsInTypeCast() throws Exception { doTest(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index a4c54b800d8c..3b48d5e41fd3 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -17,13 +17,12 @@ package com.intellij.codeInsight.folding; import com.intellij.codeInsight.folding.impl.CodeFoldingManagerImpl -import com.intellij.openapi.application.ex.PathManagerEx -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsImpl -import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.find.FindManager -import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.application.ex.PathManagerEx +import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** * @author Denis Zhdanov @@ -137,6 +136,37 @@ class Test { assertTrue closureEndFold.expanded } + public void "test closure folding when an abstract method is not in the direct superclass"() { + myFoldingSettings.COLLAPSE_CLOSURES = true + def text = """\ +public abstract class AroundTemplateMethod { + public abstract T execute(); +} +private static abstract class SetupTimer extends AroundTemplateMethod { +} +class Test { + void test() { + new SetupTimer() { + public Integer execute() { + return 0; + } + }; + } +} +""" + + configure text + def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl + def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("")) + assertNotNull closureStartFold + assertFalse closureStartFold.expanded + + assertNotNull closureStartFold.group + def closureFolds = foldingModel.getGroupedRegions(closureStartFold.group) + assertNotNull closureFolds + assertEquals(2, closureFolds.size()) + } + public void testFindInFolding() { def text = """\ class Test { diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java index 6ecf24925f1a..070f2626f449 100644 --- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -152,6 +152,18 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest { doClassTest(text, text); } + public void testWrapCompoundStringLiteralThatEndsAtRightMargin() { + // Inspired by IDEA-82398 + getSettings().getRootSettings().RIGHT_MARGIN = 30; + getSettings().getRootSettings().getCommonSettings(JavaLanguage.INSTANCE).WRAP_LONG_LINES = true; + + final String text = "class Test {\n" + + " String s = \"first line \" +\n" + + " +\"second line\";\n" + + "}"; + doTextTest(text, text); + } + public void testWrapLongLine() { // Inspired by IDEA-55782 getSettings().getRootSettings().RIGHT_MARGIN = 50; diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index c2f9e5bfffb2..89db4e5f1132 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -22,9 +22,7 @@ import com.intellij.util.io.TestFileSystemBuilder; import com.intellij.util.text.UniqueNameGenerator; import groovy.lang.Closure; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.Library; -import org.jetbrains.jps.Module; -import org.jetbrains.jps.Project; +import org.jetbrains.jps.*; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.artifacts.Artifact; import org.jetbrains.jps.incremental.*; @@ -32,6 +30,7 @@ import org.jetbrains.jps.incremental.java.JavaBuilderLoggerImpl; import org.jetbrains.jps.incremental.messages.BuildMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.ProjectTimestamps; +import org.jetbrains.jps.server.ClasspathBootstrap; import org.jetbrains.jps.server.ProjectDescriptor; import java.io.File; @@ -48,6 +47,7 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { private Project myProject; private File myProjectDir; private TestArtifactBuilderLogger myArtifactBuilderLogger; + private Sdk myJdk; protected void setUp() throws Exception { super.setUp(); @@ -112,8 +112,21 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { } protected Module addModule(String moduleName, @Nullable String srcPath) { + if (myJdk == null) { + try { + myJdk = myProject.createSdk("JavaSDK", "jdk", System.getProperty("java.home"), null); + final List paths = new LinkedList(); + paths.add(FileUtil.toSystemIndependentName(ClasspathBootstrap.getResourcePath(Object.class).getCanonicalPath())); + myJdk.setClasspath(paths); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } final Module module = myProject.createModule(moduleName, Closure.IDENTITY); module.forceInit(); + module.setSdk(myJdk); + module.getDependencies().add(new Module.ModuleDependency(myJdk, PredefinedDependencyScopes.getCOMPILE(), false)); if (srcPath != null) { module.getContentRoots().add(srcPath); module.getSourceRoots().add(srcPath); @@ -163,12 +176,16 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { myArtifactBuilderLogger.clear(); IncProjectBuilder builder = new IncProjectBuilder(myDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL); final List errorMessages = new ArrayList(); + final List infoMessages = new ArrayList(); builder.addMessageHandler(new MessageHandler() { @Override public void processMessage(BuildMessage msg) { if (msg.getKind() == BuildMessage.Kind.ERROR) { errorMessages.add(msg); } + else { + infoMessages.add(msg); + } } }); builder.build(new AllProjectScope(myDescriptor.project, new HashSet(Arrays.asList(artifacts)), force), !force, false); @@ -176,7 +193,7 @@ public abstract class ArtifactBuilderTestCase extends UsefulTestCase { assertFalse("Build not failed as expected", errorMessages.isEmpty()); } else { - assertTrue("Build failed: " + errorMessages, errorMessages.isEmpty()); + assertTrue("Build failed. \nErrors:\n" + errorMessages + "\nInfo messages:\n" + infoMessages, errorMessages.isEmpty()); } } diff --git a/jps/model/src/org/jetbrains/jps/Module.groovy b/jps/model/src/org/jetbrains/jps/Module.groovy index 43323675d01c..7a3dd178408f 100644 --- a/jps/model/src/org/jetbrains/jps/Module.groovy +++ b/jps/model/src/org/jetbrains/jps/Module.groovy @@ -11,7 +11,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {//}, Com String name; Sdk sdk; - private List dependencies = [] + List dependencies = [] List contentRoots = [] List sourceRoots = [] List testRoots = [] @@ -115,7 +115,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {//}, Com return dependencies.findAll({it.scope.isIncludedIn(kind) && (!exportedOnly || it.exported)})*.item; } - private static class ModuleDependency { + public static class ModuleDependency { ClasspathItem item DependencyScope scope boolean exported diff --git a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java index 2e243827fdc6..239a3501b392 100644 --- a/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java +++ b/platform/lang-impl/src/com/intellij/ide/highlighter/custom/tokens/KeywordParser.java @@ -47,19 +47,32 @@ public class KeywordParser extends TokenParser { if (regex.length() > 0) { regex.append("|"); } - regex.append(word); + regex.append(escapeSpecialCharacters(word)); } } Pattern pattern = null; try { - pattern = Pattern.compile("(" + regex + ")($|[\\W])", (ignoreCase ? Pattern.CASE_INSENSITIVE : 0) | Pattern.DOTALL); + String pat = "(" + regex + ")($|[^\\w-])"; + pattern = Pattern.compile(pat, (ignoreCase ? Pattern.CASE_INSENSITIVE : 0) | Pattern.DOTALL); } catch (PatternSyntaxException e) { - LOG.error(e); + LOG.info(e); } myPattern = pattern; } + private static String escapeSpecialCharacters(String word) { + StringBuilder esc = new StringBuilder(); + word = word.replace("\\", "\\\\"); + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if ("-*+?$%^.()".indexOf(ch) >= 0) esc.append('\\'); + esc.append(ch); + } + word = esc.toString(); + return word; + } + private Set getKeywordSet(Set keywordSet) { if (!myIgnoreCase) { return new THashSet(keywordSet); 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 b61df45a94f2..5a9529260e5b 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -593,7 +593,7 @@ public class FileStructurePopup implements Disposable { myFilteringStructure.rebuild(); final Object sel = selection; - ApplicationManager.getApplication().invokeLater(new Runnable() { + final Runnable runnable = new Runnable() { public void run() { final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock(); try { @@ -610,7 +610,12 @@ public class FileStructurePopup implements Disposable { token.finish(); } } - }); + }; + if (ApplicationManager.getApplication().isUnitTestMode()) { + runnable.run(); + } else { + ApplicationManager.getApplication().invokeLater(runnable); + } } }); chkFilter.setFocusable(false); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java index eef29826d38a..bfd33af9a830 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java @@ -32,6 +32,7 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.MasterDetailsComponent; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Condition; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import com.intellij.util.EventDispatcher; @@ -214,8 +215,16 @@ public class ProjectSdksModel implements SdkModel { } public void createAddActions(DefaultActionGroup group, final JComponent parent, final Consumer updateTree) { + createAddActions(group, parent, updateTree, null); + } + + public void createAddActions(DefaultActionGroup group, + final JComponent parent, + final Consumer updateTree, + @Nullable Condition filter) { final SdkType[] types = SdkType.getAllTypes(); for (final SdkType type : types) { + if (filter != null && !filter.value(type)) continue; final AnAction addAction = new DumbAwareAction(type.getPresentableName(), null, type.getIconForAddAction()) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index 6db1c4aa405b..d9af7a4b628a 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.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. @@ -339,7 +339,7 @@ public class CodeFormatterFacade { int preferredWrapPosition = Integer.MAX_VALUE; if (!hasTabs) { - if (Math.min(endLineOffset, endOffsetToUse) - startLineOffset >= mySettings.RIGHT_MARGIN) { + if (Math.min(endLineOffset, endOffsetToUse) - startLineOffset > mySettings.RIGHT_MARGIN) { preferredWrapPosition = startLineOffset + mySettings.RIGHT_MARGIN - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS; } } diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java b/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java index 6ed7a278cb3b..cef0acf2dba3 100644 --- a/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java +++ b/platform/lang-impl/src/com/intellij/util/download/impl/FileSetVersionsFetcherBase.java @@ -70,9 +70,17 @@ public abstract class FileSetVersionsFetcherBase 0) { @@ -4083,8 +4083,6 @@ public class AbstractTreeUi { } public void expandAll(@Nullable final Runnable onDone) { - if (isPassthroughMode()) expandAllWithoutRecursion(onDone); - final JTree tree = getTree(); if (tree.getRowCount() > 0) { final int expandRecursionDepth = Math.max(2, Registry.intValue("ide.tree.expandRecursionDepth")); diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy index 7311244aae15..b7333a184b5a 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTest.groovy @@ -15,15 +15,21 @@ */ package com.intellij.ide.highlighter.custom -import com.intellij.psi.tree.IElementType -import static com.intellij.psi.CustomHighlighterTokenType.* +import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.Nullable +import com.intellij.testFramework.LexerTestCase +import junit.framework.TestCase /** * @author peter */ -class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { - @Override - protected SyntaxTable createSyntaxTable() { +class CustomFileTypeLexerTest extends TestCase { + + protected void doTest(SyntaxTable table, @NonNls String text, @Nullable String expected) { + assertEquals(expected, LexerTestCase.printTokens(text, 0, new CustomFileTypeLexer(table))); + } + + private SyntaxTable createGenericTable() { SyntaxTable table = new SyntaxTable(); table.lineComment = ';' @@ -40,20 +46,276 @@ class CustomFileTypeLexerTest extends CustomFileTypeLexerTestBase { } public void testSpacesInsideKeywords() { - checkTypesAndTokens('if length(variable)then return 1', - [KEYWORD_1, WHITESPACE, KEYWORD_1, CHARACTER, IDENTIFIER, CHARACTER, KEYWORD_1, WHITESPACE, KEYWORD_2, WHITESPACE, NUMBER] as IElementType[], - ['if', ' ', 'length', '(', 'variable', ')', 'then', ' ', 'return', ' ', '1'] as String[]) - + doTest createGenericTable(), 'if length(variable)then return 1', '''\ +KEYWORD_1 ('if') +WHITESPACE (' ') +KEYWORD_1 ('length') +CHARACTER ('(') +IDENTIFIER ('variable') +CHARACTER (')') +KEYWORD_1 ('then') +WHITESPACE (' ') +KEYWORD_2 ('return') +WHITESPACE (' ') +NUMBER ('1') +''' } public void testFortranComments() { - checkTypesAndTokens(''' + doTest createGenericTable(), ''' foo;noncomment ;comment ;noncomment -''', - [WHITESPACE, IDENTIFIER, PUNCTUATION, IDENTIFIER, WHITESPACE, LINE_COMMENT, WHITESPACE, PUNCTUATION, IDENTIFIER, WHITESPACE] as IElementType[], - ['\n', 'foo', ';', 'noncomment', '\n', ';comment', '\n ', ';', 'noncomment', '\n'] as String[]) - +''', '''\ +WHITESPACE ('\\n') +IDENTIFIER ('foo') +PUNCTUATION (';') +IDENTIFIER ('noncomment') +WHITESPACE ('\\n') +LINE_COMMENT (';comment') +WHITESPACE ('\\n ') +PUNCTUATION (';') +IDENTIFIER ('noncomment') +WHITESPACE ('\\n') +''' } + + private SyntaxTable createJavaSyntaxTable() { + SyntaxTable table = new SyntaxTable(); + + table.setLineComment("//"); + table.setStartComment("/*"); + table.setEndComment("*/"); + + table.setHexPrefix("0x"); + table.setNumPostfixChars("cfdle"); + + table.addKeyword1("package"); + table.addKeyword1("import"); + table.addKeyword1("this"); + table.addKeyword1("super"); + table.addKeyword1("public"); + table.addKeyword1("private"); + table.addKeyword1("protected"); + table.addKeyword1("null"); + table.addKeyword1("if"); + table.addKeyword1("else"); + table.addKeyword1("throws"); + table.addKeyword1("switch"); + table.addKeyword1("case"); + table.addKeyword1("break"); + table.addKeyword1("default"); + table.addKeyword1("continue"); + table.addKeyword1("goto"); + table.addKeyword1("boolean"); + table.addKeyword1("true"); + table.addKeyword1("false"); + table.addKeyword1("final"); + table.addKeyword1("class"); + table.addKeyword1("static"); + table.addKeyword1("final"); + table.addKeyword1("void"); + table.addKeyword1("int"); + table.addKeyword1("while"); + table.addKeyword1("new"); + table.addKeyword1("for"); + table.addKeyword1("byte"); + table.addKeyword1("float"); + table.addKeyword1("double"); + table.addKeyword1("short"); + table.addKeyword1("extends"); + table.addKeyword1("implements"); + table.addKeyword1("interface"); + table.addKeyword1("abstract"); + table.addKeyword1("char"); + table.addKeyword1("try"); + table.addKeyword1("catch"); + table.addKeyword1("finally"); + table.addKeyword1("synchronized"); + + return table; + } + + public void testParseSampleCode() { + doTest createJavaSyntaxTable(), "private some text f b g\n\n\n// 1\n public static void main(String[] args) {\n}\n-10 - 10\n\"dsfdfdf\"\n/* a\n *bc */", '''\ +KEYWORD_1 ('private') +WHITESPACE (' ') +IDENTIFIER ('some') +WHITESPACE (' ') +IDENTIFIER ('text') +WHITESPACE (' ') +IDENTIFIER ('f') +WHITESPACE (' ') +IDENTIFIER ('b') +WHITESPACE (' ') +IDENTIFIER ('g') +WHITESPACE ('\\n\\n\\n') +LINE_COMMENT ('// 1') +WHITESPACE ('\\n ') +KEYWORD_1 ('public') +WHITESPACE (' ') +KEYWORD_1 ('static') +WHITESPACE (' ') +KEYWORD_1 ('void') +WHITESPACE (' ') +IDENTIFIER ('main') +CHARACTER ('(') +IDENTIFIER ('String') +CHARACTER ('[') +CHARACTER (']') +WHITESPACE (' ') +IDENTIFIER ('args') +CHARACTER (')') +WHITESPACE (' ') +CHARACTER ('{') +WHITESPACE ('\\n') +CHARACTER ('}') +WHITESPACE ('\\n') +CHARACTER ('-') +NUMBER ('10') +WHITESPACE (' ') +CHARACTER ('-') +WHITESPACE (' ') +NUMBER ('10') +WHITESPACE ('\\n') +STRING ('"dsfdfdf"') +WHITESPACE ('\\n') +MULTI_LINE_COMMENT ('/* a\\n *bc */') +''' + } + + public void testBlockCommentStart() { + doTest createJavaSyntaxTable(), "/*", 'MULTI_LINE_COMMENT (\'/*\')\n' + } + + public void testLineCommentStart() { + doTest createJavaSyntaxTable(), "//", 'LINE_COMMENT (\'//\')\n' + } + + public void testEmpty() { + doTest createJavaSyntaxTable(), "", '' + } + + public void testSpace() { + doTest createJavaSyntaxTable(), " ", 'WHITESPACE (\' \')\n' + } + + public void testParseSampleCodeFromTo() { + String sampleCode = " int n=123;\n float z=1;"; + def lexer = new CustomFileTypeLexer(createJavaSyntaxTable()) + lexer.start(sampleCode, 5, 5); + assertEquals(lexer.getTokenType(), null); + lexer.start(sampleCode, 5, 6); + lexer.getTokenType(); + assertEquals(5, lexer.getTokenStart()); + assertEquals(6, lexer.getTokenEnd()); + assertEquals(6, lexer.getBufferEnd()); + } + + private SyntaxTable createPropTable() { + SyntaxTable table = new SyntaxTable(); + + table.setLineComment("#"); + table.setIgnoreCase(true); + + table.addKeyword1("value"); + table.addKeyword2("Value"); + table.setNumPostfixChars("LGH"); + return table; + } + + public void testSimple() { + doTest createPropTable(), "# Comment\n" + + "x.1.a=12.2L\n" + + " y.2.b=13.4 # comment\n" + + "VALUE value VaLuE Value1 17.00h 11.0k", '''\ +LINE_COMMENT ('# Comment') +WHITESPACE ('\\n') +IDENTIFIER ('x') +PUNCTUATION ('.') +NUMBER ('1') +PUNCTUATION ('.') +IDENTIFIER ('a') +CHARACTER ('=') +NUMBER ('12.2L') +WHITESPACE ('\\n ') +IDENTIFIER ('y') +PUNCTUATION ('.') +NUMBER ('2') +PUNCTUATION ('.') +IDENTIFIER ('b') +CHARACTER ('=') +NUMBER ('13.4') +WHITESPACE (' ') +LINE_COMMENT ('# comment') +WHITESPACE ('\\n') +KEYWORD_1 ('VALUE') +WHITESPACE (' ') +KEYWORD_1 ('value') +WHITESPACE (' ') +KEYWORD_1 ('VaLuE') +WHITESPACE (' ') +IDENTIFIER ('Value1') +WHITESPACE (' ') +NUMBER ('17.00h') +WHITESPACE (' ') +NUMBER ('11') +PUNCTUATION ('.') +NUMBER ('0') +IDENTIFIER ('k') +''' + } + + public void testNumber() { + doTest createPropTable(), "1.23=1.24", '''\ +NUMBER ('1.23') +CHARACTER ('=') +NUMBER ('1.24') +''' + } + + public void testPostfix() { + doTest createPropTable(), "abc 1.2ltext", '''\ +IDENTIFIER ('abc') +WHITESPACE (' ') +NUMBER ('1.2l') +IDENTIFIER ('text') +''' + } + + public void testWeird() { + doTest createPropTable(), "test.1.", '''\ +IDENTIFIER ('test') +PUNCTUATION ('.') +NUMBER ('1.') +''' + } + + public void testParenths() throws Exception { + doTest createPropTable(),"value(255)", '''\ +KEYWORD_1 ('value') +CHARACTER ('(') +NUMBER ('255') +CHARACTER (')') +''' + } + + public void testSpecialCharactersInKeywords() { + SyntaxTable table = new SyntaxTable() + table.addKeyword1("a*") + table.addKeyword1("b-c") + table.addKeyword2("d#") + table.addKeyword2("e") + doTest table, 'a* b-c d# e-', '''\ +KEYWORD_1 ('a*') +WHITESPACE (' ') +KEYWORD_1 ('b-c') +WHITESPACE (' ') +KEYWORD_2 ('d#') +WHITESPACE (' ') +IDENTIFIER ('e-') +''' + } + + } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java deleted file mode 100644 index 62d706d60cc4..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/CustomFileTypeLexerTestBase.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.lexer.Lexer; -import com.intellij.psi.tree.IElementType; -import junit.framework.TestCase; - -/** - * @author dsl - */ -public abstract class CustomFileTypeLexerTestBase extends TestCase { - protected Lexer lexer; - - @Override - protected void setUp() throws Exception { - lexer = new CustomFileTypeLexer(createSyntaxTable()); - } - - protected abstract SyntaxTable createSyntaxTable(); - - protected void checkTypesAndTokens(String sampleCode, IElementType[] types, String[] matches) { - lexer.start(sampleCode); - assertEquals(types.length, matches.length); - - for (int i = 0; i < types.length; i++) { - assertEquals("Failed at index=" + i, types[i], lexer.getTokenType()); - assertEquals("Failed at index=" + i, matches[i], sampleCode.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - lexer.advance(); - } - } - - protected void checkSameText(String sampleCode) { - lexer.start(sampleCode); - StringBuffer sb = new StringBuffer(); - String result; - while (lexer.getTokenType() != null) { - result = sampleCode.substring(lexer.getTokenStart(), lexer.getTokenEnd()); - sb.append(result); - lexer.advance(); - } - - assertEquals("Text created by lexer's output does not match the original text", sampleCode, sb.toString()); - } - - public void testNothing() throws Exception { - //TODO[dsl] Testcase fails if there's no any testcase. So I've added an empty one. - } -} diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java deleted file mode 100644 index 44aa6b6f2311..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/JavaCodeTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.psi.CustomHighlighterTokenType; -import com.intellij.psi.tree.IElementType; - -/** - * @author Yura Cangea - * @version 1.0 - */ -public class JavaCodeTest extends CustomFileTypeLexerTestBase { - - @Override - public SyntaxTable createSyntaxTable() { - SyntaxTable table = new SyntaxTable(); - - table.setLineComment("//"); - table.setStartComment("/*"); - table.setEndComment("*/"); - - table.setHexPrefix("0x"); - table.setNumPostfixChars("cfdle"); - - table.addKeyword1("package"); - table.addKeyword1("import"); - table.addKeyword1("this"); - table.addKeyword1("super"); - table.addKeyword1("public"); - table.addKeyword1("private"); - table.addKeyword1("protected"); - table.addKeyword1("null"); - table.addKeyword1("if"); - table.addKeyword1("else"); - table.addKeyword1("throws"); - table.addKeyword1("switch"); - table.addKeyword1("case"); - table.addKeyword1("break"); - table.addKeyword1("default"); - table.addKeyword1("continue"); - table.addKeyword1("goto"); - table.addKeyword1("boolean"); - table.addKeyword1("true"); - table.addKeyword1("false"); - table.addKeyword1("final"); - table.addKeyword1("class"); - table.addKeyword1("static"); - table.addKeyword1("final"); - table.addKeyword1("void"); - table.addKeyword1("int"); - table.addKeyword1("while"); - table.addKeyword1("new"); - table.addKeyword1("for"); - table.addKeyword1("byte"); - table.addKeyword1("float"); - table.addKeyword1("double"); - table.addKeyword1("short"); - table.addKeyword1("extends"); - table.addKeyword1("implements"); - table.addKeyword1("interface"); - table.addKeyword1("abstract"); - table.addKeyword1("char"); - table.addKeyword1("try"); - table.addKeyword1("catch"); - table.addKeyword1("finally"); - table.addKeyword1("synchronized"); - - return table; - } - - public void testParseSampleCode() { - String sampleCode = - "private some text f b g\n\n\n// 1\n public static void main(String[] args) {\n}\n-10 - 10\n\"dsfdfdf\"\n/* a\n *bc */"; - String sampleCode2 = "/*"; - String sampleCode3 = "//"; - String sampleCode4 = ""; - String sampleCode5 = " "; - - checkSameText(sampleCode); - String result; - - - IElementType[] types = new IElementType[]{CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.STRING, CustomHighlighterTokenType.WHITESPACE, CustomHighlighterTokenType.MULTI_LINE_COMMENT, - }; - - String[] matches = new String[]{"private", " ", "some", " ", "text", " ", "f", " ", "b", " ", "g", "\n\n\n", "// 1", "\n ", "public", - " ", "static", " ", "void", " ", "main", "(", - "String", "[", "]", " ", "args", ")", " ", "{", "\n", "}", "\n", "-", "10", - " ", "-", " ", "10", "\n", "\"dsfdfdf\"", "\n", "/* a\n *bc */", - }; - - checkTypesAndTokens(sampleCode, types, matches); - - lexer.start(sampleCode2); - assertEquals(CustomHighlighterTokenType.MULTI_LINE_COMMENT, lexer.getTokenType()); - assertEquals("/*", sampleCode2.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode3); - assertEquals(CustomHighlighterTokenType.LINE_COMMENT, lexer.getTokenType()); - assertEquals("//", sampleCode3.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode4); - assertEquals(null, lexer.getTokenType()); - assertEquals("", sampleCode4.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - - lexer.start(sampleCode5); - assertEquals(CustomHighlighterTokenType.WHITESPACE, lexer.getTokenType()); - assertEquals(" ", sampleCode5.substring(lexer.getTokenStart(), lexer.getTokenEnd())); - } - - public void testParseSampleCodeFromTo() { - String sampleCode = " int n=123;\n float z=1;"; - lexer.start(sampleCode, 5, 5); - assertEquals(lexer.getTokenType(), null); - lexer.start(sampleCode, 5, 6); - lexer.getTokenType(); - assertEquals(5, lexer.getTokenStart()); - assertEquals(6, lexer.getTokenEnd()); - assertEquals(6, lexer.getBufferEnd()); - } -} diff --git a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java b/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java deleted file mode 100644 index 88c956c403a8..000000000000 --- a/platform/platform-tests/testSrc/com/intellij/ide/highlighter/custom/PropertiesFileTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.intellij.ide.highlighter.custom; - -import com.intellij.psi.CustomHighlighterTokenType; -import com.intellij.psi.tree.IElementType; - -/** - * @author dsl - */ -public class PropertiesFileTest extends CustomFileTypeLexerTestBase { - - @Override - protected void setUp() throws Exception { - lexer = new CustomFileTypeLexer(createSyntaxTable()); - } - - @Override - protected SyntaxTable createSyntaxTable() { - SyntaxTable table = new SyntaxTable(); - - table.setLineComment("#"); - table.setIgnoreCase(true); - - table.addKeyword1("value"); - table.addKeyword2("Value"); - table.setNumPostfixChars("LGH"); - return table; - } - - public void testSimple() { - String sampleFile = - "# Comment\n" + - "x.1.a=12.2L\n" + - " y.2.b=13.4 # comment\n" + - "VALUE value VaLuE Value1 17.00h 11.0k"; - checkSameText(sampleFile); - IElementType[] types = { - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.LINE_COMMENT, CustomHighlighterTokenType.WHITESPACE, - - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.PUNCTUATION, - CustomHighlighterTokenType.NUMBER, - CustomHighlighterTokenType.IDENTIFIER - }; - - String[] matches = { - "# Comment", "\n", - - "x", ".", "1", ".", "a", "=", "12.2L", "\n ", - "y", ".", "2", ".", "b", "=", "13.4", " ", "# comment", "\n", - "VALUE", " ", "value", " ", "VaLuE", " ", "Value1", " ", "17.00h", " ", "11", ".", "0", "k" - }; - - checkTypesAndTokens(sampleFile, types, matches); - } - - public void testNumber() { - String sample = "1.23=1.24"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.CHARACTER, CustomHighlighterTokenType.NUMBER - }; - String[] matches = { "1.23", "=", "1.24" }; - checkTypesAndTokens(sample, types, matches); - } - - public void testPostfix() { - String sample = "abc 1.2ltext"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.WHITESPACE, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.IDENTIFIER - }; - String[] matches = { "abc", " ", "1.2l", "text" }; - checkTypesAndTokens(sample, types, matches); - } - - public void testWeird() { - String sample = "test.1."; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.IDENTIFIER, CustomHighlighterTokenType.PUNCTUATION, CustomHighlighterTokenType.NUMBER - }; - String[] matches = { "test", ".", "1." }; - checkTypesAndTokens(sample, types, matches); - } - - public void testParenths() throws Exception { - String sample = "value(255)"; - checkSameText(sample); - IElementType[] types = { - CustomHighlighterTokenType.KEYWORD_1, CustomHighlighterTokenType.CHARACTER, - CustomHighlighterTokenType.NUMBER, CustomHighlighterTokenType.CHARACTER - }; - String[] matches = { "value", "(", "255", ")" }; - checkTypesAndTokens(sample, types, matches); - } -} diff --git a/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java index a9e6435fcc9b..ed4f46179fba 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LexerTestCase.java @@ -72,7 +72,7 @@ public abstract class LexerTestCase extends UsefulTestCase { return printTokens(text, start, createLexer()); } - private static String printTokens(String text, int start, Lexer lexer) { + public static String printTokens(String text, int start, Lexer lexer) { lexer.start(text, start, text.length()); String result = ""; while (true) { diff --git a/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java b/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java index 75113e470776..dd6e7a0c2653 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestDataProvider.java @@ -40,6 +40,11 @@ public class TestDataProvider implements DataProvider { @Override public Object getData(@NonNls String dataId) { + if (myProject.isDisposed()) { + throw new RuntimeException("TestDataProvider is already disposed.\n" + + "If you closed a project in test, please reset IdeaTestApplication.setDataProvider."); + } + if (PlatformDataKeys.PROJECT.is(dataId)) { return myProject; } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java index 1c784afe91a3..c850c88d6820 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java @@ -599,7 +599,7 @@ public class CommittedChangesCache implements PersistentStateComponent receivedChanges) { - final ArrayList listCopy = receivedChanges == null ? null : new ArrayList(receivedChanges); + final Collection changes = receivedChanges == null ? myCachedIncomingChangeLists : receivedChanges; + if (changes == null) { + final List lists = loadIncomingChanges(false); + myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(new ArrayList(lists)); + return; + } + final ArrayList listCopy = new ArrayList(changes); myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(listCopy); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java index 572f101e1953..540cc5985b6a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/LabeledComboBoxAction.java @@ -93,4 +93,8 @@ public abstract class LabeledComboBoxAction extends AnAction implements CustomCo boxModel.setSelectedItem(boxModel.getElementAt(idx)); } } + + protected JComboBox getComboBox() { + return myComboBox; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java index e67325582563..0ed24cc232f5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/SelectGroupingAction.java @@ -26,6 +26,7 @@ public class SelectGroupingAction extends LabeledComboBoxAction { public SelectGroupingAction(final CommittedChangesTreeBrowser browser) { super("Group by"); myBrowser = browser; + getComboBox().setPrototypeDisplayValue("Date+"); } protected void selectionChanged(Object selection) { 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 7738eaab0d47..af65241836cb 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 @@ -29,14 +29,11 @@ public final class AndroidTreeDecorator extends TreeComponentDecorator { public void decorate(RadComponent component, ColoredTreeCellRenderer renderer) { MetaModel metaModel = component.getMetaModel(); - // TODO - if (metaModel == null) { - RadViewComponent viewComponent = (RadViewComponent)component; - renderer.append(viewComponent.getTag().getName()); - } - else { - renderer.append(metaModel.getPaletteItem().getTitle()); - renderer.setIcon(metaModel.getIcon()); - } + StringBuffer fullTitle = new StringBuffer(); + String title1 = new String(metaModel.getPaletteItem().getTitle()); + fullTitle.append(title1.replaceAll("%tag%", ((RadViewComponent)component).getTag().getName())); + renderer.append(fullTitle.toString()); + + renderer.setIcon(metaModel.getIcon()); } } \ No newline at end of file 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 e02de1ae423f..fe9a90bb7f99 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 @@ -17,12 +17,13 @@ package com.intellij.android.designer.designSurface; import com.android.ide.common.rendering.api.RenderSession; import com.android.ide.common.rendering.api.Result; -import com.android.ide.common.rendering.api.ViewInfo; import com.android.ide.common.resources.configuration.*; +import com.android.sdklib.IAndroidTarget; import com.intellij.android.designer.actions.ProfileAction; import com.intellij.android.designer.componentTree.AndroidTreeDecorator; +import com.intellij.android.designer.model.ModelParser; +import com.intellij.android.designer.model.PropertyParser; import com.intellij.android.designer.model.RadViewComponent; -import com.intellij.android.designer.model.ViewsMetaManager; import com.intellij.android.designer.profile.ProfileManager; import com.intellij.designer.DesignerToolWindowManager; import com.intellij.designer.componentTree.TreeComponentDecorator; @@ -30,14 +31,10 @@ import com.intellij.designer.designSurface.ComponentDecorator; import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.designer.designSurface.EditOperation; import com.intellij.designer.designSurface.OperationContext; -import com.intellij.designer.designSurface.selection.DirectionResizePoint; -import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator; +import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; import com.intellij.designer.designSurface.tools.ComponentCreationFactory; import com.intellij.designer.designSurface.tools.ComponentPasteFactory; -import com.intellij.designer.model.MetaManager; -import com.intellij.designer.model.RadComponent; import com.intellij.designer.palette.Item; -import com.intellij.designer.utils.Position; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Computable; @@ -45,16 +42,13 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; -import com.intellij.psi.XmlRecursiveElementVisitor; import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; import com.intellij.util.ThrowableRunnable; +import org.jetbrains.android.dom.attrs.AttributeDefinitions; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidPlatform; -import org.jetbrains.android.uipreview.LayoutDeviceConfiguration; -import org.jetbrains.android.uipreview.LocaleData; -import org.jetbrains.android.uipreview.RenderUtil; -import org.jetbrains.android.uipreview.RenderingException; +import org.jetbrains.android.sdk.AndroidTargetData; +import org.jetbrains.android.uipreview.*; import org.jetbrains.android.util.AndroidSdkNotConfiguredException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -62,7 +56,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Collections; import java.util.List; /** @@ -132,52 +125,24 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { } } - private void parseFile(final Runnable runnable) { - final RadViewComponent[] rootComponents = new RadViewComponent[1]; - final MetaManager metaManager = ViewsMetaManager.getInstance(getProject()); - final String layoutXmlText = ApplicationManager.getApplication().runReadAction(new Computable() { - RadViewComponent myComponent; - - @Override - public String compute() { - XmlTag root = myXmlFile.getRootTag(); - if (root != null) { - root.accept(new XmlRecursiveElementVisitor() { - @Override - public void visitXmlTag(XmlTag tag) { - myComponent = new RadViewComponent(myComponent); - myComponent.setTag(tag); - myComponent.setMetaModel(metaManager.getModelByTag(tag.getName())); - - if (rootComponents[0] == null) { - rootComponents[0] = myComponent; - } - - super.visitXmlTag(tag); - - myComponent = (RadViewComponent)myComponent.getParent(); - } - }); - } - - return myXmlFile.getText(); - } - }); - - createRenderer(layoutXmlText, new ThrowableRunnable() { + private void parseFile(final Runnable runnable) throws Exception { + final ModelParser parser = new ModelParser(getProject(), myXmlFile); + createRenderer(parser.getLayoutXmlText(), new ThrowableRunnable() { @Override public void run() throws Throwable { checkRenderer(); RootView rootView = new RootView(mySession.getImage(), 30, 20); - updateRootComponent(rootComponents, mySession.getRootViews(), rootView); + parser.updateRootComponent(mySession.getRootViews(), rootView); + + new PropertyParser(myModule, myProfileAction.getProfileManager().getSelectedTarget()).loadRecursive(parser.getRootComponent()); JPanel rootPanel = new JPanel(null); rootPanel.setBackground(Color.WHITE); rootPanel.add(rootView); removeNativeRoot(); - myRootComponent = rootComponents[0]; + myRootComponent = parser.getRootComponent(); myLayeredPane.add(rootPanel, LAYER_COMPONENT); runnable.run(); @@ -200,7 +165,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { RadViewComponent rootComponent = (RadViewComponent)myRootComponent; RootView rootView = (RootView)rootComponent.getNativeComponent(); rootView.setImage(mySession.getImage()); - updateRootComponent(rootComponent, mySession.getRootViews(), rootView); + ModelParser.updateRootComponent(rootComponent, mySession.getRootViews(), rootView); myLayeredPane.repaint(); } @@ -210,6 +175,8 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { private void checkRenderer() throws Throwable { Result result = mySession.getResult(); if (!result.isSuccess()) { + System.out.println( + "No session: " + result.getErrorMessage() + " : " + result.getStatus() + " : " + result.getData() + " : " + result.getException()); Throwable exception = result.getException(); if (exception != null) { throw exception; @@ -226,55 +193,6 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { } } - private void updateRootComponent(RadViewComponent[] rootComponents, List views, JComponent nativeComponent) { - RadViewComponent rootComponent = rootComponents[0]; - - if (views.size() == 1) { - RadViewComponent newRootComponent = new RadViewComponent(null); - newRootComponent.setMetaModel(ViewsMetaManager.getInstance(getProject()).getModelByTag("")); - newRootComponent.getChildren().add(rootComponent); - rootComponent.setParent(newRootComponent); - - updateComponent(rootComponent, views.get(0), nativeComponent, 0, 0); - - rootComponents[0] = newRootComponent; - - newRootComponent.setNativeComponent(nativeComponent); - newRootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); - } - else { - updateRootComponent(rootComponent, views, nativeComponent); - } - } - - private static void updateRootComponent(RadViewComponent rootComponent, List views, JComponent nativeComponent) { - int size = views.size(); - List children = rootComponent.getChildren(); - for (int i = 0; i < size; i++) { - updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, 0, 0); - } - - rootComponent.setNativeComponent(nativeComponent); - rootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); - } - - private static void updateComponent(RadViewComponent component, ViewInfo view, JComponent nativeComponent, int parentX, int parentY) { - component.setNativeComponent(nativeComponent); - - int left = parentX + view.getLeft(); - int top = parentY + view.getTop(); - component.setBounds(left, top, view.getRight() - view.getLeft(), view.getBottom() - view.getTop()); - - List views = view.getChildren(); - List children = component.getChildren(); - int size = views.size(); - - for (int i = 0; i < size; i++) { - updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, left, top); - } - } - - private void createRenderer(final String layoutXmlText, final ThrowableRunnable runnable) { if (mySession == null) { ApplicationManager.getApplication().invokeLater( @@ -407,9 +325,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @Override protected ComponentDecorator getRootSelectionDecorator() { - return new ResizeSelectionDecorator(Color.RED, 1, new DirectionResizePoint(Position.EAST, "top_resize_"), - new DirectionResizePoint(Position.SOUTH_EAST, "top_resize"), - new DirectionResizePoint(Position.SOUTH, "top_resize")); + return new NonResizeSelectionDecorator(Color.RED, 1); } @Override @@ -420,26 +336,12 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @Override @NotNull protected ComponentCreationFactory createCreationFactory(Item paletteItem) { - return new ComponentCreationFactory() { - @Override - @NotNull - public RadComponent create() throws Exception { - return new RadViewComponent(null); - } - }; - //return null; // TODO: Auto-generated method stub + return null; // TODO: Auto-generated method stub } @Override public ComponentPasteFactory createPasteFactory(String xmlComponents) { - return new ComponentPasteFactory() { - @NotNull - @Override - public List create() throws Exception { - return Collections.singletonList(new RadViewComponent(null)); - } - }; - //return null; // TODO: Auto-generated method stub + return null; // TODO: Auto-generated method stub } @Override diff --git a/plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png b/plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png new file mode 100644 index 000000000000..f3556e079758 Binary files /dev/null and b/plugins/android-designer/src/com/intellij/android/designer/icons/unknown.png differ 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 new file mode 100644 index 000000000000..7445dcd87f48 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java @@ -0,0 +1,177 @@ +/* + * 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.android.ide.common.rendering.api.ViewInfo; +import com.intellij.designer.model.MetaManager; +import com.intellij.designer.model.MetaModel; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.model.RadLayout; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; +import com.intellij.psi.XmlRecursiveElementVisitor; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; + +import javax.swing.*; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public class ModelParser extends XmlRecursiveElementVisitor { + private final MetaManager myMetaManager; + private final XmlFile myXmlFile; + private RadViewComponent myRootComponent; + private RadViewComponent myComponent; + private String myLayoutXmlText; + + public ModelParser(Project project, XmlFile xmlFile) { + myMetaManager = ViewsMetaManager.getInstance(project); + myXmlFile = xmlFile; + parse(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // + // + ////////////////////////////////////////////////////////////////////////////////////////// + + private void parse() { + myLayoutXmlText = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + XmlTag root = myXmlFile.getRootTag(); + if (root != null) { + root.accept(ModelParser.this); + } + + return myXmlFile.getText(); + } + }); + } + + @Override + public void visitXmlTag(XmlTag tag) { + try { + MetaModel metaModel = myMetaManager.getModelByTag(tag.getName()); + if (metaModel == null) { + metaModel = myMetaManager.getModelByTag(""); + } + + RadViewComponent component = createComponent(tag, metaModel); + + if (myRootComponent == null) { + myRootComponent = component; + } + + component.setParent(myComponent); + if (myComponent != null) { + myComponent.getChildren().add(component); + } + + myComponent = component; + super.visitXmlTag(tag); + myComponent = (RadViewComponent)component.getParent(); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } + + private static RadViewComponent createComponent(XmlTag tag, MetaModel metaModel) throws Exception { + RadViewComponent component = (RadViewComponent)metaModel.getModel().newInstance(); + component.setMetaModel(metaModel); + component.setTag(tag); + + Class layout = metaModel.getLayout(); + if (layout != null) { + component.setLayout(layout.newInstance()); + } + + return component; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // + // + ////////////////////////////////////////////////////////////////////////////////////////// + + public RadViewComponent getRootComponent() { + return myRootComponent; + } + + public String getLayoutXmlText() { + return myLayoutXmlText; + } + + public void updateRootComponent(List views, JComponent nativeComponent) throws Exception { + RadViewComponent rootComponent = myRootComponent; + + if (views.size() == 1) { + RadViewComponent newRootComponent = createComponent(myXmlFile.getRootTag(), myMetaManager.getModelByTag("")); + rootComponent.setParent(newRootComponent); + newRootComponent.getChildren().add(rootComponent); + + updateComponent(rootComponent, views.get(0), nativeComponent, 0, 0); + + newRootComponent.setNativeComponent(nativeComponent); + newRootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); + + myRootComponent = newRootComponent; + } + else { + updateRootComponent(rootComponent, views, nativeComponent); + } + } + + public static void updateRootComponent(RadViewComponent rootComponent, + List views, + JComponent nativeComponent) { + int size = views.size(); + List children = rootComponent.getChildren(); + for (int i = 0; i < size; i++) { + updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, 0, 0); + } + + rootComponent.setNativeComponent(nativeComponent); + rootComponent.setBounds(0, 0, nativeComponent.getWidth(), nativeComponent.getHeight()); + } + + private static void updateComponent(RadViewComponent component, + ViewInfo view, + JComponent nativeComponent, + int parentX, + int parentY) { + component.setViewInfo(view); + component.setNativeComponent(nativeComponent); + + int left = parentX + view.getLeft(); + int top = parentY + view.getTop(); + component.setBounds(left, top, view.getRight() - view.getLeft(), view.getBottom() - view.getTop()); + + List views = view.getChildren(); + List children = component.getChildren(); + int size = views.size(); + + for (int i = 0; i < size; i++) { + updateComponent((RadViewComponent)children.get(i), views.get(i), nativeComponent, left, top); + } + } +} \ No newline at end of file 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 new file mode 100644 index 000000000000..d89c38a908f0 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/PropertyParser.java @@ -0,0 +1,113 @@ +/* + * 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.android.ide.common.rendering.api.ViewInfo; +import com.android.sdklib.IAndroidTarget; +import com.intellij.designer.model.MetaManager; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.openapi.module.Module; +import org.jetbrains.android.dom.attrs.AttributeDefinition; +import org.jetbrains.android.dom.attrs.AttributeDefinitions; +import org.jetbrains.android.dom.attrs.StyleableDefinition; +import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.android.sdk.AndroidTargetData; +import org.jetbrains.android.uipreview.ProjectClassLoader; +import org.jetbrains.android.uipreview.RenderServiceFactory; + +import java.util.*; + +/** + * @author Alexander Lobas + */ +@SuppressWarnings("unchecked") +public class PropertyParser { + private AttributeDefinitions myDefinitions; + private ProjectClassLoader myClassLoader; + private Map> myCachedAttributes; + + public PropertyParser(Module module, IAndroidTarget target) throws Exception { + MetaManager metaManager = ViewsMetaManager.getInstance(module.getProject()); + myCachedAttributes = (Map>)metaManager.getCache().get(target.hashString()); + if (myCachedAttributes == null) { + myCachedAttributes = new HashMap>(); + metaManager.getCache().put(target.hashString(), myCachedAttributes); + } + + AndroidPlatform androidPlatform = AndroidPlatform.getInstance(module); + AndroidTargetData targetData = androidPlatform.getSdkData().getTargetData(target); + myDefinitions = targetData.getAttrDefs(module.getProject()); + + RenderServiceFactory factory = targetData.getRenderServiceFactory(module.getProject()); + myClassLoader = new ProjectClassLoader(factory.getLibrary().getClassLoader(), module); + } + + public void loadRecursive(RadViewComponent component) throws Exception { + load(component); + + for (RadComponent child : component.getChildren()) { + loadRecursive((RadViewComponent)child); + } + } + + public void load(RadViewComponent component) throws Exception { + List properties = new ArrayList(); + component.setProperties(properties); + + ViewInfo info = component.getViewInfo(); + if (info == null) { + return; + } + + List attributes = loadAttributes(myClassLoader.loadClass(info.getClassName())); + for (AttributeDefinition attribute : attributes) { + // TODO + } + } + + private List loadAttributes(Class componentClass) { + String component = componentClass.getSimpleName(); + List attributes = myCachedAttributes.get(component); + + if (attributes == null) { + attributes = new ArrayList(); + + StyleableDefinition attributeDefs = myDefinitions.getStyleableByName(component); + if (attributeDefs != null) { + attributes.addAll(attributeDefs.getAttributes()); + } + + Class superComponentClass = componentClass.getSuperclass(); + if (superComponentClass != null) { + attributes.addAll(loadAttributes(superComponentClass)); + } + + if (!attributes.isEmpty()) { + Collections.sort(attributes, new Comparator() { + @Override + public int compare(AttributeDefinition a1, AttributeDefinition a2) { + return a1.getName().compareTo(a2.getName()); + } + }); + } + + myCachedAttributes.put(component, attributes); + } + + return attributes; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java new file mode 100644 index 000000000000..1d9f893bfc41 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadLinearLayout.java @@ -0,0 +1,22 @@ +/* + * 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; + +/** + * @author Alexander Lobas + */ +public class RadLinearLayout extends RadViewLayout { +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index 5693abda2e5a..c5284df9f637 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -15,22 +15,10 @@ */ package com.intellij.android.designer.model; +import com.android.ide.common.rendering.api.ViewInfo; 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.editors.BooleanEditor; -import com.intellij.designer.propertyTable.renderers.BooleanRenderer; -import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.util.IconLoader; -import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -38,32 +26,16 @@ import java.util.ArrayList; import java.util.List; /** - * TODO: now dummy implementation for tests - * * @author Alexander Lobas */ public class RadViewComponent extends RadComponent { - public static final AnAction LinearLayout = - new AnAction("Horizontal/Vertical", "LinearLayout", IconLoader.getIcon("/com/intellij/android/designer/icons/LinearLayout.png")) { - @Override - public void actionPerformed(AnActionEvent e) { - } - }; - private final List myChildren = new ArrayList(); + private ViewInfo myViewInfo; private Component myNativeComponent; private final Rectangle myBounds = new Rectangle(); private XmlTag myTag; private List myProperties; - public RadViewComponent(RadViewComponent parent) { - setParent(parent); - if (parent != null) { - parent.getChildren().add(this); - } - setLayout(new RadViewLayout(this)); - } - public XmlTag getTag() { return myTag; } @@ -77,6 +49,14 @@ public class RadViewComponent extends RadComponent { return myChildren; } + public ViewInfo getViewInfo() { + return myViewInfo; + } + + public void setViewInfo(ViewInfo viewInfo) { + myViewInfo = viewInfo; + } + @Override public Rectangle getBounds() { return myBounds; @@ -105,92 +85,11 @@ public class RadViewComponent extends RadComponent { } @Override - public void addSelectionActions(DefaultActionGroup actionGroup, JComponent shortcuts, List selection) { - if (myTag != null && myTag.getName().equals("LinearLayout") && selection.size() == 1 && selection.get(0) == this) { - AnAction action = new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - System.out.println("LinearLayout: " + e); - } - }; - action.copyFrom(LinearLayout); - actionGroup.add(action); - } + public List getProperties() { + return myProperties; } - @Override - public List getProperties() { - if (myProperties == null && myTag != null) { - myProperties = new ArrayList(); - Property layout = new Property(null, "layout") { - private final BooleanRenderer myRenderer = new BooleanRenderer(); - private final BooleanEditor myEditor = new BooleanEditor(); - private final List myProperties = new ArrayList(); - - @Override - public List getChildren(@Nullable RadComponent component) { - return myProperties; - } - - @Override - public Object getValue(RadComponent component) throws Exception { - return component.getClientProperty(getName()); - } - - @Override - public void setValue(RadComponent component, Object value) throws Exception { - component.putClientProperty(getName(), value); - } - - @Override - public boolean isDefaultValue(RadComponent component) throws Exception { - return getValue(component) == null; - } - - @Override - public void setDefaultValue(RadComponent component) throws Exception { - component.putClientProperty(getName(), null); - } - - @NotNull - @Override - public PropertyRenderer getRenderer() { - return myRenderer; - } - - @Override - public PropertyEditor getEditor() { - return myEditor; - } - }; - layout.setImportant(true); - - for (XmlAttribute attribute : myTag.getAttributes()) { - String name = attribute.getName(); - if (name.equals("xmlns:android")) { - continue; - } - - Property parent = name.equals("android:layout_width") || name.equals("android:layout_height") ? layout : null; - Property property = new AttributeProperty(parent, new String(name).replace("android:", "").replace('_', ' '), name); - property.setImportant(name.equals("android:text")); - property.setExpert(name.equals("android:id")); - if (name.equals("android:background")) { - property.setDeprecated(true); - property.setImportant(true); - } - if (parent == null) { - myProperties.add(property); - } - else { - layout.getChildren(null).add(property); - } - } - - if (!layout.getChildren(null).isEmpty()) { - myProperties.add(0, layout); - } - } - return myProperties == null ? super.getProperties() : myProperties; + public void setProperties(List properties) { + myProperties = properties; } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java index c9872c80f061..97ff2f279b70 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java @@ -17,14 +17,9 @@ package com.intellij.android.designer.model; import com.intellij.designer.designSurface.ComponentDecorator; import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator; -import com.intellij.designer.model.MetaModel; import com.intellij.designer.model.RadComponent; import com.intellij.designer.model.RadLayout; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import javax.swing.*; import java.awt.*; import java.util.List; @@ -32,33 +27,8 @@ import java.util.List; * @author Alexander Lobas */ public class RadViewLayout extends RadLayout { - private final RadViewComponent myContainer; - - public RadViewLayout(RadViewComponent container) { - myContainer = container; - } - - @Override + @Override public ComponentDecorator getChildSelectionDecorator(RadComponent component, List selection) { return new NonResizeSelectionDecorator(Color.RED, 1); } - - @Override - public void addSelectionActions(DefaultActionGroup actionGroup, JComponent shortcuts, List selection) { - if (myContainer.getTag() != null && myContainer.getTag().getName().equals("LinearLayout")) { - for (RadComponent component : selection) { - if (myContainer != component.getParent()) { - return; - } - } - AnAction action = new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - System.out.println("LinearLayout: " + e); - } - }; - action.copyFrom(RadViewComponent.LinearLayout); - actionGroup.add(action); - } - } } \ No newline at end of file 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 449fc164cf2c..3c22363a76ce 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 @@ -1,17 +1,26 @@ + + + + + @@ -51,7 +60,7 @@ @@ -70,14 +79,6 @@ - - - - - - - - \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/actions/GitFetch.java b/plugins/git4idea/src/git4idea/actions/GitFetch.java index df93cda9841a..07d041f2f08e 100644 --- a/plugins/git4idea/src/git4idea/actions/GitFetch.java +++ b/plugins/git4idea/src/git4idea/actions/GitFetch.java @@ -46,7 +46,7 @@ public class GitFetch extends GitRepositoryAction { GitVcs.runInBackground(new Task.Backgroundable(project, "Fetching...", false) { @Override public void run(@NotNull ProgressIndicator indicator) { - new GitFetcher(project, indicator).fetchRootsAndNotify(gitRoots, null, true); + new GitFetcher(project, indicator, true).fetchRootsAndNotify(gitRoots, null, true); } }); } diff --git a/plugins/git4idea/src/git4idea/actions/GitPull.java b/plugins/git4idea/src/git4idea/actions/GitPull.java index 8533801b1492..0d2cf7c1fe4b 100644 --- a/plugins/git4idea/src/git4idea/actions/GitPull.java +++ b/plugins/git4idea/src/git4idea/actions/GitPull.java @@ -83,7 +83,7 @@ public class GitPull extends GitRepositoryAction { } if (GitHttpAdapter.shouldUseJGit(url)) { - boolean fetchSuccessful = new GitFetcher(project, indicator).fetchRootsAndNotify(gitRoots, "Pull failed", false); + boolean fetchSuccessful = new GitFetcher(project, indicator, true).fetchRootsAndNotify(gitRoots, "Pull failed", false); if (!fetchSuccessful) { return; } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java new file mode 100644 index 000000000000..d93c65550e76 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.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 git4idea.branch; + +import git4idea.GitBranch; +import git4idea.repo.GitBranchTrackInfo; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class GitBranchUtil { + + private GitBranchUtil() {} + + /** + * Returns the tracking information about the given branch in the given repository, + * or null if there is no such information (i.e. if the branch doesn't have a tracking branch). + */ + @Nullable + public static GitBranchTrackInfo getTrackInfoForBranch(@NotNull GitRepository repository, @NotNull GitBranch branch) { + for (GitBranchTrackInfo trackInfo : repository.getConfig().getBranchTrackInfos()) { + if (trackInfo.getBranch().equals(branch.getName())) { + return trackInfo; + } + } + return null; + } +} diff --git a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java index 3c3f384249b2..fbb0826f1fd8 100644 --- a/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java +++ b/plugins/git4idea/src/git4idea/config/GitVersionSpecialty.java @@ -73,10 +73,15 @@ public enum GitVersionSpecialty { } }, + /** + * {@code git fetch --prune} is actually supported since 1.7.0, + * but before 1.7.7.2 calling {@code git fetch --prune origin master} would delete all other references. + * This was fixed in {@code ed43de6ec35dfd4c4bd33ae9b5f2ebe38282209f} and added to the Git 1.7.7.2 release. + */ SUPPORTS_FETCH_PRUNE { @Override public boolean existsIn(@NotNull GitVersion version) { - return version.isLaterOrEqual(new GitVersion(1, 7, 0, 0)); + return version.isLaterOrEqual(new GitVersion(1, 7, 7, 2)); } }, diff --git a/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java b/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java index 6c121759108e..fa262695f3dd 100644 --- a/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java +++ b/plugins/git4idea/src/git4idea/jgit/GitHttpAdapter.java @@ -102,12 +102,25 @@ public final class GitHttpAdapter { * Asks username and password if needed. */ @NotNull - public static GitFetchResult fetch(@NotNull final GitRepository repository, @NotNull final GitRemote remote, @NotNull String remoteUrl) { + public static GitFetchResult fetch(@NotNull final GitRepository repository, @NotNull final GitRemote remote, + @NotNull String remoteUrl, @Nullable String remoteBranch) { GitFetchResult.Type resultType; try { final Git git = convertToGit(repository); final GitHttpCredentialsProvider provider = new GitHttpCredentialsProvider(repository.getProject(), remoteUrl); - GeneralResult result = callWithAuthRetry(new GitHttpRemoteCommand.Fetch(git, provider, remoteUrl, convertRefSpecs(remote.getFetchRefSpecs())), + + List specs; + if (remoteBranch == null) { + specs = remote.getFetchRefSpecs(); + } + else { + if (!remoteBranch.startsWith(GitBranch.REFS_HEADS_PREFIX)) { + remoteBranch = GitBranch.REFS_HEADS_PREFIX + remoteBranch; + } + specs = Collections.singletonList(remoteBranch); + } + + GeneralResult result = callWithAuthRetry(new GitHttpRemoteCommand.Fetch(git, provider, remoteUrl, convertRefSpecs(specs)), repository.getProject()); resultType = convertToFetchResultType(result); } catch (IOException e) { diff --git a/plugins/git4idea/src/git4idea/push/GitPushDialog.java b/plugins/git4idea/src/git4idea/push/GitPushDialog.java index dc42b4c33b94..079d0c7d987a 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushDialog.java +++ b/plugins/git4idea/src/git4idea/push/GitPushDialog.java @@ -27,6 +27,7 @@ import com.intellij.util.Consumer; import com.intellij.util.ui.UIUtil; import git4idea.GitBranch; import git4idea.GitUtil; +import git4idea.history.browser.GitCommit; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; @@ -58,7 +59,7 @@ public class GitPushDialog extends DialogWrapper { private final Object COMMITS_LOADING_LOCK = new Object(); private final GitManualPushToBranch myRefspecPanel; private final AtomicReference myDestBranchInfoOnRefresh = new AtomicReference(); - + private final boolean myPushPossible; public GitPushDialog(@NotNull Project project) { @@ -115,14 +116,14 @@ public class GitPushDialog extends DialogWrapper { private void loadCommitsInBackground() { myLoadingPanel.startLoading(); - + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { public void run() { final AtomicReference error = new AtomicReference(); synchronized (COMMITS_LOADING_LOCK) { error.set(collectInfoToPush()); } - + final Pair remoteAndBranch = getRemoteAndTrackedBranchForCurrentBranch(); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override @@ -175,17 +176,27 @@ public class GitPushDialog extends DialogWrapper { @Nullable private String collectInfoToPush() { try { + LOG.info("collectInfoToPush..."); myPushSpecs = pushSpecsForCurrentOrEnteredBranches(); myGitCommitsToPush = myPusher.collectCommitsToPush(myPushSpecs); + LOG.info("collectInfoToPush | Collected commits to push: " + logMessageForCommits(myGitCommitsToPush)); return null; } catch (VcsException e) { myGitCommitsToPush = GitCommitsByRepoAndBranch.empty(); - LOG.error("Couldn't collect commits to push. Push spec: " + myPushSpecs, e); + LOG.error("collectInfoToPush | Couldn't collect commits to push. Push spec: " + myPushSpecs, e); return e.getMessage(); } } - + + private static String logMessageForCommits(GitCommitsByRepoAndBranch commitsToPush) { + StringBuilder logMessage = new StringBuilder(); + for (GitCommit commit : commitsToPush.getAllCommits()) { + logMessage.append(commit.getShortHash()); + } + return logMessage.toString(); + } + private Map pushSpecsForCurrentOrEnteredBranches() throws VcsException { Map defaultSpecs = new HashMap(); for (GitRepository repository : myRepositories) { @@ -220,7 +231,7 @@ public class GitPushDialog extends DialogWrapper { } tracked = manualBranch; } - + GitPushSpec pushSpec = new GitPushSpec(remote, currentBranch, tracked); defaultSpecs.put(repository, pushSpec); } @@ -260,19 +271,23 @@ public class GitPushDialog extends DialogWrapper { // waiting for commit list loading, because this information is needed to correctly handle rejected push situation and correctly // notify about pushed commits // TODO optimize: don't refresh: information about pushed commits can be achieved from the successful push output + LOG.info("getPushInfo start"); synchronized (COMMITS_LOADING_LOCK) { GitCommitsByRepoAndBranch selectedCommits; if (myGitCommitsToPush == null) { + LOG.info("getPushInfo | myGitCommitsToPush == null. collecting..."); collectInfoToPush(); selectedCommits = myGitCommitsToPush; } else { if (refreshNeeded()) { + LOG.info("getPushInfo | refresh is needed, collecting..."); collectInfoToPush(); } Collection selectedRepositories = myListPanel.getSelectedRepositories(); selectedCommits = myGitCommitsToPush.retainAll(selectedRepositories); } + LOG.info("getPushInfo | selectedCommits: " + logMessageForCommits(selectedCommits)); return new GitPushInfo(selectedCommits, myPushSpecs); } } diff --git a/plugins/git4idea/src/git4idea/push/GitPushLog.java b/plugins/git4idea/src/git4idea/push/GitPushLog.java index f8ada332cb7b..1524ebc2aeeb 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushLog.java +++ b/plugins/git4idea/src/git4idea/push/GitPushLog.java @@ -61,6 +61,7 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { private final DefaultTreeModel myTreeModel; private final CheckedTreeNode myRootNode; private final ReentrantReadWriteLock TREE_CONSTRUCTION_LOCK = new ReentrantReadWriteLock(); + private boolean myTreeWasConstructed; private final MyTreeCellRenderer myTreeCellRenderer; GitPushLog(@NotNull Project project, @NotNull Collection repositories, @NotNull final Consumer checkboxListener) { @@ -166,6 +167,7 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { myTree.setModel(myTreeModel); // TODO: why doesn't it repaint otherwise? TreeUtil.expandAll(myTree); selectFirstCommit(); + myTreeWasConstructed = true; } finally { TREE_CONSTRUCTION_LOCK.writeLock().unlock(); @@ -259,23 +261,28 @@ class GitPushLog extends JPanel implements TypeSafeDataProvider { try { TREE_CONSTRUCTION_LOCK.readLock().lock(); // wait for tree to be constructed - Collection selectedRepositories = new ArrayList(myAllRepositories.size()); - if (myRootNode.getChildCount() == 0) { // the method is requested before tree construction began => returning all repos. + if (!myTreeWasConstructed) { return myAllRepositories; } + else { + Collection selectedRepositories = new ArrayList(myAllRepositories.size()); + if (myRootNode.getChildCount() == 0) { // the method is requested before tree construction began => returning all repos. + return myAllRepositories; + } - for (int i = 0; i < myRootNode.getChildCount(); i++) { - TreeNode child = myRootNode.getChildAt(i); - if (child instanceof CheckedTreeNode) { - CheckedTreeNode node = (CheckedTreeNode)child; - if (node.isChecked()) { - if (node.getUserObject() instanceof GitRepository) { - selectedRepositories.add((GitRepository)node.getUserObject()); + for (int i = 0; i < myRootNode.getChildCount(); i++) { + TreeNode child = myRootNode.getChildAt(i); + if (child instanceof CheckedTreeNode) { + CheckedTreeNode node = (CheckedTreeNode)child; + if (node.isChecked()) { + if (node.getUserObject() instanceof GitRepository) { + selectedRepositories.add((GitRepository)node.getUserObject()); + } } } } + return selectedRepositories; } - return selectedRepositories; } finally { TREE_CONSTRUCTION_LOCK.readLock().unlock(); diff --git a/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java b/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java index f7b79d1e6345..bc70772c27e5 100644 --- a/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java +++ b/plugins/git4idea/src/git4idea/repo/GitBranchTrackInfo.java @@ -64,6 +64,7 @@ public class GitBranchTrackInfo { return String.format("%s %s %s %b", myBranch, myRemote, myRemoteBranch, myMerge); } + @SuppressWarnings("ConstantConditions") @Override public boolean equals(Object o) { @@ -80,6 +81,7 @@ public class GitBranchTrackInfo { return true; } + @SuppressWarnings("ConstantConditions") @Override public int hashCode() { int result = myBranch != null ? myBranch.hashCode() : 0; diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java index bb160315d24b..e908f177742c 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java @@ -20,6 +20,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.roots.ModuleRootListener; @@ -53,7 +54,6 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme private final @NotNull AbstractVcs myVcs; private final @NotNull ProjectLevelVcsManager myVcsManager; - private final @NotNull PlatformFacade myPlatformFacade; private final Map myRepositories = new HashMap(); private final Set myListeners = new HashSet(); @@ -67,15 +67,14 @@ public final class GitRepositoryManager extends AbstractProjectComponent impleme public GitRepositoryManager(@NotNull Project project, @NotNull PlatformFacade platformFacade) { super(project); - myPlatformFacade = platformFacade; myVcsManager = ProjectLevelVcsManager.getInstance(myProject); - myVcs = myPlatformFacade.getVcs(myProject); + myVcs = platformFacade.getVcs(myProject); } @Override public void initComponent() { Disposer.register(myProject, this); - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { + StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() { @Override public void run() { final MessageBus messageBus = myProject.getMessageBus(); diff --git a/plugins/git4idea/src/git4idea/update/GitFetcher.java b/plugins/git4idea/src/git4idea/update/GitFetcher.java index b498934a9213..1891a93155d4 100644 --- a/plugins/git4idea/src/git4idea/update/GitFetcher.java +++ b/plugins/git4idea/src/git4idea/update/GitFetcher.java @@ -23,11 +23,14 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitBranch; import git4idea.GitVcs; import git4idea.Notificator; +import git4idea.branch.GitBranchUtil; import git4idea.commands.*; import git4idea.config.GitVersionSpecialty; import git4idea.jgit.GitHttpAdapter; +import git4idea.repo.GitBranchTrackInfo; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; @@ -43,6 +46,9 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static git4idea.GitBranch.REFS_HEADS_PREFIX; +import static git4idea.GitBranch.REFS_REMOTES_PREFIX; + /** * @author Kirill Likhodedov */ @@ -53,13 +59,19 @@ public class GitFetcher { private final Project myProject; private final GitRepositoryManager myRepositoryManager; private final ProgressIndicator myProgressIndicator; + private final boolean myFetchAll; private final GitVcs myVcs; private final Collection myErrors = new ArrayList(); - public GitFetcher(@NotNull Project project, @NotNull ProgressIndicator progressIndicator) { + /** + * @param fetchAll Pass {@code true} to fetch all remotes and all branches (like {@code git fetch} without parameters does). + * Pass {@code false} to fetch only the tracked branch of the current branch. + */ + public GitFetcher(@NotNull Project project, @NotNull ProgressIndicator progressIndicator, boolean fetchAll) { myProject = project; myProgressIndicator = progressIndicator; + myFetchAll = fetchAll; myRepositoryManager = GitRepositoryManager.getInstance(project); myVcs = GitVcs.getInstance(project); } @@ -74,22 +86,66 @@ public class GitFetcher { // TODO need to have a fair compound result here GitFetchResult fetchResult = GitFetchResult.success(); + if (myFetchAll) { + fetchResult = fetchAll(root, repository, fetchResult); + } + else { + return fetchCurrentBranch(root, repository); + } + + repository.update(GitRepository.TrackedTopic.BRANCHES); + return fetchResult; + } + + @NotNull + private GitFetchResult fetchCurrentBranch(@NotNull VirtualFile root, @NotNull GitRepository repository) { + GitBranch currentBranch = repository.getCurrentBranch(); + if (currentBranch == null) { + String message = "Current branch can't be null here. \nRepository: " + repository; + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + GitBranchTrackInfo trackInfo = GitBranchUtil.getTrackInfoForBranch(repository, currentBranch); + if (trackInfo == null) { + String message = "Tracked info is null for branch " + currentBranch + "\n Repository: " + repository; + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + + GitRemote remote = trackInfo.getRemote(); + String url = remote.getFirstUrl(); + if (url == null) { + String message = "URL is null for remote " + remote.getName(); + LOG.error(message); + return GitFetchResult.error(new Exception(message)); + } + + String remoteBranch = trackInfo.getRemoteBranch(); + if (GitHttpAdapter.shouldUseJGit(url)) { + return GitHttpAdapter.fetch(repository, remote, url, remoteBranch); + } + return fetchNatively(root, remote, remoteBranch); + } + + @NotNull + private GitFetchResult fetchAll(@NotNull VirtualFile root, @NotNull GitRepository repository, @NotNull GitFetchResult fetchResult) { for (GitRemote remote : repository.getRemotes()) { String url = remote.getFirstUrl(); if (url == null) { + LOG.error("URL is null for remote " + remote.getName()); continue; } if (GitHttpAdapter.shouldUseJGit(url)) { - GitFetchResult res = GitHttpAdapter.fetch(repository, remote, url); + GitFetchResult res = GitHttpAdapter.fetch(repository, remote, url, null); res.addPruneInfo(fetchResult.getPrunedRefs()); fetchResult = res; myErrors.addAll(fetchResult.getErrors()); if (!fetchResult.isSuccess()) { break; } - } + } else { - GitFetchResult res = fetchNatively(root, remote); + GitFetchResult res = fetchNatively(root, remote, null); res.addPruneInfo(fetchResult.getPrunedRefs()); fetchResult = res; if (!fetchResult.isSuccess()) { @@ -97,17 +153,22 @@ public class GitFetcher { } } } - - repository.update(GitRepository.TrackedTopic.BRANCHES); return fetchResult; } - private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote) { + private GitFetchResult fetchNatively(@NotNull VirtualFile root, @NotNull GitRemote remote, @Nullable String branch) { final GitLineHandlerPasswordRequestAware h = new GitLineHandlerPasswordRequestAware(myProject, root, GitCommand.FETCH); if (GitVersionSpecialty.SUPPORTS_FETCH_PRUNE.existsIn(myVcs.getVersion())) { h.addParameters("--prune"); } - h.addParameters(remote.getName()); + + String remoteName = remote.getName(); + h.addParameters(remoteName); + if (branch != null) { + branch = getRidOfPrefixIfExists(branch); + h.addParameters(REFS_HEADS_PREFIX + branch + ":" + REFS_REMOTES_PREFIX + remoteName + "/" + branch); + } + final GitTask fetchTask = new GitTask(myProject, h, "Fetching..."); fetchTask.setProgressIndicator(myProgressIndicator); fetchTask.setProgressAnalyzer(new GitStandardProgressAnalyzer()); @@ -144,6 +205,13 @@ public class GitFetcher { return result.get(); } + private static String getRidOfPrefixIfExists(String branch) { + if (branch.startsWith(REFS_HEADS_PREFIX)) { + return branch.substring(REFS_HEADS_PREFIX.length()); + } + return branch; + } + @NotNull public Collection getErrors() { return myErrors; diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 848ae5f14802..a270dbfe7e3c 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -108,6 +108,11 @@ public class GitUpdateProcess { String oldText = myProgressIndicator.getText(); myProgressIndicator.setText("Updating..."); + // check if update is possible + if (checkRebaseInProgress() || isMergeInProgress() || areUnmergedFiles() || !checkTrackedBranchesConfigured()) { + return false; + } + if (!fetchAndNotify()) { return false; } @@ -125,10 +130,6 @@ public class GitUpdateProcess { private boolean updateImpl(UpdateMethod updateMethod, ContinuationContext context) { // define updaters for roots - // check if update is possible - if (checkRebaseInProgress() || isMergeInProgress() || areUnmergedFiles()) return false; - if (!checkTrackedBranchesConfigured()) return false; - try { for (VirtualFile root : myRoots) { final GitUpdater updater; @@ -222,7 +223,7 @@ public class GitUpdateProcess { // fetch all roots. If an error happens, return false and notify about errors. private boolean fetchAndNotify() { - return new GitFetcher(myProject, myProgressIndicator).fetchRootsAndNotify(myRoots, "Update failed", false); + return new GitFetcher(myProject, myProgressIndicator, false).fetchRootsAndNotify(myRoots, "Update failed", false); } public Map getTrackedBranches() { diff --git a/plugins/git4idea/src/git4idea/update/GitUpdater.java b/plugins/git4idea/src/git4idea/update/GitUpdater.java index a70dd29aa586..d5ef3ce7923e 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdater.java @@ -24,9 +24,10 @@ import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitBranch; import git4idea.GitRevisionNumber; -import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.branch.GitBranchPair; +import git4idea.commands.GitCommand; +import git4idea.commands.GitSimpleHandler; import git4idea.config.GitConfigUtil; import git4idea.config.GitVcsSettings; import git4idea.merge.MergeChangeCollector; @@ -132,7 +133,7 @@ public abstract class GitUpdater { GitBranch dest = gitBranchPair.getDest(); assert dest != null; String remoteBranch = dest.getName(); - if (! hasRemotelyChangedPaths(currentBranch, remoteBranch)) { + if (! hasRemoteChanges(currentBranch, remoteBranch)) { LOG.info("isSaveNeeded No remote changes, save is not needed"); return false; } @@ -159,7 +160,12 @@ public abstract class GitUpdater { } } - protected boolean hasRemotelyChangedPaths(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { - return !GitUtil.getPathsDiffBetweenRefs(currentBranch, remoteBranch, myProject, myRoot).isEmpty(); + protected boolean hasRemoteChanges(@NotNull String currentBranch, @NotNull String remoteBranch) throws VcsException { + GitSimpleHandler handler = new GitSimpleHandler(myProject, myRoot, GitCommand.REV_LIST); + handler.setNoSSH(true); + handler.addParameters("-1"); + handler.addParameters(currentBranch + ".." + remoteBranch); + String output = handler.run(); + return output != null && !output.isEmpty(); } } diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index ac778fa9870e..2fb6c89c3dcf 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -29,6 +29,7 @@ gradle.import.structure.settings.label.root.excluded=Excluded roots: gradle.import.structure.settings.label.library.path.binary=Binary paths gradle.import.structure.settings.label.library.path.source=Source paths gradle.import.structure.settings.label.library.path.doc=Doc paths +gradle.import.structure.settings.label.filters=Filters: gradle.import.title.error.resolve.generic=Resolve error gradle.import.text.error.resolve.generic.without.reason=Can''t resolve target gradle project at ''{0}'' diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 72ac5c04f4c6..e0c9e44feedc 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -65,7 +65,7 @@ - @@ -100,16 +100,28 @@ - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java new file mode 100644 index 000000000000..d819627d55c0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleAbstractSyncTreeFilterAction.java @@ -0,0 +1,40 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.options.colors.AttributesDescriptor; +import com.intellij.util.ui.ColorIcon; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:48 PM + */ +public abstract class GradleAbstractSyncTreeFilterAction extends ToggleAction { + + @NotNull private final AttributesDescriptor myDescriptor; + + protected GradleAbstractSyncTreeFilterAction(@NotNull AttributesDescriptor descriptor) { + myDescriptor = descriptor; + getTemplatePresentation().setText(descriptor.getDisplayName()); + final Color color = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(descriptor.getKey()).getForegroundColor(); + getTemplatePresentation().setIcon(new ColorIcon(new JLabel("").getFont().getSize(), color)); + } + + @Override + public boolean isSelected(AnActionEvent e) { + // TODO den implement + return false; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + // TODO den implement + System.out.println("GradleAbstractSyncTreeFilterAction.setSelected(): " + state); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java new file mode 100644 index 000000000000..de21d9c421f8 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConfirmedSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 6:07 PM + */ +public class GradleConfirmedSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleConfirmedSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.CONFIRMED); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java new file mode 100644 index 000000000000..3ef8e0957b20 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleConflictSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 6:08 PM + */ +public class GradleConflictSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleConflictSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.CONFLICT); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java new file mode 100644 index 000000000000..f0a59e30c5f4 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLocalSyncTreeFilterAction.java @@ -0,0 +1,14 @@ +package org.jetbrains.plugins.gradle.action; + +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:54 PM + */ +public class GradleLocalSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public GradleLocalSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.GRADLE_LOCAL); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java new file mode 100644 index 000000000000..46bc43a9d51b --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/IntellijLocalSyncTreeFilterAction.java @@ -0,0 +1,16 @@ +package org.jetbrains.plugins.gradle.action; + +import com.intellij.openapi.options.colors.AttributesDescriptor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.config.GradleColorAndFontDescriptorsProvider; + +/** + * @author Denis Zhdanov + * @since 3/7/12 3:59 PM + */ +public class IntellijLocalSyncTreeFilterAction extends GradleAbstractSyncTreeFilterAction { + + public IntellijLocalSyncTreeFilterAction() { + super(GradleColorAndFontDescriptorsProvider.INTELLIJ_LOCAL); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java index 458659bac40b..d44ec89eb7f5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleColorAndFontDescriptorsProvider.java @@ -17,28 +17,32 @@ import org.jetbrains.plugins.gradle.util.GradleBundle; */ public class GradleColorAndFontDescriptorsProvider implements ColorAndFontDescriptorsProvider { - private static final AttributesDescriptor[] DESCRIPTORS = { - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.conflict"), - GradleTextAttributes.CHANGE_CONFLICT - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.confirmed"), - GradleTextAttributes.CONFIRMED_CONFLICT - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.gradle"), - GradleTextAttributes.GRADLE_LOCAL_CHANGE - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.intellij", ApplicationNamesInfo.getInstance().getProductName()), - GradleTextAttributes.INTELLIJ_LOCAL_CHANGE - ), - new AttributesDescriptor( - GradleBundle.message("gradle.sync.change.type.unchanged"), - GradleTextAttributes.NO_CHANGE - ) - }; + public static final AttributesDescriptor CONFLICT = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.conflict"), + GradleTextAttributes.CHANGE_CONFLICT + ); + + public static final AttributesDescriptor CONFIRMED = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.confirmed"), + GradleTextAttributes.CONFIRMED_CONFLICT + ); + + public static final AttributesDescriptor GRADLE_LOCAL = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.gradle"), + GradleTextAttributes.GRADLE_LOCAL_CHANGE + ); + + public static final AttributesDescriptor INTELLIJ_LOCAL = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.intellij", ApplicationNamesInfo.getInstance().getProductName()), + GradleTextAttributes.INTELLIJ_LOCAL_CHANGE + ); + + public static final AttributesDescriptor NO_CHANGE = new AttributesDescriptor( + GradleBundle.message("gradle.sync.change.type.unchanged", ApplicationNamesInfo.getInstance().getProductName()), + GradleTextAttributes.NO_CHANGE + ); + + private static final AttributesDescriptor[] DESCRIPTORS = { CONFLICT, CONFIRMED, GRADLE_LOCAL, INTELLIJ_LOCAL, NO_CHANGE }; @NotNull @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java index 146fa370e035..316376fb5647 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java @@ -5,7 +5,9 @@ import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.SideBorder; import com.intellij.util.messages.MessageBusConnection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +16,8 @@ import org.jetbrains.plugins.gradle.util.GradleBundle; import javax.swing.*; import java.awt.*; +import java.util.Collections; +import java.util.List; /** * Base class for high-level Gradle GUI controls used at the Gradle tool window. The basic idea is to encapsulate the same features in @@ -42,14 +46,12 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { private final JPanel myContent = new JPanel(myLayout); private final Project myProject; + private final String myPlace; protected GradleToolWindowPanel(@NotNull Project project, @NotNull String place) { super(true); myProject = project; - final ActionManager actionManager = ActionManager.getInstance(); - final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID); - ActionToolbar actionToolbar = actionManager.createActionToolbar(place, actionGroup, true); - setToolbar(actionToolbar.getComponent()); + myPlace = place; setContent(myContent); MessageBusConnection connection = project.getMessageBus().connect(project); @@ -62,6 +64,22 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { } public void initContent() { + final ActionManager actionManager = ActionManager.getInstance(); + final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID); + ActionToolbar actionToolbar = actionManager.createActionToolbar(myPlace, actionGroup, true); + JPanel toolbarControl = new JPanel(new GridBagLayout()); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.weightx = 1; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.anchor = GridBagConstraints.WEST; + toolbarControl.add(actionToolbar.getComponent(), constraints); + for (JComponent component : getToolbarControls()) { + component.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP)); + toolbarControl.add(component, constraints); + } + setToolbar(toolbarControl); + final JComponent payloadControl = buildContent(); myContent.add(ScrollPaneFactory.createScrollPane(payloadControl), CONTENT_CARD_NAME); RichTextControlBuilder builder = new RichTextControlBuilder(); @@ -74,6 +92,14 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { update(); } + /** + * @return list of UI controls to be displayed vertically at the toolbar + */ + @NotNull + protected List getToolbarControls() { + return Collections.emptyList(); + } + /** * Asks current control to update its state. */ diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java index e982b0022e79..d4814b6a4b9f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java @@ -16,7 +16,6 @@ public abstract class GradleAbstractDependencyStructureChangesCalculator gradleContentRoots = gradleEntity.getContentRoots(); final Collection intellijContentRoots = context.getPlatformFacade().getContentRoots(intellijEntity); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java index b8488781f219..3f884ccec8b2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java @@ -171,7 +171,7 @@ public class GradleApiFacadeManager { final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine( ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), params, - false // TODO den check + false ); final OSProcessHandler processHandler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) { @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index 994c9fb6f50d..3d72ad01668b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -30,7 +30,6 @@ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreePath; import java.awt.*; -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; @@ -46,9 +45,10 @@ import java.util.List; public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { private static final int TOOLTIP_DELAY_MILLIS = 500; - - private final Alarm myToolbarAppearanceAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - private final Alarm myToolbarTrackingAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + + private final Alarm myToolbarAppearanceAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final Alarm myToolbarTrackingAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final List myToolbarControls = new ArrayList(); private Tree myTree; private GradleProjectStructureTreeModel myTreeModel; @@ -75,6 +75,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { }); } }); + myToolbarControls.add(new GradleProjectStructureFiltersPanel()); initContent(); } @@ -93,6 +94,8 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { applyInitialAppearance(myTree, (DefaultMutableTreeNode)myTreeModel.getRoot()); GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.anchor = GridBagConstraints.WEST; constraints.fill = GridBagConstraints.BOTH; constraints.weightx = constraints.weighty = 1; result.add(myTree, constraints); @@ -103,10 +106,14 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { return result; } + @NotNull + @Override + protected List getToolbarControls() { + return myToolbarControls; + } + @Override protected void updateContent() { - // TODO den implement - int i = 1; } private void setupToolbar() { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java new file mode 100644 index 000000000000..9cdf3ba83ca9 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureFiltersPanel.java @@ -0,0 +1,27 @@ +package org.jetbrains.plugins.gradle.sync; + +import com.intellij.openapi.actionSystem.ActionGroup; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import org.jetbrains.plugins.gradle.util.GradleBundle; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import javax.swing.*; + +/** + * @author Denis Zhdanov + * @since 3/6/12 3:44 PM + */ +public class GradleProjectStructureFiltersPanel extends JPanel { + + + public GradleProjectStructureFiltersPanel() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + add(Box.createHorizontalStrut(7)); + add(new JLabel(GradleBundle.message("gradle.import.structure.settings.label.filters"))); + final ActionManager actionManager = ActionManager.getInstance(); + final ActionGroup group = (ActionGroup)actionManager.getAction("Gradle.SyncTreeFilter"); + final ActionToolbar toolbar = actionManager.createActionToolbar(GradleConstants.SYNC_TREE_FILTER_PLACE, group, true); + add(toolbar.getComponent()); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index 3f74a6e2adb7..1bb6991fb5ae 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -241,11 +241,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processNewProjectRenameChange(@NotNull GradleProjectRenameChange change) { - // TODO den implement } private void processNewLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { - // TODO den implement } private void processNewMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { @@ -325,11 +323,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processObsoleteProjectRenameChange(@NotNull GradleProjectRenameChange change) { - // TODO den implement } private void processObsoleteLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { - // TODO den implement } private void processObsoleteMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java index 5b24a6aed7ee..348a4c857903 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleConstants.java @@ -18,6 +18,7 @@ public class GradleConstants { @NonNls public static final String TOOL_WINDOW_TOOLBAR_PLACE = "GRADLE_SYNC_CHANGES_TOOLBAR"; @NonNls public static final String SYNC_TREE_CONTEXT_MENU_PLACE = "GRADLE_SYNC_TREE_CONTEXT_MENU_PLACE"; @NonNls public static final String SYNC_TREE_FLOATING_TOOLBAR_PLACE = "GRADLE_SYNC_TREE_FLOATING_TOOLBAR_PLACE"; + @NonNls public static final String SYNC_TREE_FILTER_PLACE = "GRADLE_SYNC_TREE_FILTER_PLACE"; @NonNls public static final String ACTION_GROUP_SYNC_TREE = "Gradle.SyncTreeGroup"; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index 902e8027ad48..505bff71191b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -256,8 +256,14 @@ public class GradleUtil { } return file.getPath(); } - - // TODO den add doc about relative coordinates + + /** + * Allows to calculate the position to use for showing hint for the given node of the given tree. + * + * @param node target node for which a hint should be shown + * @param tree target tree that contains given node + * @return preferred hint position (in coordinates relative to the given tree) + */ @NotNull public static Point getHintPosition(@NotNull GradleProjectStructureNode node, @NotNull Tree tree) { final Rectangle bounds = tree.getPathBounds(new TreePath(node.getPath())); 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 dab16040291e..e62afa172b81 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 @@ -475,6 +475,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (namedArguments.length == 0) return; Map map = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, null, false); + if (map == null) return; for (GrNamedArgument namedArgument : namedArguments) { String labelName = namedArgument.getLabelName(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java index 5c09dc23b945..f6cc56bccc94 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java @@ -16,17 +16,17 @@ package org.jetbrains.plugins.groovy.extensions; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.psi.CommonClassNames; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import java.util.HashMap; import java.util.Map; @@ -56,6 +56,7 @@ public abstract class GroovyNamedArgumentProvider { getNamedArguments(call, resolve, argumentName, forCompletion, result); } + @Nullable public static Map getNamedArgumentsFromAllProviders(@NotNull GrCall call, @Nullable String argumentName, boolean forCompletion) { @@ -80,6 +81,7 @@ public abstract class GroovyNamedArgumentProvider { } } else { + boolean mapExpected = false; for (GroovyResolveResult result : callVariants) { PsiElement element = result.getElement(); if (element instanceof GrAccessorMethod) continue; @@ -90,6 +92,8 @@ public abstract class GroovyNamedArgumentProvider { if (!method.isConstructor() && !(parameters.length > 0 && canBeMap(parameters[0]))) continue; + mapExpected = true; + for (GroovyMethodInfo methodInfo : GroovyMethodInfo.getInfos(method)) { if (methodInfo.getNamedArguments() != null) { if (methodInfo.isApplicable(method)) { @@ -107,16 +111,27 @@ public abstract class GroovyNamedArgumentProvider { for (GroovyNamedArgumentProvider namedArgumentProvider : EP_NAME.getExtensions()) { namedArgumentProvider.getNamedArguments(call, element, result, argumentName, forCompletion, namedArguments); } + + if (element instanceof GrVariable && + InheritanceUtil.isInheritor(((GrVariable)element).getTypeGroovy(), GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) { + mapExpected = true; + } + } + if (!mapExpected && namedArguments.isEmpty()) { + return null; } } return namedArguments; } - public static boolean canBeMap(PsiParameter parameter) { - if (parameter instanceof GrParameter) { - if (((GrParameter)parameter).getTypeElementGroovy() == null) return true; + private static boolean canBeMap(PsiParameter parameter) { + PsiType type = parameter.getType(); + if (parameter instanceof GrParameter && + type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && + ((GrParameter)parameter).getTypeElementGroovy() == null) { + return true; } - return GroovyPsiManager.isInheritorCached(parameter.getType(), CommonClassNames.JAVA_UTIL_MAP); + return GroovyPsiManager.isInheritorCached(type, CommonClassNames.JAVA_UTIL_MAP); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java index 5be4f0e7ed4e..0b3ab60c8134 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java @@ -29,6 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlo import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -84,13 +85,15 @@ public class GantMemberContributor extends NonCodeMembersContributor { return; } - for (GrArgumentLabel label : GantUtils.getScriptTargets((GroovyFile)file)) { - final String targetName = label.getName(); - if (targetName != null) { - final PsiNamedElement variable = new LightVariableBuilder(targetName, GroovyCommonClassNames.GROOVY_LANG_CLOSURE, label). - setBaseIcon(GantIcons.GANT_TARGET); - if (!ResolveUtil.processElement(processor, variable, state)) { - return; + if (aClass instanceof GroovyScriptClass) { + for (GrArgumentLabel label : GantUtils.getScriptTargets((GroovyFile)file)) { + final String targetName = label.getName(); + if (targetName != null) { + final PsiNamedElement variable = new LightVariableBuilder(targetName, GroovyCommonClassNames.GROOVY_LANG_CLOSURE, label). + setBaseIcon(GantIcons.GANT_TARGET); + if (!ResolveUtil.processElement(processor, variable, state)) { + return; + } } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java index 0cbe9c32803f..8a71e69e7784 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java @@ -25,6 +25,7 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.lang.ASTNode; +import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.*; import com.intellij.psi.templateLanguages.OuterLanguageElement; @@ -42,6 +43,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation. import org.jetbrains.plugins.groovy.lang.psi.api.statements.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; @@ -96,7 +98,10 @@ public class GroovyCompletionData { result.addElement(keyword("as", TailType.HUMBLE_SPACE_BEFORE_WORD)); } - if (isInfixOperatorPosition(position)) { + if (isAfterForParameter(position)) { + addKeywords(result, true, "in"); + } + else if (isInfixOperatorPosition(position)) { addKeywords(result, true, "in", PsiKeyword.INSTANCEOF); } else if (suggestThrows(position)) { result.addElement(keyword(PsiKeyword.THROWS, TailType.INSERT_SPACE)); @@ -135,6 +140,13 @@ public class GroovyCompletionData { } } + private static boolean isAfterForParameter(PsiElement position) { + ElementPattern forParameter = + psiElement().withParents(GrParameter.class, GrTraditionalForClause.class, GrForStatement.class); + return psiElement().withParent(GrReferenceExpression.class).afterLeaf(forParameter).accepts(position) || + forParameter.accepts(position) && psiElement().afterLeaf(psiElement(GroovyTokenTypes.mIDENT)).accepts(position); + } + public static void addModifiers(PsiElement position, CompletionResultSet result) { PsiClass scope = PsiTreeUtil.getParentOfType(position, PsiClass.class); PsiModifierList modifierList = ModifierChooser.findModifierList(position); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java index 70ae6f0bd85f..cba75c7052a9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyNoVariantsDelegator.java @@ -125,7 +125,7 @@ public class GroovyNoVariantsDelegator extends CompletionContributor { } return factory.createReferenceExpressionFromText("xxx.xxx", - ReferenceExpressionCompletionContributor + JavaCompletionUtil .createContextWithXxxVariable(place, qualifierType)); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java index e69a65085b31..db7f4e7a8065 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java @@ -80,6 +80,10 @@ class MapArgumentCompletionProvider extends CompletionProvider map = calcNamedArgumentsForCall(mapOrArgumentList); + if (map == null) { + return; + } + if (map.isEmpty()) { map = findOtherNamedArgumentsInFile(mapOrArgumentList); } @@ -155,6 +159,7 @@ class MapArgumentCompletionProvider extends CompletionProvider calcNamedArgumentsForCall(@NotNull PsiElement mapOrArgumentList) { PsiElement argumentList = mapOrArgumentList instanceof GrArgumentList ? mapOrArgumentList : mapOrArgumentList.getParent(); if (argumentList instanceof GrArgumentList) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java index 2bdebbfd0574..79fe633b88d5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/typeDefinitions/members/ClassMember.java @@ -53,6 +53,7 @@ public class ClassMember implements GroovyElementTypes { PsiBuilder.Marker initMarker = builder.mark(); PsiBuilder.Marker modMarker = builder.mark(); ParserUtils.getToken(builder, kSTATIC); + ParserUtils.getToken(builder, mNLS); if (mLCURLY == builder.getTokenType()) { modMarker.done(MODIFIERS); if (OpenOrClosableBlock.parseOpenBlock(builder, parser)) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java index 9210e96b8ba9..e8b06b9c8eee 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java @@ -115,4 +115,12 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { public boolean isInvokedOnProperty() { return myIsInvokedOnProperty; } + + @Override + public String toString() { + return "GroovyResolveResultImpl{" + + "myElement=" + myElement + + ", mySubstitutor=" + mySubstitutor + + '}'; + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java index fa9ba5accff3..648ffc6fcf2d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/arguments/GrArgumentLabelImpl.java @@ -44,6 +44,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUt import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import java.util.Map; + /** * @author ilyas */ @@ -79,13 +81,14 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum String labelName = getName(); - NamedArgumentDescriptor descr = - GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, labelName, false).get(labelName); - - if (descr != null) { - PsiPolyVariantReference res = descr.createReference(this); - if (res != null) { - return res; + Map providers = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, labelName, false); + if (providers != null) { + NamedArgumentDescriptor descr = providers.get(labelName); + if (descr != null) { + PsiPolyVariantReference res = descr.createReference(this); + if (res != null) { + return res; + } } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index 57e82942aeff..4eda27241e6a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -184,6 +184,7 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { assert !lookup type 'c' assert !lookup.focused + assert 'char' in myFixture.lookupElementStrings assert myFixture.editor.document.text.contains('for(final c)') type ' in c' assert lookup.focused diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 739fa2d75186..475f214ad1d4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -1188,4 +1188,9 @@ new Base().fiex''') assert myFixture.lookupElementStrings == ['field1'] } + public void testForIn() { + assert doContainsTest('in', 'for (int i i') + assert doContainsTest('in', 'for (i i') + } + } \ No newline at end of file diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy index 35500fafe438..8ff9b61f7e00 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/GantReferenceCompletionTest.groovy @@ -83,16 +83,11 @@ target(aaa: "") { } public void testMutual() throws Throwable { - complete """ + checkVariants """ target(genga: "") { } target(aaa: "") { - depends(geng) -}""" - myFixture.checkResult """ -target(genga: "") { } -target(aaa: "") { - depends(genga) -}""" + depends(gengx) +}""", 'genga' } public void testUnknownQualifier() throws Throwable { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy index 1a328b3b87bf..a828d6e60c09 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyMapAttributeTest.groovy @@ -15,16 +15,21 @@ */ package org.jetbrains.plugins.groovy.lang -import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.lookup.LookupElement import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyUncheckedAssignmentOfMemberOfRawTypeInspection +import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.plugins.groovy.completion.GrCompletionWithLibraryTest /** * @author Sergey Evdokimov */ class GroovyMapAttributeTest extends LightCodeInsightFixtureTestCase { + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return GrCompletionWithLibraryTest.GROOVY_17_PROJECT_DESCRIPTOR + } private void doTestCompletion(String fileText, boolean exists) { myFixture.configureByText("a.groovy", fileText) diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java index 3e21513f9f32..c036ab091810 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/TypesParsingTest.java @@ -34,5 +34,6 @@ public class TypesParsingTest extends GroovyParsingTestCase { public void testInnerEnum() throws Throwable { doTest(); } public void testNewlineBeforeClassBrace() throws Throwable { doTest(); } public void testNewlineBeforeExtends() throws Throwable { doTest(); } + public void testStaticInitializer() throws Throwable { doTest(); } } \ No newline at end of file diff --git a/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test b/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test new file mode 100644 index 000000000000..d0af3cac82e1 --- /dev/null +++ b/plugins/groovy/testdata/parsing/groovy/types/staticInitializer.test @@ -0,0 +1,73 @@ +class StaticDemo { + static + { + println "Demo" + } + + public static void main(String[] args) + { + + } +} +----- +Groovy script + Class definition + Modifiers + + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(identifier)('StaticDemo') + PsiWhiteSpace(' ') + Type definition body + PsiElement({)('{') + PsiWhiteSpace('\n ') + Class initializer + Modifiers + PsiElement(static)('static') + PsiElement(new line)('\n ') + Open block + PsiElement({)('{') + PsiWhiteSpace('\n ') + Call expression + Reference expression + PsiElement(identifier)('println') + PsiWhiteSpace(' ') + Command arguments + Literal + PsiElement(Gstring)('"Demo"') + PsiElement(new line)('\n ') + PsiElement(})('}') + PsiElement(new line)('\n\n ') + Method + Modifiers + PsiElement(public)('public') + PsiWhiteSpace(' ') + PsiElement(static)('static') + PsiWhiteSpace(' ') + Built in type + PsiElement(void)('void') + PsiWhiteSpace(' ') + PsiElement(identifier)('main') + PsiElement(()('(') + Parameter list + Parameter + Modifiers + + Array type + Type element + Reference element + PsiElement(identifier)('String') + PsiElement([)('[') + PsiElement(])(']') + PsiWhiteSpace(' ') + PsiElement(identifier)('args') + PsiElement())(')') + PsiElement(new line)('\n ') + Throw clause + + Open block + PsiElement({)('{') + PsiWhiteSpace('\n\n ') + PsiElement(})('}') + PsiElement(new line)('\n') + PsiElement(})('}') \ No newline at end of file diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java index 7c2f8bdaddf2..1f351951bb9d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandLineStatusClient.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.Convertor; +import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.portable.PortableStatus; import org.jetbrains.idea.svn.portable.SvnExceptionWrapper; import org.jetbrains.idea.svn.portable.SvnStatusClientI; @@ -159,7 +160,9 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI { SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(new StringBufferInputStream(result), svnHandl[0]); if (! svnHandl[0].isAnythingReported()) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + if (! SvnUtil.isSvnVersioned(myProject, path)) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + } } } catch (SvnExceptionWrapper e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java index c07f4cb00a31..edda617b3b33 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnStatusHandler.java @@ -684,6 +684,47 @@ public class SvnStatusHandler extends DefaultHandler { if (exists) { status.setKind(exists, file.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE); } else { + // this is a hack. This is done so because of strange svn native client output: + /* + c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>svn st --xml + + + + + + + + + + + while + +c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4>dir + Volume in drive C has no label. + Volume Serial Number is B4EA-B379 + + Directory of c:\TestProjects\sortedProjects\Subversion\local\withExt82420\mod4 + +03/09/2012 05:30 PM . +03/09/2012 05:30 PM .. +03/09/2012 05:30 PM 437 mod4.iml +03/09/2012 05:30 PM src + +and no "mod4" under + + */ + final SVNStatusType ns = status.getNodeStatus(); + if (myBase.getName().equals(path) && ! SVNStatusType.MISSING.equals(ns) && + ! SVNStatusType.STATUS_DELETED.equals(ns) ) { + status.setKind(true, SVNNodeKind.DIR); + status.setFile(myBase); + status.setPath(""); + return; + } status.setKind(exists, SVNNodeKind.UNKNOWN); } status.setPath(path); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java index 7cfc6fa8b34a..ebb92267e41e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java @@ -18,8 +18,10 @@ package org.jetbrains.idea.svn.dialogs; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.ToolWindowManager; @@ -279,6 +281,7 @@ public class PropertiesComponent extends JPanel { } catch (SVNException err) { // show error message + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); } } setFile(myVcs, myFile); @@ -300,6 +303,7 @@ public class PropertiesComponent extends JPanel { try { myVcs.createWCClient().doSetProperty(myFile, getSelectedPropertyName(), null, true, false, null); } catch (SVNException error) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + error.getMessage(), MessageType.ERROR); // show error message. } setFile(myVcs, myFile); @@ -333,6 +337,7 @@ public class PropertiesComponent extends JPanel { wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, null, null); } catch (SVNException err) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); // show error message } } @@ -365,6 +370,7 @@ public class PropertiesComponent extends JPanel { wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive, null); } catch (SVNException err) { + VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR); // show error message } } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java index 22d11dae714c..fdc64b146f98 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java @@ -21,7 +21,6 @@ import com.intellij.ide.palette.PaletteGroup; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.util.containers.hash.HashMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; @@ -30,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import java.beans.PropertyChangeSupport; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,6 +52,8 @@ public abstract class MetaManager { private PropertyChangeSupport myPaletteChangeSupport; + private Map myCache = new HashMap(); + protected MetaManager(Project project, String name) { try { InputStream stream = getClass().getResourceAsStream(name); @@ -119,6 +121,10 @@ public abstract class MetaManager { myPaletteGroups.add(group); } + public Map getCache() { + return myCache; + } + @Nullable public MetaModel getModelByTag(String tag) { return myTag2Model.get(tag); diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java index e03bdfdf5a8a..f68e7e48bb9f 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagValueImpl.java @@ -19,6 +19,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.psi.XmlElementFactory; import com.intellij.psi.xml.*; import com.intellij.util.IncorrectOperationException; @@ -123,4 +124,17 @@ public class XmlTagValueImpl implements XmlTagValue{ LOG.error(e); } } + + @Override + public boolean hasCDATA() { + for (XmlText xmlText : myTextElements) { + PsiElement[] children = xmlText.getChildren(); + for (PsiElement child : children) { + if (child.getNode().getElementType() == XmlElementType.XML_CDATA) { + return true; + } + } + } + return false; + } } diff --git a/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java b/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java index 9e922e58f907..aedef5bbb975 100644 --- a/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java +++ b/xml/openapi/src/com/intellij/psi/xml/XmlTagValue.java @@ -36,4 +36,6 @@ public interface XmlTagValue { String getTrimmedText(); void setText(String value); + + boolean hasCDATA(); }