1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.editors.menu.descriptors; 18 19 import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME; 20 21 import com.android.ide.common.resources.platform.DeclareStyleableInfo; 22 import com.android.ide.eclipse.adt.AdtUtils; 23 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; 24 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; 25 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; 26 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; 27 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor; 28 import com.android.sdklib.SdkConstants; 29 30 import java.util.ArrayList; 31 import java.util.Map; 32 33 34 /** 35 * Complete description of the menu structure. 36 */ 37 public final class MenuDescriptors implements IDescriptorProvider { 38 39 public static final String MENU_ROOT_ELEMENT = "menu"; //$NON-NLS-1$ 40 41 /** The root element descriptor. */ 42 private ElementDescriptor mDescriptor = null; 43 44 /** @return the root descriptor. */ 45 @Override 46 public ElementDescriptor getDescriptor() { 47 return mDescriptor; 48 } 49 50 @Override 51 public ElementDescriptor[] getRootElementDescriptors() { 52 return mDescriptor.getChildren(); 53 } 54 55 /** 56 * Updates the document descriptor. 57 * <p/> 58 * It first computes the new children of the descriptor and then updates them 59 * all at once. 60 * 61 * @param styleMap The map style => attributes from the attrs.xml file 62 */ 63 public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) { 64 65 // There are 3 elements: menu, item and group. 66 // The root element MUST be a menu. 67 // A top menu can contain items or group: 68 // - top groups can contain top items 69 // - top items can contain sub-menus 70 // A sub menu can contains sub items or sub groups: 71 // - sub groups can contain sub items 72 // - sub items cannot contain anything 73 74 if (mDescriptor == null) { 75 mDescriptor = createElement(styleMap, 76 MENU_ROOT_ELEMENT, // xmlName 77 "Menu", // uiName, 78 null, // TODO SDK URL 79 null, // extraAttribute 80 null, // childrenElements, 81 true /* mandatory */); 82 } 83 84 // -- sub menu can have sub_items, sub_groups but not sub_menus 85 86 ElementDescriptor sub_item = createElement(styleMap, 87 "item", // xmlName //$NON-NLS-1$ 88 "Item", // uiName, 89 null, // TODO SDK URL 90 null, // extraAttribute 91 null, // childrenElements, 92 false /* mandatory */); 93 94 ElementDescriptor sub_group = createElement(styleMap, 95 "group", // xmlName //$NON-NLS-1$ 96 "Group", // uiName, 97 null, // TODO SDK URL 98 null, // extraAttribute 99 new ElementDescriptor[] { sub_item }, // childrenElements, 100 false /* mandatory */); 101 102 ElementDescriptor sub_menu = createElement(styleMap, 103 MENU_ROOT_ELEMENT, // xmlName 104 "Sub-Menu", // uiName, 105 null, // TODO SDK URL 106 null, // extraAttribute 107 new ElementDescriptor[] { sub_item, sub_group }, // childrenElements, 108 true /* mandatory */); 109 110 // -- top menu can have all top groups and top items (which can have sub menus) 111 112 ElementDescriptor top_item = createElement(styleMap, 113 "item", // xmlName //$NON-NLS-1$ 114 "Item", // uiName, 115 null, // TODO SDK URL 116 null, // extraAttribute 117 new ElementDescriptor[] { sub_menu }, // childrenElements, 118 false /* mandatory */); 119 120 ElementDescriptor top_group = createElement(styleMap, 121 "group", // xmlName //$NON-NLS-1$ 122 "Group", // uiName, 123 null, // TODO SDK URL 124 null, // extraAttribute 125 new ElementDescriptor[] { top_item }, // childrenElements, 126 false /* mandatory */); 127 128 XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME, 129 SdkConstants.NS_RESOURCES); 130 131 updateElement(mDescriptor, styleMap, "Menu", xmlns); //$NON-NLS-1$ 132 mDescriptor.setChildren(new ElementDescriptor[] { top_item, top_group }); 133 } 134 135 /** 136 * Returns a new ElementDescriptor constructed from the information given here 137 * and the javadoc & attributes extracted from the style map if any. 138 */ 139 private ElementDescriptor createElement( 140 Map<String, DeclareStyleableInfo> styleMap, 141 String xmlName, String uiName, String sdkUrl, 142 AttributeDescriptor extraAttribute, 143 ElementDescriptor[] childrenElements, boolean mandatory) { 144 145 ElementDescriptor element = new ElementDescriptor(xmlName, uiName, null, sdkUrl, 146 null, childrenElements, mandatory); 147 148 return updateElement(element, styleMap, 149 getStyleName(xmlName), 150 extraAttribute); 151 } 152 153 /** 154 * Updates an ElementDescriptor with the javadoc & attributes extracted from the style 155 * map if any. 156 */ 157 private ElementDescriptor updateElement(ElementDescriptor element, 158 Map<String, DeclareStyleableInfo> styleMap, 159 String styleName, 160 AttributeDescriptor extraAttribute) { 161 ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>(); 162 163 DeclareStyleableInfo style = styleMap != null ? styleMap.get(styleName) : null; 164 if (style != null) { 165 DescriptorsUtils.appendAttributes(descs, 166 null, // elementName 167 SdkConstants.NS_RESOURCES, 168 style.getAttributes(), 169 null, // requiredAttributes 170 null); // overrides 171 element.setTooltip(style.getJavaDoc()); 172 } 173 174 if (extraAttribute != null) { 175 descs.add(extraAttribute); 176 } 177 178 element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()])); 179 return element; 180 } 181 182 /** 183 * Returns the style name (i.e. the <declare-styleable> name found in attrs.xml) 184 * for a given XML element name. 185 * <p/> 186 * The rule is that all elements have for style name: 187 * - their xml name capitalized 188 * - a "Menu" prefix, except for <menu> itself which is just "Menu". 189 */ 190 private String getStyleName(String xmlName) { 191 String styleName = AdtUtils.capitalize(xmlName); 192 193 // This is NOT the UI Name but the expected internal style name 194 final String MENU_STYLE_BASE_NAME = "Menu"; //$NON-NLS-1$ 195 196 if (!styleName.equals(MENU_STYLE_BASE_NAME)) { 197 styleName = MENU_STYLE_BASE_NAME + styleName; 198 } 199 return styleName; 200 } 201 } 202