aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/dictionary.txt1
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java17
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java14
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java236
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java153
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java13
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java13
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java172
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java63
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java11
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/baseline.pngbin0 -> 602 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/distribute.pngbin0 -> 460 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillheight.pngbin0 -> 483 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillwidth.pngbin0 -> 476 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/gravity.pngbin0 -> 563 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/hlinear.pngbin0 -> 403 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/margins.pngbin0 -> 503 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/vlinear.pngbin0 -> 369 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/weights.pngbin0 -> 520 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java32
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java228
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java253
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java14
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutActionBar.java461
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java59
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java5
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/MarginChooser.java212
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java6
35 files changed, 1518 insertions, 531 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index 83fcce5..bb8efd9 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -195,6 +195,7 @@ textfields
thematically
themed
tmp
+toolbar
tooltip
tooltips
traceview
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
index 4f91552..efd8086 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java
@@ -115,8 +115,23 @@ public interface IClientRulesEngine {
* @param currentValue the current reference to select
* @param resourceTypeName resource type, such as "id", "string", and so on (never
* null)
- * @return the resource selected by the user, or null
+ * @return the margins selected by the user in the same order as the input arguments,
+ * or null
*/
String displayResourceInput(String resourceTypeName, String currentValue);
+
+ /**
+ * Displays an input dialog tailored for editing margin properties.
+ *
+ * @param all The current, initial value display for "all" margins (applied to all
+ * sides)
+ * @param left The current, initial value to display for the "left" margin
+ * @param right The current, initial value to display for the "right" margin
+ * @param top The current, initial value to display for the "top" margin
+ * @param bottom The current, initial value to display for the "bottom" margin
+ * @return an array of length 5 containing the user entered values for the all, left,
+ * right, top and bottom margins respectively
+ */
+ String[] displayMarginInput(String all, String left, String right, String top, String bottom);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java
index fba22ba..3a28896 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java
@@ -95,6 +95,20 @@ public interface IViewRule {
*/
List<MenuAction> getContextMenu(INode node);
+ /**
+ * Invoked by the Rules Engine to ask the parent layout for the set of layout actions
+ * to display in the layout bar. The layout rule should add these into the provided
+ * list. The order the items are added in does not matter; the
+ * {@link MenuAction#getSortPriority()} values will be used to sort the actions prior
+ * to display, which makes it easier for parent rules and deriving rules to interleave
+ * their respective actions.
+ *
+ * @param actions the list of actions to add newly registered actions into
+ * @param parentNode the parent of the selection, or the selection itself if the root
+ * @param targets the targeted/selected nodes, if any
+ */
+ void addLayoutActions(List<MenuAction> actions,
+ INode parentNode, List<? extends INode> targets);
// ==== Selection ====
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java
index e4d7ebf..e54ae36 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java
@@ -18,6 +18,9 @@ package com.android.ide.common.api;
import com.android.annotations.Nullable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
/**
@@ -48,7 +51,7 @@ import java.util.Map;
* to adjust your code for the next tools release.</b>
* </p>
*/
-public abstract class MenuAction {
+public abstract class MenuAction implements Comparable<MenuAction> {
/**
* The unique id of the action.
@@ -60,6 +63,84 @@ public abstract class MenuAction {
*/
private final String mTitle;
+ /** A URL pointing to an icon, or null */
+ private URL mIconUrl;
+
+ /**
+ * The sorting priority of this item; actions can be sorted according to these
+ */
+ protected int mSortPriority;
+
+ // Factories
+
+ public static MenuAction createSeparator() {
+ return new Separator(sNextSortPriority++);
+ }
+
+ public static MenuAction createSeparator(int sortPriority) {
+ return new Separator(sortPriority);
+ }
+
+
+ public static MenuAction createAction(String id, String title, String groupId,
+ IMenuCallback callback) {
+ MenuAction.Action action = new MenuAction.Action(id, title, groupId, callback);
+ action.setSortPriority(sNextSortPriority++);
+ return action;
+ }
+
+ public static MenuAction createAction(String id, String title, String groupId,
+ IMenuCallback callback, URL iconUrl, int sortPriority) {
+ MenuAction action = new MenuAction.Action(id, title, groupId, callback);
+ action.setIconUrl(iconUrl);
+ action.setSortPriority(sortPriority);
+ return action;
+ }
+
+ public static MenuAction createToggle(String id, String title, boolean isChecked,
+ IMenuCallback callback) {
+ Toggle action = new Toggle(id, title, isChecked, callback);
+ action.setSortPriority(sNextSortPriority++);
+ return action;
+ }
+
+ public static MenuAction createToggle(String id, String title, boolean isChecked,
+ IMenuCallback callback, URL iconUrl, int sortPriority) {
+ Toggle toggle = new Toggle(id, title, isChecked, callback);
+ toggle.setIconUrl(iconUrl);
+ toggle.setSortPriority(sortPriority);
+ return toggle;
+ }
+
+ public static MenuAction createChoices(String id, String title, String groupId,
+ IMenuCallback callback, List<String> titles, List<URL> iconUrls, List<String> ids,
+ String current) {
+ OrderedChoices action = new OrderedChoices(id, title, groupId, callback, titles, iconUrls,
+ ids, current);
+ action.setSortPriority(sNextSortPriority++);
+ return action;
+ }
+
+ public static MenuAction createChoices(String id, String title, String groupId,
+ IMenuCallback callback, List<String> titles, List<URL> iconUrls, List<String> ids,
+ String current, URL iconUrl, int sortPriority) {
+ OrderedChoices choices = new OrderedChoices(id, title, groupId, callback, titles, iconUrls,
+ ids, current);
+ choices.setIconUrl(iconUrl);
+ choices.setSortPriority(sortPriority);
+ return choices;
+ }
+
+ public static MenuAction createChoices(String id, String title, String groupId,
+ IMenuCallback callback, ChoiceProvider provider,
+ String current, URL iconUrl, int sortPriority) {
+ OrderedChoices choices = new DelayedOrderedChoices(id, title, groupId, callback,
+ current, provider);
+ choices.setIconUrl(iconUrl);
+ choices.setSortPriority(sortPriority);
+ return choices;
+ }
+
/**
* Creates a new {@link MenuAction} with the given id and the given title.
* Actions which have the same id and the same title are deemed equivalent.
@@ -117,6 +198,53 @@ public abstract class MenuAction {
}
/**
+ * Gets a URL pointing to an icon to use for this action, if any.
+ *
+ * @return a URL pointing to an icon to use for this action, or null
+ */
+ public URL getIconUrl() {
+ return mIconUrl;
+ }
+
+ /**
+ * Sets a URL pointing to an icon to use for this action, if any.
+ *
+ * @param iconUrl a URL pointing to an icon to use for this action, or null
+ */
+ public void setIconUrl(URL iconUrl) {
+ mIconUrl = iconUrl;
+ }
+
+ /**
+ * Sets a priority used for sorting this action
+ *
+ * @param sortPriority a priority used for sorting this action
+ */
+ public void setSortPriority(int sortPriority) {
+ mSortPriority = sortPriority;
+ }
+
+ private static int sNextSortPriority = 0;
+
+ /**
+ * Return a priority used for sorting this action
+ *
+ * @return a priority used for sorting this action
+ */
+ public int getSortPriority() {
+ return mSortPriority;
+ }
+
+ // Implements Comparable<MenuAciton>
+ public int compareTo(MenuAction other) {
+ if (mSortPriority != other.mSortPriority) {
+ return mSortPriority - other.mSortPriority;
+ }
+
+ return mTitle.compareTo(other.mTitle);
+ }
+
+ /**
* A group of actions, displayed in a sub-menu.
* <p/>
* Note that group can be seen as a "group declaration": the group does not hold a list
@@ -223,6 +351,15 @@ public abstract class MenuAction {
}
}
+ /** A separator to display between actions */
+ public static class Separator extends MenuAction {
+ /** Construct using the factory {@link #createSeparator(int)} */
+ private Separator(int sortPriority) {
+ super("_separator", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ mSortPriority = sortPriority;
+ }
+ }
+
/**
* A toggle is a simple on/off action, displayed as an item in a context menu
* with a check mark if the item is checked.
@@ -234,7 +371,7 @@ public abstract class MenuAction {
/**
* True if the item is displayed with a check mark.
*/
- final private boolean mIsChecked;
+ private final boolean mIsChecked;
/**
* Creates a new immutable toggle action.
@@ -293,6 +430,100 @@ public abstract class MenuAction {
}
/**
+ * Like {@link Choices}, but with an explicit ordering among the children, and with
+ * optional icons on each child choice
+ */
+ public static class OrderedChoices extends Action {
+ protected List<String> mTitles;
+ protected List<URL> mIconUrls;
+ protected List<String> mIds;
+
+ /**
+ * One or more id for the checked choice(s) that will be check marked.
+ * Can be null. Can be an id not present in the choices map.
+ */
+ protected final String mCurrent;
+
+ public OrderedChoices(String id, String title, String groupId, IMenuCallback callback,
+ List<String> titles, List<URL> iconUrls, List<String> ids, String current) {
+ super(id, title, groupId, callback);
+ mTitles = titles;
+ mIconUrls = iconUrls;
+ mIds = ids;
+ mCurrent = current;
+ }
+
+ public List<URL> getIconUrls() {
+ return mIconUrls;
+ }
+
+ public List<String> getIds() {
+ return mIds;
+ }
+
+ public List<String> getTitles() {
+ return mTitles;
+ }
+
+ public String getCurrent() {
+ return mCurrent;
+ }
+ }
+
+ /** Provides the set of choices associated with an {@link OrderedChoices} object
+ when they are needed. Useful for lazy initialization of context menus and popup menus
+ until they are actually needed. */
+ public interface ChoiceProvider {
+ /**
+ * Adds in the needed titles, iconUrls (if any) and ids.
+ *
+ * @param titles a list of titles that the provider should append to
+ * @param iconUrls a list of icon URLs that the provider should append to
+ * @param ids a list of ids that the provider should append to
+ */
+ public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids);
+ }
+
+ /** Like {@link OrderedChoices}, but the set of choices is computed lazily */
+ private static class DelayedOrderedChoices extends OrderedChoices {
+ private final ChoiceProvider mProvider;
+
+ public DelayedOrderedChoices(String id, String title, String groupId,
+ IMenuCallback callback, String current, ChoiceProvider provider) {
+ super(id, title, groupId, callback, null, null, null, current);
+ mProvider = provider;
+ }
+
+ private void ensureInitialized() {
+ if (mTitles == null) {
+ mTitles = new ArrayList<String>();
+ mIconUrls = new ArrayList<URL>();
+ mIds = new ArrayList<String>();
+
+ mProvider.addChoices(mTitles, mIconUrls, mIds);
+ }
+ }
+
+ @Override
+ public List<URL> getIconUrls() {
+ ensureInitialized();
+ return mIconUrls;
+ }
+
+ @Override
+ public List<String> getIds() {
+ ensureInitialized();
+ return mIds;
+ }
+
+ @Override
+ public List<String> getTitles() {
+ ensureInitialized();
+ return mTitles;
+ }
+ }
+
+ /**
* A "choices" is a one-out-of-many-choices action, displayed as a sub-menu with one or more
* items, with either zero or more of them being checked.
* <p/>
@@ -309,6 +540,7 @@ public abstract class MenuAction {
* Special value which will insert a separator in the choices' submenu.
*/
public final static String SEPARATOR = "----";
+
/**
* Character used to split multiple checked choices, see {@link #getCurrent()}.
* The pipe character "|" is used, to natively match Android resource flag separators.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
index 91110cb..a33594c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
@@ -18,13 +18,24 @@ package com.android.ide.common.layout;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_MARGIN;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_MARGIN_BOTTOM;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_MARGIN_LEFT;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_MARGIN_RIGHT;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_MARGIN_TOP;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT;
+import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT;
+import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT;
+import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
import com.android.ide.common.api.DropFeedback;
import com.android.ide.common.api.IAttributeInfo;
-import com.android.ide.common.api.IClientRulesEngine;
import com.android.ide.common.api.IDragElement;
import com.android.ide.common.api.IGraphics;
+import com.android.ide.common.api.IMenuCallback;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.MenuAction;
@@ -32,9 +43,12 @@ import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.IAttributeInfo.Format;
import com.android.ide.common.api.IDragElement.IDragAttribute;
+import com.android.ide.common.api.MenuAction.ChoiceProvider;
import com.android.util.Pair;
+import java.net.URL;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -42,20 +56,141 @@ import java.util.Map;
import java.util.Set;
public class BaseLayoutRule extends BaseViewRule {
+ private static final String ACTION_FILL_WIDTH = "_fillW"; //$NON-NLS-1$
+ private static final String ACTION_FILL_HEIGHT = "_fillH"; //$NON-NLS-1$
+ private static final String ACTION_MARGIN = "_margin"; //$NON-NLS-1$
+ private static final URL ICON_MARGINS =
+ BaseLayoutRule.class.getResource("margins.png"); //$NON-NLS-1$
+ private static final URL ICON_GRAVITY =
+ BaseLayoutRule.class.getResource("gravity.png"); //$NON-NLS-1$
+ private static final URL ICON_FILL_WIDTH =
+ BaseLayoutRule.class.getResource("fillwidth.png"); //$NON-NLS-1$
+ private static final URL ICON_FILL_HEIGHT =
+ BaseLayoutRule.class.getResource("fillheight.png"); //$NON-NLS-1$
+
+ // ==== Layout Actions support ====
+
+ // The Margin layout parameters are available for LinearLayout, FrameLayout, RelativeLayout,
+ // and their subclasses.
+ protected MenuAction createMarginAction(final INode parentNode,
+ final List<? extends INode> children) {
+
+ final List<? extends INode> targets = children == null || children.size() == 0 ?
+ Collections.singletonList(parentNode)
+ : children;
+ final INode first = targets.get(0);
+
+ IMenuCallback actionCallback = new IMenuCallback() {
+ public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ parentNode.editXml("Change Margins", new INodeHandler() {
+ public void handle(INode n) {
+ String uri = ANDROID_URI;
+ String all = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN);
+ String left = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN_LEFT);
+ String right = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN_RIGHT);
+ String top = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN_TOP);
+ String bottom = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN_BOTTOM);
+ String[] margins = mRulesEngine.displayMarginInput(all, left,
+ right, top, bottom);
+ if (margins != null) {
+ assert margins.length == 5;
+ for (INode child : targets) {
+ child.setAttribute(uri, ATTR_LAYOUT_MARGIN, margins[0]);
+ child.setAttribute(uri, ATTR_LAYOUT_MARGIN_LEFT, margins[1]);
+ child.setAttribute(uri, ATTR_LAYOUT_MARGIN_RIGHT, margins[2]);
+ child.setAttribute(uri, ATTR_LAYOUT_MARGIN_TOP, margins[3]);
+ child.setAttribute(uri, ATTR_LAYOUT_MARGIN_BOTTOM, margins[4]);
+ }
+ }
+ }
+ });
+ }
+ };
- @Override
- public boolean onInitialize(String fqcn, IClientRulesEngine engine) {
- return super.onInitialize(fqcn, engine);
+ return MenuAction.createAction(ACTION_MARGIN, "Change Margins...", null, actionCallback,
+ ICON_MARGINS, 40);
}
- @Override
- public void onDispose() {
- super.onDispose();
+ // Both LinearLayout and RelativeLayout have a gravity (but RelativeLayout applies it
+ // to the parent whereas for LinearLayout it's on the children)
+ protected MenuAction createGravityAction(final List<? extends INode> targets) {
+ if (targets != null && targets.size() > 0) {
+ final INode first = targets.get(0);
+ ChoiceProvider provider = new ChoiceProvider() {
+ public void addChoices(List<String> titles, List<URL> iconUrls,
+ List<String> ids) {
+ IAttributeInfo info = first.getAttributeInfo(ANDROID_URI, ATTR_LAYOUT_GRAVITY);
+ if (info != null) {
+ // Generate list of possible gravity value constants
+ assert IAttributeInfo.Format.FLAG.in(info.getFormats());
+ for (String name : info.getFlagValues()) {
+ titles.add(prettyName(name));
+ ids.add(name);
+ }
+ }
+ }
+ };
+
+ return MenuAction.createChoices("_gravity", "Change Gravity", //$NON-NLS-1$
+ null,
+ new PropertyCallback(targets, "Change Gravity", ANDROID_URI,
+ ATTR_LAYOUT_GRAVITY),
+ provider,
+ first.getStringAttr(ANDROID_URI, ATTR_LAYOUT_GRAVITY), ICON_GRAVITY,
+ 43);
+ }
+
+ return null;
}
@Override
- public List<MenuAction> getContextMenu(INode selectedNode) {
- return super.getContextMenu(selectedNode);
+ public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ final List<? extends INode> children) {
+ super.addLayoutActions(actions, parentNode, children);
+
+ final List<? extends INode> targets = children == null || children.size() == 0 ?
+ Collections.singletonList(parentNode)
+ : children;
+ final INode first = targets.get(0);
+
+ // Shared action callback
+ IMenuCallback actionCallback = new IMenuCallback() {
+ public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ final String actionId = action.getId();
+ final String undoLabel;
+ if (actionId.equals(ACTION_FILL_WIDTH)) {
+ undoLabel = "Change Width Fill";
+ } else if (actionId.equals(ACTION_FILL_HEIGHT)) {
+ undoLabel = "Change Height Fill";
+ } else {
+ return;
+ }
+ parentNode.editXml(undoLabel, new INodeHandler() {
+ public void handle(INode n) {
+ String attribute = actionId.equals(ACTION_FILL_WIDTH)
+ ? ATTR_LAYOUT_WIDTH : ATTR_LAYOUT_HEIGHT;
+ String value;
+ if (newValue) {
+ if (supportsMatchParent()) {
+ value = VALUE_MATCH_PARENT;
+ } else {
+ value = VALUE_FILL_PARENT;
+ }
+ } else {
+ value = VALUE_WRAP_CONTENT;
+ }
+ for (INode child : targets) {
+ child.setAttribute(ANDROID_URI, attribute, value);
+ }
+ }
+ });
+ }
+ };
+
+ actions.add(MenuAction.createToggle(ACTION_FILL_WIDTH, "Toggle Fill Width",
+ isFilled(first, ATTR_LAYOUT_WIDTH), actionCallback, ICON_FILL_WIDTH, 10));
+ actions.add(MenuAction.createToggle(ACTION_FILL_HEIGHT, "Toggle Fill Height",
+ isFilled(first, ATTR_LAYOUT_HEIGHT), actionCallback, ICON_FILL_HEIGHT, 20));
}
// ==== Paste support ====
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java
index 1b0d2bd..d21c43d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java
@@ -452,6 +452,15 @@ public class BaseViewRule implements IViewRule {
}
/**
+ * Returns true if the given node is "filled" (e.g. has layout width set to match
+ * parent or fill parent
+ */
+ protected boolean isFilled(INode node, String attribute) {
+ String value = node.getStringAttr(ANDROID_URI, attribute);
+ return VALUE_MATCH_PARENT.equals(value) || VALUE_FILL_PARENT.equals(value);
+ }
+
+ /**
* Returns fill_parent or match_parent, depending on whether the minimum supported
* platform supports match_parent or not
*
@@ -534,6 +543,10 @@ public class BaseViewRule implements IViewRule {
return null;
}
+ public void addLayoutActions(List<MenuAction> actions, INode parentNode,
+ List<? extends INode> children) {
+ }
+
// ==== Drag'n'drop support ====
// By default Views do not accept drag'n'drop.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
index 1054c56..0f8fa18 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java
@@ -24,10 +24,12 @@ import com.android.ide.common.api.IGraphics;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.MenuAction;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.util.Pair;
+import java.util.List;
import java.util.Map;
/**
@@ -144,4 +146,15 @@ public class FrameLayoutRule extends BaseLayoutRule {
}
});
}
+
+ @Override
+ public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ final List<? extends INode> children) {
+ super.addLayoutActions(actions, parentNode, children);
+ actions.add(MenuAction.createSeparator(25));
+ actions.add(createMarginAction(parentNode, children));
+ if (children.size() > 0) {
+ actions.add(createGravityAction(children));
+ }
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
index 9342f3c..ef7bba7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
@@ -53,6 +53,14 @@ public class LayoutConstants {
public static final String ATTR_LAYOUT_PREFIX = "layout_"; //$NON-NLS-1$
public static final String ATTR_LAYOUT_HEIGHT = "layout_height"; //$NON-NLS-1$
public static final String ATTR_LAYOUT_WIDTH = "layout_width"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_GRAVITY = "layout_gravity"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_WEIGHT = "layout_weight"; //$NON-NLS-1$
+
+ public static final String ATTR_LAYOUT_MARGIN = "layout_margin"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_LEFT = "layout_marginLeft"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_RIGHT = "layout_marginRight"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_TOP = "layout_marginTop"; //$NON-NLS-1$
+ public static final String ATTR_LAYOUT_MARGIN_BOTTOM = "layout_marginBottom"; //$NON-NLS-1$
public static final String ATTR_LAYOUT_ALIGN_PARENT_TOP = "layout_alignParentTop"; //$NON-NLS-1$
public static final String ATTR_LAYOUT_ALIGN_PARENT_BOTTOM = "layout_alignParentBottom"; //$NON-NLS-1$
@@ -135,6 +143,8 @@ public class LayoutConstants {
// like fill_parent for API 8
public static final String VALUE_MATCH_PARENT = "match_parent"; //$NON-NLS-1$
+ public static final String ATTR_WEIGHT_SUM = "weightSum"; //$NON-NLS-1$
+ public static final String ATTR_BASELINE_ALIGNED = "baselineAligned"; //$NON-NLS-1$
public static String ATTR_ORIENTATION = "orientation"; //$NON-NLS-1$
public static String VALUE_HORIZONTAL = "horizontal"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java
index c098e00..3efa220 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java
@@ -17,9 +17,12 @@
package com.android.ide.common.layout;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_BASELINE_ALIGNED;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WEIGHT;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_WEIGHT_SUM;
import static com.android.ide.common.layout.LayoutConstants.VALUE_HORIZONTAL;
import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL;
@@ -39,7 +42,10 @@ import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.IViewMetadata.FillPreference;
+import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
@@ -47,45 +53,60 @@ import java.util.List;
* classes.
*/
public class LinearLayoutRule extends BaseLayoutRule {
+ private static final String ACTION_ORIENTATION = "_orientation"; //$NON-NLS-1$
+ private static final String ACTION_WEIGHT = "_weight"; //$NON-NLS-1$
+ private static final String ACTION_DISTRIBUTE = "_distribute"; //$NON-NLS-1$
+ private static final String ACTION_BASELINE = "_baseline"; //$NON-NLS-1$
+
+ private static final URL ICON_HORIZONTAL =
+ LinearLayoutRule.class.getResource("hlinear.png"); //$NON-NLS-1$
+ private static final URL ICON_VERTICAL =
+ LinearLayoutRule.class.getResource("vlinear.png"); //$NON-NLS-1$
+ private static final URL ICON_WEIGHTS =
+ LinearLayoutRule.class.getResource("weights.png"); //$NON-NLS-1$
+ private static final URL ICON_DISTRIBUTE =
+ LinearLayoutRule.class.getResource("distribute.png"); //$NON-NLS-1$
+ private static final URL ICON_BASELINE =
+ LinearLayoutRule.class.getResource("baseline.png"); //$NON-NLS-1$
+
/**
* Add an explicit Orientation toggle to the context menu.
*/
@Override
public List<MenuAction> getContextMenu(final INode selectedNode) {
if (supportsOrientation()) {
- String curr_orient = selectedNode.getStringAttr(ANDROID_URI, ATTR_ORIENTATION);
- if (curr_orient == null || curr_orient.length() == 0) {
- curr_orient = VALUE_HORIZONTAL;
- }
-
- IMenuCallback onChange = new IMenuCallback() {
- public void action(MenuAction action, final String valueId, Boolean newValue) {
- String actionId = action.getId();
- final INode node = selectedNode;
-
- if (actionId.equals("_orientation")) { //$NON-NLS-1$
- node.editXml("Change LinearLayout " + ATTR_ORIENTATION, new INodeHandler() {
- public void handle(INode n) {
- node.setAttribute(ANDROID_URI, ATTR_ORIENTATION, valueId);
- }
- });
- }
- }
- };
-
+ String current = getCurrentOrientation(selectedNode);
+ IMenuCallback onChange = new PropertyCallback(Collections.singletonList(selectedNode),
+ "Change LinearLayout Orientation",
+ ANDROID_URI, ATTR_ORIENTATION);
return concatenate(super.getContextMenu(selectedNode),
- new MenuAction.Choices("_orientation", "Orientation", //$NON-NLS-1$
+ new MenuAction.Choices(ACTION_ORIENTATION, "Orientation", //$NON-NLS-1$
mapify(
"horizontal", "Horizontal", //$NON-NLS-1$
"vertical", "Vertical" //$NON-NLS-1$
),
- curr_orient, onChange));
+ current, onChange));
} else {
return super.getContextMenu(selectedNode);
}
}
/**
+ * Returns the current orientation, regardless of whether it has been defined in XML
+ *
+ * @param node The LinearLayout to look up the orientation for
+ * @return "horizontal" or "vertical" depending on the current orientation of the
+ * linear layout
+ */
+ private String getCurrentOrientation(final INode node) {
+ String orientation = node.getStringAttr(ANDROID_URI, ATTR_ORIENTATION);
+ if (orientation == null || orientation.length() == 0) {
+ orientation = VALUE_HORIZONTAL;
+ }
+ return orientation;
+ }
+
+ /**
* Returns true if the given node represents a vertical linear layout.
* @param node the node to check layout orientation for
* @return true if the layout is in vertical mode, otherwise false
@@ -105,6 +126,113 @@ public class LinearLayoutRule extends BaseLayoutRule {
return true;
}
+ @Override
+ public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ final List<? extends INode> children) {
+ super.addLayoutActions(actions, parentNode, children);
+ if (supportsOrientation()) {
+ actions.add(MenuAction.createChoices(
+ ACTION_ORIENTATION, "Orientation", //$NON-NLS-1$
+ null,
+ new PropertyCallback(Collections.singletonList(parentNode),
+ "Change LinearLayout Orientation",
+ ANDROID_URI, ATTR_ORIENTATION),
+ Arrays.<String>asList("Set Horizontal Orientation", "Set Vertical Orientation"),
+ Arrays.<URL>asList(ICON_HORIZONTAL, ICON_VERTICAL),
+ Arrays.<String>asList("horizontal", "vertical"),
+ getCurrentOrientation(parentNode),
+ null /* icon */,
+ -10
+ ));
+ }
+ if (!isVertical(parentNode)) {
+ String current = parentNode.getStringAttr(ANDROID_URI, ATTR_BASELINE_ALIGNED);
+ boolean isAligned = current == null || Boolean.valueOf(current);
+ actions.add(MenuAction.createToggle(null, "Toggle Baseline Alignment",
+ isAligned,
+ new PropertyCallback(Collections.singletonList(parentNode),
+ "Change Baseline Alignment",
+ ANDROID_URI, ATTR_BASELINE_ALIGNED), // TODO: Also set index?
+ ICON_BASELINE, 38));
+ }
+
+ // Gravity
+ if (children != null && children.size() > 0) {
+ actions.add(MenuAction.createSeparator(35));
+
+ // Margins
+ actions.add(createMarginAction(parentNode, children));
+
+ // Gravity
+ actions.add(createGravityAction(children));
+
+ // Weights
+ IMenuCallback actionCallback = new IMenuCallback() {
+ public void action(final MenuAction action, final String valueId,
+ final Boolean newValue) {
+ parentNode.editXml("Change Weight", new INodeHandler() {
+ public void handle(INode n) {
+ if (action.getId().equals(ACTION_WEIGHT)) {
+ String weight =
+ children.get(0).getStringAttr(ANDROID_URI, ATTR_LAYOUT_WEIGHT);
+ if (weight == null || weight.length() == 0) {
+ weight = "0.0"; //$NON-NLS-1$
+ }
+ weight = mRulesEngine.displayInput("Enter Weight Value:", weight,
+ null);
+ if (weight != null) {
+ for (INode child : children) {
+ child.setAttribute(ANDROID_URI,
+ ATTR_LAYOUT_WEIGHT, weight);
+ }
+ }
+ } else if (action.getId().equals(ACTION_DISTRIBUTE)) {
+ // Any XML to get weight sum?
+ String weightSum = parentNode.getStringAttr(ANDROID_URI,
+ ATTR_WEIGHT_SUM);
+ double sum = -1.0;
+ if (weightSum != null) {
+ // Distribute
+ try {
+ sum = Double.parseDouble(weightSum);
+ } catch (NumberFormatException nfe) {
+ // Just keep using the default
+ }
+ }
+ INode[] targets = parentNode.getChildren();
+ int numTargets = targets.length;
+ double share;
+ if (sum <= 0.0) {
+ // The sum will be computed from the children, so just
+ // use arbitrary amount
+ share = 1.0;
+ } else {
+ share = sum / numTargets;
+ }
+ String value;
+ if (share != (int) share) {
+ value = String.format("%.2f", (float) share); //$NON-NLS-1$
+ } else {
+ value = Integer.toString((int) share);
+ }
+ for (INode target : targets) {
+ target.setAttribute(ANDROID_URI, ATTR_LAYOUT_WEIGHT, value);
+ }
+ } else {
+ assert action.getId().equals(ACTION_BASELINE);
+ }
+ }
+ });
+ }
+ };
+ actions.add(MenuAction.createSeparator(50));
+ actions.add(MenuAction.createAction(ACTION_DISTRIBUTE, "Distribute Weights Evenly",
+ null, actionCallback, ICON_DISTRIBUTE, 60));
+ actions.add(MenuAction.createAction(ACTION_WEIGHT, "Change Layout Weight", null,
+ actionCallback, ICON_WEIGHTS, 70));
+ }
+ }
+
// ==== Drag'n'drop support ====
@Override
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java
new file mode 100644
index 0000000..4024d5a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java
@@ -0,0 +1,63 @@
+/*
+ * 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.common.layout;
+
+import com.android.ide.common.api.IMenuCallback;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.INodeHandler;
+import com.android.ide.common.api.MenuAction;
+
+import java.util.List;
+
+/**
+ * Convenience implementation of {@link IMenuCallback} which can be used to set a
+ * particular property to the new valueId or newValue passed from the {@link IMenuCallback}
+ */
+public class PropertyCallback implements IMenuCallback {
+ private final List<? extends INode> mTargetNodes;
+ private final String mUndoLabel;
+ private final String mUri;
+ private final String mAttribute;
+
+ public PropertyCallback(List<? extends INode> targetNodes, String undoLabel,
+ String uri, String attribute) {
+ super();
+ mTargetNodes = targetNodes;
+ mUndoLabel = undoLabel;
+ mUri = uri;
+ mAttribute = attribute;
+ }
+
+ // ---- Implements IMenuCallback ----
+ public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ if (mTargetNodes != null && mTargetNodes.size() == 0) {
+ return;
+ }
+ mTargetNodes.get(0).editXml(mUndoLabel, new INodeHandler() {
+ public void handle(INode n) {
+ for (INode targetNode : mTargetNodes) {
+ if (valueId != null) {
+ targetNode.setAttribute(mUri, mAttribute, valueId);
+ } else {
+ assert newValue != null;
+ targetNode.setAttribute(mUri, mAttribute, Boolean.toString(newValue));
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java
index b80f2ec..b7160ed 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java
@@ -46,6 +46,7 @@ import com.android.ide.common.api.IGraphics;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.MenuAction;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.IAttributeInfo.Format;
@@ -653,6 +654,16 @@ public class RelativeLayoutRule extends BaseLayoutRule {
});
}
+ @Override
+ public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ final List<? extends INode> children) {
+ super.addLayoutActions(actions, parentNode, children);
+
+ actions.add(createGravityAction(Collections.<INode>singletonList(parentNode)));
+ actions.add(MenuAction.createSeparator(25));
+ actions.add(createMarginAction(parentNode, children));
+ }
+
/**
* Internal state used by the RelativeLayoutRule, stored as userData in the
* {@link DropFeedback}.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/baseline.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/baseline.png
new file mode 100644
index 0000000..acb187c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/baseline.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/distribute.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/distribute.png
new file mode 100644
index 0000000..eac2340
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/distribute.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillheight.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillheight.png
new file mode 100644
index 0000000..38e137d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillheight.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillwidth.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillwidth.png
new file mode 100644
index 0000000..f272aab
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/fillwidth.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/gravity.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/gravity.png
new file mode 100644
index 0000000..4f20928
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/gravity.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/hlinear.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/hlinear.png
new file mode 100644
index 0000000..b293fe7
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/hlinear.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/margins.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/margins.png
new file mode 100644
index 0000000..b0d8141
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/margins.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/vlinear.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/vlinear.png
new file mode 100644
index 0000000..e03c16e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/vlinear.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/weights.png b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/weights.png
new file mode 100644
index 0000000..cb654a1
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/weights.png
Binary files differ
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 7f70859..9636ec8 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
@@ -1360,7 +1360,7 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger {
public void stopEditors() {
sAndroidLogo.dispose();
- IconFactory.getInstance().Dispose();
+ IconFactory.getInstance().dispose();
// Remove the resource listener that handles compiled resources.
IWorkspace ws = ResourcesPlugin.getWorkspace();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
index 0c10363..dfdc740 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
@@ -31,7 +31,9 @@ import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import java.net.URL;
import java.util.HashMap;
/**
@@ -40,7 +42,6 @@ import java.util.HashMap;
* Icons are kept here and reused.
*/
public class IconFactory {
-
public static final int COLOR_RED = SWT.COLOR_DARK_RED;
public static final int COLOR_GREEN = SWT.COLOR_DARK_GREEN;
public static final int COLOR_BLUE = SWT.COLOR_DARK_BLUE;
@@ -53,6 +54,7 @@ public class IconFactory {
private static IconFactory sInstance;
private HashMap<String, Image> mIconMap = new HashMap<String, Image>();
+ private HashMap<URL, Image> mUrlMap = new HashMap<URL, Image>();
private HashMap<String, ImageDescriptor> mImageDescMap = new HashMap<String, ImageDescriptor>();
private IconFactory() {
@@ -65,7 +67,7 @@ public class IconFactory {
return sInstance;
}
- public void Dispose() {
+ public void dispose() {
// Dispose icons
for (Image icon : mIconMap.values()) {
// The map can contain null values
@@ -74,6 +76,13 @@ public class IconFactory {
}
}
mIconMap.clear();
+ for (Image icon : mUrlMap.values()) {
+ // The map can contain null values
+ if (icon != null) {
+ icon.dispose();
+ }
+ }
+ mUrlMap.clear();
}
/**
@@ -147,7 +156,7 @@ public class IconFactory {
String key = Character.toString((char) shape) + Integer.toString(color) + osName;
ImageDescriptor id = mImageDescMap.get(key);
if (id == null && !mImageDescMap.containsKey(key)) {
- id = AdtPlugin.imageDescriptorFromPlugin(
+ id = AbstractUIPlugin.imageDescriptorFromPlugin(
AdtPlugin.PLUGIN_ID,
String.format("/icons/%1$s.png", osName)); //$NON-NLS-1$
@@ -163,6 +172,23 @@ public class IconFactory {
}
/**
+ * Returns the image indicated by the given URL
+ *
+ * @param url the url to the image resources
+ * @return the image for the url, or null if it cannot be initialized
+ */
+ public Image getIcon(URL url) {
+ Image image = mUrlMap.get(url);
+ if (image == null) {
+ ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
+ image = descriptor.createImage();
+ mUrlMap.put(url, image);
+ }
+
+ return image;
+ }
+
+ /**
* A simple image description that generates a 16x16 image which consists
* of a colored letter inside a black & white circle.
*/
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
index 12289b9..6f521cc 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
@@ -57,7 +57,6 @@ import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
@@ -355,138 +354,6 @@ public class ConfigurationComposite extends Composite {
}
/**
- * Abstract class implemented by the part which owns a {@link ConfigurationComposite}
- * to define and handle custom buttons in the button bar. Each button is
- * implemented using a button, with a callback when the button is selected.
- */
- public static abstract class CustomButton {
-
- /** The UI label of the toggle. Can be null if the image exists. */
- private final String mUiLabel;
-
- /** The image to use for this toggle. Can be null if the label exists. */
- private final Image mImage;
-
- /** The tooltip for the toggle. Can be null. */
- private final String mUiTooltip;
-
- /** Whether the button is a toggle */
- private final boolean mIsToggle;
- /** The default value of the toggle. */
- private final boolean mDefaultValue;
-
- /**
- * the SWT button.
- */
- private Button mButton;
-
-
- /**
- * Initializes a new {@link CustomButton}. The values set here will be used
- * later to create the actual button.
- *
- * @param uiLabel The UI label of the button. Can be null if the image exists.
- * @param image The image to use for this button. Can be null if the label exists.
- * @param uiTooltip The tooltip for the button. Can be null.
- * @param isToggle Whether the button is a toggle button.
- * @param defaultValue The default value of the toggle if <var>isToggle</var> is true.
- */
- public CustomButton(
- String uiLabel,
- Image image,
- String uiTooltip,
- boolean isToggle,
- boolean defaultValue) {
- mUiLabel = uiLabel;
- mImage = image;
- mUiTooltip = uiTooltip;
- mIsToggle = isToggle;
- mDefaultValue = defaultValue;
- }
-
- /**
- * Initializes a new {@link CustomButton} that is <b>not</b> a toggle.
- * The values set here will be used later to create the actual button.
- *
- * @param uiLabel The UI label of the button. Can be null if the image exists.
- * @param image The image to use for this button. Can be null if the label exists.
- * @param uiTooltip The tooltip for the button. Can be null.
- */
- public CustomButton(
- String uiLabel,
- Image image,
- String uiTooltip) {
- this(uiLabel, image, uiTooltip, false, false);
- }
-
-
- /**
- * Called by the {@link ConfigurationComposite} when the button is selected
- * @param newState the state of the button if the button is a toggle.
- */
- public abstract void onSelected(boolean newState);
-
- private void createButton(Composite parent) {
- int style = SWT.FLAT;
- if (mIsToggle) {
- style |= SWT.TOGGLE;
- }
- mButton = new Button(parent, style);
-
- if (mUiTooltip != null) {
- mButton.setToolTipText(mUiTooltip);
- }
- if (mImage != null) {
- mButton.setImage(mImage);
- }
- if (mUiLabel != null) {
- mButton.setText(mUiLabel);
- }
-
- if (mIsToggle && mDefaultValue) {
- mButton.setSelection(true);
- }
-
- mButton.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onSelected(mButton.getSelection());
- }
- });
- }
-
- public boolean isEnabled() {
- return mButton != null && mButton.isEnabled();
- }
-
- public void setEnabled(boolean enabledState) {
- if (mButton != null) {
- mButton.setEnabled(enabledState);
- }
- }
-
- public void setToolTipText(String text) {
- if (mButton != null) {
- mButton.setToolTipText(text);
- }
- }
-
- public void setSelection(boolean selected) {
- if (mButton != null) {
- mButton.setSelection(selected);
- }
- }
-
- public boolean getSelection() {
- if (mButton != null) {
- return mButton.getSelection();
- }
-
- return mDefaultValue;
- }
- }
-
- /**
* Creates a new {@link ConfigurationComposite} and adds it to the parent.
*
* The method also receives custom buttons to set into the configuration composite. The list
@@ -495,31 +362,25 @@ public class ConfigurationComposite extends Composite {
*
* @param listener An {@link IConfigListener} that gets and sets configuration properties.
* Mandatory, cannot be null.
- * @param customButtons An array of array of {@link CustomButton} to define extra action/toggle
- * buttons to display at the top of the composite. Can be empty or null.
* @param parent The parent composite.
* @param style The style of this composite.
* @param initialState The initial state (serialized form) to use for the configuration
*/
public ConfigurationComposite(IConfigListener listener,
- CustomButton[][] customButtons,
Composite parent, int style, String initialState) {
super(parent, style);
mListener = listener;
mInitialState = initialState;
- if (customButtons == null) {
- customButtons = new CustomButton[0][0];
- }
-
GridLayout gl;
GridData gd;
- int cols = 9; // device+config+locale+dock+day/night+separator*2+theme+apiLevel
+ int cols = 6; // device+config+separator*2+theme+apiLevel
- // ---- First line: custom buttons, clipping button, editing config display.
+ // ---- First line: locale, day/night, dock, editing config display.
Composite labelParent = new Composite(this, SWT.NONE);
- labelParent.setLayout(gl = new GridLayout(2 + customButtons.length + 1, false));
+ labelParent.setLayout(gl = new GridLayout(6, false));
gl.marginWidth = gl.marginHeight = 0;
+ gl.marginTop = 3;
labelParent.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.horizontalSpan = cols;
@@ -528,20 +389,42 @@ public class ConfigurationComposite extends Composite {
mCurrentLayoutLabel.setLayoutData(gd = new GridData(GridData.FILL_HORIZONTAL));
gd.widthHint = 50;
- for (CustomButton[] buttons : customButtons) {
- if (buttons.length == 1) {
- buttons[0].createButton(labelParent);
- } else if (buttons.length > 1) {
- Composite buttonParent = new Composite(labelParent, SWT.NONE);
- buttonParent.setLayout(gl = new GridLayout(buttons.length, false));
- gl.marginWidth = gl.marginHeight = 0;
- gl.horizontalSpacing = 1;
- for (CustomButton button : buttons) {
- button.createButton(buttonParent);
- }
+ mLocaleCombo = new Combo(labelParent, SWT.DROP_DOWN | SWT.READ_ONLY);
+ mLocaleCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onLocaleChange();
+ }
+ });
+
+ // Layout bug workaround. Without this, in -some- scenarios the Locale combo box was
+ // coming up tiny. Setting a minimumWidth hint does not work either. We need to have
+ // 2 or more items in the locale combo box when the layout is first run. These items
+ // are removed as part of the locale initialization when the SDK is loaded.
+ mLocaleCombo.add("Locale"); //$NON-NLS-1$ // Dummy place holders
+ mLocaleCombo.add("Locale"); //$NON-NLS-1$
+ mDockCombo = new Combo(labelParent, SWT.DROP_DOWN | SWT.READ_ONLY);
+ for (DockMode mode : DockMode.values()) {
+ mDockCombo.add(mode.getLongDisplayValue());
+ }
+ mDockCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onDockChange();
}
+ });
+
+ mNightCombo = new Combo(labelParent, SWT.DROP_DOWN | SWT.READ_ONLY);
+ for (NightMode mode : NightMode.values()) {
+ mNightCombo.add(mode.getLongDisplayValue());
}
+ mNightCombo.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onDayChange();
+ }
+ });
mCreateButton = new Button(labelParent, SWT.PUSH | SWT.FLAT);
mCreateButton.setText("Create...");
@@ -582,42 +465,6 @@ public class ConfigurationComposite extends Composite {
}
});
- mLocaleCombo = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
- mLocaleCombo.setLayoutData(new GridData(
- GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
- mLocaleCombo.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onLocaleChange();
- }
- });
-
- mDockCombo = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
- mDockCombo.setLayoutData(new GridData(
- GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
- for (DockMode mode : DockMode.values()) {
- mDockCombo.add(mode.getLongDisplayValue());
- }
- mDockCombo.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onDockChange();
- }
- });
-
- mNightCombo = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
- mNightCombo.setLayoutData(new GridData(
- GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
- for (NightMode mode : NightMode.values()) {
- mNightCombo.add(mode.getLongDisplayValue());
- }
- mNightCombo.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onDayChange();
- }
- });
-
// first separator
Label separator = new Label(this, SWT.SEPARATOR | SWT.VERTICAL);
separator.setLayoutData(gd = new GridData(
@@ -1552,7 +1399,6 @@ public class ConfigurationComposite extends Composite {
}
}
-
/**
* Returns the current theme, or null if the combo has no selection.
*
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java
index 831367a..d00908c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java
@@ -122,8 +122,10 @@ public class CanvasTransform implements ICanvasTransform {
if (sx < cx) {
mTranslate = 0;
mScrollbar.setEnabled(false);
+ mScrollbar.setVisible(false);
} else {
mScrollbar.setEnabled(true);
+ mScrollbar.setVisible(true);
int selection = mScrollbar.getSelection();
int thumb = cx;
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 8f59710..5506319 100644
--- 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
@@ -48,7 +48,6 @@ import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.C
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
-import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.CustomButton;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.IConfigListener;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
@@ -56,7 +55,6 @@ import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.editors.xml.Hyperlinks;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
@@ -75,7 +73,6 @@ import com.android.sdklib.SdkConstants;
import com.android.sdklib.io.IAbstractFile;
import com.android.sdklib.io.StreamException;
import com.android.sdklib.xml.AndroidManifest;
-import com.android.sdkuilib.internal.widgets.ResolutionChooserDialog;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -244,15 +241,9 @@ public class GraphicalEditorPart extends EditorPart
private boolean mUseExplodeMode;
- private CustomButton mZoomRealSizeButton;
- private CustomButton mZoomOutButton;
- private CustomButton mZoomResetButton;
- private CustomButton mZoomInButton;
- private CustomButton mZoomFitButton;
- private CustomButton mClippingButton;
-
private int mMinSdkVersion;
private int mTargetSdkVersion;
+ private LayoutActionBar mActionBar;
public GraphicalEditorPart(LayoutEditor layoutEditor) {
mLayoutEditor = layoutEditor;
@@ -299,114 +290,6 @@ public class GraphicalEditorPart extends EditorPart
parent.setLayout(gl);
gl.marginHeight = gl.marginWidth = 0;
- // create the top part for the configuration control
- IconFactory iconFactory = IconFactory.getInstance();
- CustomButton[][] customButtons = new CustomButton[][] {
- new CustomButton[] {
- mZoomRealSizeButton = new CustomButton(
- null, // label
- iconFactory.getIcon("zoomreal"), //$NON-NLS-1$
- "Emulate Real Size",
- true /*isToggle*/,
- false /*defaultValue*/
- ) {
- @Override
- public void onSelected(boolean newState) {
- if (rescaleToReal(newState)) {
- mZoomOutButton.setEnabled(!newState);
- mZoomResetButton.setEnabled(!newState);
- mZoomInButton.setEnabled(!newState);
- mZoomFitButton.setEnabled(!newState);
- } else {
- mZoomRealSizeButton.setSelection(!newState);
- }
- }
- },
- mZoomFitButton = new CustomButton(
- null, // label
- iconFactory.getIcon("zoomfit"), //$NON-NLS-1$
- "Zoom to Fit (0)"
- ) {
- @Override
- public void onSelected(boolean newState) {
- rescaleToFit();
- }
- },
- mZoomResetButton = new CustomButton(
- null, // label
- iconFactory.getIcon("zoom100"), //$NON-NLS-1$
- "Reset Zoom to 100% (1)"
- ) {
- @Override
- public void onSelected(boolean newState) {
- resetScale();
- }
- }
- },
- // Group zoom in/out separately
- new CustomButton[] {
- mZoomOutButton = new CustomButton(
- null, // label
- iconFactory.getIcon("zoomminus"), //$NON-NLS-1$
- "Zoom Out (-)"
- ) {
- @Override
- public void onSelected(boolean newState) {
- rescale(-1);
- }
- },
- mZoomInButton = new CustomButton(
- null, // label
- iconFactory.getIcon("zoomplus"), //$NON-NLS-1$
- "Zoom In (+)"
- ) {
- @Override
- public void onSelected(boolean newState) {
- rescale(+1);
- }
- },
- },
- new CustomButton[] {
- new CustomButton(
- null, //text
- iconFactory.getIcon("explode"), //$NON-NLS-1$
- "Displays extra margins in the layout",
- true /*toggle*/,
- false /*defaultValue*/
- ) {
- @Override
- public void onSelected(boolean newState) {
- mUseExplodeMode = newState;
- recomputeLayout();
- }
- },
- new CustomButton(
- null, //text
- iconFactory.getIcon("outline"), //$NON-NLS-1$
- "Shows the outline of all views in the layout",
- true /*toggle*/,
- false /*defaultValue*/
- ) {
- @Override
- public void onSelected(boolean newState) {
- mCanvasViewer.getCanvas().setShowOutline(newState);
- }
- },
- mClippingButton = new CustomButton(
- null, //text
- iconFactory.getIcon("clipping"), //$NON-NLS-1$
- "Toggles screen clipping on/off",
- true /*toggle*/,
- true /*defaultValue*/
- ) {
- @Override
- public void onSelected(boolean newState) {
- recomputeLayout();
- }
- }
- }
- };
-
mConfigListener = new ConfigListener();
// Check whether somebody has requested an initial state for the newly opened file.
@@ -433,7 +316,7 @@ public class GraphicalEditorPart extends EditorPart
}
}
- mConfigComposite = new ConfigurationComposite(mConfigListener, customButtons, parent,
+ mConfigComposite = new ConfigurationComposite(mConfigListener, parent,
SWT.BORDER, initialState);
mSashPalette = new SashForm(parent, SWT.HORIZONTAL);
@@ -443,10 +326,22 @@ public class GraphicalEditorPart extends EditorPart
paleteDecor.setContent(new PaletteControl.PaletteDecor(this));
mPalette = (PaletteControl) paleteDecor.getContentControl();
- mSashError = new SashForm(mSashPalette, SWT.VERTICAL | SWT.BORDER);
+ Composite layoutBarAndCanvas = new Composite(mSashPalette, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(1, false);
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.marginHeight = 0;
+ layoutBarAndCanvas.setLayout(gridLayout);
+ mActionBar = new LayoutActionBar(layoutBarAndCanvas, SWT.NONE, this);
+ GridData detailsData = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
+ mActionBar.setLayoutData(detailsData);
+
+ mSashError = new SashForm(layoutBarAndCanvas, SWT.VERTICAL | SWT.BORDER);
mSashError.setLayoutData(new GridData(GridData.FILL_BOTH));
mCanvasViewer = new LayoutCanvasViewer(mLayoutEditor, mRulesEngine, mSashError, SWT.NONE);
+ mSashError.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
mErrorLabel = new StyledText(mSashError, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL);
mErrorLabel.setEditable(false);
@@ -466,16 +361,6 @@ public class GraphicalEditorPart extends EditorPart
}
/**
- * Returns true if zooming in/out/to-fit/etc is allowed (which is not the case while
- * emulating real size)
- *
- * @return true if zooming is allowed
- */
- boolean isZoomingAllowed() {
- return mZoomInButton.isEnabled();
- }
-
- /**
* Listens to workbench selections that does NOT come from {@link LayoutEditor}
* (those are generated by ourselves).
* <p/>
@@ -501,80 +386,6 @@ public class GraphicalEditorPart extends EditorPart
}
}
- /**
- * Rescales canvas.
- * @param direction +1 for zoom in, -1 for zoom out
- */
- void rescale(int direction) {
- double s = mCanvasViewer.getCanvas().getScale();
-
- if (direction > 0) {
- s = s * 1.2;
- } else {
- s = s / 1.2;
- }
-
- // Some operations are faster if the zoom is EXACTLY 1.0 rather than ALMOST 1.0.
- // (This is because there is a fast-path when image copying and the scale is 1.0;
- // in that case it does not have to do any scaling).
- //
- // If you zoom out 10 times and then back in 10 times, small rounding errors mean
- // that you end up with a scale=1.0000000000000004. In the cases, when you get close
- // to 1.0, just make the zoom an exact 1.0.
- if (Math.abs(s-1.0) < 0.0001) {
- s = 1.0;
- }
-
- mCanvasViewer.getCanvas().setScale(s, true /*redraw*/);
-
- }
-
- /**
- * Reset the canvas scale to 100%
- */
- private void resetScale() {
- mCanvasViewer.getCanvas().setScale(1, true /*redraw*/);
- }
-
- /**
- * Reset the canvas scale to best fit (so content is as large as possible without scrollbars)
- */
- private void rescaleToFit() {
- mCanvasViewer.getCanvas().setFitScale();
- }
-
- private boolean rescaleToReal(boolean real) {
- if (real) {
- return computeAndSetRealScale(true /*redraw*/);
- } else {
- // reset the scale to 100%
- mCanvasViewer.getCanvas().setScale(1, true /*redraw*/);
- return true;
- }
- }
-
- private boolean computeAndSetRealScale(boolean redraw) {
- // compute average dpi of X and Y
- float dpi = (mConfigComposite.getXDpi() + mConfigComposite.getYDpi()) / 2.f;
-
- // get the monitor dpi
- float monitor = AdtPrefs.getPrefs().getMonitorDensity();
- if (monitor == 0.f) {
- ResolutionChooserDialog dialog = new ResolutionChooserDialog(
- mConfigComposite.getShell());
- if (dialog.open() == Window.OK) {
- monitor = dialog.getDensity();
- AdtPrefs.getPrefs().setMonitorDensity(monitor);
- } else {
- return false;
- }
- }
-
- mCanvasViewer.getCanvas().setScale(monitor / dpi, redraw);
- return true;
- }
-
-
@Override
public void dispose() {
getSite().getPage().removeSelectionListener(this);
@@ -1138,8 +949,6 @@ public class GraphicalEditorPart extends EditorPart
private void updateCapabilities(AndroidTargetData targetData) {
if (targetData != null) {
LayoutLibrary layoutLib = targetData.getLayoutLibrary();
- setClippingSupport(layoutLib.supports(Capability.UNBOUND_RENDERING));
-
if (mIncludedWithin != null && !layoutLib.supports(Capability.EMBEDDED_LAYOUT)) {
showIn(null);
}
@@ -1226,8 +1035,8 @@ public class GraphicalEditorPart extends EditorPart
if (layoutLib != null) {
// if drawing in real size, (re)set the scaling factor.
- if (mZoomRealSizeButton.getSelection()) {
- computeAndSetRealScale(false /* redraw */);
+ if (mActionBar.isZoomingRealSize()) {
+ mActionBar.computeAndSetRealScale(false /* redraw */);
}
IProject project = mEditedFile.getProject();
@@ -1315,16 +1124,6 @@ public class GraphicalEditorPart extends EditorPart
// --- private methods ---
- private void setClippingSupport(boolean b) {
- mClippingButton.setEnabled(b);
- if (b) {
- mClippingButton.setToolTipText("Toggles screen clipping on/off");
- } else {
- mClippingButton.setSelection(true);
- mClippingButton.setToolTipText("Non clipped rendering is not supported");
- }
- }
-
/**
* Ensure that the file associated with this editor is valid (exists and is
* synchronized). Any reasons why it is not are displayed in the editor's error area.
@@ -1503,15 +1302,11 @@ public class GraphicalEditorPart extends EditorPart
RenderLogger logger = new RenderLogger(mEditedFile.getName());
RenderingMode renderingMode = RenderingMode.NORMAL;
- if (mClippingButton.getSelection() == false) {
- renderingMode = RenderingMode.FULL_EXPAND;
- } else {
- // FIXME set the rendering mode using ViewRule or something.
- List<UiElementNode> children = model.getUiChildren();
- if (children.size() > 0 &&
- children.get(0).getDescriptor().getXmlLocalName().equals(SCROLL_VIEW)) {
- renderingMode = RenderingMode.V_SCROLL;
- }
+ // FIXME set the rendering mode using ViewRule or something.
+ List<UiElementNode> children = model.getUiChildren();
+ if (children.size() > 0 &&
+ children.get(0).getDescriptor().getXmlLocalName().equals(SCROLL_VIEW)) {
+ renderingMode = RenderingMode.V_SCROLL;
}
RenderSession session = renderWithBridge(iProject, model, layoutLib, width, height,
@@ -2525,4 +2320,8 @@ public class GraphicalEditorPart extends EditorPart
public ConfigurationComposite getConfigurationComposite() {
return mConfigComposite;
}
+
+ public LayoutActionBar getLayoutActionBar() {
+ return mActionBar;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
index d455fd8..d3349e4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageControl.java
@@ -43,7 +43,7 @@ public class ImageControl extends Canvas implements MouseTrackListener {
private int mTopMargin;
private int mRightMargin;
private int mBottomMargin;
- private boolean mShowMouseOver;
+ private boolean mDisposeImage = true;
private boolean mMouseIn;
private Color mHoverColor;
private float mScale = 1.0f;
@@ -92,10 +92,20 @@ public class ImageControl extends Canvas implements MouseTrackListener {
public void dispose() {
super.dispose();
- mImage.dispose();
+ if (mDisposeImage) {
+ mImage.dispose();
+ }
mImage = null;
}
+ public void setDisposeImage(boolean mDisposeImage) {
+ this.mDisposeImage = mDisposeImage;
+ }
+
+ public boolean getDisposeImage() {
+ return mDisposeImage;
+ }
+
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
checkWidget();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutActionBar.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutActionBar.java
new file mode 100644
index 0000000..e64004d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutActionBar.java
@@ -0,0 +1,461 @@
+/*
+ * 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.layout.gle2;
+
+import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.MenuAction.OrderedChoices;
+import com.android.ide.common.api.MenuAction.Separator;
+import com.android.ide.common.api.MenuAction.Toggle;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+import com.android.sdkuilib.internal.widgets.ResolutionChooserDialog;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Toolbar shown at the top of the layout editor, which adds a number of context-sensitive
+ * layout actions (as well as zooming controls on the right).
+ */
+public class LayoutActionBar extends Composite {
+ private GraphicalEditorPart mEditor;
+ private ToolBar mLayoutToolBar;
+ private ToolBar mZoomToolBar;
+ private ToolItem mZoomRealSizeButton;
+ private ToolItem mZoomOutButton;
+ private ToolItem mZoomResetButton;
+ private ToolItem mZoomInButton;
+ private ToolItem mZoomFitButton;
+
+ public LayoutActionBar(Composite parent, int style, GraphicalEditorPart editor) {
+ super(parent, style | SWT.NO_FOCUS);
+ mEditor = editor;
+
+ GridLayout layout = new GridLayout(2, false);
+ setLayout(layout);
+
+ mLayoutToolBar = new ToolBar(this, SWT.FLAT | SWT.RIGHT | SWT.HORIZONTAL);
+ mLayoutToolBar.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false));
+ mZoomToolBar = createZoomControls();
+ mZoomToolBar.setLayoutData(new GridData(SWT.END, SWT.BEGINNING, true, false));
+ }
+
+ /** Updates the layout contents based on the current selection */
+ void updateSelection() {
+ // Get rid of any previous children
+ for (ToolItem c : mLayoutToolBar.getItems()) {
+ c.dispose();
+ }
+ mLayoutToolBar.pack();
+
+ NodeProxy parent = null;
+ LayoutCanvas canvas = mEditor.getCanvasControl();
+ SelectionManager selectionManager = canvas.getSelectionManager();
+ List<SelectionItem> selections = selectionManager.getSelections();
+ if (selections.size() > 0) {
+ // TODO: better handle multi-selection -- maybe we should disable it or
+ // something.
+ // What if you select children with different parents? Of different types?
+ // etc.
+ NodeProxy node = selections.get(0).getNode();
+ if (node != null && node.getParent() != null) {
+ parent = (NodeProxy) node.getParent();
+ }
+ }
+
+ if (parent == null) {
+ // Show the background's properties
+ CanvasViewInfo root = canvas.getViewHierarchy().getRoot();
+ if (root == null) {
+ return;
+ }
+ parent = canvas.getNodeFactory().create(root);
+ selections = Collections.emptyList();
+ }
+
+ RulesEngine engine = mEditor.getRulesEngine();
+ List<NodeProxy> selectedNodes = new ArrayList<NodeProxy>();
+ for (SelectionItem item : selections) {
+ selectedNodes.add(item.getNode());
+ }
+ List<MenuAction> actions = new ArrayList<MenuAction>();
+ engine.callAddLayoutActions(actions, parent, selectedNodes);
+ addActions(actions);
+
+ mLayoutToolBar.pack();
+ mLayoutToolBar.layout();
+ }
+
+ private void addActions(List<MenuAction> actions) {
+ if (actions.size() > 0) {
+ // Place actions in the correct order (the actions may come from different
+ // rules and should be merged properly via sorting keys)
+ Collections.sort(actions);
+
+ // Flag used to indicate that if there are any actions -after- this, it
+ // should be separated from this current action (we don't unconditionally
+ // add a separator at the end of these groups in case there are no more
+ // actions at the end so that we don't have a trailing separator)
+ boolean needSeparator = false;
+
+ for (final MenuAction action : actions) {
+ if (action instanceof Separator) {
+ addSeparator(mLayoutToolBar);
+ needSeparator = false;
+ continue;
+ } else if (needSeparator) {
+ addSeparator(mLayoutToolBar);
+ needSeparator = false;
+ }
+
+ if (action instanceof MenuAction.OrderedChoices) {
+ final MenuAction.OrderedChoices choices = (OrderedChoices) action;
+ final List<URL> icons = choices.getIconUrls();
+ if (icons == null || icons.size() == 0) {
+ addDropdown(choices);
+ } else {
+ addSeparator(mLayoutToolBar);
+ addRadio(choices);
+ needSeparator = true;
+ }
+ } else if (action instanceof MenuAction.Toggle) {
+ addToggle((Toggle) action);
+ } else if (action instanceof MenuAction.Action) {
+ addAction((MenuAction.Action) action);
+ } else {
+ AdtPlugin.log(IStatus.ERROR, "Action not supported in toolbar: %1$s",
+ action.getTitle());
+ }
+ }
+ }
+ }
+
+ /** Add a separator to the toolbar, unless there already is one there at the end already */
+ private static void addSeparator(ToolBar toolBar) {
+ int n = toolBar.getItemCount();
+ if (n > 0 && (toolBar.getItem(n - 1).getStyle() & SWT.SEPARATOR) == 0) {
+ ToolItem separator = new ToolItem(toolBar, SWT.SEPARATOR);
+ separator.setWidth(15);
+ }
+ }
+
+ private void addToggle(final Toggle toggle) {
+ final ToolItem button = new ToolItem(mLayoutToolBar, SWT.CHECK);
+
+ URL iconUrl = toggle.getIconUrl();
+ String title = toggle.getTitle();
+ if (iconUrl != null) {
+ button.setImage(IconFactory.getInstance().getIcon(iconUrl));
+ button.setToolTipText(title);
+ } else {
+ button.setText(title);
+ }
+
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ toggle.getCallback().action(toggle, toggle.getId(),
+ button.getSelection());
+ }
+ });
+ if (toggle.isChecked()) {
+ button.setSelection(true);
+ }
+ }
+
+ private void addAction(final MenuAction.Action menuAction) {
+ final ToolItem button = new ToolItem(mLayoutToolBar, SWT.PUSH);
+
+ URL iconUrl = menuAction.getIconUrl();
+ String title = menuAction.getTitle();
+ if (iconUrl != null) {
+ button.setImage(IconFactory.getInstance().getIcon(iconUrl));
+ button.setToolTipText(title);
+ } else {
+ button.setText(title);
+ }
+
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ menuAction.getCallback().action(menuAction, menuAction.getId(), false);
+ }
+ });
+ }
+
+ private void addRadio(final MenuAction.OrderedChoices choices) {
+ final List<URL> icons = choices.getIconUrls();
+ final List<String> titles = choices.getTitles();
+ final List<String> ids = choices.getIds();
+ final String current = choices.getCurrent() != null ? choices.getCurrent() : ""; //$NON-NLS-1$
+
+ assert icons != null;
+ assert icons.size() == titles.size();
+
+ for (int i = 0; i < icons.size(); i++) {
+ URL iconUrl = icons.get(i);
+ String title = titles.get(i);
+ final String id = ids.get(i);
+ final ToolItem item = new ToolItem(mLayoutToolBar, SWT.RADIO);
+ item.setToolTipText(title);
+ item.setImage(IconFactory.getInstance().getIcon(iconUrl));
+ item.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (item.getSelection()) {
+ choices.getCallback().action(choices, id, null);
+ }
+ }
+ });
+ boolean selected = current.equals(id);
+ if (selected) {
+ item.setSelection(true);
+ }
+ }
+ }
+
+ private void addDropdown(final MenuAction.OrderedChoices choices) {
+ final List<URL> icons = choices.getIconUrls();
+ final List<String> titles = choices.getTitles();
+ final List<String> ids = choices.getIds();
+ final String current = choices.getCurrent() != null ? choices.getCurrent() : ""; //$NON-NLS-1$
+
+ assert icons == null || icons.size() == 0;
+
+ final ToolItem combo = new ToolItem(mLayoutToolBar, SWT.DROP_DOWN);
+ URL iconUrl = choices.getIconUrl();
+ if (iconUrl != null) {
+ combo.setImage(IconFactory.getInstance().getIcon(iconUrl));
+ combo.setToolTipText(choices.getTitle());
+ } else {
+ combo.setText(choices.getTitle());
+ }
+
+ Listener menuListener = new Listener() {
+ public void handleEvent(Event event) {
+ // if (event.detail == SWT.ARROW) {
+ Point point = new Point(event.x, event.y);
+ point = combo.getDisplay().map(mLayoutToolBar, null, point);
+
+ final Menu menu = new Menu(mLayoutToolBar.getShell(), SWT.POP_UP);
+ for (int i = 0; i < titles.size(); i++) {
+ String title = titles.get(i);
+ final String id = ids.get(i);
+ MenuItem item = new MenuItem(menu, SWT.CHECK);
+ item.setText(title);
+
+ boolean selected = id.equals(current);
+ if (selected) {
+ item.setSelection(true);
+ }
+
+ item.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ choices.getCallback().action(choices, id, null);
+ }
+ });
+ }
+
+ // TODO - how do I dispose of this?
+
+ menu.setLocation(point);
+ menu.setVisible(true);
+ }
+ };
+ combo.addListener(SWT.Selection, menuListener);
+ }
+
+ // ---- Zoom Controls ----
+
+ private ToolBar createZoomControls() {
+ ToolBar toolBar = new ToolBar(this, SWT.FLAT | SWT.RIGHT | SWT.HORIZONTAL);
+
+ IconFactory iconFactory = IconFactory.getInstance();
+ mZoomRealSizeButton = new ToolItem(toolBar, SWT.CHECK);
+ mZoomRealSizeButton.setToolTipText("Emulate Real Size");
+ mZoomRealSizeButton.setImage(iconFactory.getIcon("zoomreal")); //$NON-NLS-1$);
+ mZoomRealSizeButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean newState = mZoomRealSizeButton.getSelection();
+ if (rescaleToReal(newState)) {
+ mZoomOutButton.setEnabled(!newState);
+ mZoomResetButton.setEnabled(!newState);
+ mZoomInButton.setEnabled(!newState);
+ mZoomFitButton.setEnabled(!newState);
+ } else {
+ mZoomRealSizeButton.setSelection(!newState);
+ }
+ }
+ });
+
+ mZoomFitButton = new ToolItem(toolBar, SWT.PUSH);
+ mZoomFitButton.setToolTipText("Zoom to Fit (0)");
+ mZoomFitButton.setImage(iconFactory.getIcon("zoomfit")); //$NON-NLS-1$);
+ mZoomFitButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ rescaleToFit();
+ }
+ });
+
+ mZoomResetButton = new ToolItem(toolBar, SWT.PUSH);
+ mZoomResetButton.setToolTipText("Reset Zoom to 100% (1)");
+ mZoomResetButton.setImage(iconFactory.getIcon("zoom100")); //$NON-NLS-1$);
+ mZoomResetButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ resetScale();
+ }
+ });
+
+ // Group zoom in/out separately
+ new ToolItem(toolBar, SWT.SEPARATOR);
+
+ mZoomOutButton = new ToolItem(toolBar, SWT.PUSH);
+ mZoomOutButton.setToolTipText("Zoom Out (-)");
+ mZoomOutButton.setImage(iconFactory.getIcon("zoomminus")); //$NON-NLS-1$);
+ mZoomOutButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ rescale(-1);
+ }
+ });
+
+ mZoomInButton = new ToolItem(toolBar, SWT.PUSH);
+ mZoomInButton.setToolTipText("Zoom In (+)");
+ mZoomInButton.setImage(iconFactory.getIcon("zoomplus")); //$NON-NLS-1$);
+ mZoomInButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ rescale(+1);
+ }
+ });
+
+ return toolBar;
+ }
+
+ /**
+ * Returns true if zooming in/out/to-fit/etc is allowed (which is not the case while
+ * emulating real size)
+ *
+ * @return true if zooming is allowed
+ */
+ boolean isZoomingAllowed() {
+ return mZoomInButton.isEnabled();
+ }
+
+ boolean isZoomingRealSize() {
+ return mZoomRealSizeButton.getSelection();
+ }
+
+ /**
+ * Rescales canvas.
+ * @param direction +1 for zoom in, -1 for zoom out
+ */
+ void rescale(int direction) {
+ LayoutCanvas canvas = mEditor.getCanvasControl();
+ double s = canvas.getScale();
+
+ if (direction > 0) {
+ s = s * 1.2;
+ } else {
+ s = s / 1.2;
+ }
+
+ // Some operations are faster if the zoom is EXACTLY 1.0 rather than ALMOST 1.0.
+ // (This is because there is a fast-path when image copying and the scale is 1.0;
+ // in that case it does not have to do any scaling).
+ //
+ // If you zoom out 10 times and then back in 10 times, small rounding errors mean
+ // that you end up with a scale=1.0000000000000004. In the cases, when you get close
+ // to 1.0, just make the zoom an exact 1.0.
+ if (Math.abs(s-1.0) < 0.0001) {
+ s = 1.0;
+ }
+
+ canvas.setScale(s, true /*redraw*/);
+ }
+
+ /**
+ * Reset the canvas scale to 100%
+ */
+ void resetScale() {
+ mEditor.getCanvasControl().setScale(1, true /*redraw*/);
+ }
+
+ /**
+ * Reset the canvas scale to best fit (so content is as large as possible without scrollbars)
+ */
+ void rescaleToFit() {
+ mEditor.getCanvasControl().setFitScale();
+ }
+
+ boolean rescaleToReal(boolean real) {
+ if (real) {
+ return computeAndSetRealScale(true /*redraw*/);
+ } else {
+ // reset the scale to 100%
+ mEditor.getCanvasControl().setScale(1, true /*redraw*/);
+ return true;
+ }
+ }
+
+ boolean computeAndSetRealScale(boolean redraw) {
+ // compute average dpi of X and Y
+ ConfigurationComposite config = mEditor.getConfigurationComposite();
+ float dpi = (config.getXDpi() + config.getYDpi()) / 2.f;
+
+ // get the monitor dpi
+ float monitor = AdtPrefs.getPrefs().getMonitorDensity();
+ if (monitor == 0.f) {
+ ResolutionChooserDialog dialog = new ResolutionChooserDialog(
+ config.getShell());
+ if (dialog.open() == Window.OK) {
+ monitor = dialog.getDensity();
+ AdtPrefs.getPrefs().setMonitorDensity(monitor);
+ } else {
+ return false;
+ }
+ }
+
+ mEditor.getCanvasControl().setScale(monitor / dpi, redraw);
+ return true;
+ }
+}
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 c7f8919..ece4c2a 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
@@ -270,15 +270,16 @@ public class LayoutCanvas extends Canvas {
} else {
// Zooming actions
char c = e.character;
- GraphicalEditorPart editor = mLayoutEditor.getGraphicalEditor();
- if (c == '1' && editor.isZoomingAllowed()) {
+ LayoutActionBar actionBar = mLayoutEditor.getGraphicalEditor()
+ .getLayoutActionBar();
+ if (c == '1' && actionBar.isZoomingAllowed()) {
setScale(1, true);
- } else if (c == '0' && editor.isZoomingAllowed()) {
+ } else if (c == '0' && actionBar.isZoomingAllowed()) {
setFitScale();
- } else if (c == '+' && editor.isZoomingAllowed()) {
- editor.rescale(1);
- } else if (c == '-' && editor.isZoomingAllowed()) {
- editor.rescale(-1);
+ } else if (c == '+' && actionBar.isZoomingAllowed()) {
+ actionBar.rescale(1);
+ } else if (c == '-' && actionBar.isZoomingAllowed()) {
+ actionBar.rescale(-1);
}
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java
index 85490c2..983bcf5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionItem.java
@@ -21,7 +21,6 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
-import com.android.sdklib.SdkConstants;
import org.eclipse.swt.graphics.Rectangle;
import org.w3c.dom.Node;
@@ -43,9 +42,6 @@ import java.util.List;
/** The node proxy for drawing the selection. Null when mCanvasViewInfo is null. */
private final NodeProxy mNodeProxy;
- /** The name displayed over the selection, typically the widget class name. Can be null. */
- private final String mName;
-
/**
* Creates a new {@link SelectionItem} object.
* @param canvasViewInfo The view info being selected. Must not be null.
@@ -68,8 +64,6 @@ import java.util.List;
mRect = new Rectangle(r.x, r.y, r.width, r.height);
mNodeProxy = nodeFactory.create(canvasViewInfo);
}
-
- mName = initDisplayName(canvasViewInfo, gre);
}
/**
@@ -96,14 +90,6 @@ import java.util.List;
return mRect;
}
- /**
- * The name displayed over the selection, typically the widget class name.
- * Can be null.
- */
- public String getName() {
- return mName;
- }
-
/** Returns the node associated with this selection (may be null) */
/* package */ NodeProxy getNode() {
return mNodeProxy;
@@ -111,51 +97,6 @@ import java.util.List;
//----
- private String initDisplayName(CanvasViewInfo canvasViewInfo, RulesEngine gre) {
- if (canvasViewInfo == null) {
- return null;
- }
-
- String fqcn = canvasViewInfo.getName();
- if (fqcn == null) {
- return null;
- }
-
- if (fqcn.equals(SdkConstants.CLASS_MOCK_VIEW)) {
- // The MockView class from the layout bridge is used to display views that
- // cannot be rendered properly (such as SurfaceView or missing custom views).
- // This view itself already displays the class name it represents so we don't
- // need to display anything here.
- return "";
- }
-
- String name = gre.callGetDisplayName(canvasViewInfo.getUiViewNode());
-
- if (name == null) {
- // The name is typically a fully-qualified class name. Let's make it a tad shorter.
-
- if (fqcn.startsWith("android.")) { //$NON-NLS-1$
- // For android classes, convert android.foo.Name to android...Name
- int first = fqcn.indexOf('.');
- int last = fqcn.lastIndexOf('.');
- if (last > first) {
- name = fqcn.substring(0, first) + ".." + fqcn.substring(last); //$NON-NLS-1$
- }
- } else {
- // For custom non-android classes, it's best to keep the 2 first segments of
- // the namespace, e.g. we want to get something like com.example...MyClass
- int first = fqcn.indexOf('.');
- first = fqcn.indexOf('.', first + 1);
- int last = fqcn.lastIndexOf('.');
- if (last > first) {
- name = fqcn.substring(0, first) + ".." + fqcn.substring(last); //$NON-NLS-1$
- }
- }
- }
-
- return name;
- }
-
/**
* Gets the XML text from the given selection for a text transfer.
* The returned string can be empty but not null.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
index cad3301..1aad0f2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
@@ -604,6 +604,8 @@ public class SelectionManager implements ISelectionProvider {
// Update menu actions that depend on the selection
updateMenuActions();
+ // Update the layout actions bar
+ mCanvas.getLayoutEditor().getGraphicalEditor().getLayoutActionBar().updateSelection();
} finally {
mInsideUpdateSelection = false;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java
index 817f2f9..a2dc88f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionOverlay.java
@@ -62,8 +62,7 @@ public class SelectionOverlay extends Overlay {
NodeProxy node = s.getNode();
if (node != null) {
- String name = s.getName();
- paintSelection(gcWrapper, s.getViewInfo(), node, name, isMultipleSelection);
+ paintSelection(gcWrapper, s.getViewInfo(), node, isMultipleSelection);
}
}
@@ -121,7 +120,7 @@ public class SelectionOverlay extends Overlay {
}
/** Called by the canvas when a view is being selected. */
- private void paintSelection(IGraphics gc, CanvasViewInfo view, INode selectedNode, String displayName,
+ private void paintSelection(IGraphics gc, CanvasViewInfo view, INode selectedNode,
boolean isMultipleSelection) {
Rect r = selectedNode.getBounds();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
index 751def1..cde4e28 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
@@ -42,6 +42,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.internal.ui.MarginChooser;
import com.android.ide.eclipse.adt.internal.ui.ReferenceChooserDialog;
import com.android.ide.eclipse.adt.internal.ui.ResourceChooser;
import com.android.resources.ResourceType;
@@ -236,6 +237,35 @@ public class RulesEngine {
}
/**
+ * Invokes {@link IViewRule#getContextMenu(INode)} on the rule matching the specified element.
+ *
+ * @param actions The list of actions to add layout actions into
+ * @param parentNode The layout node
+ * @param children The selected children of the node, if any (used to initialize values
+ * of child layout controls, if applicable)
+ * @return Null if the rule failed, there's no rule or the rule does not provide
+ * any custom menu actions. Otherwise, a list of {@link MenuAction}.
+ */
+ public List<MenuAction> callAddLayoutActions(List<MenuAction> actions,
+ NodeProxy parentNode, List<NodeProxy> children ) {
+ // try to find a rule for this element's FQCN
+ IViewRule rule = loadRule(parentNode.getNode());
+
+ if (rule != null) {
+ try {
+ mInsertType = InsertType.CREATE;
+ rule.addLayoutActions(actions, parentNode, children);
+ } catch (Exception e) {
+ AdtPlugin.log(e, "%s.getContextMenu() failed: %s",
+ rule.getClass().getSimpleName(),
+ e.toString());
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Invokes {@link IViewRule#getSelectionHint(INode, INode)}
* on the rule matching the specified element.
*
@@ -872,5 +902,24 @@ public class RulesEngine {
return null;
}
+ public String[] displayMarginInput(String all, String left, String right, String top,
+ String bottom) {
+ AndroidXmlEditor editor = mEditor.getLayoutEditor();
+ IProject project = editor.getProject();
+ if (project != null) {
+ Shell shell = AdtPlugin.getDisplay().getActiveShell();
+ if (shell == null) {
+ return null;
+ }
+ AndroidTargetData data = editor.getTargetData();
+ MarginChooser dialog = new MarginChooser(shell, project, data, all, left, right,
+ top, bottom);
+ if (dialog.open() == Window.OK) {
+ return dialog.getMargins();
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
index d51cd8f..e5957d7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
@@ -71,7 +71,6 @@ import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@@ -249,14 +248,13 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
GridData gd = new GridData();
gd.horizontalSpan = 3;
mTestContainerRadioButton.setLayoutData(gd);
- mTestContainerRadioButton.addSelectionListener(new SelectionListener() {
+ mTestContainerRadioButton.addSelectionListener(new SelectionAdapter() {
+ @Override
public void widgetSelected(SelectionEvent e) {
if (mTestContainerRadioButton.getSelection()) {
testModeChanged();
}
}
- public void widgetDefaultSelected(SelectionEvent e) {
- }
});
mContainerText = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/MarginChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/MarginChooser.java
new file mode 100644
index 0000000..1a9a78f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/MarginChooser.java
@@ -0,0 +1,212 @@
+/*
+ * 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.ui;
+
+import com.android.ide.eclipse.adt.internal.resources.IResourceRepository;
+import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.resources.ResourceType;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.SelectionStatusDialog;
+
+public class MarginChooser extends SelectionStatusDialog implements Listener {
+ private IProject mProject;
+ private AndroidTargetData mTargetData;
+ private Text mLeftField;
+ private Text mRightField;
+ private Text mTopField;
+ private Text mBottomField;
+ private Text mAllField;
+ private String mInitialAll;
+ private String mInitialLeft;
+ private String mInitialRight;
+ private String mInitialTop;
+ private String mInitialBottom;
+ private Label mErrorLabel;
+ private String[] mMargins;
+
+ // Client data key for resource buttons pointing to the associated text field
+ private final static String PROP_TEXTFIELD = "textField"; //$NON-NLS-1$
+
+ public MarginChooser(Shell parent, IProject project, AndroidTargetData targetData, String all,
+ String left, String right, String top, String bottom) {
+ super(parent);
+ setTitle("Edit Margins");
+ mProject = project;
+ mTargetData = targetData;
+ mInitialAll = all;
+ mInitialLeft = left;
+ mInitialRight = right;
+ mInitialTop = top;
+ mInitialBottom = bottom;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite container = new Composite(parent, SWT.NONE);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+ container.setLayout(new GridLayout(3, false));
+
+ Label allLabel = new Label(container, SWT.NONE);
+ allLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ allLabel.setText("All:");
+
+ mAllField = new Text(container, SWT.BORDER | SWT.LEFT);
+ mAllField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mAllField.setText(mInitialAll != null ? mInitialAll : ""); //$NON-NLS-1$
+
+ Button allButton = new Button(container, SWT.NONE);
+ allButton.setText("Resource...");
+ allButton.setData(PROP_TEXTFIELD, mAllField);
+
+ Label label = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
+
+ Label leftLabel = new Label(container, SWT.NONE);
+ leftLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ leftLabel.setText("Left:");
+
+ mLeftField = new Text(container, SWT.BORDER | SWT.LEFT);
+ mLeftField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mLeftField.setText(mInitialLeft != null ? mInitialLeft : ""); //$NON-NLS-1$
+
+ Button leftButton = new Button(container, SWT.NONE);
+ leftButton.setText("Resource...");
+ leftButton.setData(PROP_TEXTFIELD, mLeftField);
+
+ Label rightLabel = new Label(container, SWT.NONE);
+ rightLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ rightLabel.setText("Right:");
+
+ mRightField = new Text(container, SWT.BORDER | SWT.LEFT);
+ mRightField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mRightField.setText(mInitialRight != null ? mInitialRight : ""); //$NON-NLS-1$
+
+ Button rightButton = new Button(container, SWT.NONE);
+ rightButton.setText("Resource...");
+ rightButton.setData(PROP_TEXTFIELD, mRightField);
+
+ Label topLabel = new Label(container, SWT.NONE);
+ topLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ topLabel.setText("Top:");
+
+ mTopField = new Text(container, SWT.BORDER | SWT.LEFT);
+ mTopField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mTopField.setText(mInitialTop != null ? mInitialTop : ""); //$NON-NLS-1$
+
+ Button topButton = new Button(container, SWT.NONE);
+ topButton.setText("Resource...");
+ topButton.setData(PROP_TEXTFIELD, mTopField);
+
+ Label bottomLabel = new Label(container, SWT.NONE);
+ bottomLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ bottomLabel.setText("Bottom:");
+
+ mBottomField = new Text(container, SWT.BORDER | SWT.LEFT);
+ mBottomField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ mBottomField.setText(mInitialBottom != null ? mInitialBottom : ""); //$NON-NLS-1$
+
+ Button bottomButton = new Button(container, SWT.NONE);
+ bottomButton.setText("Resource...");
+ bottomButton.setData(PROP_TEXTFIELD, mBottomField);
+
+ allButton.addListener(SWT.Selection, this);
+ leftButton.addListener(SWT.Selection, this);
+ rightButton.addListener(SWT.Selection, this);
+ topButton.addListener(SWT.Selection, this);
+ bottomButton.addListener(SWT.Selection, this);
+
+ mAllField.addListener(SWT.Modify, this);
+ mLeftField.addListener(SWT.Modify, this);
+ mRightField.addListener(SWT.Modify, this);
+ mTopField.addListener(SWT.Modify, this);
+ mBottomField.addListener(SWT.Modify, this);
+
+ new Label(container, SWT.NONE);
+ mErrorLabel = new Label(container, SWT.WRAP);
+ mErrorLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+
+ return container;
+ }
+
+ @Override
+ protected void computeResult() {
+ mMargins = new String[] {
+ mAllField.getText().trim(),
+ mLeftField.getText().trim(), mRightField.getText().trim(),
+ mTopField.getText().trim(), mBottomField.getText().trim()
+ };
+ }
+
+ public String[] getMargins() {
+ return mMargins;
+ }
+
+ public void handleEvent(Event event) {
+ if (event.type == SWT.Modify) {
+ // Text field modification -- warn about non-dip numbers
+ if (event.widget instanceof Text) {
+ Text text = (Text) event.widget;
+ String input = text.getText().trim();
+ boolean isNumber = false;
+ try {
+ if (Integer.parseInt(input) > 0) {
+ isNumber = true;
+ }
+ } catch (NumberFormatException nufe) {
+ // Users are allowed to enter non-numbers here, not an error
+ }
+ if (isNumber) {
+ String message = String.format("Hint: Use \"%1$sdip\" instead", input);
+ mErrorLabel.setText(message);
+ } else {
+ mErrorLabel.setText("");
+ }
+ }
+ } else if (event.type == SWT.Selection) {
+ // Button pressed - open resource chooser
+ if (event.widget instanceof Button) {
+ Button button = (Button) event.widget;
+
+ // Open a resource chooser dialog for specified resource type.
+ IResourceRepository projectRepository = ResourceManager.getInstance()
+ .getProjectResources(mProject);
+ IResourceRepository systemRepository = mTargetData.getSystemResources();
+ ResourceChooser dlg = new ResourceChooser(mProject, ResourceType.DIMEN,
+ projectRepository, systemRepository, getShell());
+ Text text = (Text) button.getData(PROP_TEXTFIELD);
+ dlg.setCurrentResource(text.getText().trim());
+ if (dlg.open() == Window.OK) {
+ text.setText(dlg.getCurrentResource());
+ }
+ }
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java
index 21e4597..5b79ac3 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java
@@ -238,6 +238,12 @@ public abstract class LayoutTestBase extends TestCase {
fail("Not supported in tests yet");
return null;
}
+
+ public String[] displayMarginInput(String all, String left, String right, String top,
+ String bottom) {
+ fail("Not supported in tests yet");
+ return null;
+ }
}
public void testDummy() {