IDEA-67650 support for fragments in layout xml files

This commit is contained in:
Eugene Kudelevsky
2011-04-13 18:20:54 +04:00
parent 877299dad0
commit 555514ad23
14 changed files with 163 additions and 22 deletions
@@ -38,6 +38,7 @@ import org.jetbrains.android.dom.attrs.AttributeFormat;
import org.jetbrains.android.dom.attrs.StyleableDefinition;
import org.jetbrains.android.dom.converters.CompositeConverter;
import org.jetbrains.android.dom.converters.ResourceReferenceConverter;
import org.jetbrains.android.dom.layout.Fragment;
import org.jetbrains.android.dom.layout.Include;
import org.jetbrains.android.dom.layout.LayoutElement;
import org.jetbrains.android.dom.layout.LayoutViewElement;
@@ -375,7 +376,8 @@ public class AndroidDomExtender extends DomExtender<AndroidDomElement> {
private static final MyAttributeProcessor ourLayoutAttrsProcessor = new MyAttributeProcessor() {
@Override
public void process(@NotNull XmlName attrName, @NotNull DomExtension extension, @NotNull DomElement element) {
if (element instanceof LayoutViewElement && SdkConstants.NS_RESOURCES.equals(attrName.getNamespaceKey())) {
if ((element instanceof LayoutViewElement || element instanceof Fragment) &&
SdkConstants.NS_RESOURCES.equals(attrName.getNamespaceKey())) {
XmlElement xmlElement = element.getXmlElement();
XmlTag tag = xmlElement instanceof XmlTag ? (XmlTag)xmlElement : null;
String tagName = tag != null ? tag.getName() : null;
@@ -422,15 +424,21 @@ public class AndroidDomExtender extends DomExtender<AndroidDomElement> {
}
return;
}
String tagName = tag.getName();
if (!tagName.equals("view")) {
PsiClass c = map.get(tagName);
registerAttributesForClassAndSuperclasses(facet, element, c, registrar, ourLayoutAttrsProcessor);
else if (element instanceof Fragment) {
registerAttributes(facet, element, new String[]{"Fragment"}, registrar, ourLayoutAttrsProcessor);
}
else {
String[] styleableNames = getClassNames(map.values());
registerAttributes(facet, element, styleableNames, registrar, ourLayoutAttrsProcessor);
String tagName = tag.getName();
if (!tagName.equals("view")) {
PsiClass c = map.get(tagName);
registerAttributesForClassAndSuperclasses(facet, element, c, registrar, ourLayoutAttrsProcessor);
}
else {
String[] styleableNames = getClassNames(map.values());
registerAttributes(facet, element, styleableNames, registrar, ourLayoutAttrsProcessor);
}
}
registerLayoutAttributes(facet, element, tag, registrar, ourLayoutAttrsProcessor);
for (String viewClassName : map.keySet()) {
@@ -66,28 +66,28 @@ public class PackageClassConverter extends ResolvingConverter<PsiClass> implemen
if (s == null) return null;
DomElement domElement = context.getInvocationElement();
Manifest manifest = domElement.getParentOfType(Manifest.class, true);
if (manifest != null) {
s = s.replace('$', '.');
String packageName = manifest.getPackage().getValue();
String className;
s = s.replace('$', '.');
String packageName = manifest != null ? manifest.getPackage().getValue() : null;
String className = null;
if (packageName != null) {
if (s.startsWith(".")) {
className = packageName + s;
}
else {
className = packageName + "." + s;
}
JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject());
final Module module = context.getModule();
GlobalSearchScope scope = module != null
? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)
: context.getInvocationElement().getResolveScope();
PsiClass psiClass = facade.findClass(className, scope);
if (psiClass == null) {
psiClass = facade.findClass(s, scope);
}
return psiClass;
}
return null;
JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getPsiManager().getProject());
final Module module = context.getModule();
GlobalSearchScope scope = module != null
? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)
: context.getInvocationElement().getResolveScope();
PsiClass psiClass = className != null ? facade.findClass(className, scope) : null;
if (psiClass == null) {
psiClass = facade.findClass(s, scope);
}
return psiClass;
}
@NotNull
@@ -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 org.jetbrains.android.dom.layout;
import com.intellij.psi.PsiClass;
import com.intellij.util.xml.Attribute;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.ExtendClass;
import com.intellij.util.xml.GenericAttributeValue;
import org.jetbrains.android.dom.AndroidAttributeValue;
import org.jetbrains.android.dom.converters.PackageClassConverter;
/**
* @author Eugene.Kudelevsky
*/
public interface Fragment extends LayoutElement {
@Attribute("name")
@Convert(PackageClassConverter.class)
@ExtendClass("android.app.Fragment")
AndroidAttributeValue<PsiClass> getFragmentName();
@Attribute("class")
@Convert(PackageClassConverter.class)
@ExtendClass("android.app.Fragment")
GenericAttributeValue<PsiClass> getFragmentClass();
}
@@ -46,4 +46,6 @@ public interface LayoutViewElement extends LayoutElement {
GenericAttributeValue<PsiClass> getViewClass();
List<Include> getIncludes();
List<Fragment> getFragments();
}
@@ -0,0 +1,3 @@
package android.app;
public class Fragment {}
@@ -0,0 +1,6 @@
package p1.p2;
public class MyFragmentActivity extends android.app.Activity {
public static class MyFragment extends android.app.Fragment {
}
}
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="p<caret>"/>
</LinearLayout>
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="p1.p2.MyFragmentActivity$MyFragment"/>
</LinearLayout>
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<frag<caret>/>
</LinearLayout>
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment/>
</LinearLayout>
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment android:ta<caret>/>
</LinearLayout>
@@ -0,0 +1,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment android:tag=""/>
</LinearLayout>
@@ -0,0 +1,19 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="p1.p2.MyFragmentActivity$MyFragment" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<fragment class="<error>aba</error>" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<fragment android:name="p1.p2.MyFragmentActivity$MyFragment" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<fragment android:name="<error>aba</error>" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<<error>fragment</error> class="p1.p2.MyFragmentActivity$MyFragment"/>
</LinearLayout>
@@ -22,6 +22,10 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
public void setUp() throws Exception {
super.setUp();
myFixture.copyFileToProject(SdkConstants.FN_ANDROID_MANIFEST_XML, SdkConstants.FN_ANDROID_MANIFEST_XML);
// copy mock fragment, because it is not included to old android.jar
// todo: create normal mock Android sdk
copyFileToProject("Fragment.java", "src/android/app/Fragment.java");
}
@Override
@@ -206,6 +210,24 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
doTestHighlighting("merge.xml");
}
public void testFragmentHighlighting() throws Throwable {
copyFileToProject("MyFragmentActivity.java", "src/p1/p2/MyFragmentActivity.java");
doTestHighlighting(getTestName(true) + ".xml");
}
public void testFragmentCompletion1() throws Throwable {
copyFileToProject("MyFragmentActivity.java", "src/p1/p2/MyFragmentActivity.java");
toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml");
}
public void testFragmentCompletion2() throws Throwable {
toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml");
}
public void testFragmentCompletion3() throws Throwable {
toTestCompletion(getTestName(true) + ".xml", getTestName(true) + "_after.xml");
}
/*public void testCustomAttrsPerformance() throws Throwable {
myFixture.copyFileToProject("dom/resources/bigfile.xml", "res/values/bigfile.xml");
myFixture.copyFileToProject("dom/resources/bigattrs.xml", "res/values/bigattrs.xml");