All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rwt.widgets.util.MnemonicHandler.js Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2013, 2014 EclipseSource 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:
 *    EclipseSource - initial API and implementation
 ******************************************************************************/

(function() {

var EventHandlerUtil = rwt.event.EventHandlerUtil;
var WidgetUtil = rwt.widgets.util.WidgetUtil;

rwt.qx.Class.define( "rwt.widgets.util.MnemonicHandler", {

  extend : rwt.qx.Object,

  statics : {

    getInstance : function() {
      return rwt.runtime.Singletons.get( rwt.widgets.util.MnemonicHandler );
    }

  },

  construct : function() {
    this.base( arguments );
    this._map = {};
    this._activator = null;
    this._active = null;
    this._activeMenu = null;
    this._allowMenuActivate = false;
  },

  members : {

    add : function( widget, listener ) {
      var shell = WidgetUtil.getShell( widget );
      if( shell != null ) {  // TODO [tb] : this is for MenuBar items, handle them like Menu items
        this._registerFocusRoot( shell );
        var handlers = this._map[ shell.toHashCode() ];
        if( widget instanceof rwt.widgets.MenuItem ) {
          handlers.menu[ widget.toHashCode() ] = [ widget, listener ];
        } else {
          handlers.controls[ widget.toHashCode() ] = [ widget, listener ];
        }
      }
    },

    remove : function( widget ) {
      // NOTE: The shell may be gone if the widget is in dispose, therefore we have to search:
      var hash = widget.toHashCode();
      if( widget instanceof rwt.widgets.MenuItem ) {
        for( var key in this._map ) {
          if( this._map[ key ].menu[ widget.toHashCode() ] ) {
            delete this._map[ key ].menu[ hash ];
            return;
          }
        }
      } else {
        for( var key in this._map ) {
          if( this._map[ key ].controls[ widget.toHashCode() ] ) {
            delete this._map[ key ].controls[ hash ];
            return;
          }
        }
      }
    },

    setActivator : function( str ) {
      if( str ) {
        this._activator = {};
        this._activator.ctrlKey = str.indexOf( "CTRL" ) !== -1;
        this._activator.altKey = str.indexOf( "ALT" ) !== -1;
        this._activator.shiftKey = str.indexOf( "SHIFT" ) !== -1;
      } else {
        this._activator = null;
      }
    },

    isActive : function() {
      return this._active != null;
    },

    handleKeyEvent : function( eventType, keyCode, charCode, domEvent ) {
      var result = false;
      this._checkActiveMenu();
      // Some browser fire multiple keydown for modifier keys:
      if( eventType !== "keydown" || rwt.event.EventHandlerUtil.isFirstKeyDown( keyCode ) ) {
        if( this._isActivation( eventType, keyCode, charCode, domEvent ) ) {
          this.activate();
        } else if( this._isDeactivation( eventType, keyCode, charCode, domEvent ) ) {
          this.deactivate( this._allowMenuActivate || this._activeMenu );
        } else if( this._isTrigger( eventType, keyCode, charCode, domEvent ) ) {
          result = this.trigger( keyCode );
          this._allowMenuActivate = false;
        } else if( this.isActive() && !this._isActivatorCombo( domEvent ) ) {
          this._allowMenuActivate = false;
        }
      }
      return result;
    },

    activate : function() {
      if( this._noMenuOpen() ) {
        var root = rwt.widgets.base.Window.getDefaultWindowManager().getActiveWindow();
        if( root == null ) {
          root = rwt.widgets.base.ClientDocument.getInstance();
        }
        this._active = root.toHashCode();
        this._allowMenuActivate = true;
        this._fire( { "type" : "show" } );
      }
    },

    deactivate : function( allowMenuToggle ) {
      if( this._activeMenu && allowMenuToggle ) {
        this._activeMenu.setActive( false );
        this._activeMenu = null;
      }
      if( this._active ) {
        this._fire( { "type" : "hide" } );
        if( allowMenuToggle ) {
          this._activateMenuBar();
        }
        this._active = null;
      }
    },

    trigger : function( charCode ) {
      var event = {
        "type" : "trigger",
        "charCode" : charCode,
        "success" : false
      };
      this._fire( event, true );
      return event.success;
    },

    _registerFocusRoot : function( root ) {
      if( !this._map[ root.toHashCode() ] ) {
        this._map[ root.toHashCode() ] = { "menu" : {}, "controls" : {} };
        root.addEventListener( "dispose", function() {
          this.deactivate();
          delete this._map[ root.toHashCode() ];
        }, this );
        root.addEventListener( "changeActive", this._onRootChangeActive, this );
      }
    },

    _onRootChangeActive : function( event ) {
      if( event.getValue() === false ) {
        this.deactivate();
      }
    },

    _fire : function( event, onlyVisible ) {
      if( this._map[ this._active ] ) {
        this._doFire( event, onlyVisible, this._map[ this._active ].controls );
        if( !event.success ) {
          this._doFire( event, onlyVisible, this._map[ this._active ].menu );
        }
      }
    },

    _doFire : function( event, onlyVisible, handlers ) {
      for( var key in handlers ) {
        var entry = handlers[ key ];
        if( ( !onlyVisible || entry[ 0 ].isSeeable() ) && entry[ 0 ].getEnabled() ) {
          try{
            entry[ 1 ].call( entry[ 0 ], event );
            if( event.success ) {
              break;
            }
          } catch( ex ) {
            var msg = "Could not handle mnemonic " + event.type + ". ";
            if( entry[ 0 ].isDisposed() ) {
              msg +=  entry[ 0 ].classname + " is disposed. ";
            }
            msg += ex.message;
            throw new Error( msg );
          }
        }
      }
    },

    _activateMenuBar : function() {
      // Accepted limitation: MenuBars without mnemonics can not be activated by mnemonic keys
      if( this._map[ this._active ] ) {
        var items = this._map[ this._active ].menu;
        for( var key in items ) {
          var bar = items[ key ][ 0 ].getParentMenu();
          bar.setMnemonics( true );
          bar.setActive( true );
          this._activeMenu = bar;
          break;
        }
      }
    },

    _checkActiveMenu : function() {
      if( this._activeMenu && !this._activeMenu.getActive() ) {
        this._activeMenu = null;
      }
    },

    /////////
    // Helper

    _isActivation : function( eventType, keyCode, charCode, domEvent ) {
      return    this._activator
             && this._active == null && this._activeMenu == null
             && eventType === "keydown"
             && EventHandlerUtil.isModifier( keyCode )
             && this._isActivatorCombo( domEvent );
    },

    _isDeactivation : function( eventType, keyCode, charCode, domEvent ) {
      return    this._isGlobalDeactivation( eventType, keyCode, charCode, domEvent )
             || this._isMenuDeactivation( eventType, keyCode, charCode, domEvent );
    },

    _isMenuDeactivation : function( eventType, keyCode, charCode, domEvent ) {
      return    this._activator != null
             && this._activeMenu != null
             && EventHandlerUtil.isModifier( keyCode )
             && this._isActivatorCombo( domEvent );
    },

    _isGlobalDeactivation : function( eventType, keyCode, charCode, domEvent ) {
      return    this._activator != null
             && this._active != null
             && eventType != "keypress"
             && !this._isActivatorCombo( domEvent );
    },

    _isActivatorCombo : function( domEvent ) {
      return    this._activator.ctrlKey === domEvent.ctrlKey
             && this._activator.altKey === domEvent.altKey
             && this._activator.shiftKey === domEvent.shiftKey;
    },

    _isTrigger : function( eventType, keyCode ) {
      var isChar = !isNaN( keyCode ) && rwt.event.EventHandlerUtil.isAlphaNumericKeyCode( keyCode );
      return this._active != null && eventType === "keydown" && isChar;
     },

     _noMenuOpen : function() {
       return rwt.util.Objects.isEmpty( rwt.widgets.util.MenuManager.getInstance().getAll() );
     }

  }

} );

}() );




© 2015 - 2025 Weber Informatics LLC | Privacy Policy