1d5cd92b446e43e8de625142415f560ee54636317Tor Norbye/*
2d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * Copyright (C) 2011 The Android Open Source Project
3d5cd92b446e43e8de625142415f560ee54636317Tor Norbye *
4d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * you may not use this file except in compliance with the License.
6d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * You may obtain a copy of the License at
7d5cd92b446e43e8de625142415f560ee54636317Tor Norbye *
8d5cd92b446e43e8de625142415f560ee54636317Tor Norbye *      http://www.eclipse.org/org/documents/epl-v10.php
9d5cd92b446e43e8de625142415f560ee54636317Tor Norbye *
10d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * Unless required by applicable law or agreed to in writing, software
11d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
12d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * See the License for the specific language governing permissions and
14d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * limitations under the License.
15d5cd92b446e43e8de625142415f560ee54636317Tor Norbye */
16d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
17d5cd92b446e43e8de625142415f560ee54636317Tor Norbyepackage com.android.ide.eclipse.adt.internal.editors.layout.gre;
18d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ANDROID_URI;
2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ATTR_ID;
2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FQCN_BUTTON;
2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FQCN_SPINNER;
2312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FQCN_TOGGLE_BUTTON;
2412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ID_PREFIX;
2512d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.NEW_ID_PREFIX;
2612d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VIEW_FRAGMENT;
2712d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VIEW_INCLUDE;
28d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
290757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport com.android.annotations.VisibleForTesting;
30d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport com.android.ide.common.api.IViewMetadata.FillPreference;
310595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbyeimport com.android.ide.common.api.Margins;
320595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbyeimport com.android.ide.common.api.ResizePolicy;
33d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin;
34e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.IconFactory;
35d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
36d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
37d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
380595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbyeimport com.android.resources.Density;
3985e4a1a9dd133abb879ec211ce8dd385004edf22Xavier Ducrohetimport com.android.utils.Pair;
406cb5c7f7141a08fd355bb92c6a4153140400890bTor Norbyeimport com.google.common.base.Splitter;
41ec7301a7433cf89c399fa3c507afe8a147adbcbaTor Norbyeimport com.google.common.io.Closeables;
42d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
43d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport org.w3c.dom.Document;
44d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport org.w3c.dom.Element;
45d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport org.w3c.dom.Node;
46d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport org.w3c.dom.NodeList;
47d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport org.xml.sax.InputSource;
48d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
49d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.io.BufferedInputStream;
50d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.io.InputStream;
51d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.ArrayList;
520757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport java.util.Collection;
53d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.Collections;
54d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.HashMap;
55e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbyeimport java.util.HashSet;
56d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.Iterator;
57d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.List;
5818bce12c5916331971b2e8108f8485cc56b696d3Tor Norbyeimport java.util.Locale;
59d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport java.util.Map;
60e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbyeimport java.util.Set;
61d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
62d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport javax.xml.parsers.DocumentBuilder;
63d5cd92b446e43e8de625142415f560ee54636317Tor Norbyeimport javax.xml.parsers.DocumentBuilderFactory;
64d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
65d5cd92b446e43e8de625142415f560ee54636317Tor Norbye/**
66d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * The {@link ViewMetadataRepository} contains additional metadata for Android view
67d5cd92b446e43e8de625142415f560ee54636317Tor Norbye * classes
68d5cd92b446e43e8de625142415f560ee54636317Tor Norbye */
69d5cd92b446e43e8de625142415f560ee54636317Tor Norbyepublic class ViewMetadataRepository {
700ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    private static final String PREVIEW_CONFIG_FILENAME = "rendering-configs.xml";  //$NON-NLS-1$
710ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    private static final String METADATA_FILENAME = "extra-view-metadata.xml";  //$NON-NLS-1$
720ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
73d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /** Singleton instance */
74d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private static ViewMetadataRepository sInstance = new ViewMetadataRepository();
75d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
76d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
77d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Returns the singleton instance
78d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     *
79d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * @return the {@link ViewMetadataRepository}
80d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
81d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    public static ViewMetadataRepository get() {
82d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        return sInstance;
83d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
84d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
85d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
86d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Ever increasing counter used to assign natural ordering numbers to views and
87d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * categories
88d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
89d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private static int sNextOrdinal = 0;
90d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
91d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
92d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * List of categories (which contain views); constructed lazily so use
93d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * {@link #getCategories()}
94d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
95d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private List<CategoryData> mCategories;
96d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
97d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
98d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Map from class names to view data objects; constructed lazily so use
99d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * {@link #getClassToView}
100d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
101d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private Map<String, ViewData> mClassToView;
102d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
103d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /** Hidden constructor: Create via factory {@link #get()} instead */
104d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private ViewMetadataRepository() {
105d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
106d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
107d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /** Returns a map from class fully qualified names to {@link ViewData} objects */
108d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private Map<String, ViewData> getClassToView() {
109d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        if (mClassToView == null) {
110d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            int initialSize = 75;
111d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mClassToView = new HashMap<String, ViewData>(initialSize);
112d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            List<CategoryData> categories = getCategories();
113d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            for (CategoryData category : categories) {
114d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                for (ViewData view : category) {
115d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                    mClassToView.put(view.getFcqn(), view);
116d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                }
117d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            }
118d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            assert mClassToView.size() <= initialSize;
119d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
120d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
121d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        return mClassToView;
122d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
123d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
1240ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    /**
1250ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * Returns an XML document containing rendering configurations for the various Android
1260ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * views. The FQN of each view can be obtained via the
1270ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * {@link #getFullClassName(Element)} method
1280ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     *
1290ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @return an XML document containing rendering elements
1300ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     */
1310ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    public Document getRenderingConfigDoc() {
1320ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1330ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        Class<ViewMetadataRepository> clz = ViewMetadataRepository.class;
1340ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        InputStream paletteStream = clz.getResourceAsStream(PREVIEW_CONFIG_FILENAME);
1350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        InputSource is = new InputSource(paletteStream);
1360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        try {
1370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            factory.setNamespaceAware(true);
1380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            factory.setValidating(false);
1396feca9ac5f8add768fef2bc2dc1382a68c158d42Tor Norbye            factory.setIgnoringComments(true);
1400ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            DocumentBuilder builder = factory.newDocumentBuilder();
1410ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return builder.parse(is);
1420ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        } catch (Exception e) {
1430ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            AdtPlugin.log(e, "Parsing palette file failed");
1440ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return null;
145ec7301a7433cf89c399fa3c507afe8a147adbcbaTor Norbye        } finally {
146ec7301a7433cf89c399fa3c507afe8a147adbcbaTor Norbye            Closeables.closeQuietly(paletteStream);
1470ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
1480ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    }
1490ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1500ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    /**
1510ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * Returns a fully qualified class name for an element in the rendering document
1520ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * returned by {@link #getRenderingConfigDoc()}
1530ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     *
1540ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @param element the element to look up the fqcn for
1550ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @return the fqcn of the view the element represents a preview for
1560ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     */
1570ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    public String getFullClassName(Element element) {
1580ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // We don't use the element tag name, because in some cases we have
1590ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // an outer element to render some interesting inner element, such as a tab widget
1600ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // (which must be rendered inside a tab host).
1610ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        //
1620ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // Therefore, we instead use the convention that the id is the fully qualified
1630ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // class name, with .'s replaced with _'s.
1640ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1650ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        // Special case: for tab host we aren't allowed to mess with the id
1660ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        String id = element.getAttributeNS(ANDROID_URI, ATTR_ID);
1670ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1680ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        if ("@android:id/tabhost".equals(id)) {
1690ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            // Special case to distinguish TabHost and TabWidget
1700ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            NodeList children = element.getChildNodes();
1710ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            if (children.getLength() > 1 && (children.item(1) instanceof Element)) {
1720ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                Element child = (Element) children.item(1);
1730ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                String childId = child.getAttributeNS(ANDROID_URI, ATTR_ID);
1740ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                if ("@+id/android_widget_TabWidget".equals(childId)) {
1750ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                    return "android.widget.TabWidget"; // TODO: Tab widget!
1760ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                }
1770ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            }
1780ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return "android.widget.TabHost"; // TODO: Tab widget!
1790ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
1800ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1810ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        StringBuilder sb = new StringBuilder();
1820ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        int i = 0;
1830ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        if (id.startsWith(NEW_ID_PREFIX)) {
1840ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            i = NEW_ID_PREFIX.length();
1850ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        } else if (id.startsWith(ID_PREFIX)) {
1860ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            i = ID_PREFIX.length();
1870ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
1880ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1890ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        for (; i < id.length(); i++) {
1900ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            char c = id.charAt(i);
1910ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            if (c == '_') {
1920ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                sb.append('.');
1930ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            } else {
1940ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                sb.append(c);
1950ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            }
1960ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
1970ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
1980ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        return sb.toString();
1990ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    }
2000ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
201d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /** Returns an ordered list of categories and views, parsed from a metadata file */
202c7df8d23830cc48f5741d44e2a978fc9ca52b003Tor Norbye    @SuppressWarnings("resource") // streams passed to parser InputSource closed by parser
203d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private List<CategoryData> getCategories() {
204d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        if (mCategories == null) {
205d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mCategories = new ArrayList<CategoryData>();
206d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
207d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
2080ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            Class<ViewMetadataRepository> clz = ViewMetadataRepository.class;
2090ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            InputStream inputStream = clz.getResourceAsStream(METADATA_FILENAME);
210d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            InputSource is = new InputSource(new BufferedInputStream(inputStream));
211d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            try {
212d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                factory.setNamespaceAware(true);
213d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                factory.setValidating(false);
2146feca9ac5f8add768fef2bc2dc1382a68c158d42Tor Norbye                factory.setIgnoringComments(true);
215d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                DocumentBuilder builder = factory.newDocumentBuilder();
216d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                Document document = builder.parse(is);
217d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                Map<String, FillPreference> fillTypes = new HashMap<String, FillPreference>();
218d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                for (FillPreference pref : FillPreference.values()) {
21918bce12c5916331971b2e8108f8485cc56b696d3Tor Norbye                    fillTypes.put(pref.toString().toLowerCase(Locale.US), pref);
220d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                }
221d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
222d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                NodeList categoryNodes = document.getDocumentElement().getChildNodes();
223d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                for (int i = 0, n = categoryNodes.getLength(); i < n; i++) {
224d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                    Node node = categoryNodes.item(i);
225d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                    if (node.getNodeType() == Node.ELEMENT_NODE) {
226d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                        Element element = (Element) node;
227d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                        if (element.getNodeName().equals("category")) { //$NON-NLS-1$
228d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            String name = element.getAttribute("name"); //$NON-NLS-1$
229d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            CategoryData category = new CategoryData(name);
230d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            NodeList children = element.getChildNodes();
231d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            for (int j = 0, m = children.getLength(); j < m; j++) {
232d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                                Node childNode = children.item(j);
233d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                                if (childNode.getNodeType() == Node.ELEMENT_NODE) {
234d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                                    Element child = (Element) childNode;
235e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                                    ViewData view = createViewData(fillTypes, child,
236429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                                            null, FillPreference.NONE, RenderMode.NORMAL, null);
237d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                                    category.addView(view);
238d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                                }
239d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            }
240d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                            mCategories.add(category);
241d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                        }
242d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                    }
243d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                }
244d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            } catch (Exception e) {
245d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                AdtPlugin.log(e, "Invalid palette metadata"); //$NON-NLS-1$
246d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            }
247d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
248d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
249d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        return mCategories;
250d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
251d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
252e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye    private ViewData createViewData(Map<String, FillPreference> fillTypes,
253e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            Element child, String defaultFqcn, FillPreference defaultFill,
254429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            RenderMode defaultRender, String defaultSize) {
255e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String fqcn = child.getAttribute("class"); //$NON-NLS-1$
256e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (fqcn.length() == 0) {
257e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            fqcn = defaultFqcn;
258e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
259e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String fill = child.getAttribute("fill"); //$NON-NLS-1$
260e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        FillPreference fillPreference = null;
261e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (fill.length() > 0) {
262e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            fillPreference = fillTypes.get(fill);
263e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
264e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (fillPreference == null) {
265e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            fillPreference = defaultFill;
266e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
267e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String skip = child.getAttribute("skip"); //$NON-NLS-1$
268e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        RenderMode renderMode = defaultRender;
269e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String render = child.getAttribute("render"); //$NON-NLS-1$
270e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (render.length() > 0) {
271e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            renderMode = RenderMode.get(render);
272e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
273e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String displayName = child.getAttribute("name"); //$NON-NLS-1$
274e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (displayName.length() == 0) {
275e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            displayName = null;
276e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
277429ae88878cf781753d8261d350ad89fe5864169Tor Norbye
278e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String relatedTo = child.getAttribute("relatedTo"); //$NON-NLS-1$
279e287bc8580e19d72a911615475b353790cf000ebTor Norbye        String topAttrs = child.getAttribute("topAttrs"); //$NON-NLS-1$
280429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        String resize = child.getAttribute("resize"); //$NON-NLS-1$
281e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        ViewData view = new ViewData(fqcn, displayName, fillPreference,
282e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                skip.length() == 0 ? false : Boolean.valueOf(skip),
283e287bc8580e19d72a911615475b353790cf000ebTor Norbye                renderMode, relatedTo, resize, topAttrs);
284e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
285e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String init = child.getAttribute("init"); //$NON-NLS-1$
286e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        String icon = child.getAttribute("icon"); //$NON-NLS-1$
287e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
288e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        view.setInitString(init);
289e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (icon.length() > 0) {
290e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            view.setIconName(icon);
291e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
292e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
293e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        // Nested variations?
294e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (child.hasChildNodes()) {
295e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            // Palette variations
296e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            NodeList childNodes = child.getChildNodes();
297e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            for (int k = 0, kl = childNodes.getLength(); k < kl; k++) {
298e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                Node variationNode = childNodes.item(k);
299e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                if (variationNode.getNodeType() == Node.ELEMENT_NODE) {
300e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    Element variation = (Element) variationNode;
301e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    ViewData variationView = createViewData(fillTypes, variation,
302429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                            fqcn, fillPreference, renderMode, resize);
303e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    view.addVariation(variationView);
304e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                }
305e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            }
306e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
307e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
308e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        return view;
309e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye    }
310e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
311d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
312d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Computes the palette entries for the given {@link AndroidTargetData}, looking up the
313d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * available node descriptors, categorizing and sorting them.
314d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     *
315d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * @param targetData the target data for which to compute palette entries
3160ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @param alphabetical if true, sort all items in alphabetical order
3170ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @param createCategories if true, organize the items into categories
318d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * @return a list of pairs where each pair contains of the category label and an
319d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     *         ordered list of elements to be included in that category
320d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
321d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    public List<Pair<String, List<ViewElementDescriptor>>> getPaletteEntries(
3220ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            AndroidTargetData targetData, boolean alphabetical, boolean createCategories) {
323d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        List<Pair<String, List<ViewElementDescriptor>>> result =
324d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            new ArrayList<Pair<String, List<ViewElementDescriptor>>>();
325d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
326d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        List<List<ViewElementDescriptor>> lists = new ArrayList<List<ViewElementDescriptor>>(2);
327d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        LayoutDescriptors layoutDescriptors = targetData.getLayoutDescriptors();
328d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        lists.add(layoutDescriptors.getViewDescriptors());
329d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        lists.add(layoutDescriptors.getLayoutDescriptors());
330d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
331e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        // First record map of FQCN to ViewElementDescriptor such that we can quickly
332e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        // determine if a particular palette entry is available
333e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        Map<String, ViewElementDescriptor> fqcnToDescriptor =
334e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            new HashMap<String, ViewElementDescriptor>();
335d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        for (List<ViewElementDescriptor> list : lists) {
336d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            for (ViewElementDescriptor view : list) {
337e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                String fqcn = view.getFullClassName();
338e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                if (fqcn == null) {
339e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    // <view> and <merge> tags etc
340e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    fqcn = view.getUiName();
341d5cd92b446e43e8de625142415f560ee54636317Tor Norbye                }
342e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                fqcnToDescriptor.put(fqcn, view);
343e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            }
344e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
345d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
346e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        Set<ViewElementDescriptor> remaining = new HashSet<ViewElementDescriptor>(
347e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                layoutDescriptors.getViewDescriptors().size()
348e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                + layoutDescriptors.getLayoutDescriptors().size());
349e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        remaining.addAll(layoutDescriptors.getViewDescriptors());
350e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        remaining.addAll(layoutDescriptors.getLayoutDescriptors());
351d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
352e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        // Now iterate in palette metadata order over the items in the palette and include
353e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        // any that also appear as a descriptor
354e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        List<ViewElementDescriptor> categoryItems = new ArrayList<ViewElementDescriptor>();
355e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        for (CategoryData category : getCategories()) {
356e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            if (createCategories) {
357e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                categoryItems = new ArrayList<ViewElementDescriptor>();
358e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            }
359e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            for (ViewData view : category) {
360e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                String fqcn = view.getFcqn();
361e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                ViewElementDescriptor descriptor = fqcnToDescriptor.get(fqcn);
362e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                if (descriptor != null) {
363ec22f92d53f4bb74313b91aa491acbfbbb6dc9ceTor Norbye                    remaining.remove(descriptor);
364ec22f92d53f4bb74313b91aa491acbfbbb6dc9ceTor Norbye                    if (view.getSkip()) {
365ec22f92d53f4bb74313b91aa491acbfbbb6dc9ceTor Norbye                        continue;
366ec22f92d53f4bb74313b91aa491acbfbbb6dc9ceTor Norbye                    }
367ec22f92d53f4bb74313b91aa491acbfbbb6dc9ceTor Norbye
368e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    if (view.getDisplayName() != null || view.getInitString().length() > 0) {
369e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                        categoryItems.add(new PaletteMetadataDescriptor(descriptor,
370e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                                view.getDisplayName(), view.getInitString(), view.getIconName()));
371e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    } else {
372e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                        categoryItems.add(descriptor);
373e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    }
374e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
375e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    if (view.hasVariations()) {
376e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                        for (ViewData variation : view.getVariations()) {
377e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                            String init = variation.getInitString();
378e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                            String icon = variation.getIconName();
379e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                            ViewElementDescriptor desc = new PaletteMetadataDescriptor(descriptor,
380e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                                    variation.getDisplayName(), init, icon);
381e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                            categoryItems.add(desc);
382e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                        }
383e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    }
384e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                }
385d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            }
386d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
387e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            if (createCategories && categoryItems.size() > 0) {
388e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                if (alphabetical) {
389e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                    Collections.sort(categoryItems);
390e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                }
391e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                result.add(Pair.of(category.getName(), categoryItems));
3920ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            }
3930ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
3940ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
395e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (remaining.size() > 0) {
396e287bc8580e19d72a911615475b353790cf000ebTor Norbye            List<ViewElementDescriptor> otherItems =
397e287bc8580e19d72a911615475b353790cf000ebTor Norbye                    new ArrayList<ViewElementDescriptor>(remaining);
398e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            // Always sorted, we don't have a natural order for these unknowns
399e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            Collections.sort(otherItems);
400e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            if (createCategories) {
401e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                result.add(Pair.of("Other", otherItems));
402e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            } else {
403e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                categoryItems.addAll(otherItems);
404d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            }
405e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
406d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
407e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        if (!createCategories) {
4080ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            if (alphabetical) {
409e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                Collections.sort(categoryItems);
4100ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            }
411e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            result.add(Pair.of("Views", categoryItems));
412d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
413d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
414d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        return result;
415d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
416d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
4170757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    @VisibleForTesting
4180757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    Collection<String> getAllFqcns() {
4190757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        return getClassToView().keySet();
4200757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    }
4210757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
422d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
423d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Metadata holder for a particular category - contains the name of the category, its
424d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * ordinal (for natural/logical sorting order) and views contained in the category
425d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
426d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private static class CategoryData implements Iterable<ViewData>, Comparable<CategoryData> {
427d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Category name */
428d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final String mName;
429d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Views included in this category */
430d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final List<ViewData> mViews = new ArrayList<ViewData>();
431d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Natural ordering rank */
432d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final int mOrdinal = sNextOrdinal++;
433d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
434d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Constructs a new category with the given name */
435d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private CategoryData(String name) {
436d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            super();
437d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mName = name;
438d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
439d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
440d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Adds a new view into this category */
441d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private void addView(ViewData view) {
442d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mViews.add(view);
443d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
444d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
445d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private String getName() {
446d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mName;
447d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
448d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
449d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        // Implements Iterable<ViewData> such that we can use for-each on the category to
450d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        // enumerate its views
451ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye        @Override
452d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        public Iterator<ViewData> iterator() {
453d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mViews.iterator();
454d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
455d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
456d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        // Implements Comparable<CategoryData> such that categories can be naturally sorted
457ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye        @Override
458d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        public int compareTo(CategoryData other) {
459d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mOrdinal - other.mOrdinal;
460d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
461d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
462d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
463d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /** Metadata holder for a view of a given fully qualified class name */
464d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    private static class ViewData implements Comparable<ViewData> {
465d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** The fully qualified class name of the view */
466d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final String mFqcn;
467d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Fill preference of the view */
468d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final FillPreference mFillPreference;
4690ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        /** Skip this item in the palette? */
4700ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        private final boolean mSkip;
4710ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        /** Must this item be rendered alone? skipped? etc */
4720ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        private final RenderMode mRenderMode;
4730757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        /** Related views */
4740757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        private final String mRelatedTo;
475d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** The relative rank of the view for natural ordering */
476d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private final int mOrdinal = sNextOrdinal++;
477e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        /** List of optional variations */
478e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private List<ViewData> mVariations;
479e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        /** Display name. Can be null. */
480e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String mDisplayName;
481e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        /**
482e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye         * Optional initialization string - a comma separate set of name/value pairs to
483e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye         * initialize the element with
484e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye         */
485e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String mInitString;
486e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        /** The name of an icon (known to the {@link IconFactory} to show for this view */
487e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String mIconName;
488429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        /** The resize preference of this view */
489429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        private String mResize;
490e287bc8580e19d72a911615475b353790cf000ebTor Norbye        /** The most commonly set attributes of this view */
491e287bc8580e19d72a911615475b353790cf000ebTor Norbye        private String mTopAttrs;
492d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
493d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Constructs a new view data for the given class */
494e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private ViewData(String fqcn, String displayName,
4950757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                FillPreference fillPreference, boolean skip, RenderMode renderMode,
496e287bc8580e19d72a911615475b353790cf000ebTor Norbye                String relatedTo, String resize, String topAttrs) {
497d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            super();
498d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mFqcn = fqcn;
499e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            mDisplayName = displayName;
500d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            mFillPreference = fillPreference;
5010ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            mSkip = skip;
5020ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            mRenderMode = renderMode;
5030757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye            mRelatedTo = relatedTo;
504429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            mResize = resize;
505e287bc8580e19d72a911615475b353790cf000ebTor Norbye            mTopAttrs = topAttrs;
506d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
507d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
508d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Returns the {@link FillPreference} for views of this type */
509d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private FillPreference getFillPreference() {
510d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mFillPreference;
511d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
512d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
513d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        /** Fully qualified class name of views of this type */
514d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        private String getFcqn() {
515d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mFqcn;
516d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
517d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
518e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String getDisplayName() {
519e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            return mDisplayName;
520d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
521d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
522429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        private String getResize() {
523429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            return mResize;
524429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        }
525429ae88878cf781753d8261d350ad89fe5864169Tor Norbye
526d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        // Implements Comparable<ViewData> such that views can be sorted naturally
527ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye        @Override
528d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        public int compareTo(ViewData other) {
529d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return mOrdinal - other.mOrdinal;
530d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
5310ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
5320ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        public RenderMode getRenderMode() {
5330ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return mRenderMode;
5340ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
5350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
5360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        public boolean getSkip() {
5370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return mSkip;
5380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
5390757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
5400757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        public List<String> getRelatedTo() {
5410757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye            if (mRelatedTo == null || mRelatedTo.length() == 0) {
5420757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                return Collections.emptyList();
5430757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye            } else {
5440757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                List<String> result = new ArrayList<String>();
5450757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                ViewMetadataRepository repository = ViewMetadataRepository.get();
5460757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                Map<String, ViewData> classToView = repository.getClassToView();
5470757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
5480757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                List<String> fqns = new ArrayList<String>(classToView.keySet());
5496cb5c7f7141a08fd355bb92c6a4153140400890bTor Norbye                for (String basename : Splitter.on(',').split(mRelatedTo)) {
5500757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                    boolean found = false;
5510757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                    for (String fqcn : fqns) {
5520757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                        String suffix = '.' + basename;
5530757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                        if (fqcn.endsWith(suffix)) {
5540757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                            result.add(fqcn);
5550757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                            found = true;
5560757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                            break;
5570757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                        }
5580757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                    }
55947412b5c2252df2624e5ff4ad2f9054af86c5065Tor Norbye                    if (basename.equals(VIEW_FRAGMENT) || basename.equals(VIEW_INCLUDE)) {
56047412b5c2252df2624e5ff4ad2f9054af86c5065Tor Norbye                        result.add(basename);
56147412b5c2252df2624e5ff4ad2f9054af86c5065Tor Norbye                    } else {
56247412b5c2252df2624e5ff4ad2f9054af86c5065Tor Norbye                        assert found : basename;
56347412b5c2252df2624e5ff4ad2f9054af86c5065Tor Norbye                    }
5640757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                }
5650757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
5660757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye                return result;
5670757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye            }
5680757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        }
569e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
570e287bc8580e19d72a911615475b353790cf000ebTor Norbye        public List<String> getTopAttributes() {
571e287bc8580e19d72a911615475b353790cf000ebTor Norbye            // "id" is a top attribute for all views, so it is not included in the XML, we just
572e287bc8580e19d72a911615475b353790cf000ebTor Norbye            // add it in dynamically here
573e287bc8580e19d72a911615475b353790cf000ebTor Norbye            if (mTopAttrs == null || mTopAttrs.length() == 0) {
574e287bc8580e19d72a911615475b353790cf000ebTor Norbye                return Collections.singletonList(ATTR_ID);
575e287bc8580e19d72a911615475b353790cf000ebTor Norbye            } else {
576e287bc8580e19d72a911615475b353790cf000ebTor Norbye                String[] split = mTopAttrs.split(","); //$NON-NLS-1$
577e287bc8580e19d72a911615475b353790cf000ebTor Norbye                List<String> topAttributes = new ArrayList<String>(split.length + 1);
578e287bc8580e19d72a911615475b353790cf000ebTor Norbye                topAttributes.add(ATTR_ID);
579e287bc8580e19d72a911615475b353790cf000ebTor Norbye                for (int i = 0, n = split.length; i < n; i++) {
580e287bc8580e19d72a911615475b353790cf000ebTor Norbye                    topAttributes.add(split[i]);
581e287bc8580e19d72a911615475b353790cf000ebTor Norbye                }
582e287bc8580e19d72a911615475b353790cf000ebTor Norbye                return Collections.<String>unmodifiableList(topAttributes);
583e287bc8580e19d72a911615475b353790cf000ebTor Norbye            }
584e287bc8580e19d72a911615475b353790cf000ebTor Norbye        }
585e287bc8580e19d72a911615475b353790cf000ebTor Norbye
586e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        void addVariation(ViewData variation) {
587e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            if (mVariations == null) {
588e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye                mVariations = new ArrayList<ViewData>(4);
589e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            }
590e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            mVariations.add(variation);
591e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
592e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
593e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        List<ViewData> getVariations() {
594e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            return mVariations;
595e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
596e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
597e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        boolean hasVariations() {
598e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            return mVariations != null && mVariations.size() > 0;
599e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
600e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
601e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private void setInitString(String initString) {
602e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            this.mInitString = initString;
603e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
604e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
605e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String getInitString() {
606e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            return mInitString;
607e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
608e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
609e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private void setIconName(String iconName) {
610e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            this.mIconName = iconName;
611e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
612e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye
613e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        private String getIconName() {
614e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye            return mIconName;
615e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        }
616d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
617d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
618d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    /**
619d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * Returns the {@link FillPreference} for classes with the given fully qualified class
620d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * name
621d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     *
622d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * @param fqcn the fully qualified class name of the view
623d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     * @return a suitable {@link FillPreference} for the given view type
624d5cd92b446e43e8de625142415f560ee54636317Tor Norbye     */
625d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    public FillPreference getFillPreference(String fqcn) {
626d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        ViewData view = getClassToView().get(fqcn);
627d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        if (view != null) {
628d5cd92b446e43e8de625142415f560ee54636317Tor Norbye            return view.getFillPreference();
629d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        }
630d5cd92b446e43e8de625142415f560ee54636317Tor Norbye
631d5cd92b446e43e8de625142415f560ee54636317Tor Norbye        return FillPreference.NONE;
632d5cd92b446e43e8de625142415f560ee54636317Tor Norbye    }
6330ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
6340ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    /**
6350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * Returns the {@link RenderMode} for classes with the given fully qualified class
6360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * name
6370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     *
6380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @param fqcn the fully qualified class name
6390ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @return the {@link RenderMode} to use for previews of the given view type
6400ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     */
6410ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    public RenderMode getRenderMode(String fqcn) {
6420ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        ViewData view = getClassToView().get(fqcn);
6430ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        if (view != null) {
6440ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return view.getRenderMode();
6450ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
6460ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
647e7abbed2fe84c25bcd6d68cef4140963c10a1e5dTor Norbye        return RenderMode.NORMAL;
6480ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    }
6490ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
6500ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    /**
651429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     * Returns the {@link ResizePolicy} for the given class.
652429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     *
653429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     * @param fqcn the fully qualified class name of the target widget
654429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     * @return the {@link ResizePolicy} for the widget, which will never be null (but may
655429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     *         be the default of {@link ResizePolicy#full()} if no metadata is found for
656429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     *         the given widget)
657429ae88878cf781753d8261d350ad89fe5864169Tor Norbye     */
658429ae88878cf781753d8261d350ad89fe5864169Tor Norbye    public ResizePolicy getResizePolicy(String fqcn) {
659429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        ViewData view = getClassToView().get(fqcn);
660429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        if (view != null) {
661429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            String resize = view.getResize();
662429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            if (resize != null && resize.length() > 0) {
663429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                if ("full".equals(resize)) { //$NON-NLS-1$
664429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    return ResizePolicy.full();
665429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                } else if ("none".equals(resize)) { //$NON-NLS-1$
666429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    return ResizePolicy.none();
667429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                } else if ("horizontal".equals(resize)) { //$NON-NLS-1$
668429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    return ResizePolicy.horizontal();
669429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                } else if ("vertical".equals(resize)) { //$NON-NLS-1$
670429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    return ResizePolicy.vertical();
671429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                } else if ("scaled".equals(resize)) { //$NON-NLS-1$
672429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    return ResizePolicy.scaled();
673429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                } else {
674429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                    assert false : resize;
675429ae88878cf781753d8261d350ad89fe5864169Tor Norbye                }
676429ae88878cf781753d8261d350ad89fe5864169Tor Norbye            }
677429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        }
678429ae88878cf781753d8261d350ad89fe5864169Tor Norbye
679429ae88878cf781753d8261d350ad89fe5864169Tor Norbye        return ResizePolicy.full();
680429ae88878cf781753d8261d350ad89fe5864169Tor Norbye    }
681429ae88878cf781753d8261d350ad89fe5864169Tor Norbye
682429ae88878cf781753d8261d350ad89fe5864169Tor Norbye    /**
6830ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * Returns true if classes with the given fully qualified class name should be hidden
6840ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * or skipped from the palette
6850ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     *
6860ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @param fqcn the fully qualified class name
6870ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     * @return true if views of the given type should be hidden from the palette
6880ac475d29f793079783f501126239ed6ce8aa31dTor Norbye     */
6890ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    public boolean getSkip(String fqcn) {
6900ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        ViewData view = getClassToView().get(fqcn);
6910ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        if (view != null) {
6920ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            return view.getSkip();
6930ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
6940ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
6950ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        return false;
6960ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    }
6970ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
6980757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    /**
699e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * Returns a list of the top (most commonly set) attributes of the given
700e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * view.
701e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *
702e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * @param fqcn the fully qualified class name
703e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * @return a list, never null but possibly empty, of popular attribute names
704e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *         (not including a namespace prefix)
705e287bc8580e19d72a911615475b353790cf000ebTor Norbye     */
706e287bc8580e19d72a911615475b353790cf000ebTor Norbye    public List<String> getTopAttributes(String fqcn) {
707e287bc8580e19d72a911615475b353790cf000ebTor Norbye        ViewData view = getClassToView().get(fqcn);
708e287bc8580e19d72a911615475b353790cf000ebTor Norbye        if (view != null) {
709e287bc8580e19d72a911615475b353790cf000ebTor Norbye            return view.getTopAttributes();
710e287bc8580e19d72a911615475b353790cf000ebTor Norbye        }
711e287bc8580e19d72a911615475b353790cf000ebTor Norbye
712e287bc8580e19d72a911615475b353790cf000ebTor Norbye        return Collections.singletonList(ATTR_ID);
713e287bc8580e19d72a911615475b353790cf000ebTor Norbye    }
714e287bc8580e19d72a911615475b353790cf000ebTor Norbye
715e287bc8580e19d72a911615475b353790cf000ebTor Norbye    /**
7160757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     * Returns a set of fully qualified names for views that are closely related to the
7170757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     * given view
7180757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     *
7190757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     * @param fqcn the fully qualified class name
7200757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     * @return a list, never null but possibly empty, of views that are related to the
7210757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     *         view of the given type
7220757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye     */
7230757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    public List<String> getRelatedTo(String fqcn) {
7240757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        ViewData view = getClassToView().get(fqcn);
7250757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        if (view != null) {
7260757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye            return view.getRelatedTo();
7270757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        }
7280757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
7290757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye        return Collections.emptyList();
7300757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye    }
7310757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye
7320ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    /** Render mode for palette preview */
7330ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    public enum RenderMode {
7340ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        /**
7350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         * Render previews, and it can be rendered as a sibling of many other views in a
7360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         * big linear layout
7370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         */
7380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        NORMAL,
7390ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        /** This view needs to be rendered alone */
7400ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        ALONE,
7410ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        /**
7420ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         * Skip this element; it doesn't work or does not produce any visible artifacts
7430ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         * (such as the basic layouts)
7440ac475d29f793079783f501126239ed6ce8aa31dTor Norbye         */
7450ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        SKIP;
7460ac475d29f793079783f501126239ed6ce8aa31dTor Norbye
747e287bc8580e19d72a911615475b353790cf000ebTor Norbye        /**
748e287bc8580e19d72a911615475b353790cf000ebTor Norbye         * Returns the {@link RenderMode} for the given render XML attribute
749e287bc8580e19d72a911615475b353790cf000ebTor Norbye         * value
750e287bc8580e19d72a911615475b353790cf000ebTor Norbye         *
751e287bc8580e19d72a911615475b353790cf000ebTor Norbye         * @param render the attribute value in the metadata XML file
752e287bc8580e19d72a911615475b353790cf000ebTor Norbye         * @return a corresponding {@link RenderMode}, never null
753e287bc8580e19d72a911615475b353790cf000ebTor Norbye         */
7540ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        public static RenderMode get(String render) {
755e287bc8580e19d72a911615475b353790cf000ebTor Norbye            if ("alone".equals(render)) {       //$NON-NLS-1$
7560ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                return ALONE;
757e287bc8580e19d72a911615475b353790cf000ebTor Norbye            } else if ("skip".equals(render)) { //$NON-NLS-1$
7580ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                return SKIP;
7590ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            } else {
7600ac475d29f793079783f501126239ed6ce8aa31dTor Norbye                return NORMAL;
7610ac475d29f793079783f501126239ed6ce8aa31dTor Norbye            }
7620ac475d29f793079783f501126239ed6ce8aa31dTor Norbye        }
7630ac475d29f793079783f501126239ed6ce8aa31dTor Norbye    }
7640595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye
7650595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    /**
7660595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * Are insets supported yet? This flag indicates whether the {@link #getInsets} method
7670595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * can return valid data, such that clients can avoid doing any work computing the
7680595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * current theme or density if there's no chance that valid insets will be returned
7690595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     */
7700595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    public static final boolean INSETS_SUPPORTED = false;
7710595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye
7720595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    /**
7730595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * Returns the insets of widgets with the given fully qualified name, in the given
7740595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * theme and the given screen density.
7750595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     *
7760595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * @param fqcn the fully qualified name of the view
7770595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * @param density the screen density
7780595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * @param theme the theme name
7790595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     * @return the insets of the visual bounds relative to the view info bounds, or null
7800595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     *         if not known or if there are no insets
7810595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye     */
7820595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    public static Margins getInsets(String fqcn, Density density, String theme) {
7830595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye        if (INSETS_SUPPORTED) {
7840595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye            // Some sample data measured manually for common themes and widgets.
7850595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye            if (fqcn.equals(FQCN_BUTTON)) {
7860595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                if (density == Density.HIGH) {
7870595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
7880595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, WVGA
7890595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(5, 5, 5, 5);
7900595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
7910595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, WVGA
7920595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(4, 4, 0, 7);
7930595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
7940595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                } else if (density == Density.MEDIUM) {
7950595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
7960595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, WVGA
7970595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(3, 3, 3, 3);
7980595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
7990595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, HVGA
8000595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(2, 2, 0, 4);
8010595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8020595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                } else if (density == Density.LOW) {
8030595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
8040595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, QVGA
8050595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(2, 2, 2, 2);
8060595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
8070595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, QVGA
8080595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(1, 3, 0, 4);
8090595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8100595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                }
8110595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye            } else if (fqcn.equals(FQCN_TOGGLE_BUTTON)) {
8120595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                if (density == Density.HIGH) {
8130595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
8140595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, WVGA
8150595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(5, 5, 5, 5);
8160595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
8170595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, WVGA
8180595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(2, 2, 0, 5);
8190595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8200595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                } else if (density == Density.MEDIUM) {
8210595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
8220595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, WVGA
8230595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(3, 3, 3, 3);
8240595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
8250595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, HVGA
8260595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(0, 1, 0, 3);
8270595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8280595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                } else if (density == Density.LOW) {
8290595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (theme.startsWith(HOLO_PREFIX)) {
8300595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Holo, Theme.Holo.Light, QVGA
8310595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(2, 2, 2, 2);
8320595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } else {
8330595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, QVGA
8340595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(2, 2, 0, 4);
8350595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8360595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                }
8370595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye            } else if (fqcn.equals(FQCN_SPINNER)) {
8380595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                if (density == Density.HIGH) {
8390595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (!theme.startsWith(HOLO_PREFIX)) {
8400595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, WVGA
8410595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(3, 4, 2, 8);
8420595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    } // Doesn't render on Holo!
8430595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                } else if (density == Density.MEDIUM) {
8440595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    if (!theme.startsWith(HOLO_PREFIX)) {
8450595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        // Theme.Light, HVGA
8460595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                        return new Margins(1, 1, 0, 4);
8470595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                    }
8480595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye                }
8490595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye            }
8500595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye        }
8510595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye
8520595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye        return null;
8530595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    }
8540595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye
8550595b4123048f53179b5c2c65cf88968ac488ad3Tor Norbye    private static final String HOLO_PREFIX = "Theme.Holo"; //$NON-NLS-1$
856d5cd92b446e43e8de625142415f560ee54636317Tor Norbye}
857