aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-08-15 14:15:09 -0700
committerAndroid Code Review <code-review@android.com>2011-08-15 14:15:10 -0700
commit47d72b010e64bf0aa231895dd70a59ba3fde3630 (patch)
tree2bee2a78dc8d463cd69876d92b4ab66d599d8d10 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common
parentee4e5b7f818d1296aadc4d70eed417ff4f2de46b (diff)
parent94986e745141118cace0391da1b4dc8533408751 (diff)
downloadsdk-47d72b010e64bf0aa231895dd70a59ba3fde3630.zip
sdk-47d72b010e64bf0aa231895dd70a59ba3fde3630.tar.gz
sdk-47d72b010e64bf0aa231895dd70a59ba3fde3630.tar.bz2
Merge "Action API improvements"
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IMenuCallback.java17
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IViewRule.java23
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java669
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/RuleAction.java656
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java418
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java13
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java50
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java70
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java25
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java29
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java4
15 files changed, 1093 insertions, 970 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IMenuCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IMenuCallback.java
index 1906436..80f77b8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IMenuCallback.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IMenuCallback.java
@@ -16,9 +16,13 @@
package com.android.ide.common.api;
+import java.util.List;
+
/**
- * Callback interface for {@link MenuAction}s. The callback performs the actual
- * work of the menu.
+ * Callback interface for a {@link RuleAction}. The callback performs the actual
+ * work of the action, and this level of indirection allows multiple actions (which
+ * typically do not have their own class, only their own instances) to share a single
+ * implementation callback class.
* <p>
* <b>NOTE: This is not a public or final API; if you rely on this be prepared
* to adjust your code for the next tools release.</b>
@@ -26,14 +30,15 @@ package com.android.ide.common.api;
*/
public interface IMenuCallback {
/**
- * Performs the actual work promised by the {@link MenuAction}.
- *
- * @param action The MenuAction being applied.
+ * Performs the actual work promised by the {@link RuleAction}.
+ * @param action The action being applied.
+ * @param selectedNodes The nodes to apply the action to
* @param valueId For a Choices action, the string id of the selected choice
* @param newValue For a toggle or for a flag, true if the item is being
* checked, false if being unchecked. For enums this is not
* useful; however for flags it allows one to add or remove items
* to the flag's choices.
*/
- void action(MenuAction menuAction, String valueId, Boolean newValue);
+ void action(RuleAction action, List<? extends INode> selectedNodes, String valueId,
+ Boolean newValue);
}
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 a16db28..d29ef71 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
@@ -67,19 +67,22 @@ public interface IViewRule {
* If null is returned, the GLE will automatically shorten the class name using its
* own heuristic, which is to keep the first 2 package components and the class name.
* The class name is the <code>fqcn</code> argument that was given
- * to {@link #onInitialize(String)}.
+ * to {@link #onInitialize(String,IClientRulesEngine)}.
*
* @return Null for the default behavior or a shortened string.
*/
String getDisplayName();
/**
- * Invoked by the Rules Engine to retrieve a set of actions to customize
+ * Invoked by the Rules Engine to produce a set of actions to customize
* the context menu displayed for this view. The result is not cached and the
* method is invoked every time the context menu is about to be shown.
+ * <p>
+ * The order of the menu items is determined by the sort priority set on
+ * the actions.
* <p/>
- * Most rules should consider returning <code>super.getContextMenu(node)</code>
- * and appending their own custom menu actions, if any.
+ * Most rules should consider calling super.{@link #addContextMenuActions(List, INode)}
+ * as well.
* <p/>
* Menu actions are either toggles or fixed lists with one currently-selected
* item. It is expected that the rule will need to recreate the actions with
@@ -87,16 +90,18 @@ public interface IViewRule {
* is not cached. However rules are encouraged to cache some or all of the result
* to speed up following calls if it makes sense.
*
- * @return Null for no context menu, or a new {@link MenuAction} describing one
- * or more actions to display in the context menu.
+ * @param actions a list of actions to add new context menu actions into. The order
+ * of the actions in this list is not important; it will be sorted by
+ * {@link RuleAction#getSortPriority()} later.
+ * @param node the node to add actions for.
*/
- List<MenuAction> getContextMenu(INode node);
+ void addContextMenuActions(List<RuleAction> actions, 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
+ * {@link RuleAction#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.
*
@@ -104,7 +109,7 @@ public interface IViewRule {
* @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,
+ void addLayoutActions(List<RuleAction> 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
deleted file mode 100755
index 3e912f8..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/MenuAction.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2010 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.api;
-
-import com.android.annotations.Nullable;
-
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A menu action represents one item in the context menu displayed by the GLE canvas.
- * <p/>
- * Each action should have a reasonably unique ID. By default actions are stored using
- * the lexicographical order of the IDs.
- * Duplicated IDs will be ignored -- that is the first one found will be used.
- * <p/>
- * When the canvas has a multiple selection, only actions that are present in <em>all</em>
- * the selected nodes are shown. Moreover, for a given ID all actions must be equal, for
- * example they must have the same title and choice but not necessarily the same selection. <br/>
- * This allows the canvas to only display compatible actions that will work on all selected
- * elements.
- * <p/>
- * Actions can be grouped in sub-menus if necessary. Whether groups (sub-menus) can contain
- * other groups is implementation dependent. Currently the canvas does not support this, but
- * we may decide to change this behavior later if deemed useful.
- * <p/>
- * All actions and groups are sorted by their ID, using String's natural sorting order.
- * The only way to change this sorting is by choosing the IDs so they the result end up
- * sorted as you want it.
- * <p/>
- * The {@link MenuAction} is abstract. Users should instantiate either {@link Toggle},
- * {@link Choices} or {@link Group} instead. These classes are immutable.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- * </p>
- */
-public abstract class MenuAction implements Comparable<MenuAction> {
-
- /**
- * The unique id of the action.
- * @see #getId()
- */
- private final String mId;
- /**
- * The UI-visible title of the action.
- */
- 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 OrderedChoices 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 OrderedChoices 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.
- *
- * @param id The unique id of the action, which must be similar for all actions that
- * perform the same task. Cannot be null.
- * @param title The UI-visible title of the action.
- */
- private MenuAction(String id, String title) {
- mId = id;
- mTitle = title;
- }
-
- /**
- * Returns the unique id of the action. In the context of a multiple selection,
- * actions which have the same id are collapsed together and must represent the same
- * action. Cannot be null.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Returns the UI-visible title of the action, shown in the context menu.
- * Cannot be null.
- */
- public String getTitle() {
- return mTitle;
- }
-
- /**
- * Actions which have the same id and the same title are deemed equivalent.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof MenuAction) {
- MenuAction rhs = (MenuAction) obj;
-
- if (mId != rhs.mId && !(mId != null && mId.equals(rhs.mId))) return false;
- if (mTitle != rhs.mTitle &&
- !(mTitle != null && mTitle.equals(rhs.mTitle))) return false;
- return true;
- }
- return false;
- }
-
- /**
- * Actions which have the same id and the same title have the same hash code.
- */
- @Override
- public int hashCode() {
- int h = mId == null ? 0 : mId.hashCode();
- h = h ^ (mTitle == null ? 0 : mTitle.hashCode());
- return h;
- }
-
- /**
- * 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
- * actions that it will contain. This merely let the canvas create a sub-menu with the
- * given title and actions that define this group-id will be placed in the sub-menu.
- * <p/>
- * The current canvas has the following implementation details: <br/>
- * - There's only one level of sub-menu.
- * That is you can't have a sub-menu inside another sub-menu.
- * This is expressed by the fact that groups do not have a parent group-id. <br/>
- * - It is not currently necessary to define a group before defining actions that refer
- * to that group. Moreover, in the context of a multiple selection, one view could
- * contribute actions to any group even if created by another view. Both practices
- * are discouraged. <br/>
- * - Actions which group-id do not match any known group will simply be placed in the
- * root context menu. <br/>
- * - Empty groups do not create visible sub-menus. <br/>
- * These implementations details may change in the future and should not be relied upon.
- */
- public static class Group extends MenuAction {
-
- /**
- * Constructs a new group of actions.
- *
- * @param id The id of the group. Must be unique. Cannot be null.
- * @param title The UI-visible title of the group, shown in the sub-menu.
- */
- public Group(String id, String title) {
- super(id, title);
- }
- }
-
- /**
- * The base class for {@link Toggle} and {@link Choices}.
- */
- public static class Action extends MenuAction {
-
- /**
- * A callback executed when the action is selected in the context menu.
- */
- private final IMenuCallback mCallback;
-
- /**
- * An optional group id, to place the action in a given sub-menu.
- * @null This value can be null.
- */
- @Nullable
- private final String mGroupId;
-
- /**
- * Constructs a new base {@link MenuAction} with its ID, title and action callback.
- *
- * @param id The unique ID of the action. Must not be null.
- * @param title The title of the action. Must not be null.
- * @param groupId The optional group id, to place the action in a given sub-menu.
- * Can be null.
- * @param callback The callback executed when the action is selected.
- * Must not be null.
- */
- public Action(String id, String title, String groupId, IMenuCallback callback) {
- super(id, title);
- mGroupId = groupId;
- mCallback = callback;
- }
-
- /**
- * Returns the callback executed when the action is selected in the
- * context menu. Cannot be null.
- */
- public IMenuCallback getCallback() {
- return mCallback;
- }
-
- /**
- * Returns the optional id of an existing group or null
- * @null This value can be null.
- */
- @Nullable
- public String getGroupId() {
- return mGroupId;
- }
-
- /**
- * Two actions are equal if the have the same id, title and group-id.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof Action && super.equals(obj)) {
- Action rhs = (Action) obj;
- return mGroupId == rhs.mGroupId ||
- (mGroupId != null && mGroupId.equals(rhs.mGroupId));
- }
- return false;
- }
-
- /**
- * Two actions have the same hash code if the have the same id, title and group-id.
- */
- @Override
- public int hashCode() {
- int h = super.hashCode();
- h = h ^ (mGroupId == null ? 0 : mGroupId.hashCode());
- return h;
- }
- }
-
- /** 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.
- * <p/>
- * Two toggles are equal if they have the same id, title and group-id.
- * It is expected for the checked state and action callback to be different.
- */
- public static class Toggle extends Action {
- /**
- * True if the item is displayed with a check mark.
- */
- private final boolean mIsChecked;
-
- /**
- * Creates a new immutable toggle action.
- * This action has no group-id and will show up in the root of the context menu.
- *
- * @param id The unique id of the action. Cannot be null.
- * @param title The UI-visible title of the context menu item. Cannot be null.
- * @param isChecked Whether the context menu item has a check mark.
- * @param callback A callback to execute when the context menu item is
- * selected.
- */
- public Toggle(String id, String title, boolean isChecked, IMenuCallback callback) {
- this(id, title, isChecked, null /* group-id */, callback);
- }
-
- /**
- * Creates a new immutable toggle action.
- *
- * @param id The unique id of the action. Cannot be null.
- * @param title The UI-visible title of the context menu item. Cannot be null.
- * @param isChecked Whether the context menu item has a check mark.
- * @param groupId The optional group id, to place the action in a given sub-menu.
- * Can be null.
- * @param callback A callback to execute when the context menu item is
- * selected.
- */
- public Toggle(String id, String title, boolean isChecked, String groupId,
- IMenuCallback callback) {
- super(id, title, groupId, callback);
- mIsChecked = isChecked;
- }
-
- /**
- * Returns true if the item is displayed with a check mark.
- */
- public boolean isChecked() {
- return mIsChecked;
- }
-
- /**
- * Two toggles are equal if they have the same id, title and group-id.
- * It is acceptable for the checked state and action callback to be different.
- */
- @Override
- public boolean equals(Object obj) {
- return super.equals(obj);
- }
-
- /**
- * Two toggles have the same hash code if they have the same id, title and group-id.
- */
- @Override
- public int hashCode() {
- return super.hashCode();
- }
- }
-
- /**
- * 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;
- private boolean mRadio;
-
- /**
- * 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;
- }
-
- /**
- * Set whether this choice list is best visualized as a radio group (instead of a
- * dropdown)
- *
- * @param radio true if this choice list should be visualized as a radio group
- */
- public void setRadio(boolean radio) {
- mRadio = radio;
- }
-
- /**
- * Returns true if this choice list is best visualized as a radio group (instead
- * of a dropdown)
- *
- * @return true if this choice list should be visualized as a radio group
- */
- public boolean isRadio() {
- return mRadio;
- }
- }
-
- /** 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/>
- * Implementation detail: empty choices will not be displayed in the context menu.
- * <p/>
- * Choice items are sorted by their id, using String's natural sorting order.
- * <p/>
- * Two multiple choices are equal if they have the same id, title, group-id and choices.
- * It is expected for the current state and action callback to be different.
- */
- public static class Choices extends Action {
-
- /**
- * 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.
- */
- public final static String CHOICE_SEP = "|";
-
- /**
- * A non-null map of id=>choice-title. The map could be empty but not null.
- */
- private final Map<String, String> mChoices;
- /**
- * 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.
- * If more than one choice, they must be separated by {@link #CHOICE_SEP}.
- */
- private final String mCurrent;
-
- /**
- * Creates a new immutable multiple-choice action.
- * This action has no group-id and will show up in the root of the context menu.
- *
- * @param id The unique id of the action. Cannot be null.
- * @param title The UI-visible title of the context menu item. Cannot be null.
- * @param choices A map id=>title for all the multiple-choice items. Cannot be null.
- * @param current The id(s) of the current choice(s) that will be check marked.
- * Can be null. Can be an id not present in the choices map.
- * There can be more than one id separated by {@link #CHOICE_SEP}.
- * @param callback A callback to execute when the context menu item is
- * selected.
- */
- public Choices(String id, String title,
- Map<String, String> choices,
- String current,
- IMenuCallback callback) {
- this(id, title, choices, current, null /* group-id */, callback);
- }
-
- /**
- * Creates a new immutable multiple-choice action.
- *
- * @param id The unique id of the action. Cannot be null.
- * @param title The UI-visible title of the context menu item. Cannot be null.
- * @param choices A map id=>title for all the multiple-choice items. Cannot be null.
- * @param current The id(s) of the current choice(s) that will be check marked.
- * Can be null. Can be an id not present in the choices map.
- * There can be more than one id separated by {@link #CHOICE_SEP}.
- * @param groupId The optional group id, to place the action in a given sub-menu.
- * Can be null.
- * @param callback A callback to execute when the context menu item is
- * selected.
- */
- public Choices(String id, String title,
- Map<String, String> choices,
- String current,
- String groupId,
- IMenuCallback callback) {
- super(id, title, groupId, callback);
- mChoices = choices;
- mCurrent = current;
- }
-
- /**
- * Return the map of id=>choice-title. The map could be empty but not null.
- */
- public Map<String, String> getChoices() {
- return mChoices;
- }
-
- /**
- * Returns the id(s) of the current choice(s) that are check marked.
- * Can be null. Can be an id not present in the choices map.
- * There can be more than one id separated by {@link #CHOICE_SEP}.
- */
- public String getCurrent() {
- return mCurrent;
- }
-
- /**
- * Two multiple choices are equal if they have the same id, title, group-id and choices.
- * It is acceptable for the current state and action callback to be different.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof Choices && super.equals(obj)) {
- Choices rhs = (Choices) obj;
- return mChoices.equals(rhs.mChoices);
- }
- return false;
- }
-
- /**
- * Two multiple choices have the same hash code if they have the same id, title,
- * group-id and choices.
- */
- @Override
- public int hashCode() {
- int h = super.hashCode();
-
- if (mChoices != null) {
- h = h ^ mChoices.hashCode();
- }
- return h;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/RuleAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/RuleAction.java
new file mode 100755
index 0000000..2ebab36
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/RuleAction.java
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2010 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.api;
+
+import com.android.util.Pair;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * A {@link RuleAction} represents an action provided by an {@link IViewRule}, typically
+ * shown in a context menu or in the layout actions bar.
+ * <p/>
+ * Each action should have a reasonably unique ID. This is used when multiple nodes
+ * are selected to filter the actions down to just those actions that are supported
+ * across all selected nodes. If an action does not support multiple nodes, it can
+ * return false from {@link #supportsMultipleNodes()}.
+ * <p/>
+ * Actions can be grouped into a hierarchy of sub-menus using the {@link NestedAction} class,
+ * or into a flat submenu using the {@link Choices} class.
+ * <p/>
+ * Actions (including separators) all have a "sort priority", and this is used to
+ * sort the menu items or toolbar buttons into a specific order.
+ * <p>
+ * <b>NOTE: This is not a public or final API; if you rely on this be prepared
+ * to adjust your code for the next tools release.</b>
+ * </p>
+ */
+public class RuleAction implements Comparable<RuleAction> {
+ /**
+ * Character used to split multiple checked choices.
+ * The pipe character "|" is used, to natively match Android resource flag separators.
+ */
+ public final static String CHOICE_SEP = "|"; //$NON-NLS-1$
+
+ /**
+ * Same as {@link #CHOICE_SEP} but safe for use in regular expressions.
+ */
+ public final static String CHOICE_SEP_PATTERN = Pattern.quote(CHOICE_SEP);
+
+ /**
+ * The unique id of the action.
+ * @see #getId()
+ */
+ private final String mId;
+ /**
+ * The UI-visible title of the action.
+ */
+ private final String mTitle;
+
+ /** A URL pointing to an icon, or null */
+ private URL mIconUrl;
+
+ /**
+ * A callback executed when the action is selected in the context menu.
+ */
+ private final IMenuCallback mCallback;
+
+ /**
+ * The sorting priority of this item; actions can be sorted according to these
+ */
+ protected final int mSortPriority;
+
+ /**
+ * Whether this action supports multiple nodes, see
+ * {@link #supportsMultipleNodes()} for details.
+ */
+ private final boolean mSupportsMultipleNodes;
+
+ /**
+ * Special value which will insert a separator in the choices' submenu.
+ */
+ public final static String SEPARATOR = "----";
+
+ // Factories
+
+ /**
+ * Constructs a new separator which will be shown in places where separators
+ * are supported such as context menus
+ *
+ * @param sortPriority a priority used for sorting this action
+ * @return a new separator
+ */
+ public static Separator createSeparator(int sortPriority) {
+ return new Separator(sortPriority, true /* supportsMultipleNodes*/);
+ }
+
+ /**
+ * Constructs a new base {@link RuleAction} with its ID, title and action callback.
+ *
+ * @param id The unique ID of the action. Must not be null.
+ * @param title The title of the action. Must not be null.
+ * @param callback The callback executed when the action is selected.
+ * Must not be null.
+ * @param iconUrl a URL pointing to an icon to use for this action, or null
+ * @param sortPriority a priority used for sorting this action
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @return the new {@link RuleAction}
+ */
+ public static RuleAction createAction(String id, String title,
+ IMenuCallback callback, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) {
+ RuleAction action = new RuleAction(id, title, callback, sortPriority,
+ supportsMultipleNodes);
+ action.setIconUrl(iconUrl);
+
+ return action;
+ }
+
+ /**
+ * Creates a new immutable toggle action.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The UI-visible title of the context menu item. Cannot be null.
+ * @param isChecked Whether the context menu item has a check mark.
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param iconUrl a URL pointing to an icon to use for this action, or null
+ * @param sortPriority a priority used for sorting this action
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @return the new {@link Toggle}
+ */
+ public static Toggle createToggle(String id, String title, boolean isChecked,
+ IMenuCallback callback, URL iconUrl, int sortPriority,
+ boolean supportsMultipleNodes) {
+ Toggle toggle = new Toggle(id, title, isChecked, callback, sortPriority,
+ supportsMultipleNodes);
+ toggle.setIconUrl(iconUrl);
+ return toggle;
+ }
+
+ /**
+ * Creates a new immutable multiple-choice action with a defined ordered set
+ * of action children.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The title of the action to be displayed to the user
+ * @param provider Provides the actions to be shown as children of this
+ * action
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param iconUrl the icon to use for the multiple choice action itself
+ * @param sortPriority the sorting priority to use for the multiple choice
+ * action itself
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @return the new {@link NestedAction}
+ */
+ public static NestedAction createChoices(String id, String title,
+ IMenuCallback callback, URL iconUrl,
+ int sortPriority, boolean supportsMultipleNodes, ActionProvider provider) {
+ NestedAction choices = new NestedAction(id, title, provider, callback,
+ sortPriority, supportsMultipleNodes);
+ choices.setIconUrl(iconUrl);
+ return choices;
+ }
+
+ /**
+ * Creates a new immutable multiple-choice action with a defined ordered set
+ * of children.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The title of the action to be displayed to the user
+ * @param iconUrls The icon urls for the children items (may be null)
+ * @param ids The internal ids for the children
+ * @param current The id(s) of the current choice(s) that will be check
+ * marked. Can be null. Can be an id not present in the choices
+ * map. There can be more than one id separated by
+ * {@link #CHOICE_SEP}.
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param titles The UI-visible titles of the children
+ * @param iconUrl the icon to use for the multiple choice action itself
+ * @param sortPriority the sorting priority to use for the multiple choice
+ * action itself
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @return the new {@link Choices}
+ */
+ public static Choices createChoices(String id, String title,
+ IMenuCallback callback, List<String> titles, List<URL> iconUrls, List<String> ids,
+ String current, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) {
+ Choices choices = new Choices(id, title, callback, titles, iconUrls,
+ ids, current, sortPriority, supportsMultipleNodes);
+ choices.setIconUrl(iconUrl);
+
+ return choices;
+ }
+
+ /**
+ * Creates a new immutable multiple-choice action with a defined ordered set
+ * of children.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The title of the action to be displayed to the user
+ * @param iconUrls The icon urls for the children items (may be null)
+ * @param current The id(s) of the current choice(s) that will be check
+ * marked. Can be null. Can be an id not present in the choices
+ * map. There can be more than one id separated by
+ * {@link #CHOICE_SEP}.
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param iconUrl the icon to use for the multiple choice action itself
+ * @param sortPriority the sorting priority to use for the multiple choice
+ * action itself
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @param idsAndTitles a list of pairs (of ids and titles) to use for the
+ * menu items
+ * @return the new {@link Choices}
+ */
+ public static Choices createChoices(String id, String title,
+ IMenuCallback callback, List<URL> iconUrls,
+ String current, URL iconUrl, int sortPriority,
+ boolean supportsMultipleNodes, List<Pair<String, String>> idsAndTitles) {
+ int itemCount = idsAndTitles.size();
+ List<String> titles = new ArrayList<String>(itemCount);
+ List<String> ids = new ArrayList<String>(itemCount);
+ for (Pair<String, String> pair : idsAndTitles) {
+ ids.add(pair.getFirst());
+ titles.add(pair.getSecond());
+ }
+ Choices choices = new Choices(id, title, callback, titles, iconUrls,
+ ids, current, sortPriority, supportsMultipleNodes);
+ choices.setIconUrl(iconUrl);
+ return choices;
+ }
+
+ /**
+ * Creates a new immutable multiple-choice action with lazily computed children.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The title of the multiple-choice itself
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param provider the provider which provides choices lazily
+ * @param current The id(s) of the current choice(s) that will be check
+ * marked. Can be null. Can be an id not present in the choice
+ * alternatives. There can be more than one id separated by
+ * {@link #CHOICE_SEP}.
+ * @param iconUrl the icon to use for the multiple choice action itself
+ * @param sortPriority the sorting priority to use for the multiple choice
+ * action itself
+ * @param supportsMultipleNodes whether this action supports multiple nodes,
+ * see {@link #supportsMultipleNodes()} for details
+ * @return the new {@link Choices}
+ */
+ public static Choices createChoices(String id, String title,
+ IMenuCallback callback, ChoiceProvider provider,
+ String current, URL iconUrl, int sortPriority, boolean supportsMultipleNodes) {
+ Choices choices = new DelayedChoices(id, title, callback,
+ current, provider, sortPriority, supportsMultipleNodes);
+ choices.setIconUrl(iconUrl);
+ return choices;
+ }
+
+ /**
+ * Creates a new {@link RuleAction} with the given id and the given title.
+ * Actions which have the same id and the same title are deemed equivalent.
+ *
+ * @param id The unique id of the action, which must be similar for all actions that
+ * perform the same task. Cannot be null.
+ * @param title The UI-visible title of the action.
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ * @param sortPriority a priority used for sorting this action
+ * @param supportsMultipleNodes the new return value for
+ * {@link #supportsMultipleNodes()}
+ */
+ private RuleAction(String id, String title, IMenuCallback callback, int sortPriority,
+ boolean supportsMultipleNodes) {
+ mId = id;
+ mTitle = title;
+ mSortPriority = sortPriority;
+ mSupportsMultipleNodes = supportsMultipleNodes;
+ mCallback = callback;
+ }
+
+ /**
+ * Returns the unique id of the action. In the context of a multiple selection,
+ * actions which have the same id are collapsed together and must represent the same
+ * action. Cannot be null.
+ *
+ * @return the unique id of the action, never null
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the UI-visible title of the action, shown in the context menu.
+ * Cannot be null.
+ *
+ * @return the user name of the action, never null
+ */
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Actions which have the same id and the same title are deemed equivalent.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof RuleAction) {
+ RuleAction rhs = (RuleAction) obj;
+
+ if (mId != rhs.mId && !(mId != null && mId.equals(rhs.mId))) return false;
+ if (mTitle != rhs.mTitle &&
+ !(mTitle != null && mTitle.equals(rhs.mTitle))) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Whether this action supports multiple nodes. An action which supports
+ * multiple nodes can be applied to different nodes by passing in different
+ * nodes to its callback. Some actions are hardcoded for a specific node (typically
+ * one that isn't selected, such as an action which affects the parent of a selected
+ * node), and these actions will not be added to the context menu when more than
+ * one node is selected.
+ *
+ * @return true if this node supports multiple nodes
+ */
+ public boolean supportsMultipleNodes() {
+ return mSupportsMultipleNodes;
+ }
+
+ /**
+ * Actions which have the same id and the same title have the same hash code.
+ */
+ @Override
+ public int hashCode() {
+ int h = mId == null ? 0 : mId.hashCode();
+ h = h ^ (mTitle == null ? 0 : mTitle.hashCode());
+ return h;
+ }
+
+ /**
+ * 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
+ * @return this action, to allow setter chaining
+ */
+ public RuleAction setIconUrl(URL iconUrl) {
+ mIconUrl = iconUrl;
+
+ return this;
+ }
+
+ /**
+ * Return a priority used for sorting this action
+ *
+ * @return a priority used for sorting this action
+ */
+ public int getSortPriority() {
+ return mSortPriority;
+ }
+
+ /**
+ * Returns the callback executed when the action is selected in the
+ * context menu. Cannot be null.
+ *
+ * @return the callback, never null
+ */
+ public IMenuCallback getCallback() {
+ return mCallback;
+ }
+
+ // Implements Comparable<MenuAciton>
+ public int compareTo(RuleAction other) {
+ if (mSortPriority != other.mSortPriority) {
+ return mSortPriority - other.mSortPriority;
+ }
+
+ return mTitle.compareTo(other.mTitle);
+ }
+
+ @Override
+ public String toString() {
+ return "RuleAction [id=" + mId + ", title=" + mTitle + ", priority=" + mSortPriority + "]";
+ }
+
+ /** A separator to display between actions */
+ public static class Separator extends RuleAction {
+ /** Construct using the factory {@link #createSeparator(int)} */
+ private Separator(int sortPriority, boolean supportsMultipleNodes) {
+ super("_separator", "", null, sortPriority, //$NON-NLS-1$ //$NON-NLS-2$
+ supportsMultipleNodes);
+ }
+ }
+
+ /**
+ * 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.
+ * <p/>
+ * Two toggles are equal if they have the same id, title and group-id.
+ * It is expected for the checked state and action callback to be different.
+ */
+ public static class Toggle extends RuleAction {
+ /**
+ * True if the item is displayed with a check mark.
+ */
+ private final boolean mIsChecked;
+
+ /**
+ * Creates a new immutable toggle action.
+ *
+ * @param id The unique id of the action. Cannot be null.
+ * @param title The UI-visible title of the context menu item. Cannot be null.
+ * @param isChecked Whether the context menu item has a check mark.
+ * @param callback A callback to execute when the context menu item is
+ * selected.
+ */
+ private Toggle(String id, String title, boolean isChecked,
+ IMenuCallback callback, int sortPriority, boolean supportsMultipleNodes) {
+ super(id, title, callback, sortPriority, supportsMultipleNodes);
+ mIsChecked = isChecked;
+ }
+
+ /**
+ * Returns true if the item is displayed with a check mark.
+ *
+ * @return true if the item is displayed with a check mark.
+ */
+ public boolean isChecked() {
+ return mIsChecked;
+ }
+
+ /**
+ * Two toggles are equal if they have the same id and title.
+ * It is acceptable for the checked state and action callback to be different.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * Two toggles have the same hash code if they have the same id and title.
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+ }
+
+ /**
+ * An ordered list of choices the user can choose between. For choosing between
+ * actions, there is a {@link NestedAction} class.
+ */
+ public static class Choices extends RuleAction {
+ protected List<String> mTitles;
+ protected List<URL> mIconUrls;
+ protected List<String> mIds;
+ private boolean mRadio;
+
+ /**
+ * 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;
+
+ private Choices(String id, String title, IMenuCallback callback,
+ List<String> titles, List<URL> iconUrls, List<String> ids, String current,
+ int sortPriority, boolean supportsMultipleNodes) {
+ super(id, title, callback, sortPriority, supportsMultipleNodes);
+ mTitles = titles;
+ mIconUrls = iconUrls;
+ mIds = ids;
+ mCurrent = current;
+ }
+
+ /**
+ * Returns the list of urls to icons to display for each choice, or null
+ *
+ * @return the list of urls to icons to display for each choice, or null
+ */
+ public List<URL> getIconUrls() {
+ return mIconUrls;
+ }
+
+ /**
+ * Returns the list of ids for the menu choices, never null
+ *
+ * @return the list of ids for the menu choices, never null
+ */
+ public List<String> getIds() {
+ return mIds;
+ }
+
+ /**
+ * Returns the titles to be displayed for the menu choices, never null
+ *
+ * @return the titles to be displayed for the menu choices, never null
+ */
+ public List<String> getTitles() {
+ return mTitles;
+ }
+
+ /**
+ * Returns the current value of the choice
+ *
+ * @return the current value of the choice, possibly null
+ */
+ public String getCurrent() {
+ return mCurrent;
+ }
+
+ /**
+ * Set whether this choice list is best visualized as a radio group (instead of a
+ * dropdown)
+ *
+ * @param radio true if this choice list should be visualized as a radio group
+ */
+ public void setRadio(boolean radio) {
+ mRadio = radio;
+ }
+
+ /**
+ * Returns true if this choice list is best visualized as a radio group (instead
+ * of a dropdown)
+ *
+ * @return true if this choice list should be visualized as a radio group
+ */
+ public boolean isRadio() {
+ return mRadio;
+ }
+ }
+
+ /**
+ * An ordered list of actions the user can choose between. Similar to
+ * {@link Choices} but for actions instead.
+ */
+ public static class NestedAction extends RuleAction {
+ /** The provider to produce the list of nested actions when needed */
+ private final ActionProvider mProvider;
+
+ private NestedAction(String id, String title, ActionProvider provider,
+ IMenuCallback callback, int sortPriority,
+ boolean supportsMultipleNodes) {
+ super(id, title, callback, sortPriority, supportsMultipleNodes);
+ mProvider = provider;
+ }
+
+ /**
+ * Returns the nested actions available for the given node
+ *
+ * @param node the node to look up nested actions for
+ * @return a list of nested actions
+ */
+ public List<RuleAction> getNestedActions(INode node) {
+ return mProvider.getNestedActions(node);
+ }
+ }
+
+ /** Like {@link Choices}, but the set of choices is computed lazily */
+ private static class DelayedChoices extends Choices {
+ private final ChoiceProvider mProvider;
+
+ private DelayedChoices(String id, String title,
+ IMenuCallback callback, String current, ChoiceProvider provider,
+ int sortPriority, boolean supportsMultipleNodes) {
+ super(id, title, callback, null, null, null, current, sortPriority,
+ supportsMultipleNodes);
+ 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;
+ }
+ }
+
+ /**
+ * Provides the set of nested action choices associated with a {@link NestedAction}
+ * object when they are needed. Useful for lazy initialization of context
+ * menus and popup menus until they are actually needed.
+ */
+ public interface ActionProvider {
+ /**
+ * Returns the nested actions available for the given node
+ *
+ * @param node the node to look up nested actions for
+ * @return a list of nested actions
+ */
+ public List<RuleAction> getNestedActions(INode node);
+ }
+
+ /**
+ * Provides the set of choices associated with an {@link Choices}
+ * 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.
+ * Use {@link RuleAction#SEPARATOR} to create separators.
+ *
+ * @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);
+ }
+}
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 1a99385..5191d25 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
@@ -66,8 +66,9 @@ 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;
-import com.android.ide.common.api.MenuAction.ChoiceProvider;
+import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.RuleAction;
+import com.android.ide.common.api.RuleAction.ChoiceProvider;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.Segment;
@@ -85,6 +86,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+/**
+ * A {@link IViewRule} for all layouts.
+ */
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$
@@ -102,7 +106,7 @@ public class BaseLayoutRule extends BaseViewRule {
// The Margin layout parameters are available for LinearLayout, FrameLayout, RelativeLayout,
// and their subclasses.
- protected final MenuAction createMarginAction(final INode parentNode,
+ protected final RuleAction createMarginAction(final INode parentNode,
final List<? extends INode> children) {
final List<? extends INode> targets = children == null || children.size() == 0 ?
@@ -111,7 +115,8 @@ public class BaseLayoutRule extends BaseViewRule {
final INode first = targets.get(0);
IMenuCallback actionCallback = new IMenuCallback() {
- public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ public void action(RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
parentNode.editXml("Change Margins", new INodeHandler() {
public void handle(INode n) {
String uri = ANDROID_URI;
@@ -137,13 +142,13 @@ public class BaseLayoutRule extends BaseViewRule {
}
};
- return MenuAction.createAction(ACTION_MARGIN, "Change Margins...", null, actionCallback,
- ICON_MARGINS, 40);
+ return RuleAction.createAction(ACTION_MARGIN, "Change Margins...", actionCallback,
+ ICON_MARGINS, 40, false);
}
// Both LinearLayout and RelativeLayout have a gravity (but RelativeLayout applies it
// to the parent whereas for LinearLayout it's on the children)
- protected final MenuAction createGravityAction(final List<? extends INode> targets, final
+ protected final RuleAction createGravityAction(final List<? extends INode> targets, final
String attributeName) {
if (targets != null && targets.size() > 0) {
final INode first = targets.get(0);
@@ -162,20 +167,19 @@ public class BaseLayoutRule extends BaseViewRule {
}
};
- return MenuAction.createChoices("_gravity", "Change Gravity", //$NON-NLS-1$
- null,
+ return RuleAction.createChoices("_gravity", "Change Gravity", //$NON-NLS-1$
new PropertyCallback(targets, "Change Gravity", ANDROID_URI,
attributeName),
provider,
first.getStringAttr(ANDROID_URI, attributeName), ICON_GRAVITY,
- 43);
+ 43, false);
}
return null;
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
@@ -186,7 +190,8 @@ public class BaseLayoutRule extends BaseViewRule {
// Shared action callback
IMenuCallback actionCallback = new IMenuCallback() {
- public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ public void action(RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
final String actionId = action.getId();
final String undoLabel;
if (actionId.equals(ACTION_FILL_WIDTH)) {
@@ -218,10 +223,10 @@ public class BaseLayoutRule extends BaseViewRule {
}
};
- 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));
+ actions.add(RuleAction.createToggle(ACTION_FILL_WIDTH, "Toggle Fill Width",
+ isFilled(first, ATTR_LAYOUT_WIDTH), actionCallback, ICON_FILL_WIDTH, 10, false));
+ actions.add(RuleAction.createToggle(ACTION_FILL_HEIGHT, "Toggle Fill Height",
+ isFilled(first, ATTR_LAYOUT_HEIGHT), actionCallback, ICON_FILL_HEIGHT, 20, false));
}
// ==== Paste support ====
@@ -256,6 +261,10 @@ public class BaseLayoutRule extends BaseViewRule {
* This method is invoked by BaseView when onPaste() is called --
* views don't generally accept children and instead use the target node as
* a hint to paste "before" it.
+ *
+ * @param parentNode the parent node we're pasting into
+ * @param targetNode the first selected node
+ * @param elements the elements being pasted
*/
public void onPasteBeforeChild(INode parentNode, INode targetNode, IDragElement[] elements) {
@@ -737,6 +746,12 @@ public class BaseLayoutRule extends BaseViewRule {
}
}
+ /**
+ * Returns the maximum number of pixels will be considered a "match" when snapping
+ * resize or move positions to edges or other constraints
+ *
+ * @return the maximum number of pixels to consider for snapping
+ */
public static final int getMaxMatchDistance() {
// TODO - make constant once we're happy with the feel
return 20;
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 625ae34..66688d9 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
@@ -35,22 +35,29 @@ 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.IValidator;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
-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.RuleAction;
+import com.android.ide.common.api.RuleAction.ActionProvider;
+import com.android.ide.common.api.RuleAction.ChoiceProvider;
+import com.android.ide.common.api.RuleAction.Choices;
import com.android.ide.common.api.SegmentType;
+import com.android.util.Pair;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
/**
@@ -58,16 +65,15 @@ import java.util.Set;
*/
public class BaseViewRule implements IViewRule {
// Strings used as internal ids, group ids and prefixes for actions
- private static final String FALSE_ID = "2f"; //$NON-NLS-1$
- private static final String TRUE_ID = "1t"; //$NON-NLS-1$
+ private static final String FALSE_ID = "false"; //$NON-NLS-1$
+ private static final String TRUE_ID = "true"; //$NON-NLS-1$
private static final String PROP_PREFIX = "@prop@"; //$NON-NLS-1$
- private static final String SEPARATOR_ID = "~1sep"; //$NON-NLS-1$
- private static final String DEFAULT_ID = "~2clr"; //$NON-NLS-1$
+ private static final String CLEAR_ID = "clear"; //$NON-NLS-1$
private static final String PROPERTIES_ID = "properties"; //$NON-NLS-1$
private static final String EDIT_TEXT_ID = "edittext"; //$NON-NLS-1$
private static final String EDIT_ID_ID = "editid"; //$NON-NLS-1$
- private static final String WIDTH_ID = "layout_1width"; //$NON-NLS-1$
- private static final String HEIGHT_ID = "layout_2height"; //$NON-NLS-1$
+ private static final String WIDTH_ID = "layout_width"; //$NON-NLS-1$
+ private static final String HEIGHT_ID = "layout_height"; //$NON-NLS-1$
private static final String ZCUSTOM = "zcustom"; //$NON-NLS-1$
protected IClientRulesEngine mRulesEngine;
@@ -115,108 +121,114 @@ public class BaseViewRule implements IViewRule {
* - Explicit layout_width and layout_height attributes.
* - List of all other simple toggle attributes.
*/
- public List<MenuAction> getContextMenu(final INode selectedNode) {
- // Compute the key for mAttributesMap. This depends on the type of this
- // node and its parent in the view hierarchy.
- StringBuilder keySb = new StringBuilder();
- keySb.append(selectedNode.getFqcn());
- keySb.append('_');
- INode parent = selectedNode.getParent();
- if (parent != null) {
- keySb.append(parent.getFqcn());
- }
- final String key = keySb.toString();
-
- String custom_w = null;
- String curr_w = selectedNode.getStringAttr(ANDROID_URI, ATTR_LAYOUT_WIDTH);
+ public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) {
+ String width = null;
+ String currentWidth = selectedNode.getStringAttr(ANDROID_URI, ATTR_LAYOUT_WIDTH);
String fillParent = getFillParentValueName();
boolean canMatchParent = supportsMatchParent();
- if (canMatchParent && VALUE_FILL_PARENT.equals(curr_w)) {
- curr_w = VALUE_MATCH_PARENT;
- } else if (!canMatchParent && VALUE_MATCH_PARENT.equals(curr_w)) {
- curr_w = VALUE_FILL_PARENT;
- } else if (!VALUE_WRAP_CONTENT.equals(curr_w) && !fillParent.equals(curr_w)) {
- custom_w = curr_w;
+ if (canMatchParent && VALUE_FILL_PARENT.equals(currentWidth)) {
+ currentWidth = VALUE_MATCH_PARENT;
+ } else if (!canMatchParent && VALUE_MATCH_PARENT.equals(currentWidth)) {
+ currentWidth = VALUE_FILL_PARENT;
+ } else if (!VALUE_WRAP_CONTENT.equals(currentWidth) && !fillParent.equals(currentWidth)) {
+ width = currentWidth;
}
- String custom_h = null;
- String curr_h = selectedNode.getStringAttr(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
+ String height = null;
+ String currentHeight = selectedNode.getStringAttr(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- if (canMatchParent && VALUE_FILL_PARENT.equals(curr_h)) {
- curr_h = VALUE_MATCH_PARENT;
- } else if (!canMatchParent && VALUE_MATCH_PARENT.equals(curr_h)) {
- curr_h = VALUE_FILL_PARENT;
- } else if (!VALUE_WRAP_CONTENT.equals(curr_h) && !fillParent.equals(curr_h)) {
- custom_h = curr_h;
+ if (canMatchParent && VALUE_FILL_PARENT.equals(currentHeight)) {
+ currentHeight = VALUE_MATCH_PARENT;
+ } else if (!canMatchParent && VALUE_MATCH_PARENT.equals(currentHeight)) {
+ currentHeight = VALUE_FILL_PARENT;
+ } else if (!VALUE_WRAP_CONTENT.equals(currentHeight)
+ && !fillParent.equals(currentHeight)) {
+ height = currentHeight;
}
- final String customWidth = custom_w;
- final String customHeight = custom_h;
-
- IMenuCallback onChange = new IMenuCallback() {
+ final String newWidth = width;
+ final String newHeight = height;
+ final IMenuCallback onChange = new IMenuCallback() {
public void action(
- final MenuAction action,
- final String valueId,
- final Boolean newValue) {
+ final RuleAction action,
+ final List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
String fullActionId = action.getId();
boolean isProp = fullActionId.startsWith(PROP_PREFIX);
final String actionId = isProp ?
fullActionId.substring(PROP_PREFIX.length()) : fullActionId;
- final INode node = selectedNode;
if (fullActionId.equals(WIDTH_ID)) {
- final String newAttrValue = getValue(valueId, customWidth);
+ final String newAttrValue = getValue(valueId, newWidth);
if (newAttrValue != null) {
- node.editXml("Change Attribute " + ATTR_LAYOUT_WIDTH,
- new PropertySettingNodeHandler(ANDROID_URI,
- ATTR_LAYOUT_WIDTH, newAttrValue));
+ for (INode node : selectedNodes) {
+ node.editXml("Change Attribute " + ATTR_LAYOUT_WIDTH,
+ new PropertySettingNodeHandler(ANDROID_URI,
+ ATTR_LAYOUT_WIDTH, newAttrValue));
+ }
}
return;
} else if (fullActionId.equals(HEIGHT_ID)) {
// Ask the user
- final String newAttrValue = getValue(valueId, customHeight);
+ final String newAttrValue = getValue(valueId, newHeight);
if (newAttrValue != null) {
- node.editXml("Change Attribute " + ATTR_LAYOUT_HEIGHT,
- new PropertySettingNodeHandler(ANDROID_URI,
- ATTR_LAYOUT_HEIGHT, newAttrValue));
+ for (INode node : selectedNodes) {
+ node.editXml("Change Attribute " + ATTR_LAYOUT_HEIGHT,
+ new PropertySettingNodeHandler(ANDROID_URI,
+ ATTR_LAYOUT_HEIGHT, newAttrValue));
+ }
}
return;
} else if (fullActionId.equals(EDIT_ID_ID)) {
- // Strip off the @id prefix stuff
- String oldId = node.getStringAttr(ANDROID_URI, ATTR_ID);
- oldId = stripIdPrefix(ensureValidString(oldId));
- IValidator validator = mRulesEngine.getResourceValidator();
- String newId = mRulesEngine.displayInput("New Id:", oldId, validator);
- if (newId != null && newId.trim().length() > 0) {
- if (!newId.startsWith(NEW_ID_PREFIX)) {
- newId = NEW_ID_PREFIX + stripIdPrefix(newId);
+ // Ids must be set individually so open the id dialog for each
+ // selected node (though allow cancel to break the loop)
+ for (INode node : selectedNodes) {
+ // Strip off the @id prefix stuff
+ String oldId = node.getStringAttr(ANDROID_URI, ATTR_ID);
+ oldId = stripIdPrefix(ensureValidString(oldId));
+ IValidator validator = mRulesEngine.getResourceValidator();
+ String newId = mRulesEngine.displayInput("New Id:", oldId, validator);
+ if (newId != null && newId.trim().length() > 0) {
+ if (!newId.startsWith(NEW_ID_PREFIX)) {
+ newId = NEW_ID_PREFIX + stripIdPrefix(newId);
+ }
+ node.editXml("Change ID", new PropertySettingNodeHandler(ANDROID_URI,
+ ATTR_ID, newId));
+ } else if (newId == null) {
+ // Cancelled
+ break;
}
- node.editXml("Change ID", new PropertySettingNodeHandler(ANDROID_URI,
- ATTR_ID, newId));
- }
- } else if (fullActionId.equals(EDIT_TEXT_ID)) {
- String oldText = node.getStringAttr(ANDROID_URI, ATTR_TEXT);
- oldText = ensureValidString(oldText);
- String newText = mRulesEngine.displayResourceInput("string", oldText); //$NON-NLS-1$
- if (newText != null) {
- node.editXml("Change Text", new PropertySettingNodeHandler(ANDROID_URI,
- ATTR_TEXT, newText.length() > 0 ? newText : null));
}
- }
-
- if (isProp) {
- Map<String, Prop> props = mAttributesMap.get(key);
- final Prop prop = (props != null) ? props.get(actionId) : null;
-
- if (prop != null) {
- // For custom values (requiring an input dialog) input the
- // value outside the undo-block
- final String customValue = prop.isStringEdit()
- ? inputAttributeValue(node, actionId) : null;
-
- node.editXml("Change Attribute " + actionId, new INodeHandler() {
- public void handle(INode n) {
+ return;
+ } else {
+ INode firstNode = selectedNodes.get(0);
+ if (fullActionId.equals(EDIT_TEXT_ID)) {
+ String oldText = selectedNodes.size() == 1
+ ? firstNode.getStringAttr(ANDROID_URI, ATTR_TEXT)
+ : ""; //$NON-NLS-1$
+ oldText = ensureValidString(oldText);
+ String newText = mRulesEngine.displayResourceInput("string", oldText); //$NON-NLS-1$
+ if (newText != null) {
+ for (INode node : selectedNodes) {
+ node.editXml("Change Text",
+ new PropertySettingNodeHandler(ANDROID_URI,
+ ATTR_TEXT, newText.length() > 0 ? newText : null));
+ }
+ }
+ return;
+ } else if (isProp) {
+ String key = getPropertyMapKey(selectedNode);
+ Map<String, Prop> props = mAttributesMap.get(key);
+ final Prop prop = (props != null) ? props.get(actionId) : null;
+
+ if (prop != null) {
+ // For custom values (requiring an input dialog) input the
+ // value outside the undo-block
+ final String customValue = prop.isStringEdit()
+ ? inputAttributeValue(firstNode, actionId) : null;
+
+ for (INode n : selectedNodes) {
if (prop.isToggle()) {
// case of toggle
String value = ""; //$NON-NLS-1$
@@ -229,7 +241,7 @@ public class BaseViewRule implements IViewRule {
} else if (prop.isFlag()) {
// case of a flag
String values = ""; //$NON-NLS-1$
- if (!valueId.equals(DEFAULT_ID)) {
+ if (!valueId.equals(CLEAR_ID)) {
values = n.getStringAttr(ANDROID_URI, actionId);
Set<String> newValues = new HashSet<String>();
if (values != null) {
@@ -247,7 +259,7 @@ public class BaseViewRule implements IViewRule {
} else if (prop.isEnum()) {
// case of an enum
String value = ""; //$NON-NLS-1$
- if (!valueId.equals(DEFAULT_ID)) {
+ if (!valueId.equals(CLEAR_ID)) {
value = newValue ? valueId : ""; //$NON-NLS-1$
}
n.setAttribute(ANDROID_URI, actionId, value);
@@ -259,7 +271,7 @@ public class BaseViewRule implements IViewRule {
}
}
}
- });
+ }
}
}
}
@@ -318,40 +330,91 @@ public class BaseViewRule implements IViewRule {
}
};
- MenuAction.Action editText = null;
IAttributeInfo textAttribute = selectedNode.getAttributeInfo(ANDROID_URI, ATTR_TEXT);
if (textAttribute != null) {
- editText = new MenuAction.Action(EDIT_TEXT_ID, "Edit Text...", null, onChange);
+ actions.add(RuleAction.createAction(EDIT_TEXT_ID, "Edit Text...", onChange,
+ null, 10, true));
}
- List<MenuAction> list1 = Arrays.asList(new MenuAction[] {
- editText, // could be null - will be ignored by menu creation code
- new MenuAction.Action(EDIT_ID_ID, "Edit ID...", null, onChange),
-
- new MenuAction.Choices(WIDTH_ID, "Layout Width",
- mapify(
- VALUE_WRAP_CONTENT, "Wrap Content",
- canMatchParent ? VALUE_MATCH_PARENT : VALUE_FILL_PARENT,
- canMatchParent ? "Match Parent" : "Fill Parent",
- custom_w, custom_w,
- ZCUSTOM, "Other..."
- ),
- curr_w,
- onChange ),
- new MenuAction.Choices(HEIGHT_ID, "Layout Height",
- mapify(
- VALUE_WRAP_CONTENT, "Wrap Content",
- canMatchParent ? VALUE_MATCH_PARENT : VALUE_FILL_PARENT,
- canMatchParent ? "Match Parent" : "Fill Parent",
- custom_h, custom_h,
- ZCUSTOM, "Other..."
- ),
- curr_h,
- onChange ),
- new MenuAction.Group(PROPERTIES_ID, "Properties")
+ actions.add(RuleAction.createAction(EDIT_ID_ID, "Edit ID...", onChange, null, 20, true));
+
+ // Create width choice submenu
+ List<Pair<String, String>> widthChoices = new ArrayList<Pair<String,String>>(4);
+ widthChoices.add(Pair.of(VALUE_WRAP_CONTENT, "Wrap Content"));
+ if (canMatchParent) {
+ widthChoices.add(Pair.of(VALUE_MATCH_PARENT, "Match Parent"));
+ } else {
+ widthChoices.add(Pair.of(VALUE_FILL_PARENT, "Fill Parent"));
+ }
+ if (width != null) {
+ widthChoices.add(Pair.of(width, width));
+ }
+ widthChoices.add(Pair.of(ZCUSTOM, "Other..."));
+ actions.add(RuleAction.createChoices(
+ WIDTH_ID, "Layout Width",
+ onChange,
+ null /* iconUrls */,
+ currentWidth,
+ null, 30,
+ true, // supportsMultipleNodes
+ widthChoices));
+
+ // Create height choice submenu
+ List<Pair<String, String>> heightChoices = new ArrayList<Pair<String,String>>(4);
+ heightChoices.add(Pair.of(VALUE_WRAP_CONTENT, "Wrap Content"));
+ if (canMatchParent) {
+ heightChoices.add(Pair.of(VALUE_MATCH_PARENT, "Match Parent"));
+ } else {
+ heightChoices.add(Pair.of(VALUE_FILL_PARENT, "Fill Parent"));
+ }
+ if (height != null) {
+ heightChoices.add(Pair.of(height, height));
+ }
+ heightChoices.add(Pair.of(ZCUSTOM, "Other..."));
+ actions.add(RuleAction.createChoices(
+ HEIGHT_ID, "Layout Height",
+ onChange,
+ null /* iconUrls */,
+ currentHeight,
+ null, 40,
+ true,
+ heightChoices));
+
+ actions.add(RuleAction.createSeparator(45));
+ RuleAction properties = RuleAction.createChoices(PROPERTIES_ID, "Properties",
+ onChange /*callback*/, null /*icon*/, 50,
+ true /*supportsMultipleNodes*/, new ActionProvider() {
+ public List<RuleAction> getNestedActions(INode node) {
+ List<RuleAction> propertyActions = createPropertyActions(node,
+ getPropertyMapKey(node), onChange);
+
+ return propertyActions;
+ }
});
- // Prepare a list of all simple properties.
+ actions.add(properties);
+ }
+
+ private static String getPropertyMapKey(INode node) {
+ // Compute the key for mAttributesMap. This depends on the type of this
+ // node and its parent in the view hierarchy.
+ StringBuilder sb = new StringBuilder();
+ sb.append(node.getFqcn());
+ sb.append('_');
+ INode parent = node.getParent();
+ if (parent != null) {
+ sb.append(parent.getFqcn());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Creates a list of nested actions representing the property-setting
+ * actions for the given selected node
+ */
+ private List<RuleAction> createPropertyActions(final INode selectedNode, final String key,
+ final IMenuCallback onChange) {
+ List<RuleAction> propertyActions = new ArrayList<RuleAction>();
Map<String, Prop> props = mAttributesMap.get(key);
if (props == null) {
@@ -399,12 +462,10 @@ public class BaseViewRule implements IViewRule {
mAttributesMap.put(key, props);
}
- List<MenuAction> list2 = new ArrayList<MenuAction>();
-
+ int nextPriority = 10;
for (Map.Entry<String, Prop> entry : props.entrySet()) {
String id = entry.getKey();
Prop p = entry.getValue();
- MenuAction a = null;
if (p.isToggle()) {
// Toggles are handled as a multiple-choice between true, false
// and nothing (clear)
@@ -416,51 +477,91 @@ public class BaseViewRule implements IViewRule {
} else if ("false".equals(value)) { //$NON-NLS-1$
value = FALSE_ID;
} else {
- value = "4clr"; //$NON-NLS-1$
+ value = CLEAR_ID;
}
-
- a = new MenuAction.Choices(
- PROP_PREFIX + id,
- p.getTitle(),
- mapify(
- TRUE_ID, "True",
- FALSE_ID, "False",
- "3sep", MenuAction.Choices.SEPARATOR, //$NON-NLS-1$
- "4clr", "Default"), //$NON-NLS-1$
- value,
- PROPERTIES_ID,
- onChange);
+ Choices action = RuleAction.createChoices(PROP_PREFIX + id, p.getTitle(),
+ onChange, BOOLEAN_CHOICE_PROVIDER,
+ value,
+ null, nextPriority++,
+ true);
+ propertyActions.add(action);
} else if (p.getChoices() != null) {
// Enum or flags. Their possible values are the multiple-choice
// items, with an extra "clear" option to remove everything.
String current = selectedNode.getStringAttr(ANDROID_URI, id);
if (current == null || current.length() == 0) {
- current = DEFAULT_ID;
+ current = CLEAR_ID;
}
- a = new MenuAction.Choices(
- PROP_PREFIX + id,
- p.getTitle(),
- concatenate(
- p.getChoices(),
- mapify(
- SEPARATOR_ID, MenuAction.Choices.SEPARATOR,
- DEFAULT_ID, "Default"
- )
- ),
- current,
- PROPERTIES_ID,
- onChange);
+ Choices action = RuleAction.createChoices(PROP_PREFIX + id, p.getTitle(),
+ onChange, new EnumPropertyChoiceProvider(p),
+ current,
+ null, nextPriority++,
+ true);
+ propertyActions.add(action);
} else {
- a = new MenuAction.Action(
+ RuleAction action = RuleAction.createAction(
PROP_PREFIX + id,
p.getTitle(),
- PROPERTIES_ID,
- onChange);
+ onChange,
+ null, nextPriority++,
+ true);
+ propertyActions.add(action);
+ }
+ }
+
+ // The properties are coming out of map key order which isn't right
+ Collections.sort(propertyActions, new Comparator<RuleAction>() {
+ public int compare(RuleAction action1, RuleAction action2) {
+ return action1.getTitle().compareTo(action2.getTitle());
}
- list2.add(a);
+ });
+ return propertyActions;
+ }
+
+ /**
+ * A {@link ChoiceProvder} which provides alternatives suitable for choosing
+ * values for a boolean property: true, false, or "default".
+ */
+ private static ChoiceProvider BOOLEAN_CHOICE_PROVIDER = new ChoiceProvider() {
+ public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids) {
+ titles.add("True");
+ ids.add(TRUE_ID);
+
+ titles.add("False");
+ ids.add(FALSE_ID);
+
+ titles.add(RuleAction.SEPARATOR);
+ ids.add(RuleAction.SEPARATOR);
+
+ titles.add("Default");
+ ids.add(CLEAR_ID);
+ }
+ };
+
+ /**
+ * A {@link ChoiceProvider} which provides the various available
+ * attribute values available for a given {@link Prop} property descriptor.
+ */
+ private static class EnumPropertyChoiceProvider implements ChoiceProvider {
+ private Prop mProperty;
+
+ public EnumPropertyChoiceProvider(Prop property) {
+ super();
+ this.mProperty = property;
}
- return concatenate(list1, list2);
+ public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids) {
+ for (Entry<String, String> entry : mProperty.getChoices().entrySet()) {
+ ids.add(entry.getKey());
+ titles.add(entry.getValue());
+ }
+
+ titles.add(RuleAction.SEPARATOR);
+ ids.add(RuleAction.SEPARATOR);
+
+ titles.add("Default");
+ ids.add(CLEAR_ID);
+ }
}
/**
@@ -504,21 +605,6 @@ public class BaseViewRule implements IViewRule {
return sb.toString();
}
- // Concatenate two menu action lists. Move these utilities into MenuAction
- static List<MenuAction> concatenate(List<MenuAction> pre, List<MenuAction> post) {
- List<MenuAction> result = new ArrayList<MenuAction>(pre.size() + post.size());
- result.addAll(pre);
- result.addAll(post);
- return result;
- }
-
- static List<MenuAction> concatenate(List<MenuAction> pre, MenuAction post) {
- List<MenuAction> result = new ArrayList<MenuAction>(pre.size() + 1);
- result.addAll(pre);
- result.add(post);
- return result;
- }
-
static Map<String, String> concatenate(Map<String, String> pre, Map<String, String> post) {
Map<String, String> result = new HashMap<String, String>(pre.size() + post.size());
result.putAll(pre);
@@ -555,7 +641,7 @@ public class BaseViewRule implements IViewRule {
return null;
}
- public void addLayoutActions(List<MenuAction> actions, INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, INode parentNode,
List<? extends INode> children) {
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java
index dfe9d6f..e26df79 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java
@@ -23,7 +23,7 @@ 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.InsertType;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import java.util.List;
@@ -51,12 +51,15 @@ public class EditTextRule extends BaseViewRule {
* Adds a "Request Focus" menu item.
*/
@Override
- public List<MenuAction> getContextMenu(final INode selectedNode) {
+ public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) {
+ super.addContextMenuActions(actions, selectedNode);
+
final boolean hasFocus = hasFocus(selectedNode);
final String label = hasFocus ? "Clear Focus" : "Request Focus";
IMenuCallback onChange = new IMenuCallback() {
- public void action(MenuAction menuAction, String valueId, Boolean newValue) {
+ public void action(RuleAction menuAction, List<? extends INode> selectedNodes,
+ String valueId, Boolean newValue) {
selectedNode.editXml(label, new INodeHandler() {
public void handle(INode node) {
INode focus = findFocus(findRoot(node));
@@ -71,8 +74,8 @@ public class EditTextRule extends BaseViewRule {
}
};
- return concatenate(super.getContextMenu(selectedNode),
- new MenuAction.Action("_setfocus", label, null, onChange)); //$NON-NLS-1$
+ actions.add(RuleAction.createAction("_setfocus", label, onChange, //$NON-NLS-1$
+ null, 5, false /*supportsMultipleNodes*/));
}
/** Returns true if the given node currently has focus */
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 b8c7408..884034f 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
@@ -31,7 +31,7 @@ import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.IViewMetadata;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.IViewMetadata.FillPreference;
@@ -156,10 +156,10 @@ public class FrameLayoutRule extends BaseLayoutRule {
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
- actions.add(MenuAction.createSeparator(25));
+ actions.add(RuleAction.createSeparator(25));
actions.add(createMarginAction(parentNode, children));
if (children != null && children.size() > 0) {
actions.add(createGravityAction(children, ATTR_LAYOUT_GRAVITY));
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
index 2e28713..47ea3d9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
@@ -31,8 +31,8 @@ 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.IViewRule;
-import com.android.ide.common.api.MenuAction;
-import com.android.ide.common.api.MenuAction.OrderedChoices;
+import com.android.ide.common.api.RuleAction;
+import com.android.ide.common.api.RuleAction.Choices;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.SegmentType;
@@ -130,32 +130,32 @@ public class GridLayoutRule extends BaseLayoutRule {
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
- OrderedChoices orientationAction = MenuAction.createChoices(
+ Choices orientationAction = RuleAction.createChoices(
ACTION_ORIENTATION,
"Orientation", //$NON-NLS-1$
- null, new PropertyCallback(Collections.singletonList(parentNode),
+ 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);
+ null /* icon */, -10, false);
orientationAction.setRadio(true);
actions.add(orientationAction);
// Gravity and margins
if (children != null && children.size() > 0) {
- actions.add(MenuAction.createSeparator(35));
+ actions.add(RuleAction.createSeparator(35));
actions.add(createMarginAction(parentNode, children));
actions.add(createGravityAction(children, ATTR_LAYOUT_GRAVITY));
}
IMenuCallback actionCallback = new IMenuCallback() {
- public void action(final MenuAction action, final String valueId,
- final Boolean newValue) {
+ public void action(final RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
parentNode.editXml("Add/Remove Row/Column", new INodeHandler() {
public void handle(INode n) {
String id = action.getId();
@@ -194,33 +194,33 @@ public class GridLayoutRule extends BaseLayoutRule {
};
// Add Row and Add Column
- actions.add(MenuAction.createSeparator(150));
- actions.add(MenuAction.createAction(ACTION_ADD_COL, "Add Column", null, actionCallback,
- ICON_ADD_COL, 160));
- actions.add(MenuAction.createAction(ACTION_ADD_ROW, "Add Row", null, actionCallback,
- ICON_ADD_ROW, 165));
+ actions.add(RuleAction.createSeparator(150));
+ actions.add(RuleAction.createAction(ACTION_ADD_COL, "Add Column", actionCallback,
+ ICON_ADD_COL, 160, false /* supportsMultipleNodes */));
+ actions.add(RuleAction.createAction(ACTION_ADD_ROW, "Add Row", actionCallback,
+ ICON_ADD_ROW, 165, false));
// Remove Row and Remove Column (if something is selected)
if (children != null && children.size() > 0) {
// TODO: Add "Merge Columns" and "Merge Rows" ?
- actions.add(MenuAction.createAction(ACTION_REMOVE_COL, "Remove Column", null,
- actionCallback, ICON_REMOVE_COL, 170));
- actions.add(MenuAction.createAction(ACTION_REMOVE_ROW, "Remove Row", null,
- actionCallback, ICON_REMOVE_ROW, 175));
+ actions.add(RuleAction.createAction(ACTION_REMOVE_COL, "Remove Column",
+ actionCallback, ICON_REMOVE_COL, 170, false));
+ actions.add(RuleAction.createAction(ACTION_REMOVE_ROW, "Remove Row",
+ actionCallback, ICON_REMOVE_ROW, 175, false));
}
- actions.add(MenuAction.createSeparator(185));
+ actions.add(RuleAction.createSeparator(185));
- actions.add(MenuAction.createToggle(ACTION_SNAP, "Snap to Grid",
- sSnapToGrid, actionCallback, ICON_SNAP, 190));
+ actions.add(RuleAction.createToggle(ACTION_SNAP, "Snap to Grid",
+ sSnapToGrid, actionCallback, ICON_SNAP, 190, false));
- actions.add(MenuAction.createToggle(ACTION_SHOW_GRID, "Show Structure",
- sShowStructure, actionCallback, ICON_SHOW_GRID, 200));
+ actions.add(RuleAction.createToggle(ACTION_SHOW_GRID, "Show Structure",
+ sShowStructure, actionCallback, ICON_SHOW_GRID, 200, false));
// Temporary: Diagnostics for GridLayout
- actions.add(MenuAction.createToggle(ACTION_DEBUG, "Debug",
- sDebugGridLayout, actionCallback, null, 210));
+ actions.add(RuleAction.createToggle(ACTION_DEBUG, "Debug",
+ sDebugGridLayout, actionCallback, null, 210, false));
}
/**
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 bf1efb5..ae42fc3 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
@@ -44,13 +44,14 @@ import com.android.ide.common.api.IViewMetadata;
import com.android.ide.common.api.IViewMetadata.FillPreference;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
-import com.android.ide.common.api.MenuAction;
-import com.android.ide.common.api.MenuAction.OrderedChoices;
+import com.android.ide.common.api.RuleAction;
+import com.android.ide.common.api.RuleAction.Choices;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.SegmentType;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.sdklib.SdkConstants;
+import com.android.util.Pair;
import java.net.URL;
import java.util.ArrayList;
@@ -91,21 +92,26 @@ public class LinearLayoutRule extends BaseLayoutRule {
* Add an explicit Orientation toggle to the context menu.
*/
@Override
- public List<MenuAction> getContextMenu(final INode selectedNode) {
+ public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) {
+ super.addContextMenuActions(actions, selectedNode);
if (supportsOrientation()) {
String current = getCurrentOrientation(selectedNode);
- IMenuCallback onChange = new PropertyCallback(Collections.singletonList(selectedNode),
+ IMenuCallback onChange = new PropertyCallback(
+ null, // use passed in nodes instead to support multiple nodes
"Change LinearLayout Orientation",
ANDROID_URI, ATTR_ORIENTATION);
- return concatenate(super.getContextMenu(selectedNode),
- new MenuAction.Choices(ACTION_ORIENTATION, "Orientation", //$NON-NLS-1$
- mapify(
- "horizontal", "Horizontal", //$NON-NLS-1$
- "vertical", "Vertical" //$NON-NLS-1$
- ),
- current, onChange));
- } else {
- return super.getContextMenu(selectedNode);
+ List<Pair<String, String>> alternatives = new ArrayList<Pair<String,String>>(2);
+ alternatives.add(Pair.of("horizontal", "Horizontal")); //$NON-NLS-1$
+ alternatives.add(Pair.of("vertical", "Vertical")); //$NON-NLS-1$
+ RuleAction action = RuleAction.createChoices(
+ ACTION_ORIENTATION, "Orientation", //$NON-NLS-1$
+ onChange,
+ null /* iconUrls */,
+ current,
+ null /* icon */, 5, true,
+ alternatives);
+
+ actions.add(action);
}
}
@@ -145,22 +151,22 @@ public class LinearLayoutRule extends BaseLayoutRule {
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
if (supportsOrientation()) {
- OrderedChoices action = MenuAction.createChoices(
+ Choices action = RuleAction.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.<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
+ -10,
+ false /* supportsMultipleNodes */
);
action.setRadio(true);
actions.add(action);
@@ -168,17 +174,17 @@ public class LinearLayoutRule extends BaseLayoutRule {
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",
+ actions.add(RuleAction.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));
+ ICON_BASELINE, 38, false));
}
// Gravity
if (children != null && children.size() > 0) {
- actions.add(MenuAction.createSeparator(35));
+ actions.add(RuleAction.createSeparator(35));
// Margins
actions.add(createMarginAction(parentNode, children));
@@ -188,8 +194,8 @@ public class LinearLayoutRule extends BaseLayoutRule {
// Weights
IMenuCallback actionCallback = new IMenuCallback() {
- public void action(final MenuAction action, final String valueId,
- final Boolean newValue) {
+ public void action(final RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
parentNode.editXml("Change Weight", new INodeHandler() {
public void handle(INode n) {
String id = action.getId();
@@ -222,15 +228,15 @@ public class LinearLayoutRule extends BaseLayoutRule {
});
}
};
- actions.add(MenuAction.createSeparator(50));
- actions.add(MenuAction.createAction(ACTION_DISTRIBUTE, "Distribute Weights Evenly",
- null, actionCallback, ICON_DISTRIBUTE, 60));
- actions.add(MenuAction.createAction(ACTION_DOMINATE, "Assign All Weight",
- null, actionCallback, ICON_DOMINATE, 70));
- actions.add(MenuAction.createAction(ACTION_WEIGHT, "Change Layout Weight", null,
- actionCallback, ICON_WEIGHTS, 80));
- actions.add(MenuAction.createAction(ACTION_CLEAR, "Clear All Weights",
- null, actionCallback, ICON_CLEAR_WEIGHTS, 90));
+ actions.add(RuleAction.createSeparator(50));
+ actions.add(RuleAction.createAction(ACTION_DISTRIBUTE, "Distribute Weights Evenly",
+ actionCallback, ICON_DISTRIBUTE, 60, false /*supportsMultipleNodes*/));
+ actions.add(RuleAction.createAction(ACTION_DOMINATE, "Assign All Weight",
+ actionCallback, ICON_DOMINATE, 70, false));
+ actions.add(RuleAction.createAction(ACTION_WEIGHT, "Change Layout Weight",
+ actionCallback, ICON_WEIGHTS, 80, false));
+ actions.add(RuleAction.createAction(ACTION_CLEAR, "Clear All Weights",
+ actionCallback, ICON_CLEAR_WEIGHTS, 90, false));
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java
index 77f5c22..12358f9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java
@@ -17,7 +17,7 @@
package com.android.ide.common.layout;
import com.android.ide.common.api.INode;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import java.util.List;
@@ -29,9 +29,8 @@ public class MergeRule extends FrameLayoutRule {
// on top of each other at (0,0)
@Override
- public List<MenuAction> getContextMenu(INode selectedNode) {
+ public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) {
// Deliberately ignore super.getContextMenu(); we don't want to attempt to list
// properties for the <merge> tag
- return null;
}
}
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
index 559aac8..45cd2c5 100644
--- 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
@@ -19,7 +19,7 @@ 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 com.android.ide.common.api.RuleAction;
import java.util.List;
@@ -33,6 +33,16 @@ public class PropertyCallback implements IMenuCallback {
private final String mUri;
private final String mAttribute;
+ /**
+ * Creates a new property callback.
+ *
+ * @param targetNodes the nodes to apply the property to, or null to use the
+ * nodes pass into the
+ * {@link #action(RuleAction, List, String, Boolean)} method.
+ * @param undoLabel the label to use for the undo action
+ * @param uri the attribute URI to apply
+ * @param attribute the attribute name to apply
+ */
public PropertyCallback(List<? extends INode> targetNodes, String undoLabel,
String uri, String attribute) {
super();
@@ -43,13 +53,18 @@ public class PropertyCallback implements IMenuCallback {
}
// ---- Implements IMenuCallback ----
- public void action(MenuAction action, final String valueId, final Boolean newValue) {
- if (mTargetNodes == null || mTargetNodes.size() == 0) {
+ public void action(RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
+ if (mTargetNodes != null && mTargetNodes.size() > 0) {
+ selectedNodes = mTargetNodes;
+ }
+ if (selectedNodes == null || selectedNodes.size() == 0) {
return;
}
- mTargetNodes.get(0).editXml(mUndoLabel, new INodeHandler() {
+ final List<? extends INode> nodes = selectedNodes;
+ selectedNodes.get(0).editXml(mUndoLabel, new INodeHandler() {
public void handle(INode n) {
- for (INode targetNode : mTargetNodes) {
+ for (INode targetNode : nodes) {
if (valueId != null) {
targetNode.setAttribute(mUri, mAttribute, valueId);
} else {
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 d53436f..90952c9 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
@@ -50,7 +50,7 @@ import com.android.ide.common.api.INode.IAttribute;
import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.common.api.SegmentType;
@@ -315,17 +315,18 @@ public class RelativeLayoutRule extends BaseLayoutRule {
// ==== Layout Actions Bar ====
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
actions.add(createGravityAction(Collections.<INode>singletonList(parentNode),
ATTR_GRAVITY));
- actions.add(MenuAction.createSeparator(25));
+ actions.add(RuleAction.createSeparator(25));
actions.add(createMarginAction(parentNode, children));
IMenuCallback callback = new IMenuCallback() {
- public void action(MenuAction action, final String valueId, final Boolean newValue) {
+ public void action(RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
final String id = action.getId();
if (id.equals(ACTION_CENTER_VERTICAL)|| id.equals(ACTION_CENTER_HORIZONTAL)) {
parentNode.editXml("Center", new INodeHandler() {
@@ -356,18 +357,18 @@ public class RelativeLayoutRule extends BaseLayoutRule {
// Centering actions
if (children != null && children.size() > 0) {
- actions.add(MenuAction.createSeparator(150));
- actions.add(MenuAction.createAction(ACTION_CENTER_VERTICAL, "Center Vertically", null,
- callback, ICON_CENTER_VERTICALLY, 160));
- actions.add(MenuAction.createAction(ACTION_CENTER_HORIZONTAL, "Center Horizontally",
- null, callback, ICON_CENTER_HORIZONTALLY, 170));
+ actions.add(RuleAction.createSeparator(150));
+ actions.add(RuleAction.createAction(ACTION_CENTER_VERTICAL, "Center Vertically",
+ callback, ICON_CENTER_VERTICALLY, 160, false));
+ actions.add(RuleAction.createAction(ACTION_CENTER_HORIZONTAL, "Center Horizontally",
+ callback, ICON_CENTER_HORIZONTALLY, 170, false));
}
- actions.add(MenuAction.createSeparator(80));
- actions.add(MenuAction.createToggle(ACTION_SHOW_CONSTRAINTS, "Show Constraints",
- sShowConstraints, callback, ICON_SHOW_CONSTRAINTS, 180));
- actions.add(MenuAction.createToggle(ACTION_SHOW_STRUCTURE, "Show All Relationships",
- sShowStructure, callback, ICON_SHOW_STRUCTURE, 190));
+ actions.add(RuleAction.createSeparator(80));
+ actions.add(RuleAction.createToggle(ACTION_SHOW_CONSTRAINTS, "Show Constraints",
+ sShowConstraints, callback, ICON_SHOW_CONSTRAINTS, 180, false));
+ actions.add(RuleAction.createToggle(ACTION_SHOW_STRUCTURE, "Show All Relationships",
+ sShowStructure, callback, ICON_SHOW_STRUCTURE, 190, false));
}
private void centerHorizontally(INode node) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
index d556e7d..4ae31b7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java
@@ -24,7 +24,7 @@ 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.InsertType;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import com.android.ide.common.api.SegmentType;
import java.net.URL;
@@ -69,21 +69,22 @@ public class TableLayoutRule extends LinearLayoutRule {
* Add an explicit "Add Row" action to the context menu
*/
@Override
- public List<MenuAction> getContextMenu(final INode selectedNode) {
+ public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) {
+ super.addContextMenuActions(actions, selectedNode);
+
IMenuCallback addTab = new IMenuCallback() {
- public void action(MenuAction action, final String valueId, Boolean newValue) {
+ public void action(RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, Boolean newValue) {
final INode node = selectedNode;
INode newRow = node.appendChild(FQCN_TABLE_ROW);
mRulesEngine.select(Collections.singletonList(newRow));
}
};
- return concatenate(super.getContextMenu(selectedNode),
- new MenuAction.Action("_addrow", "Add Row", //$NON-NLS-1$
- null, addTab));
+ actions.add(RuleAction.createAction("_addrow", "Add Row", addTab, null, 5, false)); //$NON-NLS-1$
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
addTableLayoutActions(mRulesEngine, actions, parentNode, children);
@@ -93,11 +94,11 @@ public class TableLayoutRule extends LinearLayoutRule {
* Adds layout actions to add and remove toolbar items
*/
static void addTableLayoutActions(final IClientRulesEngine rulesEngine,
- List<MenuAction> actions, final INode parentNode,
+ List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
IMenuCallback actionCallback = new IMenuCallback() {
- public void action(final MenuAction action, final String valueId,
- final Boolean newValue) {
+ public void action(final RuleAction action, List<? extends INode> selectedNodes,
+ final String valueId, final Boolean newValue) {
parentNode.editXml("Add/Remove Table Row", new INodeHandler() {
public void handle(INode n) {
if (action.getId().equals(ACTION_ADD_ROW)) {
@@ -155,14 +156,14 @@ public class TableLayoutRule extends LinearLayoutRule {
};
// Add Row
- actions.add(MenuAction.createSeparator(150));
- actions.add(MenuAction.createAction(ACTION_ADD_ROW, "Add Table Row", null, actionCallback,
- ICON_ADD_ROW, 160));
+ actions.add(RuleAction.createSeparator(150));
+ actions.add(RuleAction.createAction(ACTION_ADD_ROW, "Add Table Row", actionCallback,
+ ICON_ADD_ROW, 160, false));
// Remove Row (if something is selected)
if (children != null && children.size() > 0) {
- actions.add(MenuAction.createAction(ACTION_REMOVE_ROW, "Remove Table Row", null,
- actionCallback, ICON_REMOVE_ROW, 170));
+ actions.add(RuleAction.createAction(ACTION_REMOVE_ROW, "Remove Table Row",
+ actionCallback, ICON_REMOVE_ROW, 170, false));
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java
index 031e17b..dad71ed 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java
@@ -21,7 +21,7 @@ import com.android.ide.common.api.DropFeedback;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
-import com.android.ide.common.api.MenuAction;
+import com.android.ide.common.api.RuleAction;
import com.android.ide.common.api.SegmentType;
import java.util.List;
@@ -48,7 +48,7 @@ public class TableRowRule extends LinearLayoutRule {
}
@Override
- public void addLayoutActions(List<MenuAction> actions, final INode parentNode,
+ public void addLayoutActions(List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);