1  /*
     2   Copyright aswing.org, see the LICENCE.txt.
     3  */
     4   
     5  import org.aswing.Component;
     6  import org.aswing.Container;
     7  import org.aswing.DefaultListCellFactory;
     8  import org.aswing.Event;
     9  import org.aswing.events.ListDataEvent;
    10  import org.aswing.events.ListDataListener;
    11  import org.aswing.geom.Dimension;
    12  import org.aswing.geom.Point;
    13  import org.aswing.geom.Rectangle;
    14  import org.aswing.LayoutManager;
    15  import org.aswing.ListCell;
    16  import org.aswing.ListCellFactory;
    17  import org.aswing.ListModel;
    18  import org.aswing.plaf.ListUI;
    19  import org.aswing.UIManager;
    20  import org.aswing.utils.Delegate;
    21  import org.aswing.utils.HashMap;
    22  import org.aswing.utils.Vector;
    23  import org.aswing.VectorListModel;
    24  import org.aswing.Viewportable;
    25  
    26  /** 
    27   * A component that allows the user to select one or more objects from a
    28   * list.  A separate model, <code>ListModel</code>, represents the contents
    29   * of the list.  It's easy to display an array objects, using
    30   * a <code>JList</code> constructor that builds a <code>ListModel</code> 
    31   * instance for you:
    32   * <pre>
    33   * // Create a JList that displays the strings in data[]
    34   *
    35   * var data:Array = ["one", "two", "three", "four"];
    36   * var dataList:JList = new JList(data);
    37   * 
    38   * // The value of the JList model property is an object that provides
    39   * // a read-only view of the data.  It was constructed automatically.
    40   *
    41   * for(int i = 0; i < dataList.getModel().getSize(); i++) {
    42   *     System.out.println(dataList.getModel().getElementAt(i));
    43   * }
    44   *
    45   * // Create a JList that displays the values in a IVector--<code>VectorListModel</code>.
    46   *
    47   * var vec:VectorListModel = new VectorListModel(["one", "two", "three", "four"]);
    48   * var vecList:JList = new JList(vec);
    49   * 
    50   * //When you add elements to the vector, the JList will be automatically updated.
    51   * vec.append("five");
    52   * </pre>
    53   * <p>
    54   * <code>JList</code> doesn't support scrolling directly. 
    55   * To create a scrolling
    56   * list you make the <code>JList</code> the viewport of a
    57   * <code>JScrollPane</code>.  For example:
    58   * <pre>
    59   * JScrollPane scrollPane = new JScrollPane(dataList);
    60   * // Or in two steps:
    61   * JScrollPane scrollPane = new JScrollPane();
    62   * scrollPane.setView(dataList);
    63   * </pre>
    64   * <p>
    65   * By default the <code>JList</code> selection model is 
    66   * <code>SINGLE_SELECTION</code>.
    67   * <pre>
    68   * String[] data = {"one", "two", "three", "four"};
    69   * JList dataList = new JList(data);
    70   *
    71   * dataList.setSelectedIndex(1);  // select "two"
    72   * dataList.getSelectedValue();   // returns "two"
    73   * </pre>
    74   * <p>
    75   * The contents of a <code>JList</code> can be dynamic,
    76   * in other words, the list elements can
    77   * change value and the size of the list can change after the
    78   * <code>JList</code> has
    79   * been created.  The <code>JList</code> observes changes in its model with a
    80   * <code>ListDataListener</code> implementation.  A correct 
    81   * implementation of <code>ListModel</code> notifies
    82   * it's listeners each time a change occurs.  The changes are
    83   * characterized by a <code>ListDataEvent</code>, which identifies
    84   * the range of list indices that have been modified, added, or removed.
    85   * Simple dynamic-content <code>JList</code> applications can use the
    86   * <code>VectorListModel</code> class to store list elements.  This class
    87   * implements the <code>ListModel</code> and <code>IVector</code> interfaces
    88   * and provides the Vector API.  Applications that need to 
    89   * provide custom <code>ListModel</code> implementations can subclass 
    90   * <code>AbstractListModel</code>, which provides basic 
    91   * <code>ListDataListener</code> support.
    92   * <p>
    93   * <code>JList</code> uses a <code>Component</code> provision, provided by 
    94   * a delegate called the
    95   * <code>ListCell</code>, to paint the visible cells in the list.
    96   * <p>
    97   * <code>ListCell</code> created by a <code>ListCellFactory</code>, to custom 
    98   * the item representation of the list, you need a custom <code>ListCellFactory</code>.
    99   * For example a IconListCellFactory create IconListCells.
   100   * <p>
   101   * <code>ListCellFactory</code> is related to the List's performace too, see the doc 
   102   * comments of <code>ListCellFactory</code> for the details.
   103   * And if you want a horizontal scrollvar visible when item width is bigger than the visible 
   104   * width, you need a not <code>shareCells</code> Factory(and of course the List should located 
   105   * in a JScrollPane first). <code>shareCells</code> Factory 
   106   * can not count the maximum width of list items.
   107   * @author iiley
   108   * @see ListCellFactory
   109   * @see ListCell
   110   * @see ListModel
   111   * @see VectorListModel
   112   */
   113  class org.aswing.JList extends Container implements Viewportable, LayoutManager, ListDataListener{
   114  	
   115  	/**
   116  	 * When the JList Viewportable state changed.
   117  	 *<br>
   118  	 * onStateChanged Event{source:JList}
   119  	 */	
   120  	public static var ON_STATE_CHANGED:String = "onStateChanged";// Component.ON_STATE_CHANGED; 	
   121  	
   122  	/**
   123  	 * When the list selection changed.<br>
   124  	 * onSelectionChange Event{source:JList}
   125  	 */	
   126  	public static var ON_SELECTION_CHANGE:String = "onSelectionChange";
   127  	
   128  	/**
   129  	 * onListScroll Event{source:JList}
   130  	 */	
   131  	public static var ON_LIST_SCROLL:String = "onListScroll";
   132  	
   133  	/**
   134  	 * onItemPress Event{source:JList, value:Object, cell:ListCell}
   135  	 */
   136  	public static var ON_ITEM_PRESS:String = "onItemPress";
   137  	/**
   138  	 * onItemRelease Event{source:JList, value:Object, cell:ListCell}
   139  	 */	
   140  	public static var ON_ITEM_RELEASE:String = "onItemRelease";	
   141  	/**
   142  	 * onItemReleaseOutSide Event{source:JList, value:Object, cell:ListCell}
   143  	 */	
   144  	public static var ON_ITEM_RELEASEOUTSIDE:String = "onItemReleaseOutSide";
   145  	/**
   146  	 * onItemRollOver Event{source:JList, value:Object, cell:ListCell}
   147  	 */	
   148  	public static var ON_ITEM_ROLLOVER:String = "onItemRollOver";
   149  	/**
   150  	 * onItemRollOut Event{source:JList, value:Object, cell:ListCell}
   151  	 */
   152  	public static var ON_ITEM_ROLLOUT:String = "onItemRollOut";		
   153  	/**
   154  	 * onItemClicked Event{source:JList, value:Object, cell:ListCell, clickCount:Number}
   155  	 */
   156  	public static var ON_ITEM_CLICKED:String = "onItemClicked";
   157  	
   158  	//---------------	
   159  	
   160  	/**
   161  	 * Only can select one most item at a time.
   162  	 */
   163  	public static var SINGLE_SELECTION:Number = 0;
   164  	/**
   165  	 * Can select any item at a time.
   166  	 */
   167  	public static var MULTIPLE_SELECTION:Number = 1;
   168  	
   169  	//---------------------caches------------------
   170  	private var viewHeight:Number;
   171  	private var viewWidth:Number;
   172  	private var maxWidthCell:ListCell;
   173  	private var cellPrefferSizes:HashMap; //use for catche sizes when not all cells same height
   174  	private var comToCellMap:HashMap; 
   175  	//--
   176  	
   177  	private var preferredWidthWhenNoCount:Number;
   178  	
   179  	private var verticalUnitIncrement:Number;
   180  	private var verticalBlockIncrement:Number;
   181  	
   182  	private var viewPosition:Point;
   183  	
   184  	private var cellFactory:ListCellFactory;
   185  	private var model:ListModel;
   186  	private var cells:Vector;
   187  	
   188  	private var selectedIndices:Array;
   189  	private var singleSelectedIndex:Number;
   190  	private var selectionMode:Number;
   191  	private var firstVisibleIndex:Number;
   192  	private var lastVisibleIndex:Number;
   193  	
   194  	private var itemHandler:Object;
   195  	
   196  	/**
   197  	 * JList(listData:Array, cellFactory:ListCellFactory)<br>
   198  	 * JList(model:ListModel, cellFactory:ListCellFactory)<br>
   199  	 * JList(listData:Array)<br>
   200  	 * JList(model:ListModel)<br>
   201  	 * JList()
   202  	 * @param listData a ListModel or a Array.
   203  	 * @param cellFactory the cellFactory for this List.
   204  	 */
   205  	public function JList(listData:Object, cellFactory:ListCellFactory) {
   206  		super();
   207  		
   208  		setName("JList");
   209  		layout = this;
   210  		
   211  		verticalUnitIncrement = 1;
   212  		verticalBlockIncrement = 10;
   213  		viewPosition = new Point(0, 0);
   214  		selectionMode = SINGLE_SELECTION;
   215  		singleSelectedIndex = -1;
   216  		selectedIndices = new Array();
   217  		firstVisibleIndex = 0;
   218  		lastVisibleIndex = 0;
   219  		preferredWidthWhenNoCount = 20; //Default 20
   220  		
   221  		viewWidth = 0;
   222  		viewHeight = 0;
   223  		maxWidthCell = null;
   224  		cellPrefferSizes = new HashMap();
   225  		comToCellMap = new HashMap();
   226  		cells = new Vector();
   227  		model = null;
   228  		initItemHandler();
   229  		
   230  		if(cellFactory == undefined){
   231  			cellFactory = new DefaultListCellFactory(true);
   232  		}
   233  		this.cellFactory = cellFactory;
   234  		
   235  		if(listData instanceof ListModel){
   236  			setModel(ListModel(listData));
   237  		}else{
   238  			var o = listData;//avoid Array casting
   239  			if(o instanceof Array){
   240  				setListData(o);
   241  			}else{
   242  				setListData(null); //create new
   243  			}
   244  		}
   245  		
   246  		updateUI();
   247  	}
   248  	
   249      public function updateUI():Void{
   250      	setUI(ListUI(UIManager.getUI(this)));
   251      }
   252      
   253      public function setUI(newUI:ListUI):Void{
   254      	super.setUI(newUI);
   255      }
   256  	
   257  	public function getUIClassID():String{
   258  		return "ListUI";
   259  	}
   260  	
   261  	
   262  	/**
   263  	 * Can not set layout to JList, its layout is itself.
   264  	 * @throws Error when set any layout.
   265  	 */
   266  	public function setLayout(layout:LayoutManager):Void{
   267  		trace("Can not set layout to JList, its layout is itself");
   268  		throw new Error("Can not set layout to JList, its layout is itself");
   269  	}	
   270  	
   271  	/**
   272  	 * set a array to be the list data, but array is not a List Mode.
   273  	 * So when the array content was changed, you should call updateListView
   274  	 * to update the JList.But this is not a good way, its slow.
   275  	 * So suggest you to create a ListMode ex VectorListMode to JList,
   276  	 * When you modify ListMode, it will automatic update JList.
   277  	 * @see #setMode()
   278  	 * @see org.aswing.ListModel
   279  	 */
   280  	public function setListData(ld:Array):Void{
   281  		var m:ListModel = new VectorListModel(ld);
   282  		setModel(m);
   283  	}
   284  	
   285  	/**
   286  	 * Set the list mode to provide the data to JList.
   287  	 * @see org.aswing.ListModel
   288  	 */
   289  	public function setModel(m:ListModel):Void{
   290  		if(m == null) return;
   291  		if(m != model){
   292  			model.removeListDataListener(this);
   293  			model = m;
   294  			model.addListDataListener(this);
   295  			updateListView();
   296  		}
   297  	}
   298  	
   299  	/**
   300  	 * @return the model of this List
   301  	 */
   302  	public function getModel():ListModel{
   303  		return model;
   304  	}
   305  		
   306  	/**
   307  	 * @return the cellFactory of this List
   308  	 */
   309  	public function getCellFactory():ListCellFactory{
   310  		return cellFactory;
   311  	}
   312  	
   313  	/**
   314  	 * This will cause all cells recreating by new factory.
   315  	 * @param newFactory the new cell factory for this List
   316  	 */
   317  	public function setCellFactory(newFactory:ListCellFactory):Void{
   318  		cellFactory = newFactory;
   319  		removeAllCells();
   320  		updateListView();
   321  	}
   322  	
   323  	/**
   324  	 * Add listener to selection changed.
   325  	 * @see #ON_SELECTION_CHANGE
   326  	 */	
   327  	public function addSelectionListener(func:Function, obj:Object):Object{
   328  		return addEventListener(ON_SELECTION_CHANGE, func, obj);
   329  	}
   330  
   331  	/**
   332  	 * @see #setPreferredWidthWhenNoCount()
   333  	 * @return the default preferred with of the List when <code>shareCelles</code>.
   334  	 */
   335  	public function getPreferredWidthWhenNoCount():Number {
   336  		return preferredWidthWhenNoCount;
   337  	}
   338  
   339  	/**
   340  	 * The preferred with of the List, it is only used when List have no counting for its prefferredWidth.
   341  	 * <p>
   342  	 * When <code>ListCellFactory</code> is <code>shareCelles</code>, List will not count prefferred width.
   343  	 * @param preferredWidthWhenNoCount the preferred with of the List.
   344  	 */
   345  	public function setPreferredWidthWhenNoCount(preferredWidthWhenNoCount:Number):Void {
   346  		this.preferredWidthWhenNoCount = preferredWidthWhenNoCount;
   347  	}	
   348  	
   349  	/**
   350  	 * When your list data changed, and you want to update list view by hand.
   351  	 * call this method.
   352  	 * <p>This method is called automatically when setModel called with a different model to set. 
   353  	 */
   354  	public function updateListView() : Void {
   355  		createCells();
   356  		validateCells();
   357  	}
   358  	
   359  	/**
   360  	 * Clears the selection - after calling this method isSelectionEmpty will return true. 
   361  	 * This is a convenience method that just delegates to the selectionModel.
   362  	 */
   363  	public function clearSelection():Void{
   364  		if(selectionMode == MULTIPLE_SELECTION){
   365  			selectedIndices = new Array();
   366  		}else{
   367  			singleSelectedIndex = -1;
   368  		}
   369  		revalidate();
   370  	}
   371  	
   372  	/**
   373  	 * Determines whether single-item or multiple-item selections are allowed.
   374  	 * If selection mode changed, will cause clear selection;
   375  	 * @see #SINGLE_SELECTION
   376  	 * @see #MULTIPLE_SELECTION
   377  	 */
   378  	public function setSelectionMode(sm:Number):Void{
   379  		if(sm != selectionMode){
   380  			selectionMode = sm;
   381  			clearSelection();
   382  		}
   383  	}
   384  	
   385  	/**
   386  	 * Return whether single-item or multiple-item selections are allowed.
   387  	 * @see #SINGLE_SELECTION
   388  	 * @see #MULTIPLE_SELECTION
   389  	 */	
   390  	public function getSelectionMode():Number{
   391  		return selectionMode;
   392  	}
   393  	
   394  	/**
   395  	 * Return the selected index, if selection multiple, return the first.
   396  	 * if not selected any, return -1.
   397  	 * @return the selected index
   398  	 */
   399  	public function getSelectedIndex():Number{
   400  		if(selectionMode == MULTIPLE_SELECTION){
   401  			for(var i:Number=0; i<selectedIndices.length; i++){
   402  				if(selectedIndices[i] == true){
   403  					return i;
   404  				}
   405  			}
   406  			return -1;
   407  		}else{
   408  			return singleSelectedIndex;
   409  		}		
   410  	}
   411  	
   412  	/**
   413  	 * Returns true if nothing is selected.
   414  	 * @return true if nothing is selected, false otherwise.
   415  	 */
   416  	public function isSelectionEmpty():Boolean{
   417  		return getSelectedIndex() < 0;
   418  	}
   419  	
   420  	/**
   421  	 * Returns an array of all of the selected indices in increasing order.
   422  	 * @return a array contains all selected indices
   423  	 */
   424  	public function getSelectedIndices():Array{
   425  		var indices:Array = new Array();
   426  		if(selectionMode == MULTIPLE_SELECTION){
   427  			for(var i:Number=0; i<selectedIndices.length; i++){
   428  				if(selectedIndices[i] == true){
   429  					indices.push(i);
   430  				}
   431  			}
   432  		}else{
   433  			if(singleSelectedIndex >= 0)
   434  				indices.push(singleSelectedIndex);
   435  		}
   436  		return indices;
   437  	}
   438  	
   439  	/**
   440  	 * @return true if the index is selected, otherwise false.
   441  	 */
   442  	public function isSelectedIndex(index:Number):Boolean{
   443  		var indices:Array = new Array();
   444  		if(selectionMode == MULTIPLE_SELECTION){
   445  			return selectedIndices[index] == true;
   446  		}else{
   447  			return singleSelectedIndex == index;
   448  		}
   449  	}
   450  	
   451  	/**
   452  	 * Returns the first selected value, or null if the selection is empty.
   453  	 * @return the first selected value
   454  	 */
   455  	public function getSelectedValue():Object{
   456  		var i:Number = getSelectedIndex();
   457  		if(i < 0){
   458  			return null;
   459  		}else{
   460  			return model.getElementAt(i);
   461  		}
   462  	}
   463  	
   464  	/**
   465  	 * Returns an array of the values for the selected cells.
   466       * The returned values are sorted in increasing index order.
   467       * @return the selected values or an empty list if nothing is selected
   468  	 */
   469  	public function getSelectedValues():Array{
   470  		var values:Array = new Array();
   471  		if(selectionMode == MULTIPLE_SELECTION){
   472  			for(var i:Number=0; i<selectedIndices.length; i++){
   473  				if(selectedIndices[i] == true){
   474  					values.push(model.getElementAt(i));
   475  				}
   476  			}
   477  		}else{
   478  			if(singleSelectedIndex >= 0){
   479  				values.push(model.getElementAt(singleSelectedIndex));
   480  			}
   481  		}
   482  		return values;
   483  	}
   484  	
   485  	/**
   486  	 * Selects a single cell.  This will cause ON_SELECTION_CHANGE event 
   487  	 * only if the new index is different from currently selection.
   488  	 * <p>This will not cause a scroll, if you want to 
   489  	 * scroll to visible the selected value, call ensureIndexIsVisible().
   490  	 * @param index the index of the one cell to select
   491  	 * @see #ensureIndexIsVisible()
   492  	 */
   493  	public function setSelectedIndex(index:Number):Void{
   494  		if(selectionMode == MULTIPLE_SELECTION && selectedIndices[index] == true){
   495  			var notChanged:Boolean = true;
   496  			var selectedIndeces:Array = getSelectedIndices();
   497  			if(selectedIndeces.length == index + 1){
   498  				for(var i:Number=0; i<index; i++){
   499  					if(selectedIndeces[i] == true){
   500  						notChanged = false;
   501  						break;
   502  					}
   503  				}
   504  			}else{
   505  				notChanged = true;
   506  			}
   507  			if(notChanged){
   508  				return;
   509  			}
   510  		}else{
   511  			if(singleSelectedIndex == index){
   512  				return;
   513  			}
   514  		}
   515  		
   516  		clearSelection();
   517  		if(selectionMode == MULTIPLE_SELECTION){
   518  			selectedIndices[index] = true;
   519  		}else{
   520  			singleSelectedIndex = index;
   521  		}
   522  		dispatchEvent(ON_SELECTION_CHANGE, createEventObj(ON_SELECTION_CHANGE));
   523  		revalidate();
   524  	}
   525  	
   526  	/**
   527  	 * Selects a set of cells. This will cause ON_SELECTION_CHANGE event what ever the new 
   528  	 * indices is different from current selection or not.
   529  	 * If new the selection mode is <code>SINGAL_SELECTION</code> mode, just set the first index in indices.
   530  	 * <p> This will not cause a scroll, if you want to 
   531  	 * scroll to visible the selected value, call ensureIndexIsVisible().
   532  	 * @param indices an array of the indices of the cells to select
   533  	 * @see #getSelectionMode()
   534  	 * @see #setSelectedIndex()
   535  	 * @see #ensureIndexIsVisible()
   536  	 */	
   537  	public function setSelectedIndices(indices:Array):Void{
   538  		clearSelection();
   539  		if(selectionMode == MULTIPLE_SELECTION){
   540  			for(var i:Number=0; i<indices.length; i++)
   541  				selectedIndices[indices[i]] = true;
   542  		}else{
   543  			if(indices.length > 0 )
   544  				singleSelectedIndex = indices[0];
   545  		}
   546  		dispatchEvent(ON_SELECTION_CHANGE, createEventObj(ON_SELECTION_CHANGE));
   547  		revalidate();
   548  	}
   549  	
   550  	/**
   551  	 * Selects the specified object from the list. This will not cause a scroll, if you want to 
   552  	 * scroll to visible the selected value, call ensureIndexIsVisible().
   553  	 * @see #setSelectedIndex()
   554  	 * @see #ensureIndexIsVisible()
   555  	 */
   556  	public function setSelectedValue(value:Object):Void{
   557  		var n:Number = model.getSize();
   558  		for(var i:Number=0; i<n; i++){
   559  			if(model.getElementAt(i) == value){
   560  				setSelectedIndex(i);
   561  				return;
   562  			}
   563  		}
   564  	}
   565  		
   566  	/**
   567  	 * Scrolls the JList to make the specified cell completely visible.
   568  	 * @see setFirstVisibleIndex()
   569  	 */
   570  	public function ensureIndexIsVisible(index:Number):Void{
   571  		if(index<=getFirstVisibleIndex() || index>=getLastVisibleIndex()){
   572  			setFirstVisibleIndex(index);
   573  		}
   574  	}
   575  	
   576  	public function getFirstVisibleIndex():Number{
   577  		return firstVisibleIndex;
   578  	}
   579  	
   580  	/**
   581  	 * scroll the list to view the specified index as first visible.
   582  	 * If the list data elements is too short can not move the specified
   583  	 * index to be first, just scroll as top as can.
   584  	 * @see ensureIndexIsVisible()
   585  	 * @see setLastVisibleIndex()
   586  	 */
   587  	public function setFirstVisibleIndex(index:Number):Void{
   588      	var factory:ListCellFactory = getCellFactory();
   589  		var m:ListModel = getModel();		
   590  		var p:Point = getViewPosition();
   591  		if(factory.isAllCellHasSameHeight() || factory.isShareCells()){
   592  			p.y = index * factory.getCellHeight();
   593  		}else{
   594  			var num:Number = Math.min(cells.getSize()-1, index);
   595  			var y:Number = 0;
   596  			for(var i:Number=0; i<num; i++){
   597  				var cell:ListCell = ListCell(cells.get(i));
   598  				var s:Dimension = getCachedCellPreferSize(cell);
   599  				if(s == null){
   600  					s = cell.getListCellComponent().getPreferredSize();
   601  					trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
   602  				}
   603  				y += s.height;
   604  			}
   605  			p.y = y;
   606  		}
   607  		p.y = Math.max(0, Math.min(getViewMaxPos().y, p.y));
   608  		setViewPosition(p);
   609  	}
   610  	
   611  	public function getLastVisibleIndex():Number{
   612  		return lastVisibleIndex;
   613  	}
   614  	
   615  	/**
   616  	 * scroll the list to view the specified index as last visible
   617  	 * If the list data elements is too short can not move the specified
   618  	 * index to be last, just scroll as bottom as can.
   619  	 * @see ensureIndexIsVisible()
   620  	 * @see setFirstVisibleIndex()
   621  	 */
   622  	public function setLastVisibleIndex(index:Number):Void{
   623      	var factory:ListCellFactory = getCellFactory();
   624  		var m:ListModel = getModel();		
   625  		var p:Point = getViewPosition();
   626  		if(factory.isAllCellHasSameHeight() || factory.isShareCells()){
   627  			p.y = (index + 1) * factory.getCellHeight() - getExtentSize().height;
   628  		}else{
   629  			var num:Number = Math.min(cells.getSize(), index+1);
   630  			var y:Number = 0;
   631  			for(var i:Number=0; i<num; i++){
   632  				var cell:ListCell = ListCell(cells.get(i));
   633  				var s:Dimension = getCachedCellPreferSize(cell);
   634  				if(s == null){
   635  					s = cell.getListCellComponent().getPreferredSize();
   636  					trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
   637  				}
   638  				y += s.height;
   639  			}
   640  			p.y = y - getExtentSize().height;
   641  		}
   642  		p.y = Math.max(0, Math.min(getViewMaxPos().y, p.y));
   643  		setViewPosition(p);
   644  	}
   645  	
   646  	/**
   647  	 * Return currently visible cells count.
   648  	 */
   649  	public function getVisibleRowCount():Number{
   650  		return getLastVisibleIndex() - getFirstVisibleIndex() + 1;
   651  	}
   652  	
   653  	/**
   654  	 * Scrolls to view bottom left content. 
   655  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   656  	 * if it is located in a <code>JScrollPane</code>.
   657  	 */
   658  	public function scrollToBottomLeft():Void{
   659  		setViewPosition(new Point(0, Number.MAX_VALUE));
   660  	}
   661  	/**
   662  	 * Scrolls to view bottom right content. 
   663  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   664  	 * if it is located in a <code>JScrollPane</code>.
   665  	 */	
   666  	public function scrollToBottomRight():Void{
   667  		setViewPosition(new Point(Number.MAX_VALUE, Number.MAX_VALUE));
   668  	}
   669  	/**
   670  	 * Scrolls to view top left content. 
   671  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   672  	 * if it is located in a <code>JScrollPane</code>.
   673  	 */	
   674  	public function scrollToTopLeft():Void{
   675  		setViewPosition(new Point(0, 0));
   676  	}
   677  	/**
   678  	 * Scrolls to view to right content. 
   679  	 * This will make the scrollbars of <code>JScrollPane</code> scrolled automatically, 
   680  	 * if it is located in a <code>JScrollPane</code>.
   681  	 */	
   682  	public function scrollToTopRight():Void{
   683  		setViewPosition(new Point(Number.MAX_VALUE, 0));
   684  	}	
   685  	
   686  	/**
   687       * Enables the list so that items can be selected.
   688       */
   689  	public function setEnabled(b:Boolean):Void{
   690  		if(b != isEnabled()){
   691  			var n:Number = getComponentCount();
   692  			for(var i:Number=n-1; i>=0; i--){
   693  				var com:Component = getComponent(i);
   694  				com.setEnabled(b);
   695  			}
   696  			repaint();
   697  		}
   698  		super.setEnabled(b);
   699  	}	
   700  	//----------------------privates-------------------------
   701  	private function addCellToContainer(cell:ListCell):Void{
   702  		append(cell.getListCellComponent());
   703  		comToCellMap.put(cell.getListCellComponent().getID(), cell);
   704  		cell.getListCellComponent().addEventListener(itemHandler);
   705  	}
   706  	
   707  	private function removeCellFromeContainer(cell:ListCell):Void{
   708  		remove(cell.getListCellComponent());
   709  		comToCellMap.remove(cell.getListCellComponent().getID());
   710  		cell.getListCellComponent().removeEventListener(itemHandler);
   711  	}
   712  	
   713  	private function checkCreateCellsWhenShareCells():Void{
   714  		createCellsWhenShareCells();
   715  	}
   716  	
   717  	private function createCellsWhenShareCells():Void{
   718  		var ih:Number = getCellFactory().getCellHeight();
   719  		var needNum:Number = Math.floor(getExtentSize().height/ih) + 2;
   720  		
   721  		viewWidth = getPreferredWidthWhenNoCount();
   722  		viewHeight = getModel().getSize()*ih;
   723  		
   724  		if(cells.getSize() == needNum/* || !displayable*/){
   725  			return;
   726  		}
   727  		
   728  		var iw:Number = getWidth();
   729  		//create needed
   730  		if(cells.getSize() < needNum){
   731  			var addNum:Number = needNum - cells.getSize();
   732  			for(var i:Number=0; i<addNum; i++){
   733  				var cell:ListCell = getCellFactory().createNewCell();
   734  				addCellToContainer(cell);
   735  				cells.append(cell);
   736  			}
   737  		}else if(cells.getSize() > needNum){ //remove mored
   738  			var removeIndex:Number = needNum;
   739  			var removed:Array = cells.removeRange(removeIndex, cells.getSize()-1);
   740  			for(var i:Number=0; i<removed.length; i++){
   741  				var cell:ListCell = ListCell(removed[i]);
   742  				removeCellFromeContainer(cell);
   743  			}
   744  		}
   745  	}
   746  	
   747  	private function createCellsWhenNotShareCells():Void{
   748  		var factory:ListCellFactory = getCellFactory();
   749  		var m:ListModel = getModel();
   750  		
   751  		var w:Number = 0;
   752  		var h:Number = 0;
   753  		var sameHeight:Boolean = factory.isAllCellHasSameHeight();
   754  		
   755  		var mSize:Number = m.getSize();
   756  		var cSize:Number = cells.getSize();
   757  		
   758  		cellPrefferSizes.clear();
   759  		
   760  		var n:Number = Math.min(mSize, cSize);
   761  		//reuse created cells
   762  		for(var i:Number=0; i<n; i++){
   763  			var cell:ListCell = ListCell(cells.get(i));
   764  			cell.setValue(m.getElementAt(i));
   765  			var s:Dimension = cell.getListCellComponent().getPreferredSize();
   766  			cellPrefferSizes.put(cell.getListCellComponent().getID(), s);
   767  			if(s.width > w){
   768  				w = s.width;
   769  				maxWidthCell = cell;
   770  			}
   771  			if(!sameHeight){
   772  				h += s.height;
   773  			}
   774  		}
   775  		
   776  		//create lest needed cells
   777  		if(mSize > cSize){
   778  			for(var i:Number = cSize; i<mSize; i++){
   779  				var cell:ListCell = factory.createNewCell();
   780  				cells.append(cell);
   781  				cell.setValue(m.getElementAt(i));
   782  				addCellToContainer(cell);
   783  				var s:Dimension = cell.getListCellComponent().getPreferredSize();
   784  				cellPrefferSizes.put(cell.getListCellComponent().getID(), s);
   785  				if(s.width > w){
   786  					w = s.width;
   787  					maxWidthCell = cell;
   788  				}
   789  				if(!sameHeight){
   790  					h += s.height;
   791  				}
   792  			}
   793  		}else if(mSize < cSize){ //remove unwanted cells
   794  			var removed:Array = cells.removeRange(mSize, cSize-1);
   795  			for(var i:Number=0; i<removed.length; i++){
   796  				var cell:ListCell = ListCell(removed[i]);
   797  				cell.getListCellComponent().removeFromContainer();
   798  				removeCellFromeContainer(cell);
   799  				cellPrefferSizes.remove(cell.getListCellComponent().getID());
   800  			}
   801  		}
   802  		
   803  		if(sameHeight){
   804  			h = m.getSize()*factory.getCellHeight();
   805  		}
   806  		
   807  		viewWidth = w;
   808  		viewHeight = h;
   809  	}
   810  	
   811  	private function createCells():Void{
   812  		if(getCellFactory().isShareCells()){
   813  			createCellsWhenShareCells();
   814  		}else{
   815  			createCellsWhenNotShareCells();
   816  		}
   817  	}
   818  	
   819  	private function removeAllCells() : Void {
   820  		for(var i:Number=0; i<cells.getSize(); i++){
   821  			var cell:ListCell = ListCell(cells.get(i));
   822  			cell.getListCellComponent().removeFromContainer();
   823  		}
   824  		cells.clear();
   825  	}
   826  	
   827  	private function validateCells():Void{
   828  		revalidate();
   829  	}
   830  	
   831  	//--------------------------------------------------------
   832  
   833  	public function getVerticalUnitIncrement() : Number {
   834  		if(getCellFactory().isAllCellHasSameHeight()){
   835  			return getCellFactory().getCellHeight();
   836  		}else{
   837  			return verticalUnitIncrement;
   838  		}
   839  	}
   840  
   841  	public function getVerticalBlockIncrement() : Number {
   842  		if(getCellFactory().isAllCellHasSameHeight()){
   843  			return getExtentSize().height - getCellFactory().getCellHeight();
   844  		}else{
   845  			return getExtentSize().height - verticalBlockIncrement;
   846  		}
   847  	}
   848  
   849  	public function getHorizontalUnitIncrement() : Number {
   850  		return 1;
   851  	}
   852  
   853  	public function getHorizontalBlockIncrement() : Number {
   854  		return getExtentSize().width - 1;
   855  	}
   856  	
   857      public function setViewportTestSize(s:Dimension):Void{
   858      	setSize(s);
   859      }	
   860  		
   861  	public function getExtentSize() : Dimension {	
   862      	return getInsets().inroundsSize(getSize());
   863  	}
   864  
   865  	public function getViewSize() : Dimension {
   866  		return new Dimension(viewWidth, viewHeight);
   867  	}
   868  
   869  	public function getViewPosition() : Point {
   870  		return new Point(viewPosition.x, viewPosition.y);
   871  	}
   872  
   873  	public function setViewPosition(p : Point) : Void {
   874  		restrictionViewPos(p);
   875  		if(!viewPosition.equals(p)){
   876  			viewPosition.setLocation(p);
   877  			fireStateChanged();
   878  			revalidate();
   879  		}
   880  	}
   881  
   882  	public function scrollRectToVisible(contentRect : Rectangle) : Void {
   883  		setViewPosition(new Point(contentRect.x, contentRect.y));
   884  	}
   885  	
   886  	private function restrictionViewPos(p:Point):Point{
   887  		var maxPos:Point = getViewMaxPos();
   888  		p.x = Math.max(0, Math.min(maxPos.x, p.x));
   889  		p.y = Math.max(0, Math.min(maxPos.y, p.y));
   890  		return p;
   891  	}
   892  	
   893  	private function getViewMaxPos():Point{
   894  		var showSize:Dimension = getExtentSize();
   895  		var viewSize:Dimension = getViewSize();
   896  		var p:Point = new Point(viewSize.width-showSize.width, viewSize.height-showSize.height);
   897  		if(p.x < 0) p.x = 0;
   898  		if(p.y < 0) p.y = 0;
   899  		return p;
   900  	}
   901  
   902  	public function addChangeListener(func : Function, obj : Object) : Object {
   903  		return addEventListener(ON_STATE_CHANGED, func, obj);
   904  	}
   905  
   906  	public function getViewportPane() : Component {
   907  		return this;
   908  	}
   909  	//------------------------Layout implementation---------------------
   910  	
   911  
   912      /**
   913       * do nothing
   914       */
   915      public function addLayoutComponent(comp:Component, constraints:Object):Void{
   916      }
   917  
   918      /**
   919       * do nothing
   920       */
   921      public function removeLayoutComponent(comp:Component):Void{
   922      }
   923  	
   924      public function preferredLayoutSize(target:Container):Dimension{
   925      	return getViewSize();
   926      }
   927  
   928      public function minimumLayoutSize(target:Container):Dimension{
   929      	return getInsets().getRoundBounds().getSize();
   930      }
   931  	
   932      public function maximumLayoutSize(target:Container):Dimension{
   933      	return new Dimension(Number.MAX_VALUE, Number.MAX_VALUE);
   934      }
   935      
   936      /**
   937       * position and fill cells here
   938       */
   939      public function layoutContainer(target:Container):Void{
   940      	var factory:ListCellFactory = getCellFactory();
   941      	if(factory.isShareCells()){
   942      		layoutWhenShareCells();
   943      	}else{
   944      		if(factory.isAllCellHasSameHeight()){
   945      			layoutWhenNotShareCellsAndSameHeight();
   946      		}else{
   947      			layoutWhenNotShareCellsAndNotSameHeight();
   948      		}
   949      	}
   950      }
   951      
   952      private function layoutWhenShareCells():Void{
   953      	checkCreateCellsWhenShareCells();
   954      	
   955      	var factory:ListCellFactory = getCellFactory();
   956  		var m:ListModel = getModel();
   957  		var ir:Rectangle = getInsets().getInsideBounds(getSize().getBounds());
   958      	var cellWidth:Number = ir.width;
   959      	
   960      	restrictionViewPos(viewPosition);
   961  		var x:Number = viewPosition.x;
   962  		var y:Number = viewPosition.y;
   963  		var ih:Number = factory.getCellHeight();
   964  		var startIndex:Number = Math.floor(y/ih);
   965  		var startY:Number = startIndex*ih - y;
   966  		var listSize:Number = m.getSize();
   967  		
   968  		var cx:Number = ir.x - x;
   969  		var cy:Number = ir.y + startY;
   970  		for(var i:Number = 0; i<cells.getSize(); i++){
   971  			var cell:ListCell = ListCell(cells.get(i));
   972  			var ldIndex:Number = startIndex + i;
   973  			var cellCom:Component = cell.getListCellComponent();
   974  			if(ldIndex < listSize){
   975  				cell.setValue(m.getElementAt(ldIndex));
   976  				cellCom.setVisible(true);
   977  				cellCom.setBounds(cx, cy, cellWidth, ih);
   978  				cy += ih;
   979  				if(selectionMode == MULTIPLE_SELECTION){
   980  					cell.setSelected((selectedIndices[ldIndex]==true));
   981  				}else{
   982  					cell.setSelected(ldIndex == singleSelectedIndex);
   983  				}
   984  			}else{
   985  				cellCom.setVisible(false);
   986  			}
   987  		}
   988  		firstVisibleIndex = startIndex;
   989  		lastVisibleIndex = Math.min(startIndex + cells.getSize() - 1, listSize - 1);
   990      }
   991      
   992      private function layoutWhenNotShareCellsAndSameHeight():Void{
   993      	var factory:ListCellFactory = getCellFactory();
   994  		var m:ListModel = getModel();
   995  		var ir:Rectangle = getInsets().getInsideBounds(getSize().getBounds());
   996      	var cellWidth:Number = Math.max(ir.width, viewWidth);
   997      	
   998      	restrictionViewPos(viewPosition);
   999  		var x:Number = viewPosition.x;
  1000  		var y:Number = viewPosition.y;
  1001  		var ih:Number = factory.getCellHeight();
  1002  		var startIndex:Number = Math.floor(y/ih);
  1003  		var listSize:Number = m.getSize();
  1004  		var endIndex:Number = startIndex + Math.floor(ir.height / ih) + 2 - 1;
  1005  		if(endIndex >= listSize){
  1006  			endIndex = listSize - 1;
  1007  		}
  1008  		var startY:Number = startIndex*ih - y;
  1009  		
  1010  		var cx:Number = ir.x - x;
  1011  		var cy:Number = ir.y + startY;
  1012  		//invisible last viewed
  1013  		for(var i:Number=firstVisibleIndex; i<startIndex; i++){
  1014  			ListCell(cells.get(i)).getListCellComponent().setVisible(false);
  1015  		}
  1016  		for(var i:Number=endIndex+1; i<=lastVisibleIndex; i++){
  1017  			ListCell(cells.get(i)).getListCellComponent().setVisible(false);
  1018  		}
  1019  		
  1020  		//visible current needed
  1021  		for(var i:Number=startIndex; i<=endIndex; i++){
  1022  			var cell:ListCell = ListCell(cells.get(i));
  1023  			var cellCom:Component = cell.getListCellComponent();
  1024  			cellCom.setVisible(true);
  1025  			var s:Dimension = getCachedCellPreferSize(cell);
  1026  			if(s == null){
  1027  				s = cell.getListCellComponent().getPreferredSize();
  1028  				trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1029  			}
  1030  			cellCom.setBounds(cx, cy, Math.max(cellWidth, s.width), ih);
  1031  			cy += ih;
  1032  			if(selectionMode == MULTIPLE_SELECTION){
  1033  				cell.setSelected((selectedIndices[i]==true));
  1034  			}else{
  1035  				cell.setSelected(i == singleSelectedIndex);
  1036  			}
  1037  		}
  1038  		firstVisibleIndex = startIndex;
  1039  		lastVisibleIndex = endIndex;
  1040      }
  1041      
  1042      private function getCachedCellPreferSize(cell:ListCell):Dimension{
  1043      	return Dimension(cellPrefferSizes.get(cell.getListCellComponent().getID()));
  1044      }
  1045      
  1046      private function layoutWhenNotShareCellsAndNotSameHeight():Void{
  1047      	var factory:ListCellFactory = getCellFactory();
  1048  		var m:ListModel = getModel();
  1049  		var ir:Rectangle = getInsets().getInsideBounds(getSize().getBounds());
  1050      	var cellWidth:Number = Math.max(ir.width, viewWidth);
  1051      	
  1052      	restrictionViewPos(viewPosition);
  1053  		var x:Number = viewPosition.x;
  1054  		var y:Number = viewPosition.y;
  1055  		
  1056  		var startIndex:Number = 0;
  1057  		var cellsCount:Number = cells.getSize();
  1058  		
  1059  		var tryY:Number = 0;
  1060  		var startY:Number = 0;
  1061  		for(var i:Number=0; i<cellsCount; i++){
  1062  			var cell:ListCell = ListCell(cells.get(i));
  1063  			var s:Dimension = getCachedCellPreferSize(cell);
  1064  			if(s == null){
  1065  				s = cell.getListCellComponent().getPreferredSize();
  1066  				trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1067  			}
  1068  			tryY += s.height;
  1069  			if(tryY >= y){
  1070  				startIndex = i;
  1071  				startY = -(s.height - (tryY - y));
  1072  				break;
  1073  			}
  1074  		}
  1075  		
  1076  		var listSize:Number = m.getSize();
  1077  		var cx:Number = ir.x - x;
  1078  		var cy:Number = ir.y + startY;
  1079  		var maxY:Number = ir.y + ir.height;
  1080  		
  1081  		//visible current needed
  1082  		var endIndex:Number = startIndex;
  1083  		for(var i:Number=startIndex; i<cellsCount; i++){
  1084  			var cell:ListCell = ListCell(cells.get(i));
  1085  			var cellCom:Component = cell.getListCellComponent();
  1086  			var s:Dimension = getCachedCellPreferSize(cell);
  1087  			if(s == null){
  1088  				s = cell.getListCellComponent().getPreferredSize();
  1089  				trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1090  			}
  1091  			if(selectionMode == MULTIPLE_SELECTION){
  1092  				cell.setSelected((selectedIndices[i]==true));
  1093  			}else{
  1094  				cell.setSelected(i == singleSelectedIndex);
  1095  			}
  1096  			cellCom.setVisible(true);
  1097  			cellCom.setBounds(cx, cy, Math.max(cellWidth, s.width), s.height);
  1098  			cy += s.height;
  1099  			endIndex = i;
  1100  			if(cy >= maxY){
  1101  				break;
  1102  			}
  1103  		}
  1104  		
  1105  		//invisible last viewed
  1106  		for(var i:Number=firstVisibleIndex; i<startIndex; i++){
  1107  			ListCell(cells.get(i)).getListCellComponent().setVisible(false);
  1108  		}
  1109  		for(var i:Number=endIndex+1; i<=lastVisibleIndex; i++){
  1110  			ListCell(cells.get(i)).getListCellComponent().setVisible(false);
  1111  		}
  1112  		
  1113  		firstVisibleIndex = startIndex;
  1114  		lastVisibleIndex = endIndex;  	
  1115      }
  1116      
  1117  	/**
  1118  	 * return 0
  1119  	 */
  1120      public function getLayoutAlignmentX(target:Container):Number{
  1121      	return 0;
  1122      }
  1123  
  1124  	/**
  1125  	 * return 0
  1126  	 */
  1127      public function getLayoutAlignmentY(target:Container):Number{
  1128      	return 0;
  1129      }
  1130  
  1131      public function invalidateLayout(target:Container):Void{
  1132      }
  1133  	
  1134  	//------------------------ListMode Listener Methods-----------------
  1135  	
  1136  	/**
  1137  	 * data in list has changed, update JList if needed.
  1138  	 */
  1139      public function intervalAdded(e:ListDataEvent):Void{
  1140      	clearSelection();
  1141      	var factory:ListCellFactory = getCellFactory();
  1142  		var m:ListModel = getModel();
  1143  		
  1144  		var w:Number = viewWidth;
  1145  		var h:Number = viewHeight;
  1146  		var sameHeight:Boolean = factory.isAllCellHasSameHeight();
  1147  		
  1148  		var i0:Number = e.getIndex0();
  1149  		var i1:Number = e.getIndex1();
  1150  		
  1151  		if(factory.isShareCells()){
  1152  			w = getPreferredWidthWhenNoCount();
  1153  			h = m.getSize()*factory.getCellHeight();
  1154  		}else{
  1155  			for(var i:Number=i0; i<=i1; i++){
  1156  				var cell:ListCell = factory.createNewCell();
  1157  				cells.append(cell, i);
  1158  				cell.setValue(m.getElementAt(i));
  1159  				addCellToContainer(cell);
  1160  				var s:Dimension = cell.getListCellComponent().getPreferredSize();
  1161  				cellPrefferSizes.put(cell.getListCellComponent().getID(), s);
  1162  				if(s.width > w){
  1163  					w = s.width;
  1164  					maxWidthCell = cell;
  1165  				}
  1166  				w = Math.max(w, s.width);
  1167  				if(!sameHeight){
  1168  					h += s.height;
  1169  				}
  1170  			}
  1171  			if(sameHeight){
  1172  				h = m.getSize()*factory.getCellHeight();
  1173  			}
  1174  		}
  1175  		
  1176  		viewWidth = w;
  1177  		viewHeight = h;
  1178  		
  1179  		revalidate();
  1180      }
  1181      
  1182  	/**
  1183  	 * data in list has changed, update JList if needed.
  1184  	 */
  1185      public function intervalRemoved(e:ListDataEvent):Void{
  1186      	clearSelection();
  1187      	var factory:ListCellFactory = getCellFactory();
  1188  		var m:ListModel = getModel();
  1189  		
  1190  		var w:Number = viewWidth;
  1191  		var h:Number = viewHeight;
  1192  		var sameHeight:Boolean = factory.isAllCellHasSameHeight();
  1193  		
  1194  		var i0:Number = e.getIndex0();
  1195  		var i1:Number = e.getIndex1();
  1196  		
  1197  		if(factory.isShareCells()){
  1198  			w = getPreferredWidthWhenNoCount();
  1199  			h = m.getSize()*factory.getCellHeight();
  1200  		}else{
  1201  			var needRecountWidth:Boolean = false;
  1202  			for(var i:Number=i0; i<=i1; i++){
  1203  				var cell:ListCell = ListCell(cells.get(i));
  1204  				if(cell == maxWidthCell){
  1205  					needRecountWidth = true;
  1206  				}
  1207  				if(!sameHeight){
  1208  					var s:Dimension = getCachedCellPreferSize(cell);
  1209  					if(s == null){
  1210  						s = cell.getListCellComponent().getPreferredSize();
  1211  						trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1212  					}
  1213  					h -= s.height;
  1214  				}
  1215  				removeCellFromeContainer(cell);
  1216  				cellPrefferSizes.remove(cell.getListCellComponent().getID());
  1217  			}
  1218  			cells.removeRange(i0, i1);
  1219  			if(sameHeight){
  1220  				h = m.getSize()*factory.getCellHeight();
  1221  			}
  1222  			if(needRecountWidth){
  1223  				w = 0;
  1224  				for(var i:Number=cells.getSize()-1; i>=0; i--){
  1225  					var cell:ListCell = ListCell(cells.get(i));
  1226  					var s:Dimension = getCachedCellPreferSize(cell);
  1227  					if(s == null){
  1228  						s = cell.getListCellComponent().getPreferredSize();
  1229  						trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1230  					}
  1231  					if(s.width > w){
  1232  						w = s.width;
  1233  						maxWidthCell = cell;
  1234  					}
  1235  				}
  1236  			}
  1237  		}
  1238  		
  1239  		viewWidth = w;
  1240  		viewHeight = h;
  1241  		
  1242  		revalidate();
  1243      }
  1244      
  1245  	/**
  1246  	 * data in list has changed, update JList if needed.
  1247  	 */
  1248      public function contentsChanged(e:ListDataEvent):Void{
  1249      	var factory:ListCellFactory = getCellFactory();
  1250  		var m:ListModel = getModel();
  1251  		
  1252  		var w:Number = viewWidth;
  1253  		var h:Number = viewHeight;
  1254  		var sameHeight:Boolean = factory.isAllCellHasSameHeight();
  1255  		
  1256  		var i0:Number = e.getIndex0();
  1257  		var i1:Number = e.getIndex1();
  1258  		
  1259  		if(factory.isShareCells()){
  1260  			w = getPreferredWidthWhenNoCount();
  1261  			h = m.getSize()*factory.getCellHeight();
  1262  		}else{
  1263  			var needRecountWidth:Boolean = false;
  1264  			for(var i:Number=i0; i<=i1; i++){
  1265  				var newValue:Object = m.getElementAt(i);
  1266  				var cell:ListCell = ListCell(cells.get(i));
  1267  				var s:Dimension = getCachedCellPreferSize(cell);
  1268  				if(s == null){
  1269  					s = cell.getListCellComponent().getPreferredSize();
  1270  					trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1271  				}
  1272  				if(cell == maxWidthCell){
  1273  					h -= s.height;
  1274  					cell.setValue(newValue);
  1275  					var ns:Dimension = cell.getListCellComponent().getPreferredSize();
  1276  					cellPrefferSizes.put(cell.getListCellComponent().getID(), ns);
  1277  					if(ns.width < s.width){
  1278  						needRecountWidth = true;
  1279  					}else{
  1280  						w = ns.width;
  1281  					}
  1282  					h += ns.height;
  1283  				}else{
  1284  					h -= s.height;
  1285  					cell.setValue(newValue);
  1286  					var ns:Dimension = cell.getListCellComponent().getPreferredSize();
  1287  					cellPrefferSizes.put(cell.getListCellComponent().getID(), ns);
  1288  					h += ns.height;
  1289  					if(!needRecountWidth){
  1290  						if(ns.width > w){
  1291  							maxWidthCell = cell;
  1292  							w = ns.width;
  1293  						}
  1294  					}
  1295  				}
  1296  			}
  1297  			if(sameHeight){
  1298  				h = m.getSize()*factory.getCellHeight();
  1299  			}
  1300  			if(needRecountWidth || maxWidthCell == null){
  1301  				w = 0;
  1302  				for(var i:Number=cells.getSize()-1; i>=0; i--){
  1303  					var cell:ListCell = ListCell(cells.get(i));
  1304  					var s:Dimension = getCachedCellPreferSize(cell);
  1305  					if(s == null){
  1306  						s = cell.getListCellComponent().getPreferredSize();
  1307  						trace("Warnning : cell size not cached index = " + i + ", value = " + cell.getValue());
  1308  					}
  1309  					if(s.width > w){
  1310  						w = s.width;
  1311  						maxWidthCell = cell;
  1312  					}
  1313  				}
  1314  			}
  1315  		}
  1316  		
  1317  		viewWidth = w;
  1318  		viewHeight = h;
  1319  		
  1320  		revalidate();
  1321      }
  1322      
  1323      //-------------------------------Event Listener For All Items----------------
  1324      
  1325  	private function initItemHandler():Void{
  1326  		itemHandler = new Object();
  1327  		itemHandler[Component.ON_PRESS] = Delegate.create(this, __onItemPress);
  1328  		itemHandler[Component.ON_RELEASE] = Delegate.create(this, __onItemRelease);
  1329  		itemHandler[Component.ON_RELEASEOUTSIDE] = Delegate.create(this, __onItemReleaseOutside);
  1330  		itemHandler[Component.ON_ROLLOVER] = Delegate.create(this, __onItemRollOver);
  1331  		itemHandler[Component.ON_ROLLOUT] = Delegate.create(this, __onItemRollOut);
  1332  		itemHandler[Component.ON_CLICKED] = Delegate.create(this, __onItemClicked);
  1333  	}
  1334  	
  1335  	private function createItemEventObj(ie:Event, type:String):Event{
  1336  		var event:Event = createEventObj(type);
  1337  		var item:Component = Component(ie.getSource());
  1338  		var cell:ListCell = getCellByCellComponent(item);
  1339  		event.value = cell.getValue();
  1340  		event.cell = cell;
  1341  		return event;
  1342  	}
  1343  	
  1344  	private function getItemIndexByCellComponent(item:Component):Number{
  1345  		var cell:Object = comToCellMap.get(item.getID());
  1346  		if(getCellFactory().isShareCells()){
  1347  			return firstVisibleIndex + cells.indexOf(cell);
  1348  		}else{
  1349  			return cells.indexOf(cell);
  1350  		}
  1351  	}
  1352  	
  1353  	private function getCellByCellComponent(item:Component):ListCell{
  1354  		return ListCell(comToCellMap.get(item.getID()));
  1355  	}
  1356  	
  1357  	private function getCellByIndex(index:Number):ListCell{
  1358  		if(getCellFactory().isShareCells()){
  1359  			return ListCell(cells.get(index - firstVisibleIndex));
  1360  		}else{
  1361  			return ListCell(cells.get(index));
  1362  		}
  1363  	}
  1364  	
  1365      /**
  1366       * Event Listener For All Items, Do not override this method.
  1367       */
  1368  	private function __onItemPress(event:Event):Void{
  1369  		dispatchEvent(ON_ITEM_PRESS, createItemEventObj(event, ON_ITEM_PRESS));
  1370  		
  1371  		var source:Component = Component(event.getSource());
  1372  		var index:Number = getItemIndexByCellComponent(source);
  1373  		var cell:ListCell = getCellByCellComponent(source);
  1374  		if(selectionMode == MULTIPLE_SELECTION){
  1375  			selectedIndices[index] = !selectedIndices[index];
  1376  			cell.setSelected(selectedIndices[index]);
  1377  			cacheIsJustPressMakeSelectionChanged = true;
  1378  		}else{
  1379  			if(singleSelectedIndex != index){
  1380  				if(singleSelectedIndex >= 0){ //clear last selected
  1381  					getCellByIndex(singleSelectedIndex).setSelected(false);
  1382  				}
  1383  				singleSelectedIndex = index;
  1384  				cell.setSelected(true);
  1385  				cacheIsJustPressMakeSelectionChanged = true;
  1386  			}else{
  1387  				cacheIsJustPressMakeSelectionChanged = false;
  1388  			}
  1389  		}
  1390  	}
  1391  	private var cacheIsJustPressMakeSelectionChanged:Boolean;
  1392      /**
  1393       * Event Listener For All Items, Do not override this method.
  1394       */	
  1395  	private function __onItemRelease(event:Event):Void{
  1396  		dispatchEvent(ON_ITEM_RELEASE, createItemEventObj(event, ON_ITEM_RELEASE));
  1397  		if(cacheIsJustPressMakeSelectionChanged){
  1398  			dispatchEvent(ON_SELECTION_CHANGE, createEventObj());
  1399  		}
  1400  	}
  1401  	
  1402      /**
  1403       * Event Listener For All Items, Do not override this method.
  1404       */	
  1405  	private function __onItemReleaseOutside(event:Event):Void{
  1406  		dispatchEvent(ON_ITEM_RELEASEOUTSIDE, createItemEventObj(event, ON_ITEM_RELEASEOUTSIDE));
  1407  		if(cacheIsJustPressMakeSelectionChanged){
  1408  			dispatchEvent(ON_SELECTION_CHANGE, createEventObj());
  1409  		}
  1410  	}
  1411  	
  1412      /**
  1413       * Event Listener For All Items, Do not override this method.
  1414       */	
  1415  	private function __onItemRollOver(event:Event):Void{
  1416  		dispatchEvent(ON_ITEM_ROLLOVER, createItemEventObj(event, ON_ITEM_ROLLOVER));
  1417  	}
  1418  	
  1419      /**
  1420       * Event Listener For All Items, Do not override this method.
  1421       */	
  1422  	private function __onItemRollOut(event:Event):Void{
  1423  		dispatchEvent(ON_ITEM_ROLLOUT, createItemEventObj(event, ON_ITEM_ROLLOUT));
  1424  	}
  1425  	
  1426      /**
  1427       * Event Listener For All Items, Do not override this method.
  1428       */	
  1429  	private function __onItemClicked(event:Event):Void{
  1430  		var ie:Event = createItemEventObj(event, ON_ITEM_CLICKED);
  1431  		ie.clickCount = event.clickCount;
  1432  		dispatchEvent(ON_ITEM_CLICKED, ie);
  1433  	}
  1434  }
  1435