diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index 406addec2c41..65e9f578aee6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -234,6 +234,7 @@ public class JavaMethodCallElement extends LookupItem implements Type presentation.setItemTextBold(getAttribute(HIGHLIGHTED_ATTR) != null); MemberLookupHelper helper = myHelper != null ? myHelper : new MemberLookupHelper(myMethod, myContainingClass, false, false); - helper.renderElement(presentation, getAttribute(FORCE_QUALIFY) != null, getSubstitutor()); + final Boolean qualify = getAttribute(FORCE_QUALIFY) != null ? Boolean.TRUE : myHelper == null ? Boolean.FALSE : null; + helper.renderElement(presentation, qualify, getSubstitutor()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java index c36c9f9c7fd1..8403668b5b05 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java @@ -45,18 +45,18 @@ public class MemberLookupHelper { return myShouldImport; } - public void renderElement(LookupElementPresentation presentation, boolean forceQualify, PsiSubstitutor substitutor) { + public void renderElement(LookupElementPresentation presentation, @Nullable Boolean qualify, PsiSubstitutor substitutor) { final String className = myContainingClass == null ? "???" : myContainingClass.getName(); final String memberName = myMember.getName(); - if (!myShouldImport && StringUtil.isNotEmpty(className) || forceQualify) { + if (!Boolean.FALSE.equals(qualify) && (!myShouldImport && StringUtil.isNotEmpty(className) || Boolean.TRUE.equals(qualify))) { presentation.setItemText(className + "." + memberName); } else { presentation.setItemText(memberName); } final String qname = myContainingClass == null ? "" : myContainingClass.getQualifiedName(); - String pkg = StringUtil.getPackageName(qname); + String pkg = qname == null ? "" : StringUtil.getPackageName(qname); String location = StringUtil.isEmpty(pkg) ? "" : " (" + pkg + ")"; final String params = myMergedOverloads diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index 247e5fdaf429..34e6ae81765c 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -57,7 +57,6 @@ import java.util.*; */ public class PsiClassImplUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiClassImplUtil"); - private static final Key NAME_MAPS_BUILT_FLAG = Key.create("NAME_MAPS_BUILT_FLAG"); private static final Key> MAP_IN_CLASS_KEY = Key.create("MAP_KEY"); @@ -102,35 +101,6 @@ public class PsiClassImplUtil { final PsiMethod patternMethod, final boolean checkBases, final boolean stopOnFirst) { -/* final MethodSignature patternSignature = MethodSignatureBackedByPsiMethod.create(patternMethod, PsiSubstitutor.EMPTY); - if (!checkBases) { - final PsiMethod[] methodsByName = aClass.findMethodsByName(patternMethod.getName(), false); - if (methodsByName.length == 0) return PsiMethod.EMPTY_ARRAY; - List result = new ArrayList(); - for (PsiMethod method : methodsByName) { - final MethodSignature otherSignature = method.getSignature(PsiSubstitutor.EMPTY); - if (otherSignature.equals(patternSignature)) { - result.add(method); - if (stopOnFirst) break; - } - } - - return result.toArray(new PsiMethod[result.size()]); - } - else { - final Set signatures = getOverrideEquivalentSignatures(aClass); - final HierarchicalMethodSignature signatureWithSupers = signatures.get(patternSignature); - if (signatureWithSupers == null) return PsiMethod.EMPTY_ARRAY; - final List result = new ArrayList(); - MethodSignatureUtil.processMethodHierarchy(signatureWithSupers, new Processor() { - public boolean process(final HierarchicalMethodSignature sig) { - result.add(sig.getSignature().getMethod()); - return !stopOnFirst; - } - }); - return result.toArray(new PsiMethod[result.size()]); - }*/ - final PsiMethod[] methodsByName = aClass.findMethodsByName(patternMethod.getName(), checkBases); if (methodsByName.length == 0) return Collections.emptyList(); final List methods = new SmartList(); @@ -238,14 +208,12 @@ public class PsiClassImplUtil { } } }; - PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); - processDeclarationsInClassNotCached(psiClass, processor, ResolveState.initial(), new THashSet(), null, psiClass, false, factory); + processDeclarationsInClassNotCached(psiClass, processor, ResolveState.initial(), new THashSet(), null, psiClass, false); Map, Map>>> result = new HashMap, Map>>>(3); result.put(PsiClass.class, generateMapByList(classes)); result.put(PsiMethod.class, generateMapByList(methods)); result.put(PsiField.class, generateMapByList(fields)); - psiClass.putUserData(NAME_MAPS_BUILT_FLAG, Boolean.TRUE); return result; } @@ -275,6 +243,12 @@ public class PsiClassImplUtil { value = ((UserDataHolderEx)aClass).putUserDataIfAbsent(MAP_IN_CLASS_KEY, value); } } + return getCachedMembers(value, memberClazz); + } + + private static Map>> getCachedMembers(CachedValue value, + Class memberClazz) { + //noinspection unchecked return (Map>>)value.getValue().get(memberClazz); } @@ -308,7 +282,7 @@ public class PsiClassImplUtil { } } - private static final Function FULL_ICON_EVALUATOR = new Function() { + private static final Function FULL_ICON_EVALUATOR = new NullableFunction() { public Icon fun(ClassIconRequest r) { if (!r.psiClass.isValid() || r.psiClass.getProject().isDisposed()) return null; @@ -406,112 +380,140 @@ public class PsiClassImplUtil { PsiElement last, PsiElement place, boolean isRaw) { + if (last instanceof PsiTypeParameterList || last instanceof PsiModifierList) return true; //TypeParameterList and ModifierList do not see our declarations if (visited != null && visited.contains(aClass)) return true; + PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); isRaw = isRaw || PsiUtil.isRawSubstitutor(aClass, substitutor); - if (last instanceof PsiTypeParameterList || last instanceof PsiModifierList) return true; //TypeParameterList and ModifierList do not see our declarations - final Boolean built = aClass.getUserData(NAME_MAPS_BUILT_FLAG); - PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); - if (built == null) { - return processDeclarationsInClassNotCached(aClass, processor, state, visited, last, place, isRaw, factory); - } - final NameHint nameHint = processor.getHint(NameHint.KEY); + CachedValue cache = aClass.getUserData(MAP_IN_CLASS_KEY); + if (cache != null && cache.hasUpToDateValue()) { + final NameHint nameHint = processor.getHint(NameHint.KEY); + if (nameHint != null) { + return processCachedMembersByName(aClass, processor, state, visited, last, place, isRaw, substitutor, cache, nameHint); + } + } + return processDeclarationsInClassNotCached(aClass, processor, state, visited, last, place, isRaw); + } + + private static boolean processCachedMembersByName(PsiClass aClass, + PsiScopeProcessor processor, + ResolveState state, + Set visited, + PsiElement last, + PsiElement place, + boolean isRaw, + PsiSubstitutor substitutor, + CachedValue cache, NameHint nameHint) { final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY); - if (nameHint != null) { - if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) { - final PsiField fieldByName = aClass.findFieldByName(nameHint.getName(state), false); - if (fieldByName != null) { - processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); - if (!processor.execute(fieldByName, state)) return false; - } - else { - final Map>> allFieldsMap = getMap(aClass, PsiField.class); + PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); - final List> list = allFieldsMap.get(nameHint.getName(state)); - if (list != null) { - for (final Pair candidate : list) { - PsiField candidateField = candidate.getFirst(); - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(candidateField.getContainingClass(), candidate.getSecond(), aClass, - substitutor, place, factory); + if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.FIELD)) { + final PsiField fieldByName = aClass.findFieldByName(nameHint.getName(state), false); + if (fieldByName != null) { + processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); + if (!processor.execute(fieldByName, state)) return false; + } + else { + final Map>> allFieldsMap = getCachedMembers(cache, PsiField.class); - processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, candidateField.getContainingClass()); - if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; - } + final List> list = allFieldsMap.get(nameHint.getName(state)); + if (list != null) { + for (final Pair candidate : list) { + PsiField candidateField = candidate.getFirst(); + PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(candidateField.getContainingClass(), candidate.getSecond(), aClass, + substitutor, place, factory); + + processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, candidateField.getContainingClass()); + if (!processor.execute(candidateField, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; } } } - if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) { - if (last != null && last.getParent() == aClass) { - if (last instanceof PsiClass) { - if (!processor.execute(last, state)) return false; - } - // Parameters - final PsiTypeParameterList list = aClass.getTypeParameterList(); - if (list != null && !list.processDeclarations(processor, state, last, place)) return false; + } + if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) { + if (last != null && last.getParent() == aClass) { + if (last instanceof PsiClass) { + if (!processor.execute(last, state)) return false; } - if (!(last instanceof PsiReferenceList)) { - final PsiClass classByName = aClass.findInnerClassByName(nameHint.getName(state), false); - if (classByName != null) { - processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); - if (!processor.execute(classByName, state)) return false; - } - else { - final Map>> allClassesMap = getMap(aClass, PsiClass.class); + // Parameters + final PsiTypeParameterList list = aClass.getTypeParameterList(); + if (list != null && !list.processDeclarations(processor, state, last, place)) return false; + } + if (!(last instanceof PsiReferenceList)) { + final PsiClass classByName = aClass.findInnerClassByName(nameHint.getName(state), false); + if (classByName != null) { + processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); + if (!processor.execute(classByName, state)) return false; + } + else { + final Map>> allClassesMap = getCachedMembers(cache, PsiClass.class); - final List> list = allClassesMap.get(nameHint.getName(state)); - if (list != null) { - for (final Pair candidate : list) { - final PsiClass inner = candidate.getFirst(); - final PsiClass containingClass = inner.getContainingClass(); - if (containingClass != null) { - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, - substitutor, place, factory); - processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); - if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; - } + final List> list = allClassesMap.get(nameHint.getName(state)); + if (list != null) { + for (final Pair candidate : list) { + final PsiClass inner = candidate.getFirst(); + final PsiClass containingClass = inner.getContainingClass(); + if (containingClass != null) { + PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, + substitutor, place, factory); + processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); + if (!processor.execute(inner, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; } } } } } - if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) { - if (processor instanceof MethodResolverProcessor) { - final MethodResolverProcessor methodResolverProcessor = (MethodResolverProcessor)processor; - if (methodResolverProcessor.isConstructor()) { - final PsiMethod[] constructors = aClass.getConstructors(); - methodResolverProcessor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); - for (PsiMethod constructor : constructors) { - if (!methodResolverProcessor.execute(constructor, state)) return false; - } - return true; - } - } - final Map>> allMethodsMap = getMap(aClass, PsiMethod.class); - final List> list = allMethodsMap.get(nameHint.getName(state)); - if (list != null) { - for (final Pair candidate : list) { - PsiMethod candidateMethod = candidate.getFirst(); - if (processor instanceof MethodResolverProcessor) { - if (candidateMethod.isConstructor() != ((MethodResolverProcessor)processor).isConstructor()) continue; - } - final PsiClass containingClass = candidateMethod.getContainingClass(); - PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, - substitutor, place, factory); - if (isRaw && !candidateMethod.hasModifierProperty(PsiModifier.STATIC)) { //static methods are not erased due to raw overriding - PsiTypeParameter[] methodTypeParameters = candidateMethod.getTypeParameters(); - finalSubstitutor = factory.createRawSubstitutor(finalSubstitutor, methodTypeParameters); - } - processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); - if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; + } + if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) { + if (processor instanceof MethodResolverProcessor) { + final MethodResolverProcessor methodResolverProcessor = (MethodResolverProcessor)processor; + if (methodResolverProcessor.isConstructor()) { + final PsiMethod[] constructors = aClass.getConstructors(); + methodResolverProcessor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); + for (PsiMethod constructor : constructors) { + if (!methodResolverProcessor.execute(constructor, state)) return false; } + return true; } } - return true; + final Map>> allMethodsMap = getCachedMembers(cache, PsiMethod.class); + final List> list = allMethodsMap.get(nameHint.getName(state)); + if (list != null) { + for (final Pair candidate : list) { + PsiMethod candidateMethod = candidate.getFirst(); + if (processor instanceof MethodResolverProcessor) { + if (candidateMethod.isConstructor() != ((MethodResolverProcessor)processor).isConstructor()) continue; + } + final PsiClass containingClass = candidateMethod.getContainingClass(); + if (visited != null && visited.contains(candidateMethod.getContainingClass())) { + continue; + } + + PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(containingClass, candidate.getSecond(), aClass, + substitutor, place, factory); + finalSubstitutor = checkRaw(isRaw, factory, candidateMethod, finalSubstitutor); + processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, containingClass); + if (!processor.execute(candidateMethod, state.put(PsiSubstitutor.KEY, finalSubstitutor))) return false; + } + + if (visited != null) { + for (Pair aList : list) { + visited.add(aList.getFirst().getContainingClass()); + } + } + + } + } + return true; } - return processDeclarationsInClassNotCached(aClass, processor, state, visited, last, place, isRaw, factory); + private static PsiSubstitutor checkRaw(boolean isRaw, PsiElementFactory factory, PsiMethod candidateMethod, PsiSubstitutor substitutor) { + if (isRaw && !candidateMethod.hasModifierProperty(PsiModifier.STATIC)) { //static methods are not erased due to raw overriding + PsiTypeParameter[] methodTypeParameters = candidateMethod.getTypeParameters(); + substitutor = factory.createRawSubstitutor(substitutor, methodTypeParameters); + } + return substitutor; } public static PsiSubstitutor obtainFinalSubstitutor(@NotNull PsiClass candidateClass, PsiSubstitutor candidateSubstitutor, PsiClass aClass, @@ -531,8 +533,7 @@ public class PsiClassImplUtil { private static boolean processDeclarationsInClassNotCached(PsiClass aClass, PsiScopeProcessor processor, ResolveState state, Set visited, PsiElement last, PsiElement place, - boolean isRaw, - PsiElementFactory factory) { + boolean isRaw) { if (visited == null) visited = new THashSet(); if (!visited.add(aClass)) return true; processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, aClass); @@ -555,15 +556,15 @@ public class PsiClassImplUtil { } } + PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); + if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.METHOD)) { + PsiSubstitutor baseSubstitutor = state.get(PsiSubstitutor.KEY); final PsiMethod[] methods = nameHint != null ? aClass.findMethodsByName(nameHint.getName(state), false) : aClass.getMethods(); for (final PsiMethod method : methods) { - if (isRaw && !method.hasModifierProperty(PsiModifier.STATIC)) { //static methods are not erased due to raw overriding - PsiTypeParameter[] methodTypeParameters = method.getTypeParameters(); - PsiSubstitutor raw = factory.createRawSubstitutor(state.get(PsiSubstitutor.KEY), methodTypeParameters); - state = state.put(PsiSubstitutor.KEY, raw); - } - if (!processor.execute(method, state)) return false; + PsiSubstitutor finalSubstitutor = checkRaw(isRaw, factory, method, baseSubstitutor); + ResolveState methodState = finalSubstitutor == baseSubstitutor ? state : state.put(PsiSubstitutor.KEY, finalSubstitutor); + if (!processor.execute(method, methodState)) return false; } } diff --git a/java/java-tests/testData/psi/resolve/method/MultipleInheritancePathsToMethod.java b/java/java-tests/testData/psi/resolve/method/MultipleInheritancePathsToMethod.java new file mode 100644 index 000000000000..3fea76f410e8 --- /dev/null +++ b/java/java-tests/testData/psi/resolve/method/MultipleInheritancePathsToMethod.java @@ -0,0 +1,20 @@ +interface N1 { + String getName(); +} +interface N2 { + String getName(); +} +interface NN extends N1 {} + +interface N3 { + String getName(); +} +interface VeryNamed extends NN, N2, N3, N1 {} + +class MyClass { + + void foo(VeryNamed f) { + f.getName(); + } + +} diff --git a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveMethodTest.java b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveMethodTest.java index 5ae52f7d5b86..c226e398dd3e 100644 --- a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveMethodTest.java @@ -262,4 +262,14 @@ public class ResolveMethodTest extends ResolveTestCase { PsiMethod method = (PsiMethod) target; assertEquals("PublicCloneable", method.getContainingClass().getName()); } + + public void testMultipleInheritancePathsToMethod() throws Exception { + PsiReference ref = configureByFile("method/" + getTestName(false) + ".java"); + + // just assume this is called by some highlighting inspection/intention/pass before the resolve + JavaPsiFacade.getInstance(getProject()).findClass("NN").getAllMethods(); + + PsiElement target = ref.resolve(); + assertInstanceOf(target, PsiMethod.class); + } } diff --git a/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java new file mode 100644 index 000000000000..be570cd04373 --- /dev/null +++ b/platform/lang-api/src/com/intellij/navigation/GotoRelatedItem.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2011 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.navigation; + +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Dmitry Avdeev + */ +public abstract class GotoRelatedItem { + + public abstract void navigate(); + + @NotNull + public abstract String getText(); + + @Nullable + public abstract Icon getIcon(); + + @Nullable + public abstract PsiFile getContainingFile(); +} diff --git a/platform/lang-api/src/com/intellij/navigation/GotoRelatedProvider.java b/platform/lang-api/src/com/intellij/navigation/GotoRelatedProvider.java new file mode 100644 index 000000000000..c07231989af6 --- /dev/null +++ b/platform/lang-api/src/com/intellij/navigation/GotoRelatedProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2011 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.navigation; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +public abstract class GotoRelatedProvider { + + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.gotoRelatedProvider"); + + @NotNull + public abstract List getItems(PsiElement context); +} diff --git a/platform/lang-api/src/com/intellij/navigation/PsiGotoRelatedItem.java b/platform/lang-api/src/com/intellij/navigation/PsiGotoRelatedItem.java new file mode 100644 index 000000000000..2b3c9e75c151 --- /dev/null +++ b/platform/lang-api/src/com/intellij/navigation/PsiGotoRelatedItem.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2011 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.navigation; + +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Dmitry Avdeev + */ +public class PsiGotoRelatedItem extends GotoRelatedItem { + + private final NavigatablePsiElement myElement; + + public PsiGotoRelatedItem(@NotNull NavigatablePsiElement element) { + myElement = element; + } + + @Override + public void navigate() { + myElement.navigate(true); + } + + @NotNull + @Override + public String getText() { + return myElement.getName(); + } + + @Override + public Icon getIcon() { + return myElement.getIcon(0); + } + + @Override + public PsiFile getContainingFile() { + return myElement.getContainingFile(); + } +} diff --git a/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java b/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java index 99f6fc642074..3aabf8906f7d 100644 --- a/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java +++ b/platform/lang-api/src/com/intellij/psi/impl/ElementBase.java @@ -59,8 +59,8 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable }; private TIntObjectHashMap myBaseIcon; - private static final Icon VISIBILITY_ICON_PLACHOLDER = new EmptyIcon(Icons.PUBLIC_ICON); - public static final Icon ICON_PLACHOLDER = IconLoader.getIcon("/nodes/nodePlaceholder.png"); + private static final Icon VISIBILITY_ICON_PLACEHOLDER = new EmptyIcon(Icons.PUBLIC_ICON); + public static final Icon ICON_PLACEHOLDER = IconLoader.getIcon("/nodes/nodePlaceholder.png"); @Nullable public Icon getIcon(int flags) { @@ -132,7 +132,7 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable } } } - return ICON_PLACHOLDER; + return ICON_PLACEHOLDER; } public static boolean isNativeFileType(FileType fileType) { @@ -144,7 +144,7 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable if ((flags & ICON_FLAG_VISIBILITY) > 0) { RowIcon rowIcon = new RowIcon(2); rowIcon.setIcon(icon, 0); - rowIcon.setIcon(VISIBILITY_ICON_PLACHOLDER, 1); + rowIcon.setIcon(VISIBILITY_ICON_PLACEHOLDER, 1); result = rowIcon; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/DefaultCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/DefaultCompletionContributor.java index 4b196a0b3f59..cbe534857650 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/DefaultCompletionContributor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/DefaultCompletionContributor.java @@ -15,7 +15,7 @@ */ package com.intellij.codeInsight.completion; -import com.intellij.codeInsight.documentation.actions.ShowJavaDocInfoAction; +import com.intellij.codeInsight.documentation.actions.ShowQuickDocInfoAction; import com.intellij.codeInsight.hint.actions.ShowImplementationsAction; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.LangBundle; @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Random; @@ -31,6 +32,7 @@ import java.util.Random; */ public class DefaultCompletionContributor extends CompletionContributor { + @Nullable public static String getDefaultAdvertisementText(@NotNull final CompletionParameters parameters) { final Random random = new Random(); if (random.nextInt(5) < 2 && CompletionUtil.shouldShowFeature(parameters, CodeCompletionFeatures.EDITING_COMPLETION_FINISH_BY_DOT_ETC)) { @@ -56,8 +58,8 @@ public class DefaultCompletionContributor extends CompletionContributor { } if (random.nextInt(5) < 2 && - (CompletionUtil.shouldShowFeature(parameters, ShowJavaDocInfoAction.CODEASSISTS_QUICKJAVADOC_FEATURE) || - CompletionUtil.shouldShowFeature(parameters, ShowJavaDocInfoAction.CODEASSISTS_QUICKJAVADOC_LOOKUP_FEATURE))) { + (CompletionUtil.shouldShowFeature(parameters, ShowQuickDocInfoAction.CODEASSISTS_QUICKJAVADOC_FEATURE) || + CompletionUtil.shouldShowFeature(parameters, ShowQuickDocInfoAction.CODEASSISTS_QUICKJAVADOC_LOOKUP_FEATURE))) { final String shortcut = getActionShortcut(IdeActions.ACTION_QUICK_JAVADOC); if (shortcut != null) { return LangBundle.message("completion.quick.javadoc.ad", shortcut); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index 665c62d71953..5e98b4da87b6 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -62,8 +62,8 @@ import java.awt.event.*; import java.util.List; import java.util.Stack; -public class DocumentationComponent extends JPanel implements Disposable { - +public class DocumentationComponent extends JPanel implements Disposable, DataProvider { + private static final DataContext EMPTY_DATA_CONTEXT = new DataContext() { @Override public Object getData(@NonNls String dataId) { @@ -318,6 +318,15 @@ public class DocumentationComponent extends JPanel implements Disposable { this(manager, null); } + @Override + public Object getData(@NonNls String dataId) { + if (DocumentationManager.SELECTED_QUICK_DOC_TEXT.getName().equals(dataId)) { + return myEditorPane.getSelectedText(); + } + + return null; + } + private JComponent createSettingsPanel() { JPanel result = new JPanel(new FlowLayout(FlowLayout.RIGHT, 3, 0)); result.add(new JLabel(ApplicationBundle.message("label.font.size"))); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 8606406f6a06..626a74ef2d8b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -43,7 +43,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderEntry; @@ -83,10 +82,14 @@ import java.util.*; import java.util.List; public class DocumentationManager { + + @NonNls public static final String JAVADOC_LOCATION_AND_SIZE = "javadoc.popup"; + public static final DataKey SELECTED_QUICK_DOC_TEXT = DataKey.create("QUICK_DOC.SELECTED_TEXT"); + private static final Logger LOG = Logger.getInstance("#" + DocumentationManager.class.getName()); private static final String SHOW_DOCUMENTATION_IN_TOOL_WINDOW = "ShowDocumentationInToolWindow"; private static final String DOCUMENTATION_AUTO_UPDATE_ENABLED = "DocumentationAutoUpdateEnabled"; - @NonNls public static final String JAVADOC_LOCATION_AND_SIZE = "javadoc.popup"; + private final Project myProject; private Editor myEditor = null; private ParameterInfoController myParameterInfoController; @@ -203,14 +206,11 @@ public class DocumentationManager { DocumentationProvider documentationProvider = getProviderFromElement(file); - PsiElement element = null; - if (documentationProvider!=null) { - element = documentationProvider.getDocumentationElementForLookupItem( - PsiManager.getInstance(myProject), - lookupIteObject, - originalElement - ); - } + PsiElement element = documentationProvider.getDocumentationElementForLookupItem( + PsiManager.getInstance(myProject), + lookupIteObject, + originalElement + ); if (element == null) return; @@ -235,7 +235,7 @@ public class DocumentationManager { Project project = getProject(element); if (myToolWindow == null && PropertiesComponent.getInstance().isTrueValue(SHOW_DOCUMENTATION_IN_TOOL_WINDOW)) { - createToolWindow(element, originalElement, true); + createToolWindow(element, originalElement); return; } else if (myToolWindow != null) { @@ -270,7 +270,7 @@ public class DocumentationManager { }); Processor pinCallback = new Processor() { public boolean process(JBPopup popup) { - createToolWindow(element, originalElement, true); + createToolWindow(element, originalElement); popup.cancel(); return false; } @@ -279,7 +279,7 @@ public class DocumentationManager { final KeyboardShortcut keyboardShortcut = ActionManagerEx.getInstanceEx().getKeyboardShortcut("QuickJavaDoc"); final List> actions = Collections.singletonList(Pair.create(new ActionListener() { public void actionPerformed(ActionEvent e) { - createToolWindow(element, originalElement, false); + createToolWindow(element, originalElement); final JBPopup hint = getDocInfoHint(); if (hint != null && hint.isVisible()) hint.cancel(); } @@ -344,7 +344,7 @@ public class DocumentationManager { } } - private void createToolWindow(final PsiElement element, PsiElement originalElement, final boolean automatic) { + private void createToolWindow(final PsiElement element, PsiElement originalElement) { assert myToolWindow == null; final DocumentationComponent component = new DocumentationComponent(this, new AnAction[]{ @@ -423,24 +423,30 @@ public class DocumentationManager { public void run() { if (myProject.isDisposed()) return; - final DataContext dataContext = DataManager.getInstance().getDataContext(); + AsyncResult asyncResult = DataManager.getInstance().getDataContextFromFocus(); + DataContext dataContext = asyncResult.getResult(); + if (dataContext == null) { + return; + } final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext); - if (editor != null) { - final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject); + if (editor == null) { + return; + } - final Editor injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, file); - if (injectedEditor != null) { - final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(injectedEditor, myProject); - if (psiFile != null) { - showJavaDocInfo(injectedEditor, psiFile, false, true); - return; - } - } + final PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject); - if (file != null) { - showJavaDocInfo(editor, file, false, true); + final Editor injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, file); + if (injectedEditor != null) { + final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(injectedEditor, myProject); + if (psiFile != null) { + showJavaDocInfo(injectedEditor, psiFile, false, true); + return; } } + + if (file != null) { + showJavaDocInfo(editor, file, false, true); + } } }; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/CopyQuickDocAction.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/CopyQuickDocAction.java new file mode 100644 index 000000000000..d7fcebe61cab --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/CopyQuickDocAction.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2011 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.documentation.actions; + +import com.intellij.codeInsight.documentation.DocumentationManager; +import com.intellij.codeInsight.hint.HintManagerImpl; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.project.DumbAware; + +import java.awt.datatransfer.StringSelection; + +/** + * @author Denis Zhdanov + * @since 3/29/11 1:28 PM + */ +public class CopyQuickDocAction extends AnAction implements DumbAware, HintManagerImpl.ActionToIgnore { + + public CopyQuickDocAction() { + setEnabledInModalContext(true); + } + + @Override + public void actionPerformed(AnActionEvent e) { + String selected = e.getData(DocumentationManager.SELECTED_QUICK_DOC_TEXT); + if (selected == null || selected.isEmpty()) { + return; + } + + CopyPasteManager.getInstance().setContents(new StringSelection(selected)); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowJavaDocInfoAction.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowQuickDocInfoAction.java similarity index 96% rename from platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowJavaDocInfoAction.java rename to platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowQuickDocInfoAction.java index cea5400d218f..ea8339928dc0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowJavaDocInfoAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/actions/ShowQuickDocInfoAction.java @@ -34,11 +34,11 @@ import com.intellij.psi.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -public class ShowJavaDocInfoAction extends BaseCodeInsightAction implements HintManagerImpl.ActionToIgnore, DumbAware, PopupAction { +public class ShowQuickDocInfoAction extends BaseCodeInsightAction implements HintManagerImpl.ActionToIgnore, DumbAware, PopupAction { @NonNls public static final String CODEASSISTS_QUICKJAVADOC_LOOKUP_FEATURE = "codeassists.quickjavadoc.lookup"; @NonNls public static final String CODEASSISTS_QUICKJAVADOC_FEATURE = "codeassists.quickjavadoc"; - public ShowJavaDocInfoAction() { + public ShowQuickDocInfoAction() { setEnabledInModalContext(true); setInjectedContext(true); } diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java index 31845dd7dcc9..098e18e69c8f 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java @@ -138,6 +138,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil if (findModel == null) return; final boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); final FindModel copy = (FindModel)findModel.clone(); + final ModalityState modalityState = ModalityState.current(); Runnable request = new Runnable() { @Override public void run() { @@ -150,7 +151,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil if (unitTestMode) { denyReplace.run(); } else { - ApplicationManager.getApplication().invokeAndWait(denyReplace, ModalityState.NON_MODAL); + ApplicationManager.getApplication().invokeAndWait(denyReplace, modalityState); } mySearchResults.updateThreadSafe(copy, allowedToChangedEditorSelection, null); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java new file mode 100644 index 000000000000..1bce641bc154 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.actions; + +import com.intellij.navigation.GotoRelatedItem; +import com.intellij.navigation.GotoRelatedProvider; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.ui.CollectionListModel; +import com.intellij.ui.components.JBList; +import com.intellij.util.ui.UIUtil; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +public class GotoRelatedFileAction extends AnAction { + + @Override + public void actionPerformed(AnActionEvent e) { + + DataContext context = e.getDataContext(); + Editor editor = PlatformDataKeys.EDITOR.getData(context); + PsiFile psiFile = LangDataKeys.PSI_FILE.getData(context); + if (psiFile == null) return; + + List items = getItems(editor, psiFile); + if (items.isEmpty()) return; + if (items.size() == 1) { + items.get(0).navigate(); + return; + } + + final JBList list = new JBList(new CollectionListModel(items)); + list.setCellRenderer(new ItemCellRenderer()); + + JBPopupFactory.getInstance() + .createListPopupBuilder(list) + .setTitle("Goto Related") + .setItemChoosenCallback(new Runnable() { + @Override + public void run() { + Object value = list.getSelectedValue(); + if (value instanceof GotoRelatedItem) { + ((GotoRelatedItem)value).navigate(); + } + } + }) + .createPopup() + .showInBestPositionFor(context); + } + + public static List getItems(Editor editor, PsiFile psiFile) { + + PsiElement psiElement = psiFile; + if (editor != null) { + psiElement = psiFile.findElementAt(editor.getCaretModel().getOffset()); + } + + List items = new ArrayList(); + + for (GotoRelatedProvider provider : Extensions.getExtensions(GotoRelatedProvider.EP_NAME)) { + items.addAll(provider.getItems(psiElement)); + } + return items; + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabled(LangDataKeys.PSI_FILE.getData(e.getDataContext()) != null); + } + + private static class ItemCellRenderer extends JPanel implements ListCellRenderer { + + private final JLabel myLeft = new JLabel(); + private final JLabel myRight = new JLabel(); + private final JPanel mySpacer = new JPanel(); + + private ItemCellRenderer() { + super(new BorderLayout()); + setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); + add(myLeft, BorderLayout.WEST); + add(myRight, BorderLayout.EAST); + + mySpacer.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); + mySpacer.setOpaque(false); + add(mySpacer, BorderLayout.CENTER); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + GotoRelatedItem item = (GotoRelatedItem)value; + myLeft.setText(item.getText()); + myLeft.setIcon(item.getIcon()); + + PsiFile file = item.getContainingFile(); + myRight.setText(file == null ? null : file.getName()); + myRight.setIcon(file == null ? null : file.getIcon(0)); + + setBackground(UIUtil.getListBackground(isSelected)); + Color foreground = UIUtil.getListForeground(isSelected); + myLeft.setForeground(foreground); + myRight.setForeground(foreground); + return this; + } + } +} diff --git a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java index 2dfaaccb732f..5eac40bb93e6 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileTypes/impl/NativeFileIconProvider.java @@ -68,7 +68,7 @@ public class NativeFileIconProvider implements FileIconProvider { if (icon != null) { return icon; } - return new DeferredIconImpl(ElementBase.ICON_PLACHOLDER, file, false, new Function() { + return new DeferredIconImpl(ElementBase.ICON_PLACEHOLDER, file, false, new Function() { public Icon fun(VirtualFile virtualFile) { final File f = new File(filePath); if (!f.exists()) { diff --git a/platform/lang-impl/src/com/intellij/psi/PsiAnchor.java b/platform/lang-impl/src/com/intellij/psi/PsiAnchor.java index 91a6103b95f5..82705817268f 100644 --- a/platform/lang-impl/src/com/intellij/psi/PsiAnchor.java +++ b/platform/lang-impl/src/com/intellij/psi/PsiAnchor.java @@ -180,10 +180,10 @@ public abstract class PsiAnchor { } public int hashCode() { - int result = myClass != null ? myClass.getName().hashCode() : 0; - result = 31 * result + myStartOffset; //todo + int result = myClass.getName().hashCode(); + result = 31 * result + myStartOffset; result = 31 * result + myEndOffset; - result = 31 * result + myVirtualFile.getName().hashCode(); + result = 31 * result + myVirtualFile.hashCode(); return result; } @@ -326,6 +326,17 @@ public abstract class PsiAnchor { return ((31 * myVirtualFile.hashCode() + myIndex) * 31 + myElementType.hashCode()) * 31 + myLanguage.hashCode(); } + @Override + public String toString() { + return "StubIndexReference{" + + "myVirtualFile=" + myVirtualFile + + ", myProject=" + myProject + + ", myIndex=" + myIndex + + ", myLanguage=" + myLanguage + + ", myElementType=" + myElementType + + '}'; + } + public int getStartOffset() { final PsiElement resolved = retrieve(); if (resolved == null) throw new PsiInvalidElementAccessException(null); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java b/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java index 8aa1dbbd027d..58a90ad1f6f9 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/popup/PopupChooserBuilder.java @@ -48,7 +48,7 @@ public class PopupChooserBuilder { private JComponent myChooserComponent; private String myTitle; private final ArrayList myAdditionalKeystrokes = new ArrayList(); - private Runnable myItemChoosenRunnable; + private Runnable myItemChosenRunnable; private JComponent mySouthComponent; private JComponent myEastComponent; @@ -103,7 +103,7 @@ public class PopupChooserBuilder { @NotNull public PopupChooserBuilder setItemChoosenCallback(@NotNull Runnable runnable) { - myItemChoosenRunnable = runnable; + myItemChosenRunnable = runnable; return this; } @@ -283,7 +283,7 @@ public class PopupChooserBuilder { private void closePopup(boolean shouldPerformAction, MouseEvent e, boolean isOk) { if (shouldPerformAction) { - myPopup.setFinalRunnable(myItemChoosenRunnable); + myPopup.setFinalRunnable(myItemChosenRunnable); } if (isOk) { diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index 8ce5e8bebf3b..fbbd83351eee 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -138,6 +138,8 @@ + + diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 32efe5e05383..c5a7d3c54158 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -136,7 +136,7 @@ - + @@ -225,6 +225,9 @@ + + + diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 22b63fd3e470..bcda6f9e02e8 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -19,6 +19,7 @@ + diff --git a/platform/testFramework/src/com/intellij/testFramework/Timings.java b/platform/testFramework/src/com/intellij/testFramework/Timings.java index 5ba700eb58d4..7fa1027753c9 100644 --- a/platform/testFramework/src/com/intellij/testFramework/Timings.java +++ b/platform/testFramework/src/com/intellij/testFramework/Timings.java @@ -17,10 +17,7 @@ package com.intellij.testFramework; import com.intellij.openapi.util.io.FileUtil; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.math.BigInteger; /** @@ -28,6 +25,9 @@ import java.math.BigInteger; */ @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) public class Timings { + private static final int CPU_PROBES = 1000000; + private static final int IO_PROBES = 42; + public static final long CPU_TIMING; public static final long IO_TIMING; public static final long MACHINE_TIMING; @@ -37,13 +37,13 @@ public class Timings { start = System.currentTimeMillis(); BigInteger k = new BigInteger("1"); - for (int i = 0; i < 1000000; i++) { + for (int i = 0; i < CPU_PROBES; i++) { k = k.add(new BigInteger("1")); } CPU_TIMING = System.currentTimeMillis() - start; start = System.currentTimeMillis(); - for (int i = 0; i < 42; i++) { + for (int i = 0; i < IO_PROBES; i++) { try { final File tempFile = FileUtil.createTempFile("test", "test" + i); @@ -66,6 +66,16 @@ public class Timings { reader.close(); } + if (i == IO_PROBES - 1) { + final FileOutputStream stream = new FileOutputStream(tempFile); + try { + stream.getFD().sync(); + } + finally { + stream.close(); + } + } + if (!tempFile.delete()) { throw new IOException("Unable to delete: " + tempFile); } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 948a00cf3765..62605f5fdb76 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -758,7 +758,6 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig @Nullable public GutterIconRenderer findGutter(final String filePath) { assertInitialized(); - final Ref result = new Ref(); configureByFilesInner(filePath); int offset = myEditor.getCaretModel().getOffset(); @@ -767,12 +766,20 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig if (info.endOffset >= offset && info.startOffset <= offset) { final GutterIconRenderer renderer = info.getGutterIconRenderer(); if (renderer != null) { - result.set(renderer); - break; + return renderer; } } } - return result.get(); + RangeHighlighter[] highlighters = myEditor.getDocument().getMarkupModel(getProject()).getAllHighlighters(); + for (RangeHighlighter highlighter : highlighters) { + if (highlighter.getEndOffset() >= offset && highlighter.getStartOffset() <= offset) { + GutterIconRenderer renderer = highlighter.getGutterIconRenderer(); + if (renderer != null) { + return renderer; + } + } + } + return null; } @Override diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 1f0ada94107b..b0b2350e19c5 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -435,10 +435,18 @@ public class UIUtil { return isUnderGTKLookAndFeel() ? getTreeTextBackground() : UIManager.getColor("List.background"); } + public static Color getListBackground(boolean isSelected) { + return isSelected ? getListSelectionBackground() : getListBackground(); + } + public static Color getListForeground() { return UIManager.getColor("List.foreground"); } + public static Color getListForeground(boolean isSelected) { + return isSelected ? getListSelectionForeground() : getListForeground(); + } + public static Color getPanelBackground() { return UIManager.getColor("Panel.background"); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/TabbedShowHistoryAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/TabbedShowHistoryAction.java index 35e5e509e084..464a5d90c1a4 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/TabbedShowHistoryAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/TabbedShowHistoryAction.java @@ -22,16 +22,16 @@ import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.history.VcsHistoryProvider; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.Nullable; import java.io.File; -import java.util.ArrayList; public class TabbedShowHistoryAction extends AbstractVcsAction { protected void update(VcsContext context, Presentation presentation) { presentation.setEnabled(isEnabled(context)); final Project project = context.getProject(); - presentation.setVisible(project != null && ProjectLevelVcsManager.getInstance(project).getAllActiveVcss().length > 0); + presentation.setVisible(project != null && ProjectLevelVcsManager.getInstance(project).hasActiveVcss()); } protected VcsHistoryProvider getProvider(AbstractVcs activeVcs) { @@ -39,50 +39,51 @@ public class TabbedShowHistoryAction extends AbstractVcsAction { } protected boolean isEnabled(VcsContext context) { - FilePath[] selectedFiles = getSelectedFiles(context); - if (selectedFiles == null) return false; - if (selectedFiles.length != 1) return false; - FilePath path = selectedFiles[0]; + FilePath selectedFile = getSelectedFileOrNull(context); + if (selectedFile == null) return false; Project project = context.getProject(); if (project == null) return false; - VirtualFile someVFile = path.getVirtualFile() != null ? path.getVirtualFile() : path.getVirtualFileParent(); + VirtualFile someVFile = selectedFile.getVirtualFile() != null ? + selectedFile.getVirtualFile() : selectedFile.getVirtualFileParent(); AbstractVcs vcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(someVFile); if (vcs == null) return false; VcsHistoryProvider vcsHistoryProvider = getProvider(vcs); if (vcsHistoryProvider == null) return false; - if (selectedFiles[0].isDirectory() && (! vcsHistoryProvider.supportsHistoryForDirectories())) return false; + if (selectedFile.isDirectory() && (! vcsHistoryProvider.supportsHistoryForDirectories())) return false; final FileStatus fileStatus = FileStatusManager.getInstance(project).getStatus(someVFile); return fileStatus != FileStatus.ADDED && fileStatus != FileStatus.UNKNOWN && fileStatus != FileStatus.IGNORED; } - protected static FilePath[] getSelectedFiles(VcsContext context) { - ArrayList result = new ArrayList(); + @Nullable + protected static FilePath getSelectedFileOrNull(VcsContext context) { + FilePath result = null; VirtualFile[] virtualFileArray = context.getSelectedFiles(); if (virtualFileArray != null) { - for (VirtualFile virtualFile : virtualFileArray) { - result.add(new FilePathImpl(virtualFile)); + if (virtualFileArray.length > 1) return null; + if (virtualFileArray.length > 0) { + result = new FilePathImpl(virtualFileArray[0]); } } File[] fileArray = context.getSelectedIOFiles(); - if (fileArray != null) { + if (fileArray != null && fileArray.length > 0) { for (File file : fileArray) { final File parentIoFile = file.getParentFile(); if (parentIoFile == null) continue; final VirtualFile parent = LocalFileSystem.getInstance().findFileByIoFile(parentIoFile); if (parent != null) { final FilePathImpl child = new FilePathImpl(parent, file.getName(), false); - if (! result.contains(child)) { - result.add(child); - } + if (result != null) return null; + result = child; } } } - return result.toArray(new FilePath[result.size()]); + return result; } protected void actionPerformed(VcsContext context) { - FilePath path = getSelectedFiles(context)[0]; + FilePath path = getSelectedFileOrNull(context); + if (path == null) return; Project project = context.getProject(); VirtualFile someVFile = path.getVirtualFile() != null ? path.getVirtualFile() : path.getVirtualFileParent(); AbstractVcs activeVcs = ProjectLevelVcsManager.getInstance(project).getVcsFor(someVFile); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java index d17c6dc39211..66d7bc5aa57e 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidIdlCompiler.java @@ -162,7 +162,7 @@ public class AndroidIdlCompiler implements SourceGeneratingCompiler { if (myContext.getProject().isDisposed()) { return EMPTY_GENERATION_ITEM_ARRAY; } - VirtualFile[] files = myContext.getProjectCompileScope().getFiles(AndroidIdlFileType.ourFileType, false); + VirtualFile[] files = myContext.getProjectCompileScope().getFiles(AndroidIdlFileType.ourFileType, true); List items = new ArrayList(files.length); for (VirtualFile file : files) { Module module = myContext.getModuleByFile(file); diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.form b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.form index 085b3efb8ee1..f43a933de4c7 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.form +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.form @@ -60,7 +60,7 @@ - + diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java index ea2831327363..3d6d4f114d18 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidAppPropertiesEditor.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentEvent; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -71,6 +72,7 @@ public class AndroidAppPropertiesEditor { } public void updateActivityPanel() { + myErrorLabel.setForeground(Color.RED); UIUtil.setEnabled(myActivtiyPanel, myHelloAndroidCheckBox.isSelected(), true); } diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java index 05c1cdd71426..0278ef242abd 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java @@ -49,10 +49,12 @@ import com.intellij.psi.PsiManager; import com.intellij.util.ArrayUtil; import org.jetbrains.android.AndroidFileTemplateProvider; import org.jetbrains.android.dom.manifest.Manifest; +import org.jetbrains.android.dom.resources.ResourceElement; import org.jetbrains.android.dom.resources.ResourceValue; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidFacetConfiguration; import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.run.testing.AndroidTestRunConfiguration; import org.jetbrains.android.run.testing.AndroidTestRunConfigurationType; import org.jetbrains.android.sdk.AndroidPlatform; @@ -90,6 +92,10 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { rootModel.setSdk(mySdk); + if (myProjectType == null) { + return; + } + VirtualFile[] files = rootModel.getContentRoots(); if (files.length > 0) { final VirtualFile contentRoot = files[0]; @@ -253,10 +259,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { return; } if (myProjectType == ProjectType.APPLICATION) { - Manifest manifest = facet.getManifest(); - if (manifest != null && myApplicationName.length() > 0) { - manifest.getApplication().getLabel().setValue(ResourceValue.literal(myApplicationName)); - } + assignApplicationName(facet); createChildDirectoryIfNotExist(project, contentRoot, SdkConstants.FD_ASSETS); createChildDirectoryIfNotExist(project, contentRoot, SdkConstants.FD_NATIVE_LIBS); } @@ -284,6 +287,35 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { return true; } + private void assignApplicationName(AndroidFacet facet) { + if (myApplicationName == null || myApplicationName.length() == 0) { + return; + } + + final LocalResourceManager manager = facet.getLocalResourceManager(); + ResourceElement appNameResElement = null; + final String appNameResource = "app_name"; + + for (ResourceElement resElement : manager.getValueResources("string")) { + if (appNameResource.equals(resElement.getName().getValue())) { + appNameResElement = resElement; + } + } + + if (appNameResElement == null) { + manager.addValueResource("string", appNameResource, myApplicationName); + } + else { + appNameResElement.setStringValue(myApplicationName); + } + + final Manifest manifest = facet.getManifest(); + + if (manifest != null) { + manifest.getApplication().getLabel().setValue(ResourceValue.referenceTo('@', null, "string", appNameResource)); + } + } + private static void moveContentAndRemoveDir(Project project, @NotNull VirtualFile from, @NotNull VirtualFile to) throws IOException { for (VirtualFile child : from.getChildren()) { child.move(project, to); @@ -386,9 +418,8 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { FileDocumentManager.getInstance().saveAllDocuments(); } }); - if (myApplicationName.length() > 0) { - manifest.getApplication().getLabel().setValue(ResourceValue.literal(myApplicationName)); - } + + assignApplicationName(facet); } } }; diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.form b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.form index 9128854590ea..0df9506def97 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.form +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.form @@ -1,9 +1,9 @@
- + - + @@ -13,44 +13,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -61,10 +23,67 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java index d0d046a95076..fd38b445b94e 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleWizardStep.java @@ -57,6 +57,8 @@ public class AndroidModuleWizardStep extends ModuleWizardStep { private JPanel myPropertiesPanel; private AndroidSdkComboBoxWithBrowseButton mySdkComboBoxWithBrowseButton; + private JCheckBox myCreateDefaultStructure; + private JPanel myApplicationPanel; private final WizardContext myWizardContext; @@ -84,31 +86,47 @@ public class AndroidModuleWizardStep extends ModuleWizardStep { ActionListener listener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - if (myApplicationProjectButton.isSelected() || myLibProjectButton.isSelected()) { - myAppPropertiesEditor.getContentPanel().setVisible(true); - if (myTestPropertiesEditor != null) { - myTestPropertiesEditor.getContentPanel().setVisible(false); - } - boolean app = myApplicationProjectButton.isSelected(); - myAppPropertiesEditor.getApplicationNameField().setEnabled(app); - myAppPropertiesEditor.getHelloAndroidCheckBox().setEnabled(app); - if (app) { - myAppPropertiesEditor.updateActivityPanel(); - } - else { - UIUtil.setEnabled(myAppPropertiesEditor.getActivtiyPanel(), app, true); - } - } - else { - myAppPropertiesEditor.getContentPanel().setVisible(false); - assert myTestPropertiesEditor != null; - myTestPropertiesEditor.getContentPanel().setVisible(true); - } + updatePropertiesEditor(); } }; myApplicationProjectButton.addActionListener(listener); myLibProjectButton.addActionListener(listener); myTestProjectButton.addActionListener(listener); + + myCreateDefaultStructure.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + final boolean enabled = myCreateDefaultStructure.isSelected(); + UIUtil.setEnabled(myApplicationPanel, enabled, true); + + if (enabled) { + updatePropertiesEditor(); + } + } + }); + } + + private void updatePropertiesEditor() { + if (myApplicationProjectButton.isSelected() || myLibProjectButton.isSelected()) { + myAppPropertiesEditor.getContentPanel().setVisible(true); + if (myTestPropertiesEditor != null) { + myTestPropertiesEditor.getContentPanel().setVisible(false); + } + boolean app = myApplicationProjectButton.isSelected(); + myAppPropertiesEditor.getApplicationNameField().setEnabled(app); + myAppPropertiesEditor.getHelloAndroidCheckBox().setEnabled(app); + if (app) { + myAppPropertiesEditor.updateActivityPanel(); + } + else { + UIUtil.setEnabled(myAppPropertiesEditor.getActivtiyPanel(), app, true); + } + } + else { + myAppPropertiesEditor.getContentPanel().setVisible(false); + assert myTestPropertiesEditor != null; + myTestPropertiesEditor.getContentPanel().setVisible(true); + } } public JComponent getComponent() { @@ -135,6 +153,10 @@ public class AndroidModuleWizardStep extends ModuleWizardStep { throw new ConfigurationException(AndroidBundle.message("select.platform.error")); } + if (!myCreateDefaultStructure.isSelected()) { + return true; + } + if (myApplicationProjectButton.isSelected() || myLibProjectButton.isSelected()) { myAppPropertiesEditor.validate(myTestProjectButton.isSelected()); } @@ -153,6 +175,10 @@ public class AndroidModuleWizardStep extends ModuleWizardStep { PropertiesComponent.getInstance().setValue(AndroidSdkUtils.DEFAULT_PLATFORM_NAME_PROPERTY, selectedSdk.getName()); myModuleBuilder.setSdk(selectedSdk); + if (!myCreateDefaultStructure.isSelected()) { + return; + } + if (myApplicationProjectButton.isSelected() || myLibProjectButton.isSelected()) { myModuleBuilder.setProjectType(myApplicationProjectButton.isSelected() ? ProjectType.APPLICATION : ProjectType.LIBRARY); myModuleBuilder.setActivityName(myAppPropertiesEditor.getActivityName()); diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java index 2154d9f8b7a5..f761e33f4230 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunConfigurationBase.java @@ -277,19 +277,23 @@ public abstract class AndroidRunConfigurationBase extends ModuleBasedConfigurati } private static boolean activateDdmsIfNeccessary(@NotNull AndroidFacet facet) { - Project project = facet.getModule().getProject(); - boolean ddmsEnabled = AndroidEnableDdmsAction.isDdmsEnabled(); + final Project project = facet.getModule().getProject(); + final boolean ddmsEnabled = AndroidEnableDdmsAction.isDdmsEnabled(); + boolean shouldRestartDdms = !ddmsEnabled; + if (ddmsEnabled && isDdmsCorrupted(facet)) { - ddmsEnabled = false; + shouldRestartDdms = true; AndroidEnableDdmsAction.setDdmsEnabled(project, false); } - if (!ddmsEnabled) { - int result = Messages.showYesNoDialog(project, AndroidBundle.message("android.ddms.disabled.error"), - AndroidBundle.message("android.ddms.disabled.dialog.title"), - Messages.getQuestionIcon()); - if (result != 0) { - return false; + if (shouldRestartDdms) { + if (!ddmsEnabled) { + int result = Messages.showYesNoDialog(project, AndroidBundle.message("android.ddms.disabled.error"), + AndroidBundle.message("android.ddms.disabled.dialog.title"), + Messages.getQuestionIcon()); + if (result != 0) { + return false; + } } AndroidEnableDdmsAction.setDdmsEnabled(project, true); } diff --git a/plugins/git4idea/src/git4idea/changes/ChangeCollector.java b/plugins/git4idea/src/git4idea/changes/ChangeCollector.java index 5d58bae6ad21..57e76e96ea1d 100644 --- a/plugins/git4idea/src/git4idea/changes/ChangeCollector.java +++ b/plugins/git4idea/src/git4idea/changes/ChangeCollector.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.VcsDirtyScope; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitContentRevision; @@ -190,6 +191,10 @@ class ChangeCollector { */ private static boolean isAncestor(FilePath parentCandidate, FilePath childCandidate, boolean strict) { try { + if (childCandidate.getPath().length() < parentCandidate.getPath().length()) return false; + if (childCandidate.getVirtualFile() != null && parentCandidate.getVirtualFile() != null) { + return VfsUtil.isAncestor(parentCandidate.getVirtualFile(), childCandidate.getVirtualFile(), strict); + } return FileUtil.isAncestor(parentCandidate.getIOFile(), childCandidate.getIOFile(), strict); } catch (IOException e) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java index a1157119cba0..7c3912506457 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCheckoutProvider.java @@ -19,6 +19,7 @@ import com.intellij.ide.GeneralSettings; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.vcs.CheckoutProvider; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -82,21 +83,32 @@ public class GithubCheckoutProvider implements CheckoutProvider { } // All the preliminary work is already done, go and clone the selected repository! - final RepositoryInfo selectedRepository = checkoutDialog.getSelectedRepository(); + RepositoryInfo selectedRepository = checkoutDialog.getSelectedRepository(); + // Check if selected repository exists + final String owner = selectedRepository.getOwner(); + final String name = selectedRepository.getName(); + if (selectedRepository instanceof UnknownRepositoryInfo) { + selectedRepository = GithubUtil.getDetailedRepositoryInfo(project, owner, name); + } + if (selectedRepository == null){ + Messages.showErrorDialog(project, "Selected repository ''" + owner +"/" + name + "'' doesn't exist.", "Cannot clone repository"); + return; + } + final boolean writeAccessAllowed = GithubUtil.isWriteAccessAllowed(project, selectedRepository); if (!writeAccessAllowed){ Messages.showErrorDialog(project, "It seems that you have only read access to the selected repository.\n" + "GitHub supports only https protocol for readonly access, which is not supported yet.\n" + "As a workaround, please fork it and clone your forked repository instead.\n" + - "More details are available here: http://youtrack.jetbrains.net/issue/IDEA-55298", "Cannot clone this repository"); + "More details are available here: http://youtrack.jetbrains.net/issue/IDEA-55298", "Cannot clone repository"); return; } final String host = writeAccessAllowed ? "git@" + settings.getHost() + ":" : "https://github.com" + settings.getHost() + "/"; final String selectedPath = checkoutDialog.getSelectedPath(); final VirtualFile selectedPathFile = LocalFileSystem.getInstance().findFileByPath(selectedPath); final String projectName = checkoutDialog.getProjectName(); - final String repositoryName = selectedRepository.getName(); - final String repositoryOwner = selectedRepository.getOwner(); + final String repositoryName = name; + final String repositoryOwner = owner; final String checkoutUrl = host + repositoryOwner + "/" + repositoryName + ".git"; GitCheckoutProvider.checkout(project, listener, selectedPathFile, checkoutUrl, projectName, "origin", selectedPath); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index 7541ad618ce2..8ffcbce46d96 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -106,7 +106,7 @@ public class GithubRebaseAction extends DumbAwareAction { repoName = repoName.substring(0, repoName.length() - 4); } - final RepositoryInfo repositoryInfo = GithubUtil.getDetailedRepositoryInfo(project, repoName); + final RepositoryInfo repositoryInfo = GithubUtil.getDetailedRepositoryInfo(project, login, repoName); if (repositoryInfo == null) { Messages .showErrorDialog(project, "Github repository doesn't seem to be your own repository: " + pushUrl, CANNOT_PERFORM_GITHUB_REBASE); diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java index fec480c3eb79..e87089f1e35f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java @@ -182,9 +182,9 @@ public class GithubUtil { } @Nullable - public static RepositoryInfo getDetailedRepoInfo(final String url, final String login, final String password, final String name) { + public static RepositoryInfo getDetailedRepoInfo(final String url, final String login, final String password, final String owner, final String name) { try { - final String request = "/repos/show/" + login + "/" + name; + final String request = "/repos/show/" + owner + "/" + name; final HttpMethod method = doREST(url, login, password, request, false); final InputStream stream = method.getResponseBodyAsStream(); final Element element = new SAXBuilder(false).build(stream).getRootElement(); @@ -302,7 +302,7 @@ public class GithubUtil { * @return */ @Nullable - public static RepositoryInfo getDetailedRepositoryInfo(final Project project, final String name) { + public static RepositoryInfo getDetailedRepositoryInfo(final Project project, final String owner, final String name) { final GithubSettings settings = GithubSettings.getInstance(); final boolean validCredentials; try { @@ -330,7 +330,7 @@ public class GithubUtil { @Override public RepositoryInfo compute() { ProgressManager.getInstance().getProgressIndicator().setText("Extracting detailed info about repository ''" + name + "''"); - return getDetailedRepoInfo(settings.getHost(), settings.getLogin(), settings.getPassword(), name); + return getDetailedRepoInfo(settings.getHost(), settings.getLogin(), settings.getPassword(), owner, name); } }); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/RepositoryInfo.java b/plugins/github/src/org/jetbrains/plugins/github/RepositoryInfo.java index 7d33bf5975e0..947e236f6529 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/RepositoryInfo.java +++ b/plugins/github/src/org/jetbrains/plugins/github/RepositoryInfo.java @@ -30,6 +30,10 @@ public class RepositoryInfo { return myRepository.getChildText("parent"); } + public String getId() { + return getOwner() + "/" + getName(); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof RepositoryInfo)){ diff --git a/plugins/github/src/org/jetbrains/plugins/github/UnknownRepositoryInfo.java b/plugins/github/src/org/jetbrains/plugins/github/UnknownRepositoryInfo.java new file mode 100644 index 000000000000..afe76ce5dbca --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/UnknownRepositoryInfo.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github; + +/** +* @author oleg +*/ +public class UnknownRepositoryInfo extends RepositoryInfo { + private final String myId; + private final String myName; + private final String myOwner; + + public UnknownRepositoryInfo(final String id) { + super(null); + myId = id; + myName = myId.substring(myId.lastIndexOf('/') + 1); + myOwner = myId.substring(0, myId.lastIndexOf('/')); + } + + public String getName() { + return myName; + } + + public String getOwner() { + return myOwner; + } + + public boolean isFork() { + throw new UnsupportedOperationException("UnknownRepositoryInfo#isFork() shouldn't be called"); + } + + public String getParent() { + throw new UnsupportedOperationException("UnknownRepositoryInfo#isFork() shouldn't be called"); + } + + public String getId() { + return myId; + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectDialog.java index eb8fdc7d604f..cf2f38816d66 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectDialog.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectDialog.java @@ -4,9 +4,14 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.HashMap; +import org.intellij.lang.annotations.Pattern; import org.jetbrains.plugins.github.RepositoryInfo; +import org.jetbrains.plugins.github.UnknownRepositoryInfo; import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -14,14 +19,21 @@ import java.util.List; */ public class GithubCloneProjectDialog extends DialogWrapper { + private static final java.util.regex.Pattern PATTERN = java.util.regex.Pattern.compile("[\\w\\d-_]+/[\\w\\d-_]+"); private GithubCloneProjectPane myGithubCloneProjectPane; + private HashMap myRepositoryInfoHashMap; public GithubCloneProjectDialog(final Project project, final List repos) { super(project, true); myGithubCloneProjectPane = new GithubCloneProjectPane(this); setTitle("Select repository to clone"); setOKButtonText("Clone"); - myGithubCloneProjectPane.setAvailableRepos(repos); + myRepositoryInfoHashMap = new HashMap(); + for (RepositoryInfo repo : repos) { + myRepositoryInfoHashMap.put(repo.getId(), repo); + } + final ArrayList ids = new ArrayList(myRepositoryInfoHashMap.keySet()); + myGithubCloneProjectPane.setAvailableRepos(ids); init(); setOKActionEnabled(false); } @@ -46,8 +58,9 @@ public class GithubCloneProjectDialog extends DialogWrapper { } public void updateOkButton() { - if (getSelectedRepository() == null){ - setErrorText("No repository selected"); + final String selectedRepositoryId = getSelectedRepositoryId(); + if (!PATTERN.matcher(selectedRepositoryId).matches()){ + setErrorText("Wrong repository format. owner/repository expected"); setOKActionEnabled(false); return; } @@ -79,6 +92,11 @@ public class GithubCloneProjectDialog extends DialogWrapper { } public RepositoryInfo getSelectedRepository() { + final String id = getSelectedRepositoryId(); + return myRepositoryInfoHashMap.containsKey(id) ? myRepositoryInfoHashMap.get(id) : new UnknownRepositoryInfo(id); + } + + private String getSelectedRepositoryId() { return myGithubCloneProjectPane.getSelectedRepository(); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.form index 4b43f7674fc2..f9f124dd7709 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.form +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.form @@ -3,7 +3,7 @@ - + @@ -32,12 +32,6 @@ - - - - - - @@ -60,6 +54,12 @@ + + + + + + diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.java index 5052c447033b..35bf8e204570 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCloneProjectPane.java @@ -1,11 +1,20 @@ package org.jetbrains.plugins.github.ui; import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.EditorComboBoxEditor; +import com.intellij.ui.EditorComboBoxRenderer; +import com.intellij.ui.EditorTextField; +import com.intellij.ui.StringComboboxEditor; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; import org.jetbrains.annotations.Nullable; @@ -26,31 +35,31 @@ import java.util.List; */ public class GithubCloneProjectPane { private JPanel myPanel; - private JComboBox mySelectRepositoryComboBox; private TextFieldWithBrowseButton myTextFieldWithBrowseButton; private JTextField myProjectNameText; + private ComboBox myRepositoryComboBox; private final GithubCloneProjectDialog myDialog; public GithubCloneProjectPane(final GithubCloneProjectDialog dialog) { myDialog = dialog; - mySelectRepositoryComboBox.setRenderer(new ListCellRendererWrapper(mySelectRepositoryComboBox.getRenderer()){ - @Override - public void customize(final JList list, final RepositoryInfo value, final int index, final boolean selected, final boolean cellHasFocus) { - setText(value.getOwner() + "/" + value.getName()); - } - }); - mySelectRepositoryComboBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(final ItemEvent e) { - final RepositoryInfo repositoryInfo = (RepositoryInfo)e.getItem(); - if (repositoryInfo != null) { - myProjectNameText.setText(repositoryInfo.getName()); - myDialog.updateOkButton(); + final EditorComboBoxEditor comboEditor = new StringComboboxEditor(ProjectManager.getInstance().getDefaultProject(), FileTypes.PLAIN_TEXT, myRepositoryComboBox); + myRepositoryComboBox.setEditor(comboEditor); + ((EditorTextField) comboEditor.getEditorComponent()).addDocumentListener( + new DocumentAdapter() { + @Override + public void beforeDocumentChange(final com.intellij.openapi.editor.event.DocumentEvent e) { + updateControls(); } - } - }); - final DocumentListener updateOkButtonListener = new DocumentListener() { + @Override + public void documentChanged(final com.intellij.openapi.editor.event.DocumentEvent e) { + updateControls(); + } + }); + myRepositoryComboBox.setRenderer(new EditorComboBoxRenderer(comboEditor)); + myRepositoryComboBox.setEditable(true); + + myProjectNameText.getDocument().addDocumentListener(new DocumentListener() { // update Ok button state depending on the current state of the fields public void insertUpdate(final DocumentEvent e) { myDialog.updateOkButton(); @@ -63,9 +72,21 @@ public class GithubCloneProjectPane { public void changedUpdate(final DocumentEvent e) { myDialog.updateOkButton(); } - }; - myProjectNameText.getDocument().addDocumentListener(updateOkButtonListener); - myTextFieldWithBrowseButton.getChildComponent().getDocument().addDocumentListener(updateOkButtonListener); + }); + myTextFieldWithBrowseButton.getChildComponent().getDocument().addDocumentListener(new DocumentListener() { + // update Ok button state depending on the current state of the fields + public void insertUpdate(final DocumentEvent e) { + myDialog.updateOkButton(); + } + + public void removeUpdate(final DocumentEvent e) { + myDialog.updateOkButton(); + } + + public void changedUpdate(final DocumentEvent e) { + myDialog.updateOkButton(); + } + }); } public JComponent getPanel() { @@ -73,11 +94,11 @@ public class GithubCloneProjectPane { } public JComponent getPreferrableFocusComponent() { - return mySelectRepositoryComboBox; + return myRepositoryComboBox; } - public RepositoryInfo getSelectedRepository(){ - return (RepositoryInfo) mySelectRepositoryComboBox.getModel().getSelectedItem(); + public String getSelectedRepository(){ + return (String) myRepositoryComboBox.getEditor().getItem(); } public String getSelectedPath(){ @@ -120,12 +141,18 @@ public class GithubCloneProjectPane { }); } - public void setAvailableRepos(final List repos) { - mySelectRepositoryComboBox.setModel(new DefaultComboBoxModel(ArrayUtil.toObjectArray(repos))); - final RepositoryInfo preselectedRepository = (RepositoryInfo)mySelectRepositoryComboBox.getSelectedItem(); + public void setAvailableRepos(final List repos) { + myRepositoryComboBox.setModel(new DefaultComboBoxModel(ArrayUtil.toObjectArray(repos))); + updateControls(); + } + + private void updateControls() { + final String preselectedRepository = (String)myRepositoryComboBox.getEditor().getItem(); if (preselectedRepository != null) { - myProjectNameText.setText(preselectedRepository.getName()); + final int i = preselectedRepository.lastIndexOf('/'); + myProjectNameText.setText(i != -1 ? preselectedRepository.substring(i + 1) : ""); } + myDialog.updateOkButton(); } public void setSelectedPath(final String path) { diff --git a/plugins/ui-designer/src/META-INF/plugin.xml b/plugins/ui-designer/src/META-INF/plugin.xml index 6c1f403e23aa..c14277c05805 100644 --- a/plugins/ui-designer/src/META-INF/plugin.xml +++ b/plugins/ui-designer/src/META-INF/plugin.xml @@ -111,6 +111,7 @@ + diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/FormFileTypeFactory.java b/plugins/ui-designer/src/com/intellij/uiDesigner/FormFileTypeFactory.java index bb36249ac376..c360a994332e 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/FormFileTypeFactory.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/FormFileTypeFactory.java @@ -23,7 +23,8 @@ import org.jetbrains.annotations.NotNull; * @author yole */ public class FormFileTypeFactory extends FileTypeFactory { + public void createFileTypes(@NotNull FileTypeConsumer consumer) { - consumer.consume(new GuiFormFileType(), GuiFormFileType.DEFAULT_EXTENSION); + consumer.consume(GuiFormFileType.INSTANCE); } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/GuiFormFileType.java b/plugins/ui-designer/src/com/intellij/uiDesigner/GuiFormFileType.java index 5d6d1b5dd50d..9d9693ed5d55 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/GuiFormFileType.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/GuiFormFileType.java @@ -26,6 +26,9 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class GuiFormFileType implements FileType { + + public static final GuiFormFileType INSTANCE = new GuiFormFileType(); + @NonNls public static final String DEFAULT_EXTENSION = "form"; @NonNls public static final String DOT_DEFAULT_EXTENSION = "." + DEFAULT_EXTENSION; diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java index 62c28bbd17e9..4b455f628b75 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormClassIndex.java @@ -122,7 +122,7 @@ public class FormClassIndex extends ScalarIndexExtension { }); } - public static List findFormsBoundToClass(PsiClass psiClass) { + public static List findFormsBoundToClass(@NotNull PsiClass psiClass) { String qName = FormReferencesSearcher.getQualifiedName(psiClass); if (qName == null) return Collections.emptyList(); return findFormsBoundToClass(psiClass.getProject(), qName); diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java new file mode 100644 index 000000000000..6723d414c4ba --- /dev/null +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/binding/FormRelatedFilesProvider.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2011 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.uiDesigner.binding; + +import com.intellij.navigation.GotoRelatedItem; +import com.intellij.navigation.GotoRelatedProvider; +import com.intellij.navigation.PsiGotoRelatedItem; +import com.intellij.openapi.project.Project; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.uiDesigner.GuiFormFileType; +import com.intellij.uiDesigner.compiler.Utils; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author Dmitry Avdeev + */ +public class FormRelatedFilesProvider extends GotoRelatedProvider { + + @NotNull + @Override + public List getItems(PsiElement context) { + PsiClass psiClass = PsiTreeUtil.getParentOfType(context, PsiClass.class, false); + if (psiClass != null) { + List forms = FormClassIndex.findFormsBoundToClass(psiClass); + return ContainerUtil.map(forms, new Function() { + @Override + public GotoRelatedItem fun(PsiFile psiFile) { + return new PsiGotoRelatedItem(psiFile); + } + }); + } + else { + PsiFile file = context.getContainingFile(); + if (file.getFileType() == GuiFormFileType.INSTANCE) { + try { + String className = Utils.getBoundClassName(file.getText()); + if (className != null) { + Project project = file.getProject(); + PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); + if (aClass != null) { + return Collections.singletonList(new PsiGotoRelatedItem(aClass)); + } + } + } + catch (Exception ignore) { + + } + } + } + return Collections.emptyList(); + } +} diff --git a/xml/dom-openapi/src/com/intellij/codeInsight/navigation/DomGotoRelatedItem.java b/xml/dom-openapi/src/com/intellij/codeInsight/navigation/DomGotoRelatedItem.java new file mode 100644 index 000000000000..94233cdd5f27 --- /dev/null +++ b/xml/dom-openapi/src/com/intellij/codeInsight/navigation/DomGotoRelatedItem.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2011 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.navigation; + +import com.intellij.navigation.GotoRelatedItem; +import com.intellij.psi.DelegatePsiTarget; +import com.intellij.psi.PsiFile; +import com.intellij.util.xml.DomElement; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Dmitry Avdeev + */ +public class DomGotoRelatedItem extends GotoRelatedItem { + + private final DomElement myElement; + + public DomGotoRelatedItem(DomElement element) { + + myElement = element; + } + + @Override + public void navigate() { + new DelegatePsiTarget(myElement.getXmlElement()).navigate(true); + } + + @NotNull + @Override + public String getText() { + return myElement.getPresentation().getElementName(); + } + + @Override + public Icon getIcon() { + return myElement.getPresentation().getIcon(); + } + + @Override + public PsiFile getContainingFile() { + return myElement.getXmlElement().getContainingFile(); + } +}