/* * 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 = className.substring(index + 1); } img = icons.getIcon(className); } } } 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; } }