blob: d9d272224a953495315059c05a3ed57b40be2dc5 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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.android.ide.eclipse.adt.internal.editors.layout.uimodel;
import static com.android.SdkConstants.ANDROID_NS_NAME;
import static com.android.SdkConstants.ANDROID_URI;
import static com.android.SdkConstants.ATTR_CLASS;
import static com.android.SdkConstants.ATTR_ORIENTATION;
import static com.android.SdkConstants.FQCN_FRAME_LAYOUT;
import static com.android.SdkConstants.LINEAR_LAYOUT;
import static com.android.SdkConstants.VALUE_VERTICAL;
import static com.android.SdkConstants.VIEW_TAG;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.sdklib.IAndroidTarget;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.swt.graphics.Image;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Specialized version of {@link UiElementNode} for the {@link ViewElementDescriptor}s.
*/
public class UiViewElementNode extends UiElementNode {
/** An AttributeDescriptor array that depends on the current UiParent. */
private AttributeDescriptor[] mCachedAttributeDescriptors;
public UiViewElementNode(ViewElementDescriptor elementDescriptor) {
super(elementDescriptor);
}
/**
* Returns an AttributeDescriptor array that depends on the current UiParent.
* <p/>
* The array merges both "direct" attributes with the descriptor layout attributes.
* The array instance is cached and cleared if the UiParent is changed.
*/
@Override
public AttributeDescriptor[] getAttributeDescriptors() {
if (!getDescriptor().syncAttributes()) {
mCachedAttributeDescriptors = null;
}
if (mCachedAttributeDescriptors != null) {
return mCachedAttributeDescriptors;
}
UiElementNode ui_parent = getUiParent();
AttributeDescriptor[] direct_attrs = super.getAttributeDescriptors();
mCachedAttributeDescriptors = direct_attrs;
// Compute layout attributes: These depend on the *parent* this widget is within
AttributeDescriptor[] layout_attrs = null;
boolean need_xmlns = false;
if (ui_parent instanceof UiDocumentNode) {
// Limitation: right now the layout behaves as if everything was
// owned by a FrameLayout.
// TODO replace by something user-configurable.
IProject project = getEditor().getProject();
if (project != null) {
Sdk currentSdk = Sdk.getCurrent();
if (currentSdk != null) {
IAndroidTarget target = currentSdk.getTarget(project);
if (target != null) {
AndroidTargetData data = currentSdk.getTargetData(target);
if (data != null) {
LayoutDescriptors descriptors = data.getLayoutDescriptors();
ViewElementDescriptor desc =
descriptors.findDescriptorByClass(FQCN_FRAME_LAYOUT);
if (desc != null) {
layout_attrs = desc.getLayoutAttributes();
need_xmlns = true;
}
}
}
}
}
} else if (ui_parent instanceof UiViewElementNode) {
layout_attrs =
((ViewElementDescriptor) ui_parent.getDescriptor()).getLayoutAttributes();
}
if (layout_attrs == null || layout_attrs.length == 0) {
return mCachedAttributeDescriptors;
}
mCachedAttributeDescriptors =
new AttributeDescriptor[direct_attrs.length +
layout_attrs.length +
(need_xmlns ? 1 : 0)];
System.arraycopy(direct_attrs, 0,
mCachedAttributeDescriptors, 0,
direct_attrs.length);
System.arraycopy(layout_attrs, 0,
mCachedAttributeDescriptors, direct_attrs.length,
layout_attrs.length);
if (need_xmlns) {
AttributeDescriptor desc = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, ANDROID_URI);
mCachedAttributeDescriptors[direct_attrs.length + layout_attrs.length] = desc;
}
return mCachedAttributeDescriptors;
}
public Image getIcon() {
ElementDescriptor desc = getDescriptor();
if (desc != null) {
Image img = null;
// Special case for the common case of vertical linear layouts:
// show vertical linear icon (the default icon shows horizontal orientation)
String uiName = desc.getUiName();
IconFactory icons = IconFactory.getInstance();
if (uiName.equals(LINEAR_LAYOUT)) {
Element e = (Element) getXmlNode();
if (VALUE_VERTICAL.equals(e.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION))) {
IconFactory factory = icons;
img = factory.getIcon("VerticalLinearLayout"); //$NON-NLS-1$
}
} else if (uiName.equals(VIEW_TAG)) {
Node xmlNode = getXmlNode();
if (xmlNode instanceof Element) {
String className = ((Element) xmlNode).getAttribute(ATTR_CLASS);
if (className != null && className.length() > 0) {
int index = className.lastIndexOf('.');
if (index != -1) {
className = "customView"; //$NON-NLS-1$
}
img = icons.getIcon(className);
}
}
if (img == null) {
// Can't have both view.png and View.png; issues on case sensitive vs
// case insensitive file systems
img = icons.getIcon("View"); //$NON-NLS-1$
}
}
if (img == null) {
img = desc.getGenericIcon();
}
if (img != null) {
AndroidXmlEditor editor = getEditor();
if (editor != null) {
LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(editor);
if (delegate != null) {
IMarker marker = delegate.getIssueForNode(this);
if (marker != null) {
int severity = marker.getAttribute(IMarker.SEVERITY, 0);
if (severity == IMarker.SEVERITY_ERROR) {
return icons.addErrorIcon(img);
} else {
return icons.addWarningIcon(img);
}
}
}
}
return img;
}
return img;
}
return AdtPlugin.getAndroidLogo();
}
/**
* Sets the parent of this UI node.
* <p/>
* Also removes the cached AttributeDescriptor array that depends on the current UiParent.
*/
@Override
protected void setUiParent(UiElementNode parent) {
super.setUiParent(parent);
mCachedAttributeDescriptors = null;
}
}