diff options
author | Tor Norbye <tnorbye@google.com> | 2011-08-15 14:15:09 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2011-08-15 14:15:10 -0700 |
commit | 47d72b010e64bf0aa231895dd70a59ba3fde3630 (patch) | |
tree | 2bee2a78dc8d463cd69876d92b4ab66d599d8d10 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common | |
parent | ee4e5b7f818d1296aadc4d70eed417ff4f2de46b (diff) | |
parent | 94986e745141118cace0391da1b4dc8533408751 (diff) | |
download | sdk-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')
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); |