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