return icon;
}
+ public interface Listener {
+ public void handleAction(Object sender, Object target);
+ }
+
+ public interface Notifier extends Container {
+ public <T extends Action & Action.Listener> boolean addAction(T action);
+
+ public <T extends Action & Action.Listener> boolean removeAction(
+ T action);
+ }
+
+ public interface NotifierProxy {
+ public <T extends Action & Action.Listener> boolean addAction(T action);
+
+ public <T extends Action & Action.Listener> boolean removeAction(
+ T action);
+ }
+
/**
* Interface implemented by classes who wish to handle actions.
*
--- /dev/null
+package com.vaadin.event;
+
+import java.util.HashSet;
+import java.util.Map;
+
+import com.vaadin.event.Action.Container;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.terminal.KeyMapper;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.ui.Component;
+
+/**
+ * Javadoc TODO
+ *
+ * Notes:
+ * <p>
+ * Empties the keymapper for each repaint to avoid leaks; can cause problems in
+ * the future if the client assumes key don't change. (if lazyloading, one must
+ * not cache results)
+ * </p>
+ *
+ *
+ */
+public class ActionManager implements Action.Container, Action.Handler,
+ Action.Notifier {
+
+ private static final long serialVersionUID = 1641868163608066491L;
+
+ /** List of action handlers */
+ protected HashSet<Action> ownActions = null;
+
+ /** List of action handlers */
+ protected HashSet<Handler> actionHandlers = null;
+
+ /** Action mapper */
+ protected KeyMapper actionMapper = null;
+
+ protected Component viewer;
+
+ public ActionManager() {
+
+ }
+
+ public <T extends Component & Container> ActionManager(T viewer) {
+ this.viewer = viewer;
+ }
+
+ private void requestRepaint() {
+ if (viewer != null) {
+ viewer.requestRepaint();
+ }
+ }
+
+ public <T extends Component & Container> void setViewer(T viewer) {
+ if (viewer == this.viewer) {
+ return;
+ }
+ if (this.viewer != null) {
+ ((Container) this.viewer).removeActionHandler(this);
+ }
+ requestRepaint(); // this goes to the old viewer
+ if (viewer != null) {
+ viewer.addActionHandler(this);
+ }
+ this.viewer = viewer;
+ requestRepaint(); // this goes to the new viewer
+ }
+
+ public <T extends Action & Action.Listener> boolean addAction(T action) {
+ if (ownActions == null) {
+ ownActions = new HashSet<Action>();
+ }
+ if (ownActions.add(action)) {
+ requestRepaint();
+ return true;
+ }
+ return false;
+ }
+
+ public <T extends Action & Action.Listener> boolean removeAction(T action) {
+ if (ownActions != null) {
+ if (ownActions.remove(action)) {
+ requestRepaint();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void addActionHandler(Handler actionHandler) {
+ if (actionHandler != null) {
+
+ if (actionHandlers == null) {
+ actionHandlers = new HashSet<Handler>();
+ }
+
+ if (actionHandlers.add(actionHandler)) {
+ requestRepaint();
+ }
+ }
+ }
+
+ public void removeActionHandler(Action.Handler actionHandler) {
+
+ if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
+
+ if (actionHandlers.remove(actionHandler)) {
+ requestRepaint();
+ }
+ if (actionHandlers.isEmpty()) {
+ actionHandlers = null;
+ }
+
+ }
+ }
+
+ public void removeAllActionHandlers() {
+ if (actionHandlers != null) {
+ actionHandlers = null;
+ requestRepaint();
+ }
+ }
+
+ public void paintActions(Object actionTarget, PaintTarget paintTarget)
+ throws PaintException {
+
+ actionMapper = null;
+
+ HashSet<Action> actions = new HashSet<Action>();
+ if (actionHandlers != null) {
+ for (Action.Handler handler : actionHandlers) {
+ Action[] as = handler.getActions(actionTarget, this.viewer);
+ if (as != null) {
+ for (Action action : as) {
+ actions.add(action);
+ }
+ }
+ }
+ }
+ if (ownActions != null) {
+ actions.addAll(ownActions);
+ }
+
+ if (!actions.isEmpty()) {
+ actionMapper = new KeyMapper();
+
+ paintTarget.addVariable(this.viewer, "action", "");
+ paintTarget.startTag("actions");
+
+ for (final Action a : actions) {
+ paintTarget.startTag("action");
+ final String akey = actionMapper.key(a);
+ paintTarget.addAttribute("key", akey);
+ if (a.getCaption() != null) {
+ paintTarget.addAttribute("caption", a.getCaption());
+ }
+ if (a.getIcon() != null) {
+ paintTarget.addAttribute("icon", a.getIcon());
+ }
+ if (a instanceof ShortcutAction) {
+ final ShortcutAction sa = (ShortcutAction) a;
+ paintTarget.addAttribute("kc", sa.getKeyCode());
+ final int[] modifiers = sa.getModifiers();
+ if (modifiers != null) {
+ final String[] smodifiers = new String[modifiers.length];
+ for (int i = 0; i < modifiers.length; i++) {
+ smodifiers[i] = String.valueOf(modifiers[i]);
+ }
+ paintTarget.addAttribute("mk", smodifiers);
+ }
+ }
+ paintTarget.endTag("action");
+ }
+
+ paintTarget.endTag("actions");
+ }
+
+ }
+
+ public void handleActions(Map variables, Container sender) {
+ if (variables.containsKey("action") && actionMapper != null) {
+ final String key = (String) variables.get("action");
+ final Action action = (Action) actionMapper.get(key);
+ final Object target = variables.get("actiontarget");
+ if (action != null) {
+ handleAction(action, sender, target);
+ }
+ }
+ }
+
+ public Action[] getActions(Object target, Object sender) {
+ HashSet<Action> actions = new HashSet<Action>();
+ if (ownActions != null) {
+ for (Action a : ownActions) {
+ actions.add(a);
+ }
+ }
+ if (actionHandlers != null) {
+ for (Action.Handler h : actionHandlers) {
+ Action[] as = h.getActions(target, sender);
+ if (as != null) {
+ for (Action a : as) {
+ actions.add(a);
+ }
+ }
+ }
+ }
+ return actions.toArray(new Action[actions.size()]);
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ if (actionHandlers != null) {
+ for (Handler h : actionHandlers) {
+ h.handleAction(action, sender, target);
+ }
+ }
+ if (ownActions != null && ownActions.contains(action)
+ && action instanceof Action.Listener) {
+ ((Action.Listener) action).handleAction(sender, target);
+ }
+ }
+
+}
package com.vaadin.event;
import java.io.Serializable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import com.vaadin.terminal.Resource;
modifiers = m;
}
+ /**
+ * Used in the caption shorthand notation to indicate the ALT modifier.
+ */
+ public static final char MNEMONIC_CHAR_ALT = '&';
+ /**
+ * Used in the caption shorthand notation to indicate the SHIFT modifier.
+ */
+ public static final char MNEMONIC_CHAR_SHIFT = '%';
+ /**
+ * Used in the caption shorthand notation to indicate the CTRL modifier.
+ */
+ public static final char MNEMONIC_CHAR_CTRL = '^';
+
+ // regex-quote (escape) the characters
+ private static final String MNEMONIC_ALT = Pattern.quote(Character
+ .toString(MNEMONIC_CHAR_ALT));
+ private static final String MNEMONIC_SHIFT = Pattern.quote(Character
+ .toString(MNEMONIC_CHAR_SHIFT));
+ private static final String MNEMONIC_CTRL = Pattern.quote(Character
+ .toString(MNEMONIC_CHAR_CTRL));
+ // Used for replacing escaped chars, e.g && with &
+ private static final Pattern MNEMONICS_ESCAPE = Pattern.compile("("
+ + MNEMONIC_ALT + "?)" + MNEMONIC_ALT + "|(" + MNEMONIC_SHIFT + "?)"
+ + MNEMONIC_SHIFT + "|(" + MNEMONIC_CTRL + "?)" + MNEMONIC_CTRL);
+ // Used for removing escaped chars, only leaving real mnemonics
+ private static final Pattern MNEMONICS_REMOVE = Pattern.compile("(["
+ + MNEMONIC_ALT + "|" + MNEMONIC_SHIFT + "|" + MNEMONIC_CTRL
+ + "])\\1");
+ // Mnemonic char, optionally followed by another, and optionally a third
+ private static final Pattern MNEMONICS = Pattern.compile("(" + MNEMONIC_ALT
+ + "|" + MNEMONIC_SHIFT + "|" + MNEMONIC_CTRL + ")(?!\\1)(?:("
+ + MNEMONIC_ALT + "|" + MNEMONIC_SHIFT + "|" + MNEMONIC_CTRL
+ + ")(?!\\1|\\2))?(?:(" + MNEMONIC_ALT + "|" + MNEMONIC_SHIFT + "|"
+ + MNEMONIC_CTRL + ")(?!\\1|\\2|\\3))?.");
+
+ /**
+ * Constructs a ShortcutAction using a shorthand notation to encode the
+ * keycode and modifiers in the caption.
+ * <p>
+ * Insert one or more modifier characters before the character to use as
+ * keycode. E.g <code>"&Save"</code> will make a shortcut responding to
+ * ALT-S, <code>"E^xit"</code> will respond to CTRL-X.<br/>
+ * Multiple modifiers can be used, e.g <code>"&^Delete"</code> will respond
+ * to CTRL-ALT-D (the order of the modifier characters is not important).
+ * </p>
+ * <p>
+ * The modifier characters will be removed from the caption. The modifier
+ * character is be escaped by itself: two consecutive characters are turned
+ * into the original character w/o the special meaning. E.g
+ * <code>"Save&&&close"</code> will respond to ALT-C, and the caption will
+ * say "Save&close".
+ * </p>
+ *
+ * @param shorthandCaption
+ * the caption in modifier shorthand
+ */
+ public ShortcutAction(String shorthandCaption) {
+ this(shorthandCaption, null);
+ }
+
+ /**
+ * Constructs a ShortcutAction using a shorthand notation to encode the
+ * keycode a in the caption.
+ * <p>
+ * This works the same way as {@link #ShortcutAction(String)}, with the
+ * exception that the modifiers given override those indicated in the
+ * caption. I.e use any of the modifier characters in the caption to
+ * indicate the keycode, but the modifier will be the given set.<br/>
+ * E.g
+ * <code>new ShortcutAction("Do &stuff", new int[]{ShortcutAction.ModifierKey.CTRL}));</code>
+ * will respond to CTRL-S.
+ * </p>
+ *
+ * @param shorthandCaption
+ * @param modifierKeys
+ */
+ public ShortcutAction(String shorthandCaption, int[] modifierKeys) {
+ // && -> & etc
+ super(MNEMONICS_ESCAPE.matcher(shorthandCaption).replaceAll("$1$2$3"));
+ // replace escaped chars with something that won't accidentally match
+ shorthandCaption = MNEMONICS_REMOVE.matcher(shorthandCaption)
+ .replaceAll("\u001A");
+ Matcher matcher = MNEMONICS.matcher(shorthandCaption);
+ if (matcher.find()) {
+ String match = matcher.group();
+
+ // KeyCode from last char in match, lowercase
+ keyCode = Character.toLowerCase(matcher.group().charAt(
+ match.length() - 1));
+
+ // Given modifiers override this indicated in the caption
+ if (modifierKeys != null) {
+ modifiers = modifierKeys;
+ } else {
+ // Read modifiers from caption
+ int[] mod = new int[match.length() - 1];
+ for (int i = 0; i < mod.length; i++) {
+ int kc = match.charAt(i);
+ switch (kc) {
+ case MNEMONIC_CHAR_ALT:
+ mod[i] = ModifierKey.ALT;
+ break;
+ case MNEMONIC_CHAR_CTRL:
+ mod[i] = ModifierKey.CTRL;
+ break;
+ case MNEMONIC_CHAR_SHIFT:
+ mod[i] = ModifierKey.SHIFT;
+ break;
+ }
+ }
+ modifiers = mod;
+ }
+
+ } else {
+ keyCode = -1;
+ modifiers = modifierKeys;
+ }
+ }
+
public int getKeyCode() {
return keyCode;
}
--- /dev/null
+package com.vaadin.event;
+
+import com.vaadin.event.Action.Listener;
+import com.vaadin.terminal.Resource;
+
+public abstract class ShortcutListener extends ShortcutAction implements
+ Listener {
+
+ private static final long serialVersionUID = 1L;
+
+ public ShortcutListener(String caption, int keyCode, int... modifierKeys) {
+ super(caption, keyCode, modifierKeys);
+ }
+
+ public ShortcutListener(String shorthandCaption, int... modifierKeys) {
+ super(shorthandCaption, modifierKeys);
+ }
+
+ public ShortcutListener(String caption, Resource icon, int keyCode,
+ int... modifierKeys) {
+ super(caption, icon, keyCode, modifierKeys);
+ }
+
+ public ShortcutListener(String shorthandCaption) {
+ super(shorthandCaption);
+ }
+
+ abstract public void handleAction(Object sender, Object target);
+}
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.KeyboardListenerCollection;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
/**
while (it.hasNext()) {
final ShortcutAction a = (ShortcutAction) it.next();
if (a.getShortcutCombination().equals(kc)) {
+ Element et = DOM.eventGetTarget(event);
+ final Paintable target = client.getPaintable(et);
DOM.eventPreventDefault(event);
- shakeTarget(DOM.eventGetTarget(event));
+ shakeTarget(et);
DeferredCommand.addCommand(new Command() {
public void execute() {
+ if (target != null) {
+ client.updateVariable(paintableId, "actiontarget",
+ target, false);
+ }
client.updateVariable(paintableId, "action",
a.getKey(), true);
}
\r
import java.util.Set;\r
\r
+import com.google.gwt.event.dom.client.KeyDownEvent;\r
+import com.google.gwt.event.dom.client.KeyDownHandler;\r
import com.google.gwt.user.client.DOM;\r
import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.Event;\r
import com.google.gwt.user.client.ui.ComplexPanel;\r
import com.google.gwt.user.client.ui.Widget;\r
import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
\r
public class VForm extends ComplexPanel implements Container {\r
\r
+ protected String id;\r
+\r
private String height = "";\r
\r
private String width = "";\r
\r
private boolean rendering = false;\r
\r
+ ShortcutActionHandler shortcutHandler;\r
+\r
public VForm() {\r
setElement(DOM.createDiv());\r
DOM.appendChild(getElement(), fieldSet);\r
errorMessage.setStyleName(CLASSNAME + "-errormessage");\r
DOM.appendChild(fieldSet, errorMessage.getElement());\r
DOM.appendChild(fieldSet, footerContainer);\r
+\r
+ addDomHandler(new KeyDownHandler() {\r
+ public void onKeyDown(KeyDownEvent event) {\r
+ shortcutHandler.handleKeyboardEvent(Event.as(event\r
+ .getNativeEvent()));\r
+ return;\r
+ }\r
+ }, KeyDownEvent.getType());\r
}\r
\r
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
rendering = true;\r
this.client = client;\r
+ id = uidl.getId();\r
\r
if (client.updateComponent(this, uidl, false)) {\r
rendering = false;\r
\r
// first render footer so it will be easier to handle relative height of\r
// main layout\r
- if (uidl.getChildCount() > 1) {\r
+ if (uidl.getChildCount() > 1\r
+ && !uidl.getChildUIDL(1).getTag().equals("actions")) {\r
// render footer\r
Container newFooter = (Container) client.getPaintable(uidl\r
.getChildUIDL(1));\r
}\r
lo.updateFromUIDL(layoutUidl, client);\r
\r
+ // We may have actions attached to this panel\r
+ if (uidl.getChildCount() > 1) {\r
+ final int cnt = uidl.getChildCount();\r
+ for (int i = 1; i < cnt; i++) {\r
+ UIDL childUidl = uidl.getChildUIDL(i);\r
+ if (childUidl.getTag().equals("actions")) {\r
+ if (shortcutHandler == null) {\r
+ shortcutHandler = new ShortcutActionHandler(id, client);\r
+ }\r
+ shortcutHandler.updateActionMap(childUidl);\r
+ }\r
+ }\r
+ }\r
+\r
rendering = false;\r
}\r
\r
import com.vaadin.data.Validatable;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
+import com.vaadin.event.Action;
+import com.vaadin.event.ActionManager;
+import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.CompositeErrorMessage;
import com.vaadin.terminal.ErrorMessage;
import com.vaadin.terminal.PaintException;
*/
@SuppressWarnings("serial")
public abstract class AbstractField extends AbstractComponent implements Field,
- Property.ReadOnlyStatusChangeNotifier {
+ Property.ReadOnlyStatusChangeNotifier, Action.NotifierProxy {
/* Private members */
*/
private boolean validationVisible = true;
+ /**
+ * Keeps track of the Actions added to this component; the actual
+ * handling/notifying is delegated, usually to the containing window.
+ */
+ protected ActionManager actionManager;
+
/* Component basics */
/*
if (delayedFocus) {
focus();
}
+ if (actionManager != null && !(this instanceof Action.Container)) {
+ // Only for non Action.Containers because those want to paint
+ // actions themselves - e.g Form
+ actionManager.setViewer(getWindow());
+ }
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ if (actionManager != null && !(this instanceof Action.Container)) {
+ // Only for non Action.Containers because those want to paint
+ // actions themselves - e.g Form
+ actionManager.setViewer((Window) null);
+ }
}
/**
requestRepaint();
}
+ /*
+ * Actions
+ */
+
+ protected ActionManager getActionManager() {
+ if (actionManager == null) {
+ actionManager = new ActionManager();
+ if (getWindow() != null) {
+ actionManager.setViewer(getWindow());
+ }
+ }
+ return actionManager;
+ }
+
+ public <T extends Action & Action.Listener> boolean addAction(T action) {
+ return getActionManager().addAction(action);
+ }
+
+ public <T extends Action & Action.Listener> boolean removeAction(T action) {
+ if (actionManager == null) {
+ return actionManager.removeAction(action);
+ }
+ return false;
+ }
+
+ public static class FocusShortcut extends ShortcutListener {
+ protected Focusable focusable;
+
+ public FocusShortcut(Focusable focusable, String shorthandCaption) {
+ super(shorthandCaption);
+ this.focusable = focusable;
+ }
+
+ public FocusShortcut(Focusable focusable, int keyCode, int... modifiers) {
+ super(null, keyCode, modifiers);
+ this.focusable = focusable;
+ }
+
+ public FocusShortcut(Focusable focusable, int keyCode) {
+ this(focusable, keyCode, null);
+ }
+
+ @Override
+ public void handleAction(Object sender, Object target) {
+ this.focusable.focus();
+ }
+ }
}
\ No newline at end of file
import java.util.Map;
import com.vaadin.data.Property;
+import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VButton;
super.setInternalValue(newValue);
}
+ /*
+ * Actions
+ */
+
+ protected ClickShortcut clickMnemonic;
+
+ public ClickShortcut setClickMnemonic(int keyCode, int... modifiers) {
+ ClickShortcut old = clickMnemonic;
+ if (old != null) {
+ removeAction(old);
+ }
+ clickMnemonic = new ClickShortcut(this, keyCode, modifiers);
+ addAction(clickMnemonic);
+ return old;
+ }
+
+ public void removeClickMnemonic() {
+ if (clickMnemonic != null) {
+ removeAction(clickMnemonic);
+ clickMnemonic = null;
+ }
+ }
+
+ public static class ClickShortcut extends ShortcutListener {
+ protected Button button;
+
+ public ClickShortcut(Button button, String shorthandCaption) {
+ super(shorthandCaption);
+ this.button = button;
+ }
+
+ public ClickShortcut(Button button, int keyCode, int... modifiers) {
+ super(null, keyCode, modifiers);
+ this.button = button;
+ }
+
+ public ClickShortcut(Button button, int keyCode) {
+ this(button, keyCode, null);
+ }
+
+ @Override
+ public void handleAction(Object sender, Object target) {
+ this.button.fireClick();
+ }
+ }
+
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.Map;
import com.vaadin.data.Buffered;
import com.vaadin.data.Item;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.util.BeanItem;
+import com.vaadin.event.Action;
+import com.vaadin.event.ActionManager;
+import com.vaadin.event.Action.Handler;
import com.vaadin.terminal.CompositeErrorMessage;
import com.vaadin.terminal.ErrorMessage;
import com.vaadin.terminal.PaintException;
@SuppressWarnings("serial")
@ClientWidget(VForm.class)
public class Form extends AbstractField implements Item.Editor, Buffered, Item,
- Validatable {
+ Validatable, Action.Container {
private Object propertyValue;
private int gridlayoutCursorX = -1;
private int gridlayoutCursorY = -1;
+ /**
+ * Keeps track of the Actions added to this component, and manages the
+ * painting and handling as well.
+ */
+ ActionManager actionManager = new ActionManager(this);
+
/**
* Contructs a new form with default layout.
*
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
+
layout.paint(target);
if (formFooter != null) {
formFooter.paint(target);
}
+
+ if (actionManager != null) {
+ actionManager.paintActions(null, target);
+ }
+ }
+
+ @Override
+ public void changeVariables(Object source, Map<String, Object> variables) {
+ super.changeVariables(source, variables);
+
+ // Actions
+ if (actionManager != null) {
+ actionManager.handleActions(variables, this);
+ }
}
/**
}
}
+ /*
+ * ACTIONS
+ */
+
+ protected ActionManager getActionManager() {
+ if (actionManager == null) {
+ actionManager = new ActionManager();
+ actionManager.setViewer(this);
+ }
+ return actionManager;
+ }
+
+ public void addActionHandler(Handler actionHandler) {
+ getActionManager().addActionHandler(actionHandler);
+ }
+
+ public void removeActionHandler(Handler actionHandler) {
+ if (actionManager != null) {
+ actionManager.removeActionHandler(actionHandler);
+ }
+ }
+
+ /**
+ * Removes all action handlers
+ */
+ public void removeAllActionHandlers() {
+ if (actionManager != null) {
+ actionManager.removeAllActionHandlers();
+ }
+ }
+
}
package com.vaadin.ui;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
import com.vaadin.event.Action;
-import com.vaadin.event.ShortcutAction;
+import com.vaadin.event.ActionManager;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.MouseEvents.ClickListener;
-import com.vaadin.terminal.KeyMapper;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Scrollable;
@ClientWidget(VPanel.class)
public class Panel extends AbstractComponentContainer implements Scrollable,
ComponentContainer.ComponentAttachListener,
- ComponentContainer.ComponentDetachListener, Action.Container {
+ ComponentContainer.ComponentDetachListener, Action.Container,
+ Action.Notifier {
private static final String CLICK_EVENT = VPanel.CLICK_EVENT_IDENTIFIER;
*/
private boolean scrollable = false;
- /** List of action handlers */
- private LinkedList actionHandlers = null;
-
- /** Action mapper */
- private KeyMapper actionMapper = null;
+ /**
+ * Keeps track of the Actions added to this component, and manages the
+ * painting and handling as well.
+ */
+ protected ActionManager actionManager;
/**
* Creates a new empty panel. A VerticalLayout is used as content.
target.addVariable(this, "scrollTop", getScrollTop());
}
- target.addVariable(this, "action", "");
- target.startTag("actions");
-
- if (actionHandlers != null && !actionHandlers.isEmpty()) {
- for (final Iterator ahi = actionHandlers.iterator(); ahi.hasNext();) {
- final Action[] aa = ((Action.Handler) ahi.next()).getActions(
- null, this);
- if (aa != null) {
- for (int ai = 0; ai < aa.length; ai++) {
- final Action a = aa[ai];
- target.startTag("action");
- final String akey = actionMapper.key(aa[ai]);
- target.addAttribute("key", akey);
- if (a.getCaption() != null) {
- target.addAttribute("caption", a.getCaption());
- }
- if (a.getIcon() != null) {
- target.addAttribute("icon", a.getIcon());
- }
- if (a instanceof ShortcutAction) {
- final ShortcutAction sa = (ShortcutAction) a;
- target.addAttribute("kc", sa.getKeyCode());
- final int[] modifiers = sa.getModifiers();
- if (modifiers != null) {
- final String[] smodifiers = new String[modifiers.length];
- for (int i = 0; i < modifiers.length; i++) {
- smodifiers[i] = String
- .valueOf(modifiers[i]);
- }
- target.addAttribute("mk", smodifiers);
- }
- }
- target.endTag("action");
- }
- }
- }
+ if (actionManager != null) {
+ actionManager.paintActions(null, target);
}
- target.endTag("actions");
}
@Override
}
// Actions
- if (variables.containsKey("action")) {
- final String key = (String) variables.get("action");
- final Action action = (Action) actionMapper.get(key);
- if (action != null && actionHandlers != null) {
- Object[] array = actionHandlers.toArray();
- for (int i = 0; i < array.length; i++) {
- ((Action.Handler) array[i])
- .handleAction(action, this, this);
- }
- }
+ if (actionManager != null) {
+ actionManager.handleActions(variables, this);
}
}
content.removeAllComponents();
}
- public void addActionHandler(Handler actionHandler) {
- if (actionHandler != null) {
-
- if (actionHandlers == null) {
- actionHandlers = new LinkedList();
- actionMapper = new KeyMapper();
- }
-
- if (!actionHandlers.contains(actionHandler)) {
- actionHandlers.add(actionHandler);
- requestRepaint();
- }
+ /*
+ * ACTIONS
+ */
+ protected ActionManager getActionManager() {
+ if (actionManager == null) {
+ actionManager = new ActionManager();
+ actionManager.setViewer(this);
}
-
+ return actionManager;
}
- /**
- * Removes an action handler.
- *
- * @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler)
- */
- public void removeActionHandler(Action.Handler actionHandler) {
-
- if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
+ public <T extends Action & com.vaadin.event.Action.Listener> boolean addAction(
+ T action) {
+ return getActionManager().addAction(action);
+ }
- actionHandlers.remove(actionHandler);
+ public <T extends Action & com.vaadin.event.Action.Listener> boolean removeAction(
+ T action) {
+ if (actionManager == null) {
+ return actionManager.removeAction(action);
+ }
+ return false;
+ }
- if (actionHandlers.isEmpty()) {
- actionHandlers = null;
- actionMapper = null;
- }
+ public void addActionHandler(Handler actionHandler) {
+ getActionManager().addActionHandler(actionHandler);
+ }
- requestRepaint();
+ public void removeActionHandler(Handler actionHandler) {
+ if (actionManager != null) {
+ actionManager.removeActionHandler(actionHandler);
}
}
* Removes all action handlers
*/
public void removeAllActionHandlers() {
- actionHandlers = null;
- actionMapper = null;
- requestRepaint();
+ if (actionManager != null) {
+ actionManager.removeAllActionHandlers();
+ }
}
/**
import java.util.Set;
import com.vaadin.Application;
+import com.vaadin.event.ShortcutListener;
import com.vaadin.terminal.DownloadStream;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
requestRepaint();
}
+ /*
+ * Actions
+ */
+ protected CloseShortcut closeMnemonic;
+
+ public CloseShortcut setCloseMnemonic(int keyCode, int... modifiers) {
+ CloseShortcut old = closeMnemonic;
+ if (old != null) {
+ removeAction(old);
+ }
+ closeMnemonic = new CloseShortcut(this, keyCode, modifiers);
+ addAction(closeMnemonic);
+ return old;
+ }
+
+ public void removeCloseMnemonic() {
+ if (closeMnemonic != null) {
+ removeAction(closeMnemonic);
+ closeMnemonic = null;
+ }
+ }
+
+ public static class CloseShortcut extends ShortcutListener {
+ protected Window window;
+
+ public CloseShortcut(Window window, String shorthandCaption) {
+ super(shorthandCaption);
+ this.window = window;
+ }
+
+ public CloseShortcut(Window window, int keyCode, int... modifiers) {
+ super(null, keyCode, modifiers);
+ this.window = window;
+ }
+
+ public CloseShortcut(Window window, int keyCode) {
+ this(window, keyCode, null);
+ }
+
+ @Override
+ public void handleAction(Object sender, Object target) {
+ this.window.close();
+ }
+ }
}