    /*!
     * Ext JS Library 3.3.0
     * Copyright(c) 2006-2010 Ext JS, Inc.
     * licensing@extjs.com
     * http://www.extjs.com/license
     */
    Ext.ns('Ext.ux.form');

    /**
     * @class Ext.ux.form.SelectBox
     * @extends Ext.form.ComboBox
     * Makes a ComboBox more closely mimic an HTML SELECT.  Supports clicking and dragging
     * through the list, with item selection occurring when the mouse button is released.
     * When used will automatically set {@link #editable} to false and call {@link Ext.Element#unselectable}
     * on inner elements.  Re-enabling editable after calling this will NOT work.
     * @author Corey Gilmore http://extjs.com/forum/showthread.php?t=6392
     * @history 2007-07-08 jvs
     * Slight mods for Ext 2.0
     * @xtype selectbox
     */
    Ext.ux.form.SelectBox = Ext.extend(Ext.form.ComboBox, {
    	constructor: function(config){
    		this.searchResetDelay = 1000;
    		config = config || {};
    		config = Ext.apply(config || {}, {
    			editable: false,
    			forceSelection: true,
    			rowHeight: false,
    			lastSearchTerm: false,
    			triggerAction: 'all',
    			mode: 'local'
    		});

    		Ext.ux.form.SelectBox.superclass.constructor.apply(this, arguments);

    		this.lastSelectedIndex = this.selectedIndex || 0;
    	},

    	initEvents : function(){
    		Ext.ux.form.SelectBox.superclass.initEvents.apply(this, arguments);
    		// you need to use keypress to capture upper/lower case and shift+key, but it doesn't work in IE
    		this.el.on('keydown', this.keySearch, this, true);
    		this.cshTask = new Ext.util.DelayedTask(this.clearSearchHistory, this);
    	},

    	keySearch : function(e, target, options) {
    		var raw = e.getKey();
    		var key = String.fromCharCode(raw);
    		var startIndex = 0;

    		if( !this.store.getCount() ) {
    			return;
    		}

    		switch(raw) {
    			case Ext.EventObject.HOME:
    				e.stopEvent();
    				this.selectFirst();
    				return;

    			case Ext.EventObject.END:
    				e.stopEvent();
    				this.selectLast();
    				return;

    			case Ext.EventObject.PAGEDOWN:
    				this.selectNextPage();
    				e.stopEvent();
    				return;

    			case Ext.EventObject.PAGEUP:
    				this.selectPrevPage();
    				e.stopEvent();
    				return;
    		}

    		// skip special keys other than the shift key
    		if( (e.hasModifier() && !e.shiftKey) || e.isNavKeyPress() || e.isSpecialKey() ) {
    			return;
    		}
    		if( this.lastSearchTerm == key ) {
    			startIndex = this.lastSelectedIndex;
    		}
    		this.search(this.displayField, key, startIndex);
    		this.cshTask.delay(this.searchResetDelay);
    	},

    	onRender : function(ct, position) {
    		this.store.on('load', this.calcRowsPerPage, this);
    		Ext.ux.form.SelectBox.superclass.onRender.apply(this, arguments);
    		if( this.mode == 'local' ) {
                this.initList();
    			this.calcRowsPerPage();
    		}
    	},

    	onSelect : function(record, index, skipCollapse){
    		if(this.fireEvent('beforeselect', this, record, index) !== false){
    			this.setValue(record.data[this.valueField || this.displayField]);
    			if( !skipCollapse ) {
    				this.collapse();
    			}
    			this.lastSelectedIndex = index + 1;
    			this.fireEvent('select', this, record, index);
    		}
    	},

    	afterRender : function() {
    		Ext.ux.form.SelectBox.superclass.afterRender.apply(this, arguments);
    		if(Ext.isWebKit) {
    			this.el.swallowEvent('mousedown', true);
    		}
    		this.el.unselectable();
    		this.innerList.unselectable();
    		this.trigger.unselectable();
    		this.innerList.on('mouseup', function(e, target, options) {
    			if( target.id && target.id == this.innerList.id ) {
    				return;
    			}
    			this.onViewClick();
    		}, this);

    		this.innerList.on('mouseover', function(e, target, options) {
    			if( target.id && target.id == this.innerList.id ) {
    				return;
    			}
    			this.lastSelectedIndex = this.view.getSelectedIndexes()[0] + 1;
    			this.cshTask.delay(this.searchResetDelay);
    		}, this);

    		this.trigger.un('click', this.onTriggerClick, this);
    		this.trigger.on('mousedown', function(e, target, options) {
    			e.preventDefault();
    			this.onTriggerClick();
    		}, this);

    		this.on('collapse', function(e, target, options) {
    			Ext.getDoc().un('mouseup', this.collapseIf, this);
    		}, this, true);

    		this.on('expand', function(e, target, options) {
    			Ext.getDoc().on('mouseup', this.collapseIf, this);
    		}, this, true);
    	},

    	clearSearchHistory : function() {
    		this.lastSelectedIndex = 0;
    		this.lastSearchTerm = false;
    	},

    	selectFirst : function() {
    		this.focusAndSelect(this.store.data.first());
    	},

    	selectLast : function() {
    		this.focusAndSelect(this.store.data.last());
    	},

    	selectPrevPage : function() {
    		if( !this.rowHeight ) {
    			return;
    		}
    		var index = Math.max(this.selectedIndex-this.rowsPerPage, 0);
    		this.focusAndSelect(this.store.getAt(index));
    	},

    	selectNextPage : function() {
    		if( !this.rowHeight ) {
    			return;
    		}
    		var index = Math.min(this.selectedIndex+this.rowsPerPage, this.store.getCount() - 1);
    		this.focusAndSelect(this.store.getAt(index));
    	},

    	search : function(field, value, startIndex) {
    		field = field || this.displayField;
    		this.lastSearchTerm = value;
    		var index = this.store.find.apply(this.store, arguments);
    		if( index !== -1 ) {
    			this.focusAndSelect(index);
    		}
    	},

    	focusAndSelect : function(record) {
            var index = Ext.isNumber(record) ? record : this.store.indexOf(record);
            this.select(index, this.isExpanded());
            this.onSelect(this.store.getAt(index), index, this.isExpanded());
    	},

    	calcRowsPerPage : function() {
    		if( this.store.getCount() ) {
    			this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();
    			this.rowsPerPage = this.maxHeight / this.rowHeight;
    		} else {
    			this.rowHeight = false;
    		}
    	}

    });

    Ext.reg('selectbox', Ext.ux.form.SelectBox);

    //backwards compat
    Ext.ux.SelectBox = Ext.ux.form.SelectBox;