Package net.ajiaojr.spadger.client

Source Code of net.ajiaojr.spadger.client.HotKeysManager

/*
* Spadger - an open source discussion forum system.
*
* Copyright (C) 2010 The Spadger Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
*
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.ajiaojr.spadger.client;

import java.util.HashMap;
import java.util.Map;

import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;

/**
* Manages hot keys.
*
* <p>
* This class maintains a static map of all the hot key sequences and their
* respective commands, and upon a key press, it checks if the key, and maybe
* the previously pressed ones form the first part of any registered sequences.
*
* <p>
* The reason this is implemented this way instead of directly registering every
* key press listeners to the DOM is so that we do not have a huge number of
* listeners hanging around. Listeners can potentially have a huge impact to the
* performance of the system.
*
* <p>
* Doing so however means it is impossible to register more than 1 {@code
* Command} to a sequence. While this may sound quite restrictive, registering
* more than one command to one hot key sequence is seldom used in real-world
* cases.
*
* @author The Spadger Team
*/
public class HotKeysManager {
  private static Timer timer = new Timer() {

    @Override
    public void run() {
      possibleHotKeySequences.clear();
      possibleHotKeySequences.putAll(hotKeySequences);
    }
  };

  /**
   * Hot key sequence expiration time, in milliseconds.
   */
  public static int HOT_KEY_SEQUENCE_EXPIRATION = 2000;

  private static HandlerRegistration hotKeysHandlerRegistration;

  private static Map<Integer[], Command> hotKeySequences = new HashMap<Integer[], Command>();

  private static Map<Integer[], Command> possibleHotKeySequences = new HashMap<Integer[], Command>();

  /**
   * Activates all the hot keys registered.
   */
  public static void activateHotKeys() {
    timer.run();
    hotKeysHandlerRegistration = Event
        .addNativePreviewHandler(new NativePreviewHandler() {

          @Override
          public void onPreviewNativeEvent(NativePreviewEvent event) {
            if (event.getTypeInt() == Event.ONKEYPRESS) {
              int keyCode = event.getNativeEvent().getKeyCode();

              // Now we see what we can do with key sequences.
              // The logic is trivial:
              // 1. We iterate through the possible key sequences, and see if
              // the first of any of the the remaining keys match our current
              // key code
              // 2. If it does, check the following 2 possibilities:
              // 2.1 if it's already the last key, execute the command.
              // 2.2 if there are more keys remaining, reset the timer so that
              // the user is given another HOT_KEY_SEQUENCE_EXPIRATION to
              // attempt the next key.
              // 3. If it doesn't, it gets discarded.
              // 4. Always put all available hot key sequences to the list.

              for (Integer[] keyCodes : possibleHotKeySequences.keySet()) {
                if (keyCodes[0] == keyCode) {
                  if (keyCodes.length == 1) {
                    possibleHotKeySequences.get(keyCodes).execute();
                    timer.cancel();
                    timer.run();
                  } else {
                    Integer[] newKeyCodes = new Integer[keyCodes.length - 1];
                    for (int i = 0; i < newKeyCodes.length; i++) {
                      newKeyCodes[i] = keyCodes[i + 1];
                    }
                    possibleHotKeySequences.put(newKeyCodes,
                        possibleHotKeySequences.get(keyCodes));
                    timer.cancel();
                    timer.schedule(HOT_KEY_SEQUENCE_EXPIRATION);
                  }

                }
                possibleHotKeySequences.remove(keyCodes);
              }
              possibleHotKeySequences.putAll(hotKeySequences);
            }
          }
        });
  }

  /**
   * De-activates all the hot keys registered.
   */
  public static void deactivateHotKeys() {
    if (hotKeysHandlerRegistration != null)
      hotKeysHandlerRegistration.removeHandler();
  }

  /**
   * Registers a hot key.
   *
   * @param keyCode
   *          the key code of the hot key.
   * @param command
   *          the command to be executed.
   */
  public static void registerHotKey(int keyCode, Command command) {
    registerHotKeySequence(new int[] { keyCode }, command);
  }

  /**
   * Registers a hot key sequence.
   *
   * @param keyCodes
   *          the key codes in the order they are supposed to be pressed.
   * @param command
   *          the command to be executed.
   */
  public static void registerHotKeySequence(int[] keyCodes, Command command) {
    Integer[] _keyCodes = new Integer[keyCodes.length];
    for (int i = 0; i < keyCodes.length; i++) {
      _keyCodes[i] = keyCodes[i];
    }
    hotKeySequences.put(_keyCodes, command);
  }
}
TOP

Related Classes of net.ajiaojr.spadger.client.HotKeysManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.