Package at.bestsolution.efxclipse.runtime.workbench.fx.key

Source Code of at.bestsolution.efxclipse.runtime.workbench.fx.key.KeyBindingDispatcher$KeyDownFilter

/*******************************************************************************
* Copyright (c) 2012 BestSolution.at and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
*******************************************************************************/
package at.bestsolution.efxclipse.runtime.workbench.fx.key;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

import javax.inject.Inject;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.CommandException;
import org.eclipse.e4.core.commands.EHandlerService;
import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;

import at.bestsolution.efxclipse.runtime.bindings.Binding;
import at.bestsolution.efxclipse.runtime.bindings.KeyLookup;
import at.bestsolution.efxclipse.runtime.bindings.KeySequence;
import at.bestsolution.efxclipse.runtime.bindings.KeyStroke;
import at.bestsolution.efxclipse.runtime.bindings.e4.EBindingService;
import at.bestsolution.efxclipse.runtime.bindings.service.BindingFactory;

@SuppressWarnings("restriction")
public class KeyBindingDispatcher {
  public class KeyDownFilter implements EventHandler<KeyEvent> {
    private transient boolean enabled = true;
   
    public void handle(KeyEvent event) {
      if (!enabled) {
        return;
      }
     
      filterKeySequenceBindings(event);
    }
   
    /**
     * Returns whether the key binding filter is enabled.
     *
     * @return Whether the key filter is enabled.
     */
    public final boolean isEnabled() {
      return enabled;
    }

    /**
     * Sets whether this filter should be enabled or disabled.
     *
     * @param enabled
     *            Whether key binding filter should be enabled.
     */
    public final void setEnabled(final boolean enabled) {
      this.enabled = enabled;
    }
  }
 
  private final IEclipseContext context;
  private final EventHandler<KeyEvent> keyHandler = new KeyDownFilter();
  private EBindingService bindingService;
  private KeySequence state;

  private long startTime;
 
  private final BindingFactory factory;
  private final KeyLookup lookup;
 
  private EHandlerService handlerService;
 
  @Inject
  public KeyBindingDispatcher(IEclipseContext context, BindingFactory factory, KeyLookup lookup) {
    this.context = context;
    this.factory = factory;
    this.lookup = lookup;
    this.state = factory.getKeySequenceInstance();
  }
 
  public EventHandler<KeyEvent> getKeyHandler() {
    return keyHandler;
  }
 
  private static boolean isModifierKey(KeyEvent event) {
    switch (event.getCode()) {
    case ALT:
    case CONTROL:
    case SHIFT:
    case COMMAND:
      return true;
    default:
      return false;
    }
  }
 
  private static boolean hasModifierPressed(KeyEvent event) {
    return event.isAltDown() || event.isControlDown() || event.isMetaDown() || event.isShiftDown();
  }
 
  private void filterKeySequenceBindings(KeyEvent event) {
    /*
     * Only process key strokes containing natural keys to trigger key bindings.
     */
    if (isModifierKey(event)) {
      return;
    }

    // Allow special key out-of-order processing.
    List<KeyStroke> keyStrokes = generatePossibleKeyStrokes(event);
   
//    if (isOutOfOrderKey(keyStrokes)) {
////      Widget widget = event.widget;
//      if ((event.getCode() == KeyCode.DELETE)
//          && ! isModifierKey(event)
//          /*&& ((widget instanceof Text) || (widget instanceof Combo) || (widget instanceof Browser))*/) {
//        /*
//         * KLUDGE. Bug 54654. The text widget relies on no listener doing any work before
//         * dispatching the native delete event. This does not work, as we are restricted to
//         * listeners. However, it can be said that pressing a delete key in a text widget
//         * will never use key bindings. This can be shown be considering how the event
//         * dispatching is expected to work in a text widget. So, we should do nothing ...
//         * ever.
//         */
//        return;
//
////      } else if (widget instanceof StyledText) {
////
////        if (event.type == SWT.KeyDown) {
////          /*
////           * KLUDGE. Some people try to do useful work in verify listeners. The way verify
////           * listeners work in SWT, we need to verify the key as well; otherwise, we can't
////           * detect that useful work has been done.
////           */
////          if (!outOfOrderVerifyListener.isActive(event.time)) {
////            ((StyledText) widget).addVerifyKeyListener(outOfOrderVerifyListener);
////            outOfOrderVerifyListener.setActive(event.time);
////          }
////        }
////
//      } else {
//        if (!outOfOrderListener.isActive(event.time)) {
//          widget.addListener(SWT.KeyDown, outOfOrderListener);
//          outOfOrderListener.setActive(event.time);
//        }
//      }
//
//      /*
//       * Otherwise, we count on a key down arriving eventually. Expecting out of order
//       * handling on Ctrl+Tab, for example, is a bad idea (stick to keys that are not window
//       * traversal keys).
//       */
//
//    } else {
      processKeyEvent(keyStrokes, event);
//    }
  }
 
  public List<KeyStroke> generatePossibleKeyStrokes(KeyEvent event) {
    final List<KeyStroke> keyStrokes = new ArrayList<KeyStroke>(3);

    /*
     * If this is not a keyboard event, then there are no key strokes. This can happen if we are
     * listening to focus traversal events.
     */
    if ( !hasModifierPressed(event) && (event.getCode() == KeyCode.UNDEFINED) /*&& (event.character == 0)*/) {
      return keyStrokes;
    }

    // Add each unique key stroke to the list for consideration.
    final int firstAccelerator = FxKeySupport.convertEventToUnmodifiedAccelerator(event);
    keyStrokes.add(FxKeySupport.convertAcceleratorToKeyStroke(factory, lookup, firstAccelerator));

    // We shouldn't allow delete to undergo shift resolution.
    if (event.getCode() == KeyCode.DELETE) {
      return keyStrokes;
    }

    final int secondAccelerator = FxKeySupport.convertEventToUnshiftedModifiedAccelerator(event);
    if (secondAccelerator != firstAccelerator) {
      keyStrokes.add(FxKeySupport.convertAcceleratorToKeyStroke(factory, lookup, secondAccelerator));
    }

    final int thirdAccelerator = FxKeySupport.convertEventToModifiedAccelerator(event);
    if ((thirdAccelerator != secondAccelerator) && (thirdAccelerator != firstAccelerator)) {
      keyStrokes.add(FxKeySupport.convertAcceleratorToKeyStroke(factory, lookup, thirdAccelerator));
    }

    return keyStrokes;
  }
 
  void processKeyEvent(List<KeyStroke> keyStrokes, KeyEvent event) {
    // Dispatch the keyboard shortcut, if any.
    boolean eatKey = false;
   
    if (!keyStrokes.isEmpty()) {
      eatKey = press(keyStrokes, event);
    }

    if (eatKey) {
      event.consume();
//      switch (event.type) {
//      case SWT.KeyDown:
//        event.doit = false;
//        break;
//      case SWT.Traverse:
//        event.detail = SWT.TRAVERSE_NONE;
//        event.doit = true;
//        break;
//      default:
//      }
//      event.type = SWT.NONE;
    }
  }
 
  public boolean press(List<KeyStroke> potentialKeyStrokes, KeyEvent event) {
    KeySequence errorSequence = null;
    Collection<Binding> errorMatch = null;
   
    KeySequence sequenceBeforeKeyStroke = state;
    for (Iterator<KeyStroke> iterator = potentialKeyStrokes.iterator(); iterator.hasNext();) {
      KeySequence sequenceAfterKeyStroke = factory.getKeySequenceInstance(sequenceBeforeKeyStroke,
          iterator.next());
     
      if (isPartialMatch(sequenceAfterKeyStroke)) {
        incrementState(sequenceAfterKeyStroke);
        return true;

      } else if (isPerfectMatch(sequenceAfterKeyStroke)) {
        final ParameterizedCommand cmd = getPerfectMatch(sequenceAfterKeyStroke);
        try {
          return executeCommand(cmd, event) || !sequenceBeforeKeyStroke.isEmpty();
        } catch (final CommandException e) {
          return true;
        }

//      } else if ((keyAssistDialog != null)
//          && (keyAssistDialog.getShell() != null)
//          && ((event.keyCode == SWT.ARROW_DOWN) || (event.keyCode == SWT.ARROW_UP)
//              || (event.keyCode == SWT.ARROW_LEFT)
//              || (event.keyCode == SWT.ARROW_RIGHT) || (event.keyCode == SWT.CR)
//              || (event.keyCode == SWT.PAGE_UP) || (event.keyCode == SWT.PAGE_DOWN))) {
//        // We don't want to swallow keyboard navigation keys.
//        return false;

      } else {
        Collection<Binding> matches = getBindingService().getConflictsFor(
            sequenceAfterKeyStroke);
        if (matches != null && !matches.isEmpty()) {
          errorSequence = sequenceAfterKeyStroke;
          errorMatch = matches;
        }
      }
    }
    resetState(true);
    if (sequenceBeforeKeyStroke.isEmpty() && errorSequence != null) {
      openKeyAssistShell(errorMatch);
    }
    return !sequenceBeforeKeyStroke.isEmpty();
  }
 
  private ParameterizedCommand getPerfectMatch(KeySequence keySequence) {
    Binding perfectMatch = getBindingService().getPerfectMatch(keySequence);
    return perfectMatch == null ? null : perfectMatch.getParameterizedCommand();
  }
 
  private boolean isPartialMatch(KeySequence keySequence) {
    return getBindingService().isPartialMatch(keySequence);
  }
 
  private boolean isPerfectMatch(KeySequence keySequence) {
    return getBindingService().isPerfectMatch(keySequence);
  }
 
  private void resetState(boolean clearRememberedState) {
    startTime = Long.MAX_VALUE;
    state = factory.getKeySequenceInstance();
//    closeMultiKeyAssistShell();
//    if (keyAssistDialog != null && clearRememberedState) {
//      keyAssistDialog.clearRememberedState();
//    }
  }
  
  private EBindingService getBindingService() {
    if (bindingService == null) {
      bindingService = (EBindingService) context.get(EBindingService.class.getName());
    }
    return bindingService;
  }
 
  private void incrementState(final KeySequence sequence) {
    state = sequence;
    // Record the starting time.
    startTime = System.currentTimeMillis();
    final long myStartTime = startTime;
//    final Display display = getDisplay();
//    display.timerExec(DELAY, new Runnable() {
//      public void run() {
//        if ((System.currentTimeMillis() > (myStartTime - DELAY))
//            && (startTime == myStartTime)) {
//          Collection<Binding> partialMatches = bindingService.getPartialMatches(sequence);
//          openKeyAssistShell(partialMatches);
//        }
//      }
//    });
  }
 
  private final void openKeyAssistShell(final Collection<Binding> bindings) {
//    if (keyAssistDialog == null) {
//      keyAssistDialog = new KeyAssistDialog(context, this);
//    }
//    if (keyAssistDialog.getShell() == null) {
//      keyAssistDialog.setParentShell(getDisplay().getActiveShell());
//    }
//    keyAssistDialog.open(bindings);
  }
 
  public final boolean executeCommand(final ParameterizedCommand parameterizedCommand,
      final Event trigger) throws CommandException {

    // Reset the key binding state (close window, clear status line, etc.)
    resetState(false);

    final EHandlerService handlerService = getHandlerService();
    final Command command = parameterizedCommand.getCommand();

    final IEclipseContext staticContext = EclipseContextFactory.create("keys-staticContext"); //$NON-NLS-1$
    staticContext.set(Event.class, trigger);

    final boolean commandDefined = command.isDefined();
    // boolean commandEnabled;
    boolean commandHandled;

    try {
      // commandEnabled = handlerService.canExecute(parameterizedCommand, staticContext);
      commandHandled = HandlerServiceImpl.lookUpHandler(context, command.getId()) != null;

      try {
        handlerService.executeHandler(parameterizedCommand, staticContext);
      } catch (final Exception e) {
        commandHandled = false;
        e.printStackTrace();
      }
      /*
       * Now that the command has executed (and had the opportunity to use the remembered
       * state of the dialog), it is safe to delete that information.
       */
//      if (keyAssistDialog != null) {
//        keyAssistDialog.clearRememberedState();
//      }
    } finally {
      staticContext.dispose();
    }
    return (commandDefined && commandHandled);
  }
 
  private EHandlerService getHandlerService() {
    if (handlerService == null) {
      handlerService = (EHandlerService) context.get(EHandlerService.class.getName());
    }
    return handlerService;
  }
}
TOP

Related Classes of at.bestsolution.efxclipse.runtime.workbench.fx.key.KeyBindingDispatcher$KeyDownFilter

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.