Merge remote-tracking branch 'origin/master'

This commit is contained in:
Sascha Weinreuter
2012-03-11 08:58:19 +01:00
116 changed files with 2038 additions and 1019 deletions
@@ -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;
@@ -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<Sdk> myFilter;
private final Condition<Sdk> myFilter;
@Nullable
private final Condition<SdkType> myCreationFilter;
public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) {
this(jdkModel, null);
this(jdkModel, null, null);
}
public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, @Nullable Condition<Sdk> filter) {
public JdkComboBox(@NotNull final ProjectSdksModel jdkModel,
@Nullable Condition<Sdk> filter,
@Nullable Condition<SdkType> 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);
}
}
});
}
@@ -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) {
@@ -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);
@@ -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<MasterDetailsComponent.MyNode> getNodeComparator() {
return null;
}
/**
* @return callback or <code>null</code> if not handled
*/
@Nullable
public ActionCallback selectOrderEntry(@NotNull final Module module, @Nullable final OrderEntry entry) {
return null;
}
}
@@ -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();
@@ -30,55 +30,62 @@ import static com.intellij.psi.CommonClassNames.*;
*/
class CollectionsUtilityMethodsProvider {
public static final Key<Boolean> COLLECTION_FACTORY = Key.create("CollectionFactory");
public static void addCompletions(@NotNull final JavaSmartCompletionParameters parameters,
@NotNull final Consumer<LookupElement> result) {
final PsiElement element = parameters.getPosition();
private final PsiElement myElement;
private final PsiType myExpectedType;
private final PsiType myDefaultType;
@NotNull private final Consumer<LookupElement> myResult;
final PsiElement parent = element.getParent();
CollectionsUtilityMethodsProvider(PsiElement position,
PsiType expectedType,
PsiType defaultType, @NotNull final Consumer<LookupElement> 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<LookupElement> 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<LookupElement> 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) {
@@ -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<LookupElementDecorator<L
}
final PsiElement place = context.getFile().findElementAt(context.getStartOffset());
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
assert place != null;
boolean hasParams = hasConstructorParameters(psiClass, place);
JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous);
return true;
}
static boolean hasConstructorParameters(PsiClass psiClass, @NotNull PsiElement place) {
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper();
boolean hasParams = false;
for (PsiMethod constructor : psiClass.getConstructors()) {
if (!resolveHelper.isAccessible(constructor, place, null)) continue;
@@ -157,10 +166,7 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
break;
}
}
JavaCompletionUtil.insertParentheses(context, delegate, false, hasParams, forAnonymous);
return true;
return hasParams;
}
private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) {
@@ -210,6 +210,10 @@ public class JavaCompletionContributor extends CompletionContributor {
return;
}
if (JavaSmartCompletionContributor.IN_TYPE_ARGS.accepts(position)) {
new TypeArgumentCompletionProvider(false).addCompletions(parameters, new ProcessingContext(), result);
}
final InheritorsHolder inheritors = new InheritorsHolder(position, result);
if (JavaSmartCompletionContributor.AFTER_NEW.accepts(position)) {
new JavaInheritorsGetter(ConstructorInsertHandler.BASIC_INSTANCE).generateVariants(parameters, result.getPrefixMatcher(), inheritors);
@@ -246,7 +246,7 @@ public class JavaCompletionSorting {
myExpectedTypes = expectedTypes;
myParameters = parameters;
final Pair<PsiClass,Integer> pair = JavaSmartCompletionContributor.getTypeParameterInfo(parameters.getPosition());
final Pair<PsiClass,Integer> pair = TypeArgumentCompletionProvider.getTypeParameterInfo(parameters.getPosition());
myTypeParameter = pair == null ? null : pair.first.getTypeParameters()[pair.second.intValue()];
myLocation = new CompletionLocation(myParameters);
}
@@ -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<PairFunction<PsiExpression, CompletionParameters, PsiType>> DYNAMIC_TYPE_EVALUATOR = Key.create("DYNAMIC_TYPE_EVALUATOR");
static final Key<PsiType> 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<PsiType> 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<CompletionElement> 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<PsiMember> mentioned = new THashSet<PsiMember>();
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<LookupElement> 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<PsiExpression, CompletionParameters, PsiType> evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR);
PsiReferenceExpression context = refExpr;
PsiType type = null;
final PairFunction<PsiExpression, CompletionParameters, PsiType> 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<LookupElement> 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<LookupElement> castQualifier(final Project project, LookupElement item, final LookupElement to) {
return LookupElementDecorator.withInsertHandler(item, new InsertHandlerDecorator<LookupElement>() {
public void handleInsert(InsertionContext context, LookupElementDecorator<LookupElement> 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;
}
};
}
}
@@ -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<LookupElement>() {
@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)) {
@@ -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<PsiElement> INSIDE_TYPECAST_EXPRESSION = psiElement().withParent(
psiElement(PsiReferenceExpression.class).afterLeaf(
psiElement().withText(")").withParent(PsiTypeCastExpression.class)));
static final PsiElementPattern.Capture<PsiElement> 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<CompletionParameters>() {
protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) {
final PsiElement context = parameters.getPosition();
final Pair<PsiClass, Integer> 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<PsiClassType> typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(targetParameter));
JavaInheritorsGetter
.processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer<PsiType>() {
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<PsiClass, Integer> 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<LookupElement> completeReference(final PsiElement element,
@@ -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();
@@ -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) {
@@ -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<CompletionParameters> {
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<PsiClass, Integer> 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<PsiTypeLookupItem> typeItems = new ArrayList<PsiTypeLookupItem>();
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<PsiClassType> typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(
referencedClass.getTypeParameters()[parameterIndex]));
JavaInheritorsGetter.processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer<PsiType>() {
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<PsiClass, Integer> 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<PsiTypeLookupItem> myTypeItems;
private final TailType myGlobalTail;
private final boolean myHasParameters;
public TypeArgsLookupElement(List<PsiTypeLookupItem> typeItems, TailType globalTail, boolean hasParameters) {
myTypeItems = typeItems;
myGlobalTail = globalTail;
myHasParameters = hasParameters;
myLookupString = StringUtil.join(myTypeItems, new Function<PsiTypeLookupItem, String>() {
@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();
}
}
}
@@ -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;
@@ -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<FoldingDescriptor> list, PsiElement elementToFold, Document document, boolean allowOneLiners) {
@@ -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);
@@ -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<Boolean> EXPECTED_TYPE_INHERITOR_MEMBER = Key.create("EXPECTED_TYPE_INHERITOR_MEMBER");
public void processMembers(@NotNull final PsiElement context, final Consumer<LookupElement> 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<PsiType> consumer = new Consumer<PsiType>() {
@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<LookupElement> results, final PsiResolveHelper resolveHelper, final Set<PsiMember> importedStatically) {
Consumer<LookupElement> results, final PsiResolveHelper resolveHelper, final Set<PsiMember> importedStatically, boolean isInheritor) {
final FilterScopeProcessor<PsiElement> processor = new FilterScopeProcessor<PsiElement>(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));
}
}
-1
View File
@@ -12,7 +12,6 @@
<orderEntry type="module" module-name="resources-en" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="module" module-name="lang-api" />
</component>
</module>
@@ -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.getv<caret>x
}
}
}
@@ -0,0 +1,5 @@
import java.util.HashMap;
public class A {
private HashMap<String, String> m = new HashMap<St<caret>>()
}
@@ -0,0 +1,5 @@
import java.util.HashMap;
public class A {
private HashMap<String, String> m = new HashMap<String, String>(<caret>)
}
@@ -0,0 +1,7 @@
import java.util.Set;
class Foo {
{
Set<String> s = em<caret>
}
}
@@ -0,0 +1,8 @@
import java.util.Collections;
import java.util.Set;
class Foo {
{
Set<String> s = Collections.emptySet()<caret>
}
}
@@ -1,5 +1,5 @@
class HashMap<T,V> {}
public class A {
private HashMap<String, String> m = new HashMap<String, String><caret>();
private HashMap<String, String> m = new HashMap<String, String>();<caret>
}
@@ -0,0 +1,5 @@
import java.util.HashMap;
public class A {
private HashMap<String, String> m = new HashMap<String, String>(<caret>);
}
@@ -0,0 +1,5 @@
import java.util.HashMap;
public class A {
private HashMap<String, String> m = new HashMap<<caret>>();
}
@@ -0,0 +1,3 @@
class AAAAA<K,V,G>{
AAAAA<K,V,?> asd = new AAAAA<K, <caret>
}
@@ -0,0 +1,3 @@
class AAAAA<K,V,G>{
AAAAA<K,V,?> asd = new AAAAA<<caret>
}
@@ -1,4 +1,4 @@
class Test<T> {
Test<String> test = new Test<String><caret>
Test<String> test = new Test<String>();<caret>
}
@@ -1,3 +1,3 @@
class AAAAA<K,V>{
AAAAA<K,V> asd = new AAAAA<K, <caret>
AAAAA<K,V> asd = new AAAAA<K, V>();<caret>
}
@@ -1,8 +1,12 @@
import java.util.List;
public class Aaaaaaa {
List<String> locMethod() {}
{
java.util.List<String> local = null;
java.util.List<String> l = <caret>
List<String> local = null;
List<String> l = <caret>
}
}
@@ -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()
}
}
@@ -291,9 +291,9 @@ public class SmartTypeCompletionOrderingTest extends CompletionSortingTestCase {
myFixture.addClass("package foo; public class FList<T> implements java.util.List<T> { public static <T> FList<T> 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() {
@@ -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();
@@ -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<T> {
public abstract T execute();
}
private static abstract class SetupTimer<T> extends AroundTemplateMethod<T> {
}
class Test {
void test() {
new SetupTimer<Integer>() {
public Integer execute() {
return 0;
}
};
}
}
"""
configure text
def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl
def closureStartFold = foldingModel.getCollapsedRegionAtOffset(text.indexOf("<Integer>"))
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 {
@@ -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;
@@ -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<String> paths = new LinkedList<String>();
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.<String, String>emptyMap(), CanceledStatus.NULL);
final List<BuildMessage> errorMessages = new ArrayList<BuildMessage>();
final List<BuildMessage> infoMessages = new ArrayList<BuildMessage>();
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<Artifact>(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());
}
}
@@ -11,7 +11,7 @@ class Module extends LazyInitializeableObject implements ClasspathItem {//}, Com
String name;
Sdk sdk;
private List<ModuleDependency> dependencies = []
List<ModuleDependency> dependencies = []
List<String> contentRoots = []
List<String> sourceRoots = []
List<String> 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
@@ -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<String> getKeywordSet(Set<String> keywordSet) {
if (!myIgnoreCase) {
return new THashSet<String>(keywordSet);
@@ -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);
@@ -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<Sdk> updateTree) {
createAddActions(group, parent, updateTree, null);
}
public void createAddActions(DefaultActionGroup group,
final JComponent parent,
final Consumer<Sdk> updateTree,
@Nullable Condition<SdkType> 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()) {
@@ -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;
}
}
@@ -70,9 +70,17 @@ public abstract class FileSetVersionsFetcherBase<F extends DownloadableFileSetDe
for (ArtifactItem item : items) {
String url = item.getUrl();
final String prefix = version.getUrlPrefix();
if (!url.startsWith("http://") && prefix != null) {
url = prefix + url;
if (url == null) {
if (prefix != null) {
url = prefix + item.getName();
}
} else {
if (!url.startsWith("http://") && prefix != null) {
url = prefix + url;
}
}
assert url != null;
files.add(DownloadableFileService.getInstance().createFileDescription(url, item.getName()));
}
result.add(createVersion(version, files));
@@ -4067,7 +4067,7 @@ public class AbstractTreeUi {
return preselectedRow;
}
private void expandAllWithoutRecursion(@Nullable final Runnable onDone) {
public void expandAllWithoutRecursion(@Nullable final Runnable onDone) {
final JTree tree = getTree();
int myCurrentRow = 0;
if (tree.getRowCount() > 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"));
@@ -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-')
'''
}
}
@@ -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.
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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) {
@@ -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;
}
@@ -599,7 +599,7 @@ public class CommittedChangesCache implements PersistentStateComponent<Committed
myCachedIncomingChangeLists = result;
debug("Incoming changes loaded");
notifyIncomingChangesUpdated(null);
notifyIncomingChangesUpdated(result);
return result;
}
@@ -741,7 +741,13 @@ public class CommittedChangesCache implements PersistentStateComponent<Committed
}
private void notifyIncomingChangesUpdated(@Nullable final Collection<CommittedChangeList> receivedChanges) {
final ArrayList<CommittedChangeList> listCopy = receivedChanges == null ? null : new ArrayList<CommittedChangeList>(receivedChanges);
final Collection<CommittedChangeList> changes = receivedChanges == null ? myCachedIncomingChangeLists : receivedChanges;
if (changes == null) {
final List<CommittedChangeList> lists = loadIncomingChanges(false);
myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(new ArrayList<CommittedChangeList>(lists));
return;
}
final ArrayList<CommittedChangeList> listCopy = new ArrayList<CommittedChangeList>(changes);
myBus.syncPublisher(COMMITTED_TOPIC).incomingChangesUpdated(listCopy);
}
@@ -93,4 +93,8 @@ public abstract class LabeledComboBoxAction extends AnAction implements CustomCo
boxModel.setSelectedItem(boxModel.getElementAt(idx));
}
}
protected JComboBox getComboBox() {
return myComboBox;
}
}
@@ -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) {
@@ -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());
}
}
@@ -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<String>() {
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<Throwable>() {
private void parseFile(final Runnable runnable) throws Exception {
final ModelParser parser = new ModelParser(getProject(), myXmlFile);
createRenderer(parser.getLayoutXmlText(), new ThrowableRunnable<Throwable>() {
@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<ViewInfo> views, JComponent nativeComponent) {
RadViewComponent rootComponent = rootComponents[0];
if (views.size() == 1) {
RadViewComponent newRootComponent = new RadViewComponent(null);
newRootComponent.setMetaModel(ViewsMetaManager.getInstance(getProject()).getModelByTag("<root>"));
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<ViewInfo> views, JComponent nativeComponent) {
int size = views.size();
List<RadComponent> 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<ViewInfo> views = view.getChildren();
List<RadComponent> 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<Throwable> 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<RadComponent> create() throws Exception {
return Collections.<RadComponent>singletonList(new RadViewComponent(null));
}
};
//return null; // TODO: Auto-generated method stub
return null; // TODO: Auto-generated method stub
}
@Override
Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

@@ -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<String>() {
@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("<unknown>");
}
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<RadLayout> 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<ViewInfo> views, JComponent nativeComponent) throws Exception {
RadViewComponent rootComponent = myRootComponent;
if (views.size() == 1) {
RadViewComponent newRootComponent = createComponent(myXmlFile.getRootTag(), myMetaManager.getModelByTag("<root>"));
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<ViewInfo> views,
JComponent nativeComponent) {
int size = views.size();
List<RadComponent> 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<ViewInfo> views = view.getChildren();
List<RadComponent> 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);
}
}
}
@@ -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<String, List<AttributeDefinition>> myCachedAttributes;
public PropertyParser(Module module, IAndroidTarget target) throws Exception {
MetaManager metaManager = ViewsMetaManager.getInstance(module.getProject());
myCachedAttributes = (Map<String, List<AttributeDefinition>>)metaManager.getCache().get(target.hashString());
if (myCachedAttributes == null) {
myCachedAttributes = new HashMap<String, List<AttributeDefinition>>();
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<Property> properties = new ArrayList<Property>();
component.setProperties(properties);
ViewInfo info = component.getViewInfo();
if (info == null) {
return;
}
List<AttributeDefinition> attributes = loadAttributes(myClassLoader.loadClass(info.getClassName()));
for (AttributeDefinition attribute : attributes) {
// TODO
}
}
private List<AttributeDefinition> loadAttributes(Class<?> componentClass) {
String component = componentClass.getSimpleName();
List<AttributeDefinition> attributes = myCachedAttributes.get(component);
if (attributes == null) {
attributes = new ArrayList<AttributeDefinition>();
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<AttributeDefinition>() {
@Override
public int compare(AttributeDefinition a1, AttributeDefinition a2) {
return a1.getName().compareTo(a2.getName());
}
});
}
myCachedAttributes.put(component, attributes);
}
return attributes;
}
}
@@ -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 {
}
@@ -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<RadComponent> myChildren = new ArrayList<RadComponent>();
private ViewInfo myViewInfo;
private Component myNativeComponent;
private final Rectangle myBounds = new Rectangle();
private XmlTag myTag;
private List<Property> 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<RadComponent> 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<Property> getProperties() {
return myProperties;
}
@Override
public List<Property> getProperties() {
if (myProperties == null && myTag != null) {
myProperties = new ArrayList<Property>();
Property layout = new Property(null, "layout") {
private final BooleanRenderer myRenderer = new BooleanRenderer();
private final BooleanEditor myEditor = new BooleanEditor();
private final List<Property> myProperties = new ArrayList<Property>();
@Override
public List<Property> 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<Property> properties) {
myProperties = properties;
}
}
@@ -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<RadComponent> selection) {
return new NonResizeSelectionDecorator(Color.RED, 1);
}
@Override
public void addSelectionActions(DefaultActionGroup actionGroup, JComponent shortcuts, List<RadComponent> 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);
}
}
}
@@ -1,17 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<meta-model>
<meta model="com.intellij.android.designer.model.RadViewComponent"
layout="com.intellij.android.designer.model.RadViewLayout"
tag="&lt;root&gt;">
<palette title="Device Screen" icon="/com/intellij/android/designer/icons/DeviceScreen.png"/>
</meta>
<meta model="com.intellij.android.designer.model.RadViewComponent"
layout="com.intellij.android.designer.model.RadViewLayout"
tag="merge">
<palette title="Device Screen (#merge)" icon="/com/intellij/android/designer/icons/DeviceScreen.png"/>
</meta>
<meta model="com.intellij.android.designer.model.RadViewComponent"
layout="com.intellij.android.designer.model.RadViewLayout"
tag="&lt;unknown&gt;">
<palette title="Unknown (%tag%)" icon="/com/intellij/android/designer/icons/unknown.png"/>
</meta>
<meta model="com.intellij.android.designer.model.RadViewComponent"
class="android.widget.Button"
tag="Button">
@@ -51,7 +60,7 @@
</meta>
<meta model="com.intellij.android.designer.model.RadViewComponent"
layout="com.intellij.android.designer.model.RadViewLayout"
layout="com.intellij.android.designer.model.RadLinearLayout"
class="android.widget.LinearLayout"
tag="LinearLayout">
@@ -70,14 +79,6 @@
</meta>
<palette>
<group name="Layouts">
<item tag="LinearLayout"/>
</group>
<group name="Widgets">
<item tag="Button"/>
<item tag="TextView"/>
</group>
</palette>
</meta-model>
@@ -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);
}
});
}
@@ -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;
}
@@ -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;
}
}
@@ -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));
}
},
@@ -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<String> 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) {
@@ -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<String> myDestBranchInfoOnRefresh = new AtomicReference<String>();
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<String> error = new AtomicReference<String>();
synchronized (COMMITS_LOADING_LOCK) {
error.set(collectInfoToPush());
}
final Pair<String, String> 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<GitRepository, GitPushSpec> pushSpecsForCurrentOrEnteredBranches() throws VcsException {
Map<GitRepository, GitPushSpec> defaultSpecs = new HashMap<GitRepository, GitPushSpec>();
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<GitRepository> selectedRepositories = myListPanel.getSelectedRepositories();
selectedCommits = myGitCommitsToPush.retainAll(selectedRepositories);
}
LOG.info("getPushInfo | selectedCommits: " + logMessageForCommits(selectedCommits));
return new GitPushInfo(selectedCommits, myPushSpecs);
}
}
@@ -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<GitRepository> repositories, @NotNull final Consumer<Boolean> 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<GitRepository> selectedRepositories = new ArrayList<GitRepository>(myAllRepositories.size());
if (myRootNode.getChildCount() == 0) { // the method is requested before tree construction began => returning all repos.
if (!myTreeWasConstructed) {
return myAllRepositories;
}
else {
Collection<GitRepository> selectedRepositories = new ArrayList<GitRepository>(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();
@@ -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;
@@ -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<VirtualFile, GitRepository> myRepositories = new HashMap<VirtualFile, GitRepository>();
private final Set<GitRepositoryChangeListener> myListeners = new HashSet<GitRepositoryChangeListener>();
@@ -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();
@@ -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<Exception> myErrors = new ArrayList<Exception>();
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<Exception> getErrors() {
return myErrors;
@@ -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<VirtualFile, GitBranchPair> getTrackedBranches() {
@@ -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();
}
}
@@ -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}''
+15 -3
View File
@@ -65,7 +65,7 @@
<projectService serviceImplementation="org.jetbrains.plugins.gradle.config.GradleSettings"/>
<projectService serviceImplementation="org.jetbrains.plugins.gradle.config.GradleProjectState"/>
<toolWindow id="Gradle" anchor="right" icon="/icons/gradle.png"
<toolWindow id="JetGradle" anchor="right" icon="/icons/gradle.png"
factoryClass="org.jetbrains.plugins.gradle.ui.GradleToolWindowFactory"/>
</extensions>
@@ -100,16 +100,28 @@
<action id="Gradle.LinkToProject" class="org.jetbrains.plugins.gradle.action.GradleLinkToProjectAction" icon="/general/add.png"/>
<action id="Gradle.RefreshProject" class="org.jetbrains.plugins.gradle.action.GradleRefreshProjectAction" icon="/actions/sync.png"/>
<action id="Gradle.OpenScript" class="org.jetbrains.plugins.gradle.action.GradleOpenScriptAction" icon="/icons/gradleNavigate.png"/>
<action id="Gradle.ImportEntity" class="org.jetbrains.plugins.gradle.action.GradleImportEntityAction" icon="/icons/gradleImport.png"/>
<action id="Gradle.ShowConflict" class="org.jetbrains.plugins.gradle.action.GradleShowConflictDetailsAction" icon="/actions/diff.png"/>
<group id="Gradle.ChangeActionsToolbar">
<reference id="Gradle.RefreshProject"/>
<reference id="Gradle.OpenScript"/>
</group>
<action id="Gradle.ImportEntity" class="org.jetbrains.plugins.gradle.action.GradleImportEntityAction" icon="/icons/gradleImport.png"/>
<action id="Gradle.ShowConflict" class="org.jetbrains.plugins.gradle.action.GradleShowConflictDetailsAction" icon="/actions/diff.png"/>
<group id="Gradle.SyncTreeGroup">
<reference id="Gradle.ImportEntity"/>
<reference id="Gradle.ShowConflict"/>
</group>
<action id="Gradle.SyncTreeFilter.GradleLocal" class="org.jetbrains.plugins.gradle.action.GradleLocalSyncTreeFilterAction"/>
<action id="Gradle.SyncTreeFilter.IntellijLocal" class="org.jetbrains.plugins.gradle.action.IntellijLocalSyncTreeFilterAction"/>
<action id="Gradle.SyncTreeFilter.Conflict" class="org.jetbrains.plugins.gradle.action.GradleConflictSyncTreeFilterAction"/>
<action id="Gradle.SyncTreeFilter.Confirmed" class="org.jetbrains.plugins.gradle.action.GradleConfirmedSyncTreeFilterAction"/>
<group id="Gradle.SyncTreeFilter">
<reference id="Gradle.SyncTreeFilter.GradleLocal"/>
<reference id="Gradle.SyncTreeFilter.IntellijLocal"/>
<reference id="Gradle.SyncTreeFilter.Conflict"/>
<reference id="Gradle.SyncTreeFilter.Confirmed"/>
</group>
</actions>
</idea-plugin>
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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
@@ -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<JComponent> getToolbarControls() {
return Collections.emptyList();
}
/**
* Asks current control to update its state.
*/
@@ -16,7 +16,6 @@ public abstract class GradleAbstractDependencyStructureChangesCalculator<G exten
{
@Override
public void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context) {
// TODO den process common dependency properties here.
doCalculate(gradleEntity, intellijEntity, context);
}
@@ -17,7 +17,6 @@ public class GradleContentRootStructureChangesCalculator
@NotNull ModuleAwareContentRoot intellijEntity,
@NotNull GradleChangesCalculationContext context)
{
// TODO den implement content root conflict changes here.
}
@NotNull
@@ -56,7 +56,6 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh
@NotNull Module intellijEntity,
@NotNull GradleChangesCalculationContext context)
{
//TODO den process module-local settings
// Content roots.
final Collection<GradleContentRoot> gradleContentRoots = gradleEntity.getContentRoots();
final Collection<ModuleAwareContentRoot> intellijContentRoots = context.getPlatformFacade().getContentRoots(intellijEntity);
@@ -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
@@ -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<JComponent> myToolbarControls = new ArrayList<JComponent>();
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<JComponent> getToolbarControls() {
return myToolbarControls;
}
@Override
protected void updateContent() {
// TODO den implement
int i = 1;
}
private void setupToolbar() {
@@ -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());
}
}
@@ -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) {
@@ -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";
@@ -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()));
@@ -475,6 +475,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
if (namedArguments.length == 0) return;
Map<String, NamedArgumentDescriptor> map = GroovyNamedArgumentProvider.getNamedArgumentsFromAllProviders(call, null, false);
if (map == null) return;
for (GrNamedArgument namedArgument : namedArguments) {
String labelName = namedArgument.getLabelName();
@@ -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<String, NamedArgumentDescriptor> 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);
}
}
@@ -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;
}
}
}
}
@@ -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<PsiElement> 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);
@@ -125,7 +125,7 @@ public class GroovyNoVariantsDelegator extends CompletionContributor {
}
return factory.createReferenceExpressionFromText("xxx.xxx",
ReferenceExpressionCompletionContributor
JavaCompletionUtil
.createContextWithXxxVariable(place, qualifierType));
}

Some files were not shown because too many files have changed in this diff Show More