Skip to content
Snippets Groups Projects
Commit 568d11bb authored by David Trachtenherz's avatar David Trachtenherz
Browse files

Sub-menus (one-level) for context menu contributor

refs 713
parent aefc5a7a
No related branches found
No related tags found
No related merge requests found
......@@ -36,13 +36,15 @@ import org.fortiss.tooling.kernel.ui.extension.data.ContextMenuContextProvider;
import org.fortiss.tooling.kernel.ui.service.IContextMenuService;
/**
* Base class for context menu contributors creating a sub-menu
* {@link IMenuManager} with actions provided by actions factories
* {@link EObjectActionFactory} returned by {@link #getActionFactories()}.
*
* The class implements interface methods {@link #getMenuIcon()} and
* {@link #getMenuId()} returning {@code null} by default. Classes providing an
* own icon or id should override them.
* Base class for context menu contributors creating a sub-menu {@link IMenuManager} with actions
* provided by actions factories {@link EObjectActionFactory} returned by
* {@link #getActionFactories()}.
* <p>
* The menu can be additionally structured using {@link #getMenuStructureHintItems()}: currently
* menu separators and one-level sub-menus supported.
* <p>
* The class implements interface methods {@link #getMenuIcon()} and {@link #getMenuId()} returning
* {@code null} by default. Classes providing an own icon or id should override them.
*
* @param <T>
* Indicates the type of selection elements.
......@@ -50,20 +52,19 @@ import org.fortiss.tooling.kernel.ui.service.IContextMenuService;
* @author trachtenherz
* @author $Author: hoelzl $
* @version $Rev: 18709 $
* @ConQAT.Rating GREEN Hash: 8573587F690FC94EF1300F9200C6793A
* @ConQAT.Rating YELLOW Hash: 38206E76C5D298208F2901B878324FF5
*/
public abstract class ContextMenuSubMenuContributorBase<T extends EObject>
implements IContextMenuContributor {
public abstract class ContextMenuSubMenuContributorBase<T extends EObject> implements
IContextMenuContributor {
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public final List<IContributionItem> getContributedItems(EObject selection,
ContextMenuContextProvider contextProvider) {
if (acceptSelection(selection, contextProvider)) {
if(acceptSelection(selection, contextProvider)) {
List<IContributionItem> contributionItems = new ArrayList<IContributionItem>();
contributionItems
.add(createMenu(createActionsForElement((T) selection)));
contributionItems.add(createMenu(createActionsForElement((T)selection)));
return contributionItems;
}
return Collections.emptyList();
......@@ -72,7 +73,7 @@ public abstract class ContextMenuSubMenuContributorBase<T extends EObject>
/** Creates action instances for the given selection. */
protected Collection<Action> createActionsForElement(T selection) {
ArrayList<Action> list = new ArrayList<Action>();
for (EObjectActionFactory<? super T> factory : getActionFactories()) {
for(EObjectActionFactory<? super T> factory : getActionFactories()) {
list.add(factory.createAction(selection));
}
return list;
......@@ -82,30 +83,61 @@ public abstract class ContextMenuSubMenuContributorBase<T extends EObject>
* Creates a sub-menu {@link IMenuManager} containing specified actions.
*/
protected IMenuManager createMenu(Collection<Action> actions) {
IMenuManager menu = new MenuManager(getMenuName(), getMenuIcon(),
getMenuId());
// Prepare menu structure hints
MenuStructureHints[] hints;
if (getMenuStructureHints() != null) {
hints = Arrays.copyOf(getMenuStructureHints(), actions.size());
IMenuManager menu = new MenuManager(getMenuName(), getMenuIcon(), getMenuId());
IMenuManager subMenu = null;
// Points to the currently used menu, which is either {@code menu} or {@code subMenu}
IMenuManager currentMenu = menu;
// Prepare menu structure hint items
MenuStructureHintItem[] hintItems;
if(getMenuStructureHintItems() != null) {
hintItems = Arrays.copyOf(getMenuStructureHintItems(), actions.size());
} else {
hints = new MenuStructureHints[actions.size()];
Arrays.fill(hints, null);
hintItems = new MenuStructureHint[actions.size()];
Arrays.fill(hintItems, null);
}
// Now the hints array contains all elements from
// getMenuStructureHints(). It
// also has at least as many elements as the actions collection. If
// getMenuStructureHints() has less elements (or is null),
// than all other elements of the hints array are null.
/*
* Now the hint items array contains all elements from getMenuStructureHintItems(). It also
* has at least as many elements as the actions collection. If getMenuStructureHintItems()
* has less elements (or is null), than all other elements of the hint items array are null.
*/
int i = 0;
for (Action a : actions) {
if (hints[i] == MenuStructureHints.SEPARATOR_BEFORE) {
menu.add(new Separator());
for(Action a : actions) {
if(hintItems[i] != null &&
hintItems[i].getHint() == MenuStructureHint.SUBMENU_START_BEFORE) {
if(subMenu != null) {
// If there is a previously opened sub-menu then finish processing it because we
// use one-level sub-menus.
menu.add(subMenu);
}
final String subMenuLabel;
if(hintItems[i] instanceof MenuStructureHintSubMenuStart) {
subMenuLabel = ((MenuStructureHintSubMenuStart)hintItems[i]).getSubMenuLabel();
} else {
subMenuLabel = MenuStructureHintSubMenuStart.DEFAULT_SUB_MENU_LABEL;
}
// Open new sub-menu
currentMenu = subMenu = new MenuManager(subMenuLabel);
}
menu.add(a);
if (hints[i] == MenuStructureHints.SEPARATOR_AFTER) {
menu.add(new Separator());
if(hintItems[i] != null && hintItems[i].getHint() == MenuStructureHint.SEPARATOR_BEFORE) {
currentMenu.add(new Separator());
}
// Add the action to menu
currentMenu.add(a);
if(hintItems[i] != null &&
hintItems[i].getHint() == MenuStructureHint.SUBMENU_END_AFTER) {
if(subMenu != null) {
menu.add(subMenu);
subMenu = null;
// Return to top-level menu
currentMenu = menu;
}
}
if(hintItems[i] != null && hintItems[i].getHint() == MenuStructureHint.SEPARATOR_AFTER) {
currentMenu.add(new Separator());
}
++i;
......@@ -132,28 +164,129 @@ public abstract class ContextMenuSubMenuContributorBase<T extends EObject>
/** Returns the action factories for the actions to be shown in the menu */
protected abstract Collection<EObjectActionFactory<? super T>> getActionFactories();
/**
* Interface for menu structure hints.
*
* @author trachtenherz
* @version $Rev: 18709 $
* @ConQAT.Rating RED Hash:
*/
public static interface MenuStructureHintItem {
/** Returns the hint represented by this item. */
MenuStructureHint getHint();
/**
* Returns hints represented by this item. If it represents one hint, than a one-element
* array is returned containing the result of {@link #getHint()}.
*/
MenuStructureHint[] getHints();
}
/**
* Constants for menu structure hints.
*
* @see ContextMenuSubMenuContributorBase#getMenuStructureHints()
* @see ContextMenuSubMenuContributorBase#getMenuStructureHintItems()
*/
protected static enum MenuStructureHints {
public static enum MenuStructureHint implements MenuStructureHintItem {
/** Insert a separator before current menu item. */
SEPARATOR_BEFORE,
/** Insert a separator after current menu item. */
SEPARATOR_AFTER;
// Further future hints may be e.g.: Begin new sub-menu, End new
// sub-menu
SEPARATOR_AFTER,
/**
* Begin sub-menu before current item.
* <p>
* NOTE: Only one-level sub-menus are supported, so if there was a sub-menu previously
* started, then starting another will automatically end the previous one.
*/
SUBMENU_START_BEFORE,
/** End sub-menu after current item. */
SUBMENU_END_AFTER;
/** {@inheritDoc} */
@Override
public MenuStructureHint getHint() {
return this;
}
/** {@inheritDoc} */
@Override
public MenuStructureHint[] getHints() {
return new MenuStructureHint[] {getHint()};
}
}
/**
* {@link MenuStructureHintItem} wrapping a {@link MenuStructureHint#SUBMENU_START_BEFORE} hint
* and providing additional information for the sub-menu.
*
* @author trachtenherz
* @version $Rev: 18709 $
* @ConQAT.Rating RED Hash:
*/
public static class MenuStructureHintSubMenuStart implements MenuStructureHintItem {
/** Default sub-menu item label. */
public static final String DEFAULT_SUB_MENU_LABEL = "Sub menu";
/** @see #getSubMenuLabel() */
private String subMenuLabel;
/**
* Creates a {@link MenuStructureHintSubMenuStart} with default sub-menu label text.
*
* @see #DEFAULT_SUB_MENU_LABEL
*/
public MenuStructureHintSubMenuStart() {
this(DEFAULT_SUB_MENU_LABEL);
}
/**
* Creates a {@link MenuStructureHintSubMenuStart} with given sub-menu label text.
*/
public MenuStructureHintSubMenuStart(String subMenuLabel) {
this.subMenuLabel = subMenuLabel;
}
/** Returns the sub-menu label text. */
public String getSubMenuLabel() {
return subMenuLabel;
}
/**
* {@inheritDoc}
*
* @return MenuStructureHint.SUBMENU_START_BEFORE
*/
@Override
public MenuStructureHint getHint() {
return MenuStructureHint.SUBMENU_START_BEFORE;
}
/** {@inheritDoc} */
@Override
public MenuStructureHint[] getHints() {
return new MenuStructureHint[] {getHint()};
}
}
/**
* Returns additional informations about the structure of the menu. If
* {@code null}, the actions are linearly shown in a menu.
* Returns additional informations about the structure of the menu to be used in
* {@link #createMenu(Collection)}. Each array element at position {@code i} corresponds to the
* menu action at position @{@code i} in {@link #getActionFactories()}.
* <p>
* A {@code null} element means that there is no additional information for the corresponding
* action. If the array itself is {@code null} then this is equivalent to an array filled with
* {@code null} elements: in this case all actions are linearly shown in the menu.
* <p>
* If the array is smaller than the number of menu actions returned by
* {@link #getActionFactories()} then missing structure hints are assumed {@code null} (which is
* equivalent to padding the array with {@code null} till the length of
* {@link #getActionFactories()}).
*
* @see MenuStructureHintItem
* @see MenuStructureHint
* @see #getActionFactories()
* @see #createMenu(Collection)
*/
protected MenuStructureHints[] getMenuStructureHints() {
protected MenuStructureHintItem[] getMenuStructureHintItems() {
return null;
}
......@@ -167,4 +300,4 @@ public abstract class ContextMenuSubMenuContributorBase<T extends EObject>
return null;
}
}
\ No newline at end of file
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment