blob: 7b1c3b74cb9a4dd7f15411298c950d2f5d897198 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 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
******************************************************************************/
rwt.qx.Class.define( "rwt.widgets.Combo", {
extend : rwt.widgets.base.HorizontalBoxLayout,
construct : function( isCCombo ) {
this.base( arguments );
this._editable = true;
this._userSelection = true;
this._listMinWidth = -1;
this._field = new rwt.widgets.base.BasicText();
this._field.setTabIndex( null );
this._field.setAllowStretchY( true );
this._field.setTop( 0 );
this._field.setWidth( "1*" );
this._field.setHeight( "100%" );
this.add( this._field );
this._button = new rwt.widgets.base.BasicButton( "push", true );
this._button.setTabIndex( null );
this._button.setTop( 0 );
this._button.setHeight( "100%" );
this.add( this._button );
this.setHideFocus( true );
var appearance = isCCombo ? "ccombo" : "combo";
this.setAppearance( appearance );
this._field.setAppearance( appearance + "-field" );
this._button.setAppearance( appearance + "-button" );
this._registerListeners();
},
destruct : function() {
this._list.destroy();
this._disposeObjects( "_field", "_button" );
},
members : {
setItems : function( items ) {
this._listMinWidth = -1;
this._userSelection = false;
this._list.setItems( items );
this._userSelection = true;
this.dispatchSimpleEvent( "itemsChanged" );
if( this._list.getVisible() ) {
this._list.setMinWidth( this._getListMinWidth() );
}
},
setVisibleItemCount : function( value ) {
this._list.setVisibleItemCount( value );
},
select : function( index ) {
this._userSelection = false;
this._list.setSelectionIndex( index );
this._userSelection = true;
},
setEditable : function( value ) {
this._editable = value;
this._field.setReadOnly( !value );
},
setListVisible : function( value ) {
if( value ) {
this._list.setMinWidth( this._getListMinWidth() );
}
this._list.setVisible( value );
},
setText : function( value ) {
if( this._editable ) {
this._field.setValue( value );
}
},
setTextSelection : function( selection ) {
this._field.setSelection( selection );
},
setTextLimit : function( value ) {
this._field.setMaxLength( value );
},
addState : function( state ) {
this.base( arguments, state );
if( state === "rwt_FLAT" || state === "rwt_RIGHT_TO_LEFT" ) {
this._field.addState( state );
this._button.addState( state );
}
},
removeState : function( state ) {
this.base( arguments, state );
if( state === "rwt_RIGHT_TO_LEFT" ) {
this._field.removeState( state );
this._button.removeState( state );
}
},
_getSubWidgets : function() {
return [ this._field, this._button, this._list ];
},
_applyDirection : function( value ) {
this.base( arguments, value );
this.setReverseChildrenOrder( value === "rtl" );
this.setHorizontalChildrenAlign( value === "rtl" ? "right" : "left" );
if( this._list ) {
this._list.setDirection( value );
}
},
_registerListeners : function() {
this.addEventListener( "changeParent", this._onChangeParent, this );
this.addEventListener( "mousedown", this._onMouseDown, this );
this.addEventListener( "mousewheel", this._onMouseWheel, this );
this.addEventListener( "keypress", this._onKeyPress, this );
this._field.addEventListener( "input", this._onTextInput, this );
this._field.addEventListener( "keypress", this._onTextKeyPress, this );
this._field.addEventListener( "selectionChanged", this._onTextSelectionChange, this );
},
_onChangeParent : function() {
// DropDown requires valid parent focus root when creating
if( !this._list ) {
var appearance = this.getAppearance() + "-list";
this._list = new rwt.widgets.DropDown( { parent: this, appearance: appearance } );
this._list.setSelectionWrapping( false );
this._list.setDirection( this.getDirection() );
var that = this;
this._list.addListener( "Show", function( event ) {
that._onListVisibleChanged( event );
} );
this._list.addListener( "Hide", function( event ) {
that._onListVisibleChanged( event );
} );
this._list.addListener( "Selection", function( event ) {
that._onListSelectionChanged( event );
} );
}
},
_applyFont : function( value, old ) {
this.base( arguments, value, old );
this._field.setFont( value );
},
_applyTextColor : function( value, old ) {
this.base( arguments, value, old );
this._field.setTextColor( value );
},
_applyCursor : function( value, old ) {
this.base( arguments, value, old );
this._field.setCursor( value );
this._button.setCursor( value );
},
_ontabfocus : function() {
this._showFocusIndicator();
if( this._field.isCreated() ) {
this._field.selectAll();
}
},
_showFocusIndicator : function() {
if( !this._editable ) {
var cssSelector = ( this.getAppearance() === "combo" ? "" : "C" ) + "Combo-FocusIndicator";
rwt.widgets.util.FocusIndicator.getInstance().show( this, cssSelector, null );
}
},
_visualizeFocus : function() {
if( this._field.isCreated() ) {
this._field._visualizeFocus();
this._field._renderSelection();
}
this.addState( "focused" );
},
_visualizeBlur : function() {
if( this._field.isCreated() ) {
// setting selection lenght to 0 needed for IE to deselect text
this._field._setSelectionLength( 0 );
this._field._visualizeBlur();
}
if( !this._editable ) {
rwt.widgets.util.FocusIndicator.getInstance().hide( this );
}
this.removeState( "focused" );
},
_toggleListVisibility : function() {
if( this._list.getVisible() ) {
this._list.hide();
} else {
this._list.setMinWidth( this._getListMinWidth() );
this._list.show();
}
},
_getListMinWidth : function() {
if( this._listMinWidth === -1 ) {
var fontProps = {};
this.getFont().renderStyle( fontProps );
var calc = rwt.widgets.util.FontSizeCalculation;
var items = this._list.getItems();
for( var i = 0; i < this._list.getItemCount(); i++ ) {
var text = this._escapeText( items[ i ] );
var dimensions = calc.computeTextDimensions( text, fontProps );
this._listMinWidth = Math.max( this._listMinWidth, dimensions[ 0 ] );
}
}
return this._listMinWidth;
},
_escapeText : function( text ) {
var Encoding = rwt.util.Encoding;
var result = Encoding.escapeText( text, false );
result = Encoding.replaceNewLines( result, "" );
result = Encoding.replaceWhiteSpaces( result );
return result;
},
_onMouseDown : function( event ) {
var target = event.getTarget();
if( event.isLeftButtonPressed() ) {
if( target === this._field && this._field.getReadOnly() || target === this._button ) {
this.setFocused( true );
this._toggleListVisibility();
event.preventDefault();
}
}
},
_onMouseWheel : function( event ) {
if( !this._list.getVisible() && this.getFocused() && this._list.getItemCount() > 0 ) {
this._scrollSelection( event.getWheelDelta() < 0 );
event.preventDefault();
event.stopPropagation();
}
},
_onTextKeyPress : function( event ) {
// Key press event propagation is disabled in BasicText.js. Redispatch the event.
this.dispatchEvent( event );
},
_onKeyPress : function( event ) {
var key = event.getKeyIdentifier();
if( key === "Enter" ) {
this._handleKeyEnter( event );
} else if( key === "Up" || key === "Down" || key === "PageUp" || key === "PageDown" ) {
this._handleKeyUpDown( event );
}
this._selectByFirstLetter( event );
this._stopKeyEvent( event );
},
_handleKeyEnter : function( event ) {
if( !this._list.getVisible() && event.getModifiers() === 0 ) {
rwt.remote.EventUtil.notifyDefaultSelected( this );
}
},
_handleKeyUpDown : function( event ) {
if( event.isAltPressed() ) {
this._toggleListVisibility();
} else if( !this._list.getVisible() && this._list.getItemCount() > 0 ) {
switch( event.getKeyIdentifier() ) {
case "Up":
this._scrollSelection( false );
break;
case "Down":
this._scrollSelection( true );
break;
case "PageUp":
this._scrollSelection( false, true );
break;
case "PageDown":
this._scrollSelection( true, true );
break;
}
}
},
_selectByFirstLetter : function( event ) {
var charCode = event.getCharCode();
if( charCode !== 0 && !event.isAltPressed() && !event.isCtrlPressed() ) {
if( this._list.getVisible() || !this._editable ) {
var startIndex = this._list.getSelectionIndex() + 1;
var endIndex = this._list.getItemCount() - 1;
var letter = String.fromCharCode( charCode );
var selectionIndex = this._findIndexByFirstLetter( startIndex, endIndex, letter );
if( selectionIndex === -1 ) {
selectionIndex = this._findIndexByFirstLetter( 0, startIndex - 1, letter );
}
if( selectionIndex !== -1 ) {
this._list.setSelectionIndex( selectionIndex );
}
}
}
},
_findIndexByFirstLetter : function( startIndex, endIndex, letter ) {
var items = this._list.getItems();
for( var i = startIndex; i <= endIndex; i++ ) {
if( items[ i ].slice( 0, 1 ).toLowerCase() === letter.toLowerCase() ) {
return i;
}
}
return -1;
},
_stopKeyEvent : function( event ) {
switch( event.getKeyIdentifier() ) {
case "Enter":
case "Up":
case "Down":
case "PageUp":
case "PageDown":
event.preventDefault();
event.stopPropagation();
break;
}
},
_scrollSelection : function( down, page ) {
var index = this._list.getSelectionIndex();
var itemCount = this._list.getItemCount();
var visibleItems = this._list.getVisibleItemCount();
if( index === -1 ) {
index = 0;
} else if( down ) {
index = page ? index + visibleItems - 1 : index + 1;
index = Math.min( itemCount - 1, index );
} else {
index = page ? index - visibleItems + 1 : index - 1;
index = Math.max( 0, index );
}
if( index !== this._list.getSelectionIndex() ) {
this._list.setSelectionIndex( index );
}
},
_onTextInput : function() {
if( this._editable ) {
var remoteObject = rwt.remote.Connection.getInstance().getRemoteObject( this );
remoteObject.set( "text", this._field.getComputedValue() );
this._notifyModify( true );
this._internalSelectionChanged = true;
this._list.setSelectionIndex( -1 );
this._internalSelectionChanged = false;
}
},
_onListVisibleChanged : function() {
var listVisible = this._list.getVisible();
if( this._editable ) {
this._field.setReadOnly( listVisible );
}
if( this.getFocused() ) {
if( listVisible ) {
this._field._visualizeBlur();
} else if( this._editable ) {
this._field._visualizeFocus();
}
}
if( !rwt.remote.EventUtil.getSuspended() ) {
var connection = rwt.remote.Connection.getInstance();
connection.getRemoteObject( this ).set( "listVisible", listVisible );
}
},
_onListSelectionChanged : function( event ) {
if( !this._internalSelectionChanged ) {
if( this._userSelection ) {
this.setFocused( true );
}
this._field.setValue( event.index === -1 ? "" : event.text );
if( this._field.isCreated() && this._userSelection ) {
this._field.selectAll();
}
this._sendSelectionChanged( event );
this.dispatchSimpleEvent( "selectionChanged" );
}
},
_onTextSelectionChange : function() {
if( !rwt.remote.EventUtil.getSuspended() ) {
var remoteObject = rwt.remote.Connection.getInstance().getRemoteObject( this );
remoteObject.set( "selection", this._field.getSelection() );
}
},
_sendSelectionChanged : function( event ) {
if( !rwt.remote.EventUtil.getSuspended() ) {
var remoteObject = rwt.remote.Connection.getInstance().getRemoteObject( this );
if( this._editable ) {
remoteObject.set( "text", event.text );
}
remoteObject.set( "selectionIndex", event.index );
rwt.remote.EventUtil.notifySelected( this );
this._notifyModify();
}
},
_notifyModify : function( delayed ) {
var connection = rwt.remote.Connection.getInstance();
if( connection.getRemoteObject( this ).isListening( "Modify" ) ) {
connection.onNextSend( this._onSend, this );
if( delayed ) {
connection.sendDelayed( 500 );
} else {
connection.send();
}
}
},
_onSend : function() {
if( !this.isDisposed() ) {
rwt.remote.Connection.getInstance().getRemoteObject( this ).notify( "Modify", null, true );
}
},
applyObjectId : function( id ) {
this.base( arguments, id );
this._list.applyObjectId( id + "-listbox" );
}
}
} );