aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2010-11-21 21:37:20 -0800
committerTor Norbye <tnorbye@google.com>2010-11-23 15:51:38 -0800
commit99fd7eee15c89fd45b884842c44371326f851930 (patch)
tree3c11ac8c5545459ded392ab0a440ee245f267a1b /eclipse/plugins/com.android.ide.eclipse.adt/src/com
parent9bff2af74a7d6c4034152e76e90993160b14c458 (diff)
downloadsdk-99fd7eee15c89fd45b884842c44371326f851930.zip
sdk-99fd7eee15c89fd45b884842c44371326f851930.tar.gz
sdk-99fd7eee15c89fd45b884842c44371326f851930.tar.bz2
Open included layout on double click
On double click, if the clicked area originates from an <include>'ed XML file, open the included layout in the editor. Also opens files in the @android: namespace if available, for example if you inculde @android:layout/select_dialog_multichoice. Change-Id: I215c411257717f7b97e7b0ee1d5498c318cdb04d
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java9
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java9
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java8
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java89
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java87
7 files changed, 224 insertions, 11 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
index a4d528c..a5d772c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
@@ -43,7 +43,7 @@ public class TableLayoutRule extends LinearLayoutRule {
}
@Override
- public void onChildInserted(INode node, INode parent, InsertType insertType) {
+ public void onChildInserted(INode child, INode parent, InsertType insertType) {
// Overridden to inhibit the setting of layout_width/layout_height since
// it should always be match_parent
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java
index 7dc9169..74e86a0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java
@@ -103,6 +103,15 @@ public class LayoutEditor extends AndroidXmlEditor implements IShowEditorInput,
}
/**
+ * Returns the {@link GraphicalEditorPart} associated with this editor
+ *
+ * @return the {@link GraphicalEditorPart} associated with this editor
+ */
+ public GraphicalEditorPart getGraphicalEditor() {
+ return mGraphicalEditor;
+ }
+
+ /**
* @return The root node of the UI element hierarchy
*/
@Override
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
index 2021533..903e030 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
@@ -47,6 +47,13 @@ public final class LayoutDescriptors implements IDescriptorProvider {
*/
public static final String VIEW_INCLUDE = "include"; //$NON-NLS-1$
+ /**
+ * The attribute name of the include tag's url naming the resource to be inserted
+ * <p>
+ * <b>NOTE</b>: The layout attribute is NOT in the Android namespace!
+ */
+ public static final String ATTR_LAYOUT = "layout"; //$NON-NLS-1$
+
// Public attributes names, attributes descriptors and elements descriptors
public static final String ID_ATTR = "id"; //$NON-NLS-1$
@@ -293,7 +300,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
null, //elementXmlName
null, //nsUri
new AttributeInfo(
- "layout", //$NON-NLS-1$
+ ATTR_LAYOUT,
new Format[] { Format.REFERENCE } ),
true, //required
null); //overrides
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
index 303c58d..cc2c489 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import com.android.ide.common.api.Rect;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.UiElementPullParser;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
@@ -28,6 +29,7 @@ import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.IPropertySource;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.ArrayList;
@@ -370,4 +372,33 @@ public class CanvasViewInfo implements IPropertySource {
return e;
}
+ /**
+ * Returns the layout url attribute value for the closest surrounding include element
+ * parent, or null if this {@link CanvasViewInfo} is not rendered as part of an
+ * include tag.
+ *
+ * @return the layout url attribute value for the surrounding include tag, or null if
+ * not applicable
+ */
+ public String getIncludeUrl() {
+ CanvasViewInfo curr = this;
+ while (curr != null) {
+ if (curr.mUiViewNode != null) {
+ Node node = curr.mUiViewNode.getXmlNode();
+ if (node != null && node.getNamespaceURI() == null
+ && node.getNodeType() == Node.ELEMENT_NODE
+ && LayoutDescriptors.VIEW_INCLUDE.equals(node.getNodeName())) {
+ // Note: the layout attribute is NOT in the Android namespace
+ Element element = (Element) node;
+ String url = element.getAttribute(LayoutDescriptors.ATTR_LAYOUT);
+ if (url.length() > 0) {
+ return url;
+ }
+ }
+ }
+ curr = curr.mParent;
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
index 585f354..cb947d2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
@@ -336,7 +336,13 @@ public class GestureManager {
// in rapid succession. In any case, we only want to let you double click the
// first button to warp to XML:
if (e.button == 1) {
- mCanvas.showXml(e);
+ // Warp to the text editor and show the corresponding XML for the
+ // double-clicked widget
+ LayoutPoint p = ControlPoint.create(mCanvas, e).toLayout();
+ CanvasViewInfo vi = mCanvas.getViewHierarchy().findViewInfoAt(p);
+ if (vi != null) {
+ mCanvas.show(vi);
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 55d296d..22a1a88 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -64,9 +64,11 @@ import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.draw2d.geometry.Rectangle;
@@ -1605,6 +1607,93 @@ public class GraphicalEditorPart extends EditorPart
styledText.setStyleRange(sr);
}
+ /**
+ * Looks up the resource file corresponding to the given type
+ *
+ * @param type The type of resource to look up, such as {@link ResourceType#LAYOUT}
+ * @param name The name of the resource (not including ".xml")
+ * @param isFrameworkResource if true, the resource is a framework resource, otherwise
+ * it's a project resource
+ * @return the resource file defining the named resource, or null if not found
+ */
+ public IPath findResourceFile(ResourceType type, String name, boolean isFrameworkResource) {
+ // FIXME: This code does not handle theme value resolution.
+ // There is code to handle this, but it's in layoutlib; we should
+ // expose that and use it here.
+
+ Map<String, Map<String, IResourceValue>> map;
+ map = isFrameworkResource ? mConfiguredFrameworkRes : mConfiguredProjectRes;
+ if (map == null) {
+ // Not yet configured
+ return null;
+ }
+
+ Map<String, IResourceValue> layoutMap = map.get(type.getName());
+ if (layoutMap != null) {
+ IResourceValue value = layoutMap.get(name);
+ if (value != null) {
+ String valueStr = value.getValue();
+ if (valueStr.startsWith("?")) { //$NON-NLS-1$
+ // FIXME: It's a reference. We should resolve this properly.
+ return null;
+ }
+ return new Path(valueStr);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Looks up the path to the file corresponding to the given attribute value, such as
+ * @layout/foo, which will return the foo.xml file in res/layout/. (The general format
+ * of the resource url is {@literal @[<package_name>:]<resource_type>/<resource_name>}.
+ *
+ * @param url the attribute url
+ * @return the path to the file defining this attribute, or null if not found
+ */
+ public IPath findResourceFile(String url) {
+ if (!url.startsWith("@")) { //$NON-NLS-1$
+ return null;
+ }
+ int typeEnd = url.indexOf('/', 1);
+ if (typeEnd == -1) {
+ return null;
+ }
+ int nameBegin = typeEnd + 1;
+ int typeBegin = 1;
+ int colon = url.lastIndexOf(':', typeEnd);
+ boolean isFrameworkResource = false;
+ if (colon != -1) {
+ // The URL contains a package name.
+
+ // FIXME: We should consult the package and Do The Right Thing.
+ // If the package is @android (which is by far the most common case),
+ // then maybe we can look up the corresponding file in the "data/" folder
+ // in the SDK.
+ // Otherwise, the package MAY be the same package as the current project,
+ // in which case we can just ignore it (because it will be exactly
+ // relative to the current project's folder), and otherwise we may
+ // have to look in other projects. Fortunately, this is not common.
+
+ String packageName = url.substring(typeBegin, colon);
+ if ("android".equals(packageName)) { //$NON-NLS-1$
+ isFrameworkResource = true;
+ }
+
+ typeBegin = colon + 1;
+ }
+
+ String typeName = url.substring(typeBegin, typeEnd);
+ ResourceType type = ResourceType.getEnum(typeName);
+ if (type == null) {
+ return null;
+ }
+
+ String name = url.substring(nameBegin);
+ return findResourceFile(type, name, isFrameworkResource);
+ }
+
/** This StyleRange represents a missing class link that the user can click */
private static class ClassLinkStyleRange extends StyleRange {}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
index 8a7dd7a..c0e69b1 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
@@ -31,11 +31,19 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.layoutlib.api.LayoutScene;
import com.android.sdklib.SdkConstants;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
@@ -63,10 +71,14 @@ import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ContributionItemFactory;
import org.eclipse.ui.actions.TextActionHandler;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.w3c.dom.Node;
@@ -671,18 +683,77 @@ class LayoutCanvas extends Canvas {
}
/**
- * Show the XML element corresponding to the point under the mouse event
- * (unless it's a root).
+ * Shows the given {@link CanvasViewInfo}, which can mean exposing its XML or if it's
+ * an included element, its corresponding file.
*
- * @param e A mouse event pointing on the screen whose underlying XML
- * element we want to view
+ * @param vi the {@link CanvasViewInfo} to be shown
*/
- public void showXml(MouseEvent e) {
+ public void show(CanvasViewInfo vi) {
+ String url = vi.getIncludeUrl();
+ if (url != null) {
+ showInclude(url);
+ } else {
+ showXml(vi);
+ }
+ }
+
+ /**
+ * Shows the layout file referenced by the given url in the same project.
+ *
+ * @param url The layout attribute url of the form @layout/foo
+ */
+ private void showInclude(String url) {
+ GraphicalEditorPart graphicalEditor = mLayoutEditor.getGraphicalEditor();
+ IPath filePath = graphicalEditor.findResourceFile(url);
+
+ IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot();
+ IPath workspacePath = workspace.getLocation();
+ IEditorSite editorSite = graphicalEditor.getEditorSite();
+ if (workspacePath.isPrefixOf(filePath)) {
+ IPath relativePath = filePath.makeRelativeTo(workspacePath);
+ IResource xmlFile = workspace.findMember(relativePath);
+ try {
+ EditorUtility.openInEditor(xmlFile, true);
+ return;
+ } catch (PartInitException ex) {
+ AdtPlugin.log(ex, "Can't open %$1s", url); //$NON-NLS-1$
+ }
+ } else {
+ // It's not a path in the workspace; look externally
+ // (this is probably an @android: path)
+ if (filePath.isAbsolute()) {
+ IFileStore fileStore = EFS.getLocalFileSystem().getStore(filePath);
+ // fileStore = fileStore.getChild(names[i]);
+ if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) {
+ IWorkbenchPage page = editorSite.getWorkbenchWindow().getActivePage();
+ try {
+ IDE.openEditorOnFileStore(page, fileStore);
+ return;
+ } catch (PartInitException ex) {
+ AdtPlugin.log(ex, "Can't open %$1s", url); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ // Failed: display message to the user
+ String message = String.format("Could not find resource %1$s", url);
+ IStatusLineManager status = editorSite.getActionBars().getStatusLineManager();
+ status.setErrorMessage(message);
+ getDisplay().beep();
+ }
+
+ /**
+ * Show the XML element corresponding to the given {@link CanvasViewInfo} (unless it's
+ * a root).
+ *
+ * @param vi The clicked {@link CanvasViewInfo} whose underlying XML element we want
+ * to view
+ */
+ private void showXml(CanvasViewInfo vi) {
// Warp to the text editor and show the corresponding XML for the
// double-clicked widget
- LayoutPoint p = ControlPoint.create(this, e).toLayout();
- CanvasViewInfo vi = mViewHierarchy.findViewInfoAt(p);
- if (vi == null || vi.isRoot()) {
+ if (vi.isRoot()) {
return;
}