aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-04-21 21:25:15 -0700
committerTor Norbye <tnorbye@google.com>2011-04-22 20:23:20 -0700
commitaaa917c9c5e6f974ca20b94adfd53d1bf01bb54e (patch)
tree3e1ac620eb9ee9a04c0a8c9321a34f17f6550136 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android
parentc3216a2d0ca4978eb7e5bf34994e76b9ecb6ddb5 (diff)
downloadsdk-aaa917c9c5e6f974ca20b94adfd53d1bf01bb54e.tar.gz
Add code completion support for drawables, animations and colors
This changeset adds in descriptor metadata and XML editors for: - Drawables (res/drawable/) - Animations (res/anim/) - Animators (res/animator/) - Colors (res/color) These types have also been added to the New XML File wizard. There is some specialized completion support for animators: - Completing on the propertyName property of <objectAnimator> will offer the various integer and float properties in views - Completion for the interpolator property shows the framework interpolators immediately and on top (instead of having to complete the individual resource paths @android: and anim/ first There is also a new quickfix and marker resolution for the AAPT error which complains about an unbound prefix. This will insert a xmlns:android="http://schemas.android.com/apk/res/android" attribute declaration on the root element. This CL also includes a fix to make the New XML File Wizard preselect the current project in more scenarios. NOTE: This changeset adds new XML editors for these resource types. It does not attempt to update previous editor bindings for files of the given type, so to test this you may need to use "Open With" in the package explorer to pick the right file type. A subsequent CL will try to migrate settings over to these editors, but that work will tie into another effort: merging all these different editors into a single editor class that does its own content type switching and different viewparts for the other tabs. Change-Id: I4b12bafd8fd068176c41bac1e345bb74ccdb8b6f
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java13
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java150
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java124
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java167
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java181
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java30
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java182
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java94
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java123
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java30
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java300
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java157
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java30
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java58
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java43
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java92
26 files changed, 1822 insertions, 46 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java
index bd79e29b6..1e14f9f0e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttrsXmlParser.java
@@ -256,7 +256,7 @@ public final class AttrsXmlParser {
if (parents != null) {
String[] parentsArray =
parseStyleableParents(parents, mStyleMap, unknownParents);
- style.setParents(parentsArray); //$NON-NLS-1$
+ style.setParents(parentsArray);
}
mStyleMap.put(name, style);
unknownParents.remove(name);
@@ -441,9 +441,9 @@ public final class AttrsXmlParser {
* </ul>
* The format may be one type or two types (e.g. "reference|color").
* An extra format can be implied: "enum" or "flag" are not specified in the "format" attribute,
- * they are implicitely stated by the presence of sub-nodes <enum> or <flag>.
+ * they are implicitly stated by the presence of sub-nodes <enum> or <flag>.
* <p/>
- * By design, <attr> nodes of the same name MUST have the same type.
+ * By design, attr nodes of the same name MUST have the same type.
* Attribute nodes are thus cached by name and reused as much as possible.
* When reusing a node, it is duplicated and its javadoc reassigned.
*/
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 43fd82346..55a5ef8af 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -25,6 +25,9 @@ import com.android.ide.common.sdk.LoadStatus;
import com.android.ide.eclipse.adt.internal.VersionCheck;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimationEditor;
+import com.android.ide.eclipse.adt.internal.editors.color.ColorEditor;
+import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder;
import com.android.ide.eclipse.adt.internal.editors.menu.MenuEditor;
@@ -1511,11 +1514,17 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger {
AdtPlugin.log(IStatus.INFO, " set default editor id to layout");
}
IDE.setDefaultEditor(file, LayoutEditor.ID);
- } else if (type == ResourceFolderType.DRAWABLE
- || type == ResourceFolderType.VALUES) {
+ } else if (type == ResourceFolderType.VALUES) {
IDE.setDefaultEditor(file, ResourcesEditor.ID);
} else if (type == ResourceFolderType.MENU) {
IDE.setDefaultEditor(file, MenuEditor.ID);
+ } else if (type == ResourceFolderType.COLOR) {
+ IDE.setDefaultEditor(file, ColorEditor.ID);
+ } else if (type == ResourceFolderType.DRAWABLE) {
+ IDE.setDefaultEditor(file, DrawableEditor.ID);
+ } else if (type == ResourceFolderType.ANIMATOR
+ || type == ResourceFolderType.ANIM) {
+ IDE.setDefaultEditor(file, AnimationEditor.ID);
} else if (type == ResourceFolderType.XML) {
if (XmlEditor.canHandleFile(file)) {
if (DEBUG_XML_FILE_INIT) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java
index 436fcace9..7d79086a2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/AaptQuickFix.java
@@ -16,9 +16,12 @@
package com.android.ide.eclipse.adt.internal.build;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
+
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -31,6 +34,7 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
@@ -45,12 +49,21 @@ import org.eclipse.ui.IMarkerResolutionGenerator2;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
/**
* Shared handler for both quick assist processors (Control key handler) and quick fix
* marker resolution (Problem view handling), since there is a lot of overlap between
* these two UI handlers.
*/
+@SuppressWarnings("restriction") // XML model
public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistProcessor {
public AaptQuickFix() {
@@ -61,6 +74,11 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr
return "No resource found that matches the given name";
}
+ /** Returns the error message from aapt that signals a missing namespace declaration */
+ private static String getUnboundErrorMessage() {
+ return "Error parsing XML: unbound prefix";
+ }
+
// ---- Implements IMarkerResolution2 ----
public boolean hasResolutions(IMarker marker) {
@@ -71,12 +89,24 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr
AdtPlugin.log(e, null);
}
- return message != null && message.contains(getTargetMarkerErrorMessage());
+ return message != null
+ && (message.contains(getTargetMarkerErrorMessage())
+ || message.contains(getUnboundErrorMessage()));
}
public IMarkerResolution[] getResolutions(IMarker marker) {
IResource markerResource = marker.getResource();
IProject project = markerResource.getProject();
+ try {
+ String message = (String) marker.getAttribute(IMarker.MESSAGE);
+ if (message.contains(getUnboundErrorMessage()) && markerResource instanceof IFile) {
+ return new IMarkerResolution[] {
+ new CreateNamespaceFix((IFile) markerResource)
+ };
+ }
+ } catch (CoreException e1) {
+ AdtPlugin.log(e1, null);
+ }
int start = marker.getAttribute(IMarker.CHAR_START, 0);
int end = marker.getAttribute(IMarker.CHAR_END, 0);
@@ -158,6 +188,10 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr
};
}
}
+ } else if (message.contains(getUnboundErrorMessage())) {
+ return new ICompletionProposal[] {
+ new CreateNamespaceFix(null)
+ };
}
}
} catch (CoreException e) {
@@ -174,6 +208,120 @@ public class AaptQuickFix implements IMarkerResolutionGenerator2, IQuickAssistPr
return null;
}
+ /** Quick fix to insert namespace binding when missing */
+ private final static class CreateNamespaceFix
+ implements ICompletionProposal, IMarkerResolution2 {
+ private IFile mFile;
+
+ public CreateNamespaceFix(IFile file) {
+ mFile = file;
+ }
+
+ private IndexedRegion perform(IDocument doc) {
+ IModelManager manager = StructuredModelManager.getModelManager();
+ IStructuredModel model = manager.getExistingModelForEdit(doc);
+ if (model != null) {
+ try {
+ perform(model);
+ } finally {
+ model.releaseFromEdit();
+ }
+ }
+
+ return null;
+ }
+
+ private IndexedRegion perform(IFile file) {
+ IModelManager manager = StructuredModelManager.getModelManager();
+ IStructuredModel model;
+ try {
+ model = manager.getModelForEdit(file);
+ if (model != null) {
+ try {
+ perform(model);
+ } finally {
+ model.releaseFromEdit();
+ }
+ }
+ } catch (Exception e) {
+ AdtPlugin.log(e, "Can't look up XML model");
+ }
+
+ return null;
+ }
+
+ private IndexedRegion perform(IStructuredModel model) {
+ if (model instanceof IDOMModel) {
+ IDOMModel domModel = (IDOMModel) model;
+ Document document = domModel.getDocument();
+ Element element = document.getDocumentElement();
+ Attr attr = document.createAttributeNS(XmlnsAttributeDescriptor.XMLNS_URI,
+ "xmlns:android"); //$NON-NLS-1$
+ attr.setValue(ANDROID_URI);
+ element.getAttributes().setNamedItemNS(attr);
+ return (IndexedRegion) attr;
+ }
+
+ return null;
+ }
+
+ // ---- Implements ICompletionProposal ----
+
+ public void apply(IDocument document) {
+ perform(document);
+ }
+
+ public String getAdditionalProposalInfo() {
+ return "Adds an Android namespace declaratiopn to the root element.";
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ public String getDisplayString() {
+ return "Insert namespace binding";
+ }
+
+ public Image getImage() {
+ return AdtPlugin.getAndroidLogo();
+ }
+
+ public Point getSelection(IDocument doc) {
+ return null;
+ }
+
+
+ // ---- Implements MarkerResolution2 ----
+
+ public String getLabel() {
+ return getDisplayString();
+ }
+
+ public void run(IMarker marker) {
+ try {
+ AdtPlugin.openFile(mFile, null);
+ } catch (PartInitException e) {
+ AdtPlugin.log(e, "Can't open file %1$s", mFile.getName());
+ }
+
+ IndexedRegion indexedRegion = perform(mFile);
+ if (indexedRegion != null) {
+ try {
+ IRegion region =
+ new Region(indexedRegion.getStartOffset(), indexedRegion.getLength());
+ AdtPlugin.openFile(mFile, region);
+ } catch (PartInitException e) {
+ AdtPlugin.log(e, "Can't open file %1$s", mFile.getName());
+ }
+ }
+ }
+
+ public String getDescription() {
+ return getAdditionalProposalInfo();
+ }
+ }
+
private static class CreateResourceProposal
implements ICompletionProposal, IMarkerResolution2 {
private final IProject mProject;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
index 86ff16e88..17ffe30eb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
@@ -1163,6 +1163,11 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
return null;
}
+ /** Returns the root descriptor id to use */
+ protected int getRootDescriptorId() {
+ return mDescriptorId;
+ }
+
/**
* Computes (if needed) and returns the root descriptor.
*/
@@ -1170,7 +1175,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
if (mRootDescriptor == null) {
AndroidTargetData data = mEditor.getTargetData();
if (data != null) {
- IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId);
+ IDescriptorProvider descriptorProvider =
+ data.getDescriptorProvider(getRootDescriptorId());
if (descriptorProvider != null) {
mRootDescriptor = new ElementDescriptor("", //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java
new file mode 100644
index 000000000..dabab8784
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimDescriptors.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.animator;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
+
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
+import com.android.sdklib.SdkConstants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Descriptors for the res/anim resources */
+public class AnimDescriptors implements IDescriptorProvider {
+ /** The root element descriptor */
+ private ElementDescriptor mDescriptor;
+ /** The root element descriptors */
+ private ElementDescriptor[] mRootDescriptors;
+ private Map<String, ElementDescriptor> nameToDescriptor;
+
+ /** @return the root descriptor. */
+ public ElementDescriptor getDescriptor() {
+ if (mDescriptor == null) {
+ mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
+ }
+
+ return mDescriptor;
+ }
+
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return mRootDescriptors;
+ }
+
+ public ElementDescriptor getElementDescriptor(String mRootTag) {
+ if (nameToDescriptor == null) {
+ nameToDescriptor = new HashMap<String, ElementDescriptor>();
+ for (ElementDescriptor descriptor : getRootElementDescriptors()) {
+ nameToDescriptor.put(descriptor.getXmlName(), descriptor);
+ }
+ }
+
+ ElementDescriptor descriptor = nameToDescriptor.get(mRootTag);
+ if (descriptor == null) {
+ descriptor = getDescriptor();
+ }
+ return descriptor;
+ }
+
+ public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
+ if (styleMap == null) {
+ return;
+ }
+
+ XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
+ SdkConstants.NS_RESOURCES);
+
+ List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>();
+
+ String sdkUrl =
+ "http://developer.android.com/guide/topics/graphics/view-animation.html"; //$NON-NLS-1$
+ ElementDescriptor set = AnimatorDescriptors.addElement(descriptors, styleMap,
+ "set", "Set", "AnimationSet", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
+ "A container that holds other animation elements (<alpha>, <scale>, "
+ + "<translate>, <rotate>) or other <set> elements. ",
+ sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "alpha", "Alpha", "AlphaAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
+ "A fade-in or fade-out animation.",
+ sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "scale", "Scale", "ScaleAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
+ "A resizing animation. You can specify the center point of the image from "
+ + "which it grows outward (or inward) by specifying pivotX and pivotY. "
+ + "For example, if these values are 0, 0 (top-left corner), all growth "
+ + "will be down and to the right.",
+ sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "rotate", "Rotate", "RotateAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
+ "A rotation animation.",
+ sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "translate", "Translate", "TranslateAnimation", "Animation", //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
+ "A vertical and/or horizontal motion. Supports the following attributes in "
+ + "any of the following three formats: values from -100 to 100 ending "
+ + "with \"%\", indicating a percentage relative to itself; values from "
+ + "-100 to 100 ending in \"%p\", indicating a percentage relative to its "
+ + "parent; a float value with no suffix, indicating an absolute value.",
+ sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]);
+
+ // Allow <set> to nest the others (and other sets)
+ if (set != null) {
+ set.setChildren(mRootDescriptors);
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java
new file mode 100644
index 000000000..ee0c290c7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationContentAssist.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.animator;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME_PREFIX;
+import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.resources.ResourceItem;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.resources.ResourceFolderType;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
+
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.w3c.dom.Node;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Content Assist Processor for /res/drawable XML files
+ */
+@VisibleForTesting
+public final class AnimationContentAssist extends AndroidContentAssist {
+ private static final String OBJECT_ANIMATOR = "objectAnimator"; //$NON-NLS-1$
+ private static final String PROPERTY_NAME = "propertyName"; //$NON-NLS-1$
+ private static final String INTERPOLATOR_PROPERTY_NAME = "interpolator"; //$NON-NLS-1$
+ private static final String INTERPOLATOR_NAME_SUFFIX = "_interpolator"; //$NON-NLS-1$
+
+ public AnimationContentAssist() {
+ super(AndroidTargetData.DESCRIPTOR_ANIMATOR);
+ }
+
+ @Override
+ protected int getRootDescriptorId() {
+ String folderName = mEditor.getInputFile().getParent().getName();
+ ResourceFolderType folderType = ResourceFolderType.getFolderType(folderName);
+ if (folderType == ResourceFolderType.ANIM) {
+ return AndroidTargetData.DESCRIPTOR_ANIM;
+ } else {
+ return AndroidTargetData.DESCRIPTOR_ANIMATOR;
+ }
+ }
+
+ @Override
+ protected void computeAttributeValues(List<ICompletionProposal> proposals, int offset,
+ String parentTagName, String attributeName, Node node, String wordPrefix,
+ boolean skipEndTag, int replaceLength) {
+
+ // Add value completion for the interpolator and propertyName attributes
+
+ if (attributeName.endsWith(INTERPOLATOR_PROPERTY_NAME)) {
+ if (!wordPrefix.startsWith("@android:anim/")) { //$NON-NLS-1$
+ // List all framework interpolators with full path first
+ AndroidTargetData data = mEditor.getTargetData();
+ ResourceRepository repository = data.getFrameworkResources();
+ List<String> interpolators = new ArrayList<String>();
+ String base = '@' + ANDROID_PKG + ':' + ResourceType.ANIM.getName() + '/';
+ for (ResourceItem item : repository.getResourceItemsOfType(ResourceType.ANIM)) {
+ String name = item.getName();
+ if (name.endsWith(INTERPOLATOR_NAME_SUFFIX)) {
+ interpolators.add(base + item.getName());
+ }
+ }
+ addMatchingProposals(proposals, interpolators.toArray(), offset, node, wordPrefix,
+ (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */,
+ skipEndTag /* skipEndTag */, replaceLength);
+ }
+
+
+ super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node,
+ wordPrefix, skipEndTag, replaceLength);
+ } else if (parentTagName.equals(OBJECT_ANIMATOR)
+ && attributeName.endsWith(PROPERTY_NAME)) {
+
+ // Special case: the user is code completing inside
+ // <objectAnimator propertyName="^">
+ // In this case, offer ALL attribute names that make sense for animation
+ // (e.g. all numeric ones)
+
+ String attributePrefix = wordPrefix;
+ if (startsWith(attributePrefix, ANDROID_NS_NAME_PREFIX)) {
+ attributePrefix = attributePrefix.substring(ANDROID_NS_NAME_PREFIX.length());
+ }
+
+ AndroidTargetData data = mEditor.getTargetData();
+ if (data != null) {
+ IDescriptorProvider descriptorProvider =
+ data.getDescriptorProvider(AndroidTargetData.DESCRIPTOR_LAYOUT);
+ if (descriptorProvider != null) {
+ ElementDescriptor[] rootElementDescriptors =
+ descriptorProvider.getRootElementDescriptors();
+ Map<String, AttributeDescriptor> matches =
+ new HashMap<String, AttributeDescriptor>(180);
+ for (ElementDescriptor elementDesc : rootElementDescriptors) {
+ for (AttributeDescriptor desc : elementDesc.getAttributes()) {
+ if (desc instanceof SeparatorAttributeDescriptor) {
+ continue;
+ }
+ String name = desc.getXmlLocalName();
+ if (startsWith(name, attributePrefix)) {
+ for (Format f : desc.getAttributeInfo().getFormats()) {
+ if (f == Format.INTEGER || f == Format.FLOAT) {
+ // TODO: Filter out some common properties
+ // that the user probably isn't trying to
+ // animate:
+ // num*, min*, max*, *Index, *Threshold,
+ // *Duration, *Id, *Limit
+
+ matches.put(name, desc);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ List<AttributeDescriptor> sorted =
+ new ArrayList<AttributeDescriptor>(matches.size());
+ sorted.addAll(matches.values());
+ Collections.sort(sorted);
+ // Extract just the name+description pairs, since we don't want to
+ // use the full attribute descriptor (which forces the namespace
+ // prefix to be included)
+ List<Pair<String, String>> pairs =
+ new ArrayList<Pair<String, String>>(sorted.size());
+ for (AttributeDescriptor d : sorted) {
+ pairs.add(Pair.of(d.getXmlLocalName(), d.getAttributeInfo().getJavaDoc()));
+ }
+
+ addMatchingProposals(proposals, pairs.toArray(), offset, node, wordPrefix,
+ (char) 0 /* needTag */, true /* isAttribute */, false /* isNew */,
+ skipEndTag /* skipEndTag */, replaceLength);
+ return;
+ }
+ }
+ } else {
+ super.computeAttributeValues(proposals, offset, parentTagName, attributeName, node,
+ wordPrefix, skipEndTag, replaceLength);
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java
new file mode 100644
index 000000000..9f6123898
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditor.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.animator;
+
+import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE;
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.resources.ResourceFolderType;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Editor for /res/animator XML files.
+ */
+@SuppressWarnings("restriction")
+public class AnimationEditor extends AndroidXmlEditor {
+ public static final String ID = EDITORS_NAMESPACE + ".animator.AnimationEditor"; //$NON-NLS-1$
+
+ /** Root node of the UI element hierarchy */
+ private UiElementNode mUiRootNode;
+ /** The tag used at the root */
+ private String mRootTag;
+
+ public AnimationEditor() {
+ super();
+ }
+
+ @Override
+ public UiElementNode getUiRootNode() {
+ return mUiRootNode;
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ @Override
+ protected void createFormPages() {
+ /* Disabled for now; doesn't work quite right
+ try {
+ addPage(new AnimatorTreePage(this));
+ } catch (PartInitException e) {
+ AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$
+ AdtPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ */
+ }
+
+ /* (non-java doc)
+ * Change the tab/title name to include the project name.
+ */
+ @Override
+ protected void setInput(IEditorInput input) {
+ super.setInput(input);
+ if (input instanceof FileEditorInput) {
+ FileEditorInput fileInput = (FileEditorInput) input;
+ IFile file = fileInput.getFile();
+ setPartName(String.format("%1$s",
+ file.getName()));
+ }
+ }
+
+ /**
+ * Processes the new XML Model.
+ *
+ * @param xmlDoc The XML document, if available, or null if none exists.
+ */
+ @Override
+ protected void xmlModelChanged(Document xmlDoc) {
+ Element rootElement = xmlDoc.getDocumentElement();
+ if (rootElement != null) {
+ mRootTag = rootElement.getTagName();
+ }
+
+ // create the ui root node on demand.
+ initUiRootNode(false /*force*/);
+
+ if (mRootTag != null
+ && !mRootTag.equals(mUiRootNode.getDescriptor().getXmlLocalName())) {
+ AndroidTargetData data = getTargetData();
+ if (data != null) {
+ ElementDescriptor descriptor;
+ if (getFolderType() == ResourceFolderType.ANIM) {
+ descriptor = data.getAnimDescriptors().getElementDescriptor(mRootTag);
+ } else {
+ descriptor = data.getAnimatorDescriptors().getElementDescriptor(mRootTag);
+ }
+ // Replace top level node now that we know the actual type
+
+ // Disconnect from old
+ mUiRootNode.setEditor(null);
+ mUiRootNode.setXmlDocument(null);
+
+ // Create new
+ mUiRootNode = descriptor.createUiNode();
+ mUiRootNode.setXmlDocument(xmlDoc);
+ mUiRootNode.setEditor(this);
+ }
+ }
+
+ if (mUiRootNode.getDescriptor() instanceof DocumentDescriptor) {
+ mUiRootNode.loadFromXmlNode(xmlDoc);
+ } else {
+ mUiRootNode.loadFromXmlNode(rootElement);
+ }
+
+ super.xmlModelChanged(xmlDoc);
+ }
+
+ @Override
+ protected void initUiRootNode(boolean force) {
+ // The manifest UI node is always created, even if there's no corresponding XML node.
+ if (mUiRootNode == null || force) {
+ ElementDescriptor descriptor;
+ boolean reload = false;
+ AndroidTargetData data = getTargetData();
+ if (data == null) {
+ descriptor = new DocumentDescriptor("temp", null /*children*/);
+ } else {
+ if (getFolderType() == ResourceFolderType.ANIM) {
+ descriptor = data.getAnimDescriptors().getElementDescriptor(mRootTag);
+ } else {
+ descriptor = data.getAnimatorDescriptors().getElementDescriptor(mRootTag);
+ }
+ reload = true;
+ }
+ mUiRootNode = descriptor.createUiNode();
+ mUiRootNode.setEditor(this);
+
+ if (reload) {
+ onDescriptorsChanged();
+ }
+ }
+ }
+
+ private ResourceFolderType getFolderType() {
+ IFile inputFile = getInputFile();
+ if (inputFile != null) {
+ String folderName = inputFile.getParent().getName();
+ return ResourceFolderType.getFolderType(folderName);
+ }
+ return ResourceFolderType.ANIMATOR;
+ }
+
+ private void onDescriptorsChanged() {
+ IStructuredModel model = getModelForRead();
+ if (model != null) {
+ try {
+ Node node = getXmlDocument(model).getDocumentElement();
+ mUiRootNode.reloadFromXmlNode(node);
+ } finally {
+ model.releaseFromRead();
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java
new file mode 100644
index 000000000..87a145bc7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationSourceViewerConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.animator;
+
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig;
+
+/**
+ * Source Viewer Configuration for animation files.
+ */
+public class AnimationSourceViewerConfig extends AndroidSourceViewerConfig {
+
+ public AnimationSourceViewerConfig() {
+ super(new AnimationContentAssist());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java
new file mode 100644
index 000000000..644aebb64
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimatorDescriptors.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.animator;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
+
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
+import com.android.sdklib.SdkConstants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Descriptors for /res/animator XML files.
+ */
+public class AnimatorDescriptors implements IDescriptorProvider {
+ /** The root element descriptor */
+ private ElementDescriptor mDescriptor;
+ /** The root element descriptors */
+ private ElementDescriptor[] mRootDescriptors;
+ private Map<String, ElementDescriptor> nameToDescriptor;
+
+ /** @return the root descriptor. */
+ public ElementDescriptor getDescriptor() {
+ if (mDescriptor == null) {
+ mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
+ }
+
+ return mDescriptor;
+ }
+
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return mRootDescriptors;
+ }
+
+ public ElementDescriptor getElementDescriptor(String mRootTag) {
+ if (nameToDescriptor == null) {
+ nameToDescriptor = new HashMap<String, ElementDescriptor>();
+ for (ElementDescriptor descriptor : getRootElementDescriptors()) {
+ nameToDescriptor.put(descriptor.getXmlName(), descriptor);
+ }
+ }
+
+ ElementDescriptor descriptor = nameToDescriptor.get(mRootTag);
+ if (descriptor == null) {
+ descriptor = getDescriptor();
+ }
+ return descriptor;
+ }
+
+ public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
+ if (styleMap == null) {
+ return;
+ }
+
+ XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
+ SdkConstants.NS_RESOURCES);
+
+ List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>();
+
+ String sdkUrl =
+ "http://developer.android.com/guide/topics/graphics/animation.html"; //$NON-NLS-1$
+
+ ElementDescriptor set = addElement(descriptors, styleMap,
+ "set", "Animator Set", "AnimatorSet", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ ElementDescriptor objectAnimator = addElement(descriptors, styleMap,
+ "objectAnimator", "Object Animator", //$NON-NLS-1$
+ "PropertyAnimator", "Animator", //$NON-NLS-1$ //$NON-NLS-2$
+ null /* tooltip */, sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ ElementDescriptor animator = addElement(descriptors, styleMap,
+ "animator", "Animator", "Animator", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, sdkUrl,
+ xmlns, null, true /*mandatory*/);
+
+ mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]);
+
+ // Allow arbitrary nesting: the children of all of these element can include
+ // any of the others
+ if (objectAnimator != null) {
+ objectAnimator.setChildren(mRootDescriptors);
+ }
+ if (animator != null) {
+ animator.setChildren(mRootDescriptors);
+ }
+ if (set != null) {
+ set.setChildren(mRootDescriptors);
+ }
+ }
+
+ /**
+ * Looks up the given style, and if found creates a new {@link ElementDescriptor}
+ * corresponding to the style. It can optionally take an extra style to merge in
+ * additional attributes from, and an extra attribute to add in as well. The new
+ * element, if it exists, can also be optionally added into a list.
+ *
+ * @param descriptors an optional list to add the element into, or null
+ * @param styleMap The map style => attributes from the attrs.xml file
+ * @param xmlName the XML tag name to use for the element
+ * @param uiName the UI name to display the element as
+ * @param styleName the name of the style which must exist for this style
+ * @param extraStyle an optional extra style to merge in attributes from, or null
+ * @param tooltip the tooltip or documentation for this element, or null
+ * @param sdkUrl an optional SDK url to display for the element, or null
+ * @param extraAttribute an extra attribute to add to the attributes list, or null
+ * @param childrenElements an array of children allowed by this element, or null
+ * @param mandatory if true, this element is mandatory
+ * @return a newly created element, or null if the style does not exist
+ */
+ public static ElementDescriptor addElement(
+ List<ElementDescriptor> descriptors,
+ Map<String, DeclareStyleableInfo> styleMap,
+ String xmlName, String uiName, String styleName, String extraStyle,
+ String tooltip, String sdkUrl,
+ AttributeDescriptor extraAttribute,
+ ElementDescriptor[] childrenElements,
+ boolean mandatory) {
+ DeclareStyleableInfo style = styleMap.get(styleName);
+ if (style == null) {
+ return null;
+ }
+ ElementDescriptor element = new ElementDescriptor(xmlName, uiName, tooltip, sdkUrl,
+ null, childrenElements, mandatory);
+
+ ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
+
+ DescriptorsUtils.appendAttributes(descs,
+ null, // elementName
+ SdkConstants.NS_RESOURCES,
+ style.getAttributes(),
+ null, // requiredAttributes
+ null); // overrides
+ element.setTooltip(style.getJavaDoc());
+
+ if (extraStyle != null) {
+ style = styleMap.get(extraStyle);
+ if (style != null) {
+ DescriptorsUtils.appendAttributes(descs,
+ null, // elementName
+ SdkConstants.NS_RESOURCES,
+ style.getAttributes(),
+ null, // requiredAttributes
+ null); // overrides
+ }
+ }
+
+ if (extraAttribute != null) {
+ descs.add(extraAttribute);
+ }
+
+ element.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
+ if (descriptors != null) {
+ descriptors.add(element);
+ }
+
+ return element;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java
new file mode 100644
index 000000000..15704393e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorContentAssist.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.color;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+
+/**
+ * Content Assist Processor for /res/color XML files
+ */
+@VisibleForTesting
+public final class ColorContentAssist extends AndroidContentAssist {
+ public ColorContentAssist() {
+ super(AndroidTargetData.DESCRIPTOR_COLOR);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java
new file mode 100644
index 000000000..f6e50a8ea
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorDescriptors.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.color;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
+import static com.android.sdklib.SdkConstants.NS_RESOURCES;
+
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
+import com.android.resources.ResourceType;
+import com.android.sdklib.SdkConstants;
+
+import java.util.Map;
+
+/** Descriptors for /res/color XML files */
+public class ColorDescriptors implements IDescriptorProvider {
+ private static final String SDK_URL =
+ "http://d.android.com/guide/topics/resources/color-list-resource.html"; //$NON-NLS-1$
+
+ /** The root element descriptor */
+ private ElementDescriptor mDescriptor = new ElementDescriptor(
+ "selector", "Selector",
+ "Required. This must be the root element. Contains one or more <item> elements.",
+ SDK_URL,
+ new AttributeDescriptor[] { new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
+ NS_RESOURCES) },
+ null /*children: added later*/, true /*mandatory*/);
+
+ /** @return the root descriptor. */
+ public ElementDescriptor getDescriptor() {
+ if (mDescriptor == null) {
+ mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
+ }
+
+ return mDescriptor;
+ }
+
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return new ElementDescriptor[] { mDescriptor };
+ }
+
+ public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
+ if (styleMap == null) {
+ return;
+ }
+
+ // Selector children
+ ElementDescriptor selectorItem = AnimatorDescriptors.addElement(null, styleMap,
+ "item", "Item", "DrawableStates", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "Defines a drawable to use during certain states, as described by "
+ + "its attributes. Must be a child of a <selector> element.",
+ SDK_URL,
+ new ReferenceAttributeDescriptor(
+ ResourceType.COLOR, "color", "color", //$NON-NLS-1$ //$NON-NLS-2$
+ SdkConstants.NS_RESOURCES,
+ "Hexadeximal color. Required. The color is specified with an RGB value and "
+ + "optional alpha channel.\n"
+ + "The value always begins with a pound (#) character and then "
+ + "followed by the Alpha-Red-Green-Blue information in one of "
+ + "the following formats:\n"
+ + "* RGB\n"
+ + "* ARGB\n"
+ + "* RRGGBB\n"
+ + "* AARRGGBB",
+ new AttributeInfo("drawable", new Format[] { Format.COLOR })),
+ null, /* This is wrong -- we can now embed any above drawable
+ (but without xmlns as extra) */
+ false /*mandatory*/);
+
+ if (selectorItem != null) {
+ mDescriptor.setChildren(new ElementDescriptor[] { selectorItem });
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java
new file mode 100644
index 000000000..b0e33271e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditor.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.color;
+
+import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE;
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Editor for /res/color XML files.
+ */
+@SuppressWarnings("restriction")
+public class ColorEditor extends AndroidXmlEditor {
+ public static final String ID = EDITORS_NAMESPACE + ".color.ColorEditor"; //$NON-NLS-1$
+
+ /** Root node of the UI element hierarchy */
+ private UiElementNode mUiRootNode;
+
+ public ColorEditor() {
+ super();
+ }
+
+ @Override
+ public UiElementNode getUiRootNode() {
+ return mUiRootNode;
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ @Override
+ protected void createFormPages() {
+ /* Disabled for now; doesn't work quite right
+ try {
+ addPage(new ColorTreePage(this));
+ } catch (PartInitException e) {
+ AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$
+ AdtPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ */
+ }
+
+ /* (non-java doc)
+ * Change the tab/title name to include the project name.
+ */
+ @Override
+ protected void setInput(IEditorInput input) {
+ super.setInput(input);
+ if (input instanceof FileEditorInput) {
+ FileEditorInput fileInput = (FileEditorInput) input;
+ IFile file = fileInput.getFile();
+ setPartName(String.format("%1$s",
+ file.getName()));
+ }
+ }
+
+ @Override
+ protected void xmlModelChanged(Document xmlDoc) {
+ // create the ui root node on demand.
+ initUiRootNode(false /*force*/);
+
+ Element rootElement = xmlDoc.getDocumentElement();
+ mUiRootNode.loadFromXmlNode(rootElement);
+
+ super.xmlModelChanged(xmlDoc);
+ }
+
+ @Override
+ protected void initUiRootNode(boolean force) {
+ // The manifest UI node is always created, even if there's no corresponding XML node.
+ if (mUiRootNode == null || force) {
+ ElementDescriptor descriptor;
+ AndroidTargetData data = getTargetData();
+ if (data == null) {
+ descriptor = new ColorDescriptors().getDescriptor();
+ } else {
+ descriptor = data.getColorDescriptors().getDescriptor();
+ }
+ mUiRootNode = descriptor.createUiNode();
+ mUiRootNode.setEditor(this);
+ onDescriptorsChanged();
+ }
+ }
+
+ private void onDescriptorsChanged() {
+ IStructuredModel model = getModelForRead();
+ if (model != null) {
+ try {
+ Node node = getXmlDocument(model).getDocumentElement();
+ mUiRootNode.reloadFromXmlNode(node);
+ } finally {
+ model.releaseFromRead();
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java
new file mode 100644
index 000000000..4f12ce571
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorSourceViewerConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.color;
+
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig;
+
+/**
+ * Source Viewer Configuration that calls in ColorContentAssist.
+ */
+public class ColorSourceViewerConfig extends AndroidSourceViewerConfig {
+
+ public ColorSourceViewerConfig() {
+ super(new ColorContentAssist());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java
index d0806c583..f1def3977 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/BooleanAttributeDescriptor.java
@@ -24,11 +24,11 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiListAttributeNode;
* It is displayed by a {@link UiListAttributeNode}.
*/
public class BooleanAttributeDescriptor extends ListAttributeDescriptor {
+ private static final String[] VALUES = new String[] { "true", "false" }; //$NON-NLS-1$ //$NON-NLS-2$
public BooleanAttributeDescriptor(String xmlLocalName, String uiName, String nsUri,
String tooltip, IAttributeInfo attrInfo) {
- super(xmlLocalName, uiName, nsUri, tooltip, attrInfo,
- new String[] { "true", "false" }); //$NON-NLS-1$ //$NON-NLS-2$
+ super(xmlLocalName, uiName, nsUri, tooltip, attrInfo, VALUES);
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java
new file mode 100644
index 000000000..b0bea511d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableContentAssist.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.drawable;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+
+/**
+ * Content Assist Processor for /res/drawable XML files
+ */
+@VisibleForTesting
+public final class DrawableContentAssist extends AndroidContentAssist {
+ public DrawableContentAssist() {
+ super(AndroidTargetData.DESCRIPTOR_DRAWABLE);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java
new file mode 100644
index 000000000..1e71795c4
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableDescriptors.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.drawable;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
+
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ReferenceAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
+import com.android.resources.ResourceType;
+import com.android.sdklib.SdkConstants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Descriptors for /res/drawable files
+ */
+public class DrawableDescriptors implements IDescriptorProvider {
+ private static final String SDK_URL_BASE =
+ "http://d.android.com/guide/topics/resources/"; //$NON-NLS-1$
+
+ /** The root element descriptor */
+ private ElementDescriptor mDescriptor;
+ /** The root element descriptors */
+ private ElementDescriptor[] mRootDescriptors;
+ private Map<String, ElementDescriptor> nameToDescriptor;
+
+ /** @return the root descriptor. */
+ public ElementDescriptor getDescriptor() {
+ if (mDescriptor == null) {
+ mDescriptor = new ElementDescriptor("", getRootElementDescriptors()); //$NON-NLS-1$
+ }
+
+ return mDescriptor;
+ }
+
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return mRootDescriptors;
+ }
+
+ /**
+ * Returns a descriptor for the given root tag name
+ *
+ * @param tag the tag name to look up a descriptor for
+ * @return a descriptor with the given tag name
+ */
+ public ElementDescriptor getElementDescriptor(String tag) {
+ if (nameToDescriptor == null) {
+ nameToDescriptor = new HashMap<String, ElementDescriptor>();
+ for (ElementDescriptor descriptor : getRootElementDescriptors()) {
+ nameToDescriptor.put(descriptor.getXmlName(), descriptor);
+ }
+ }
+
+ ElementDescriptor descriptor = nameToDescriptor.get(tag);
+ if (descriptor == null) {
+ descriptor = getDescriptor();
+ }
+ return descriptor;
+ }
+
+ public synchronized void updateDescriptors(Map<String, DeclareStyleableInfo> styleMap) {
+ XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(ANDROID_NS_NAME,
+ SdkConstants.NS_RESOURCES);
+ Format[] referenceFormat = new Format[] { Format.REFERENCE };
+
+ List<ElementDescriptor> descriptors = new ArrayList<ElementDescriptor>();
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "animation-list", "Animation List", "AnimationDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An animation defined in XML that shows a sequence of images in "
+ + "order (like a film)",
+ SDK_URL_BASE + "animation-resource.html#Frame",
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "animated-rotate", "Animated Rotate", "AnimatedRotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ // Need docs
+ null /* tooltip */,
+ null /* sdk_url */,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "bitmap", "BitMap", "BitmapDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML bitmap is a resource defined in XML that points to a bitmap file. "
+ + "The effect is an alias for a raw bitmap file. The XML can "
+ + "specify additional properties for the bitmap such as "
+ + "dithering and tiling.",
+ SDK_URL_BASE + "drawable-resource.html#Bitmap", //$NON-NLS-1$
+ xmlns, null, true /* mandatory */);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "clip", "Clip", "ClipDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that defines a drawable that clips another Drawable based on "
+ + "this Drawable's current level value.",
+ SDK_URL_BASE + "drawable-resource.html#Clip", //$NON-NLS-1$
+ xmlns, null, true /*mandatory*/);
+
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "color", "Color", "ColorDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "XML resource that carries a color value (a hexadecimal color)",
+ SDK_URL_BASE + "more-resources.html#Color",
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "inset", "Inset", "InsetDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that defines a drawable that insets another drawable by a "
+ + "specified distance. This is useful when a View needs a background "
+ + "drawble that is smaller than the View's actual bounds.",
+ SDK_URL_BASE + "drawable-resource.html#Inset", //$NON-NLS-1$
+ xmlns, null, true /*mandatory*/);
+
+ // Layer list
+
+ // An <item> in a <selector> or <
+ ElementDescriptor layerItem = AnimatorDescriptors.addElement(null, styleMap,
+ "item", "Item", "LayerDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "Defines a drawable to place in the layer drawable, in a position "
+ + "defined by its attributes. Must be a child of a <selector> "
+ + "element. Accepts child <bitmap> elements.",
+ SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$
+ null, /* extra attribute */
+ null, /* This is wrong -- we can now embed any above drawable
+ (but without xmlns as extra) */
+ false /*mandatory*/);
+ ElementDescriptor[] layerChildren = layerItem != null
+ ? new ElementDescriptor[] { layerItem } : null;
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "layer-list", "Layer List", "LayerDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "A Drawable that manages an array of other Drawables. These are drawn in "
+ + "array order, so the element with the largest index is be drawn on top.",
+ SDK_URL_BASE + "drawable-resource.html#LayerList", //$NON-NLS-1$
+ xmlns,
+ layerChildren,
+ true /*mandatory*/);
+
+ // Level list children
+ ElementDescriptor levelListItem = AnimatorDescriptors.addElement(null, styleMap,
+ "item", "Item", "LevelListDrawableItem", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "Defines a drawable to use at a certain level.",
+ SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$
+ null, /* extra attribute */
+ null, /* no further children */
+ // TODO: The inflation code seems to show that all drawables can be nested here!
+ false /*mandatory*/);
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "level-list", "Level List", "LevelListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that defines a drawable that manages a number of alternate "
+ + "Drawables, each assigned a maximum numerical value",
+ SDK_URL_BASE + "drawable-resource.html#LevelList", //$NON-NLS-1$
+ xmlns,
+ levelListItem != null ? new ElementDescriptor[] { levelListItem } : null,
+ true /*mandatory*/);
+
+ // Not yet supported
+ //addElement(descriptors, styleMap, "mipmap", "Mipmap", "MipmapDrawable", null,
+ // null /* tooltip */,
+ // null /* sdk_url */,
+ // xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "nine-patch", "Nine Patch", "NinePatchDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "A PNG file with stretchable regions to allow image resizing "
+ + "based on content (.9.png).",
+ SDK_URL_BASE + "drawable-resource.html#NinePatch", //$NON-NLS-1$
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "rotate", "Rotate", "RotateDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ // Need docs
+ null /* tooltip */,
+ null /* sdk_url */,
+ xmlns, null, true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "scale", "Shape", "ScaleDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that defines a drawable that changes the size of another Drawable "
+ + "based on its current level value.",
+ SDK_URL_BASE + "drawable-resource.html#Scale", //$NON-NLS-1$
+ xmlns, null, true /*mandatory*/);
+
+ // Selector children
+ ElementDescriptor selectorItem = AnimatorDescriptors.addElement(null, styleMap,
+ "item", "Item", "DrawableStates", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "Defines a drawable to use during certain states, as described by "
+ + "its attributes. Must be a child of a <selector> element.",
+ SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$
+ new ReferenceAttributeDescriptor(
+ ResourceType.DRAWABLE, "drawable", "drawable", //$NON-NLS-1$ //$NON-NLS-2$
+ SdkConstants.NS_RESOURCES,
+ "Reference to a drawable resource.",
+ new AttributeInfo("drawable", referenceFormat)),
+ null, /* This is wrong -- we can now embed any above drawable
+ (but without xmlns as extra) */
+ false /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "selector", "Selector", "StateListDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that references different bitmap graphics for different states "
+ + "(for example, to use a different image when a button is pressed).",
+ SDK_URL_BASE + "drawable-resource.html#StateList", //$NON-NLS-1$
+ xmlns,
+ selectorItem != null ? new ElementDescriptor[] { selectorItem } : null,
+ true /*mandatory*/);
+
+ // Shape
+ // Shape children
+ List<ElementDescriptor> shapeChildren = new ArrayList<ElementDescriptor>();
+ // Selector children
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "size", "Size", "GradientDrawableSize", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "gradient", "Gradient", "GradientDrawableGradient", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "solid", "Solid", "GradientDrawableSolid", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "stroke", "Stroke", "GradientDrawableStroke", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "corners", "Corners", "DrawableCorners", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+ AnimatorDescriptors.addElement(shapeChildren, styleMap,
+ "padding", "Padding", "GradientDrawablePadding", null, //$NON-NLS-1$ //$NON-NLS-3$
+ null /* tooltip */, null /* sdk_url */, null /* extra attribute */,
+ null /* children */, false /* mandatory */);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "shape", "Shape", //$NON-NLS-1$
+
+ // The documentation says that a <shape> element creates a ShapeDrawable,
+ // but ShapeDrawable isn't finished and the code currently creates
+ // a GradientDrawable.
+ //"ShapeDrawable", //$NON-NLS-1$
+ "GradientDrawable", //$NON-NLS-1$
+
+ null,
+ "An XML file that defines a geometric shape, including colors and gradients.",
+ SDK_URL_BASE + "drawable-resource.html#Shape", //$NON-NLS-1$
+ xmlns,
+
+ // These are the GradientDrawable children, not the ShapeDrawable children
+ shapeChildren.toArray(new ElementDescriptor[shapeChildren.size()]),
+ true /*mandatory*/);
+
+ AnimatorDescriptors.addElement(descriptors, styleMap,
+ "transition", "Transition", "TransitionDrawable", null, //$NON-NLS-1$ //$NON-NLS-3$
+ "An XML file that defines a drawable that can cross-fade between two "
+ + "drawable resources. Each drawable is represented by an <item> "
+ + "element inside a single <transition> element. No more than two "
+ + "items are supported. To transition forward, call startTransition(). "
+ + "To transition backward, call reverseTransition().",
+ SDK_URL_BASE + "drawable-resource.html#Transition", //$NON-NLS-1$
+ xmlns,
+ layerChildren, // children: a TransitionDrawable is a LayerDrawable
+ true /*mandatory*/);
+
+ mRootDescriptors = descriptors.toArray(new ElementDescriptor[descriptors.size()]);
+
+ // A <selector><item> can contain any of the top level drawables
+ if (selectorItem != null) {
+ selectorItem.setChildren(mRootDescriptors);
+ }
+ // Docs says it can accept <bitmap> but code comment suggests any is possible;
+ // test and either use this or just { bitmap }
+ if (layerItem != null) {
+ layerItem.setChildren(mRootDescriptors);
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java
new file mode 100644
index 000000000..aaaeb4b6d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditor.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.drawable;
+
+import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE;
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Editor for /res/drawable XML files.
+ */
+@SuppressWarnings("restriction")
+public class DrawableEditor extends AndroidXmlEditor {
+ public static final String ID = EDITORS_NAMESPACE + ".drawable.DrawableEditor"; //$NON-NLS-1$
+
+ /** Root node of the UI element hierarchy */
+ private UiElementNode mUiRootNode;
+ /** The tag used at the root */
+ private String mRootTag;
+
+ /**
+ * Creates the form editor for resources XML files.
+ */
+ public DrawableEditor() {
+ super();
+ }
+
+ @Override
+ public UiElementNode getUiRootNode() {
+ return mUiRootNode;
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ @Override
+ protected void createFormPages() {
+ /* Disabled for now; doesn't work quite right
+ try {
+ addPage(new DrawableTreePage(this));
+ } catch (PartInitException e) {
+ AdtPlugin.log(IStatus.ERROR, "Error creating nested page"); //$NON-NLS-1$
+ AdtPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ */
+ }
+
+ @Override
+ protected void setInput(IEditorInput input) {
+ super.setInput(input);
+ if (input instanceof FileEditorInput) {
+ FileEditorInput fileInput = (FileEditorInput) input;
+ IFile file = fileInput.getFile();
+ setPartName(String.format("%1$s",
+ file.getName()));
+ }
+ }
+
+ @Override
+ protected void xmlModelChanged(Document xmlDoc) {
+ Element rootElement = xmlDoc.getDocumentElement();
+ if (rootElement != null) {
+ mRootTag = rootElement.getTagName();
+ }
+
+ initUiRootNode(false /*force*/);
+
+ if (mRootTag != null
+ && !mRootTag.equals(mUiRootNode.getDescriptor().getXmlLocalName())) {
+ AndroidTargetData data = getTargetData();
+ if (data != null) {
+ ElementDescriptor descriptor =
+ data.getDrawableDescriptors().getElementDescriptor(mRootTag);
+ // Replace top level node now that we know the actual type
+
+ // Disconnect from old
+ mUiRootNode.setEditor(null);
+ mUiRootNode.setXmlDocument(null);
+
+ // Create new
+ mUiRootNode = descriptor.createUiNode();
+ mUiRootNode.setXmlDocument(xmlDoc);
+ mUiRootNode.setEditor(this);
+ }
+ }
+
+ if (mUiRootNode.getDescriptor() instanceof DocumentDescriptor) {
+ mUiRootNode.loadFromXmlNode(xmlDoc);
+ } else {
+ mUiRootNode.loadFromXmlNode(rootElement);
+ }
+
+ super.xmlModelChanged(xmlDoc);
+ }
+
+ @Override
+ protected void initUiRootNode(boolean force) {
+ // The manifest UI node is always created, even if there's no corresponding XML node.
+ if (mUiRootNode == null || force) {
+ ElementDescriptor descriptor;
+ boolean reload = false;
+ AndroidTargetData data = getTargetData();
+ if (data == null) {
+ descriptor = new DocumentDescriptor("temp", null /*children*/);
+ } else {
+ descriptor = data.getDrawableDescriptors().getElementDescriptor(mRootTag);
+ reload = true;
+ }
+ mUiRootNode = descriptor.createUiNode();
+ mUiRootNode.setEditor(this);
+
+ if (reload) {
+ onDescriptorsChanged();
+ }
+ }
+ }
+
+ private void onDescriptorsChanged() {
+ IStructuredModel model = getModelForRead();
+ if (model != null) {
+ try {
+ Node node = getXmlDocument(model).getDocumentElement();
+ mUiRootNode.reloadFromXmlNode(node);
+ } finally {
+ model.releaseFromRead();
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java
new file mode 100644
index 000000000..eef6a9e93
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableSourceViewerConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors.drawable;
+
+
+import com.android.ide.eclipse.adt.internal.editors.AndroidSourceViewerConfig;
+
+/**
+ * Source Viewer Configuration for drawable files
+ */
+public class DrawableSourceViewerConfig extends AndroidSourceViewerConfig {
+
+ public DrawableSourceViewerConfig() {
+ super(new DrawableContentAssist());
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
index d19c1e69a..38a5e6b19 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestEditor.java
@@ -16,8 +16,8 @@
package com.android.ide.eclipse.adt.internal.editors.manifest;
-import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java
index 7bc36921c..c07b7be57 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/descriptors/AndroidManifestDescriptors.java
@@ -434,7 +434,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
* <p/>
* Capitalizes the first letter and replace non-alphabet by a space followed by a capital.
*/
- private String getUiName(String xmlName) {
+ private static String getUiName(String xmlName) {
StringBuilder sb = new StringBuilder();
boolean capitalize = true;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java
index 448c27024..166110085 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesContentAssist.java
@@ -30,6 +30,7 @@ import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescrip
import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
@@ -106,6 +107,9 @@ public class ResourcesContentAssist extends AndroidContentAssist {
new HashMap<String, AttributeDescriptor>(180);
for (ElementDescriptor elementDesc : rootElementDescriptors) {
for (AttributeDescriptor desc : elementDesc.getAttributes()) {
+ if (desc instanceof SeparatorAttributeDescriptor) {
+ continue;
+ }
String name = desc.getXmlLocalName();
if (startsWith(name, attributePrefix)) {
matches.put(name, desc);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java
index 53ea51392..83e2d8c0d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/resources/ResourcesEditor.java
@@ -16,8 +16,8 @@
package com.android.ide.eclipse.adt.internal.editors.resources;
-import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors;
@@ -38,7 +38,7 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
/**
- * Multi-page form editor for /res/values and /res/drawable XML files.
+ * Multi-page form editor for /res/values XML files.
*/
public class ResourcesEditor extends AndroidXmlEditor {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java
index c94b6c1fb..2b7f3465c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java
@@ -374,6 +374,8 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
type = "style"; //$NON-NLS-1$
} else if (attribute.equals(LayoutDescriptors.ATTR_LAYOUT)) {
type = "layout"; //$NON-NLS-1$
+ } else if (attribute.equals("drawable")) { //$NON-NLS-1$
+ type = "drawable"; //$NON-NLS-1$
}
if (type != null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java
index 95e3f984a..69f1267b7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java
@@ -21,7 +21,11 @@ import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.sdk.LoadStatus;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors;
import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors;
import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors;
@@ -51,6 +55,10 @@ public class AndroidTargetData {
public final static int DESCRIPTOR_SEARCHABLE = 6;
public final static int DESCRIPTOR_PREFERENCES = 7;
public final static int DESCRIPTOR_APPWIDGET_PROVIDER = 8;
+ public final static int DESCRIPTOR_DRAWABLE = 9;
+ public final static int DESCRIPTOR_ANIMATOR = 10;
+ public final static int DESCRIPTOR_ANIM = 11;
+ public final static int DESCRIPTOR_COLOR = 12;
private final IAndroidTarget mTarget;
@@ -67,6 +75,10 @@ public class AndroidTargetData {
private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
private AndroidManifestDescriptors mManifestDescriptors;
+ private DrawableDescriptors mDrawableDescriptors;
+ private AnimatorDescriptors mAnimatorDescriptors;
+ private AnimDescriptors mAnimDescriptors;
+ private ColorDescriptors mColorDescriptors;
private LayoutDescriptors mLayoutDescriptors;
private MenuDescriptors mMenuDescriptors;
private XmlDescriptors mXmlDescriptors;
@@ -84,14 +96,16 @@ public class AndroidTargetData {
/**
* Creates an AndroidTargetData object.
- * @param platformLibraries
- * @param optionalLibraries
*/
void setExtraData(
AndroidManifestDescriptors manifestDescriptors,
LayoutDescriptors layoutDescriptors,
MenuDescriptors menuDescriptors,
XmlDescriptors xmlDescriptors,
+ DrawableDescriptors drawableDescriptors,
+ AnimatorDescriptors animatorDescriptors,
+ AnimDescriptors animDescriptors,
+ ColorDescriptors colorDescriptors,
Map<String, Map<String, Integer>> enumValueMap,
String[] permissionValues,
String[] activityIntentActionValues,
@@ -104,6 +118,10 @@ public class AndroidTargetData {
LayoutLibrary layoutLibrary) {
mManifestDescriptors = manifestDescriptors;
+ mDrawableDescriptors = drawableDescriptors;
+ mAnimatorDescriptors = animatorDescriptors;
+ mAnimDescriptors = animDescriptors;
+ mColorDescriptors = colorDescriptors;
mLayoutDescriptors = layoutDescriptors;
mMenuDescriptors = menuDescriptors;
mXmlDescriptors = xmlDescriptors;
@@ -142,6 +160,14 @@ public class AndroidTargetData {
return mXmlDescriptors.getAppWidgetProvider();
case DESCRIPTOR_SEARCHABLE:
return mXmlDescriptors.getSearchableProvider();
+ case DESCRIPTOR_DRAWABLE:
+ return mDrawableDescriptors;
+ case DESCRIPTOR_ANIMATOR:
+ return mAnimatorDescriptors;
+ case DESCRIPTOR_ANIM:
+ return mAnimDescriptors;
+ case DESCRIPTOR_COLOR:
+ return mColorDescriptors;
default :
throw new IllegalArgumentException();
}
@@ -155,6 +181,34 @@ public class AndroidTargetData {
}
/**
+ * Returns the drawable descriptors
+ */
+ public DrawableDescriptors getDrawableDescriptors() {
+ return mDrawableDescriptors;
+ }
+
+ /**
+ * Returns the animation descriptors
+ */
+ public AnimDescriptors getAnimDescriptors() {
+ return mAnimDescriptors;
+ }
+
+ /**
+ * Returns the color descriptors
+ */
+ public ColorDescriptors getColorDescriptors() {
+ return mColorDescriptors;
+ }
+
+ /**
+ * Returns the animator descriptors
+ */
+ public AnimatorDescriptors getAnimatorDescriptors() {
+ return mAnimatorDescriptors;
+ }
+
+ /**
* Returns the layout Descriptors.
*/
public LayoutDescriptors getLayoutDescriptors() {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
index 19562e176..19b2e3d0a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
@@ -22,6 +22,10 @@ import com.android.ide.common.resources.platform.AttrsXmlParser;
import com.android.ide.common.resources.platform.DeclareStyleableInfo;
import com.android.ide.common.resources.platform.ViewClassInfo;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors;
+import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors;
import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors;
@@ -83,7 +87,7 @@ public final class AndroidTargetParser {
try {
SubMonitor progress = SubMonitor.convert(monitor,
String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
- 12);
+ 16);
AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
@@ -218,6 +222,39 @@ public final class AndroidTargetParser {
preferenceGroupsInfo);
progress.worked(1);
+ if (progress.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ DrawableDescriptors drawableDescriptors = new DrawableDescriptors();
+ Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList();
+ drawableDescriptors.updateDescriptors(map);
+ progress.worked(1);
+
+ if (progress.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ AnimatorDescriptors animatorDescriptors = new AnimatorDescriptors();
+ animatorDescriptors.updateDescriptors(map);
+ progress.worked(1);
+
+ if (progress.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ AnimDescriptors animDescriptors = new AnimDescriptors();
+ animDescriptors.updateDescriptors(map);
+ progress.worked(1);
+
+ if (progress.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ ColorDescriptors colorDescriptors = new ColorDescriptors();
+ colorDescriptors.updateDescriptors(map);
+ progress.worked(1);
+
// load the framework resources.
ResourceRepository frameworkResources =
ResourceManager.getInstance().loadFrameworkResources(mAndroidTarget);
@@ -236,6 +273,10 @@ public final class AndroidTargetParser {
layoutDescriptors,
menuDescriptors,
xmlDescriptors,
+ drawableDescriptors,
+ animatorDescriptors,
+ animDescriptors,
+ colorDescriptors,
enumValueMap,
permissionValues,
activity_actions.toArray(new String[activity_actions.size()]),
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
index 583202ace..c4f86a657 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
@@ -27,6 +27,7 @@ import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.ide.common.resources.configuration.ResourceQualifier;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
@@ -72,6 +73,11 @@ import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.FileEditorInput;
import java.util.ArrayList;
import java.util.Collections;
@@ -287,6 +293,15 @@ class NewXmlFileCreationPage extends WizardPage {
null, // default attributes
1 // target API level
),
+ new TypeInfo("Drawable", // UI name
+ "An XML file that describes a drawable.", // tooltip
+ ResourceFolderType.DRAWABLE, // folder type
+ AndroidTargetData.DESCRIPTOR_DRAWABLE, // root seed
+ null, // default root
+ SdkConstants.NS_RESOURCES, // xmlns
+ null, // default attributes
+ 1 // target API level
+ ),
new TypeInfo("Menu", // UI name
"An XML file that describes an menu.", // tooltip
ResourceFolderType.MENU, // folder type
@@ -296,6 +311,33 @@ class NewXmlFileCreationPage extends WizardPage {
null, // default attributes
1 // target API level
),
+ new TypeInfo("Color List", // UI name
+ "An XML file that describes a color state list.", // tooltip
+ ResourceFolderType.COLOR, // folder type
+ AndroidTargetData.DESCRIPTOR_COLOR, // root seed
+ null, // default root
+ SdkConstants.NS_RESOURCES, // xmlns
+ null, // default attributes
+ 1 // target API level
+ ),
+ new TypeInfo("Animator", // UI name
+ "An XML file that describes an animator.", // tooltip
+ ResourceFolderType.ANIMATOR, // folder type
+ AndroidTargetData.DESCRIPTOR_ANIMATOR, // root seed
+ "set", // default root
+ SdkConstants.NS_RESOURCES, // xmlns
+ null, // default attributes
+ 11 // target API level
+ ),
+ new TypeInfo("Animation", // UI name
+ "An XML file that describes an animation.", // tooltip
+ ResourceFolderType.ANIM, // folder type
+ AndroidTargetData.DESCRIPTOR_ANIM, // root seed
+ "set", // default root
+ null, // xmlns
+ null, // default attributes
+ 1 // target API level
+ ),
new TypeInfo("AppWidget Provider", // UI name
"An XML file that describes a widget provider.", // tooltip
ResourceFolderType.XML, // folder type
@@ -323,22 +365,6 @@ class NewXmlFileCreationPage extends WizardPage {
null, // default attributes
1 // target API level
),
- new TypeInfo("Animation", // UI name
- "An XML file that describes an animation.", // tooltip
- ResourceFolderType.ANIM, // folder type
- // TODO reuse constants if we ever make an editor with descriptors for animations
- new String[] { // root seed
- "set", //$NON-NLS-1$
- "alpha", //$NON-NLS-1$
- "scale", //$NON-NLS-1$
- "translate", //$NON-NLS-1$
- "rotate" //$NON-NLS-1$
- },
- "set", //$NON-NLS-1$ // default root
- null, // xmlns
- null, // default attributes
- 1 // target API level
- ),
};
/** Number of columns in the grid layout */
@@ -675,7 +701,7 @@ class NewXmlFileCreationPage extends WizardPage {
};
int n = sTypes.length;
- int num_lines = (n + NUM_COL/2) / NUM_COL;
+ int num_lines = (n + (NUM_COL - 1)) / NUM_COL;
for (int line = 0, k = 0; line < num_lines; line++) {
for (int i = 0; i < NUM_COL; i++, k++) {
if (k < n) {
@@ -837,6 +863,25 @@ class NewXmlFileCreationPage extends WizardPage {
}
if (targetProject == null) {
+ // Try to figure out the project from the active editor
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if (page != null) {
+ IEditorPart activeEditor = page.getActiveEditor();
+ if (activeEditor instanceof AndroidXmlEditor) {
+ Object input = ((AndroidXmlEditor) activeEditor).getEditorInput();
+ if (input instanceof FileEditorInput) {
+ FileEditorInput fileInput = (FileEditorInput) input;
+ targetScore = 1;
+ targetProject = fileInput.getFile().getProject();
+ }
+ }
+ }
+ }
+ }
+
+ if (targetProject == null) {
// If we didn't find a default project based on the selection, check how many
// open Android projects we can find in the current workspace. If there's only
// one, we'll just select it by default.
@@ -1073,19 +1118,6 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
- // For now, treat a selection of /res/animator as /res/anim/,
- // though we need to handle this better
- // TODO: Properly support ANIMATOR templates!
- if (!selected && folderName.equals(AndroidConstants.FD_RES_ANIMATOR)) {
- for (TypeInfo type : sTypes) {
- if (type.getResFolderType() == ResourceFolderType.ANIM) {
- matches.add(type);
- selected |= type.getWidget().getSelection();
- break;
- }
- }
- }
-
if (matches.size() == 1) {
// If there's only one match, select it if it's not already selected
if (!selected) {