mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-17
@@ -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) {
|
||||
|
||||
+37
-8
@@ -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);
|
||||
|
||||
+11
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -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();
|
||||
|
||||
+39
-32
@@ -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) {
|
||||
|
||||
+11
-5
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+18
-1
@@ -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)) {
|
||||
|
||||
+10
-94
@@ -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,
|
||||
|
||||
+7
-2
@@ -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();
|
||||
|
||||
+2
-21
@@ -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) {
|
||||
|
||||
+251
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>()
|
||||
}
|
||||
+5
@@ -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>
|
||||
}
|
||||
|
||||
+5
@@ -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>>();
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class AAAAA<K,V,G>{
|
||||
AAAAA<K,V,?> asd = new AAAAA<K, <caret>
|
||||
}
|
||||
+3
@@ -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>
|
||||
}
|
||||
+6
-2
@@ -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>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
@@ -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()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -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() {
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
+21
-4
@@ -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
|
||||
|
||||
+16
-3
@@ -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);
|
||||
|
||||
+9
@@ -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()) {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -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"));
|
||||
|
||||
+276
-14
@@ -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-')
|
||||
'''
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
-47
@@ -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.
|
||||
}
|
||||
}
|
||||
-130
@@ -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());
|
||||
}
|
||||
}
|
||||
-112
@@ -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;
|
||||
}
|
||||
|
||||
+8
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -93,4 +93,8 @@ public abstract class LabeledComboBoxAction extends AnAction implements CustomCo
|
||||
boxModel.setSelectedItem(boxModel.getElementAt(idx));
|
||||
}
|
||||
}
|
||||
|
||||
protected JComboBox getComboBox() {
|
||||
return myComboBox;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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) {
|
||||
|
||||
+6
-9
@@ -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());
|
||||
}
|
||||
}
|
||||
+20
-118
@@ -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 {
|
||||
}
|
||||
+14
-115
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
-31
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-9
@@ -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="<root>">
|
||||
|
||||
<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="<unknown>">
|
||||
|
||||
<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}''
|
||||
|
||||
@@ -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>
|
||||
+40
@@ -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);
|
||||
}
|
||||
}
|
||||
+14
@@ -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);
|
||||
}
|
||||
}
|
||||
+14
@@ -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);
|
||||
}
|
||||
}
|
||||
+14
@@ -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);
|
||||
}
|
||||
}
|
||||
+16
@@ -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);
|
||||
}
|
||||
}
|
||||
+26
-22
@@ -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.
|
||||
*/
|
||||
|
||||
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ public class GradleContentRootStructureChangesCalculator
|
||||
@NotNull ModuleAwareContentRoot intellijEntity,
|
||||
@NotNull GradleChangesCalculationContext context)
|
||||
{
|
||||
// TODO den implement content root conflict changes here.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
+13
-6
@@ -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() {
|
||||
|
||||
+27
@@ -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());
|
||||
}
|
||||
}
|
||||
-4
@@ -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()));
|
||||
|
||||
+1
@@ -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();
|
||||
|
||||
+23
-8
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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
Reference in New Issue
Block a user