1 /* 2 Copyright aswing.org, see the LICENCE.txt. 3 */ 4 5 import org.aswing.ComboBoxEditor; 6 import org.aswing.Component; 7 import org.aswing.Container; 8 import org.aswing.DefaultComboBoxEditor; 9 import org.aswing.EventDispatcher; 10 import org.aswing.JList; 11 import org.aswing.ListCellFactory; 12 import org.aswing.ListModel; 13 import org.aswing.plaf.ComboBoxUI; 14 import org.aswing.UIManager; 15 16 /** 17 * A component that combines a button or editable field and a drop-down list. 18 * The user can select a value from the drop-down list, which appears at the 19 * user's request. If you make the combo box editable, then the combo box 20 * includes an editable field into which the user can type a value. 21 * 22 * <p> 23 * <code>JComboBox</code> use a <code>JList</code> to be the drop-down list, so of course you can operate 24 * list to do some thing. 25 * <p> 26 * By default <code>JComboBox</code> can't count its preffered width accurately 27 * like default JList, you have to set its preffered size if you want. 28 * Or you make a not shared cell factory to it. see <code>ListCellFactory</code> and <code>JList</code> for details. 29 * @author iiley 30 * @see JList 31 * @see ComboBoxEditor 32 * @see DefaultComboBoxEditor 33 */ 34 class org.aswing.JComboBox extends Container { 35 36 /** 37 * When a selection has been made or a editing stoped. 38 *<br> 39 * onActionPerformed Event{source:DefaultComboBoxEditor} 40 */ 41 public static var ON_ACT:String = EventDispatcher.ON_ACT; 42 43 private var editor:ComboBoxEditor; 44 private var editable:Boolean; 45 private var popupList:JList; 46 private var editorLisenter:Object; 47 private var maximumRowCount:Number; 48 49 /** 50 * JComboBox(listData:Array)<br> 51 * JComboBox(model:ListModel)<br> 52 * JComboBox() 53 * <p> 54 */ 55 public function JComboBox(listData:Object) { 56 super(); 57 58 setName("JComboBox"); 59 maximumRowCount = 7; 60 editable = false; 61 setEditor(new DefaultComboBoxEditor()); 62 if(listData != undefined){ 63 if(listData instanceof ListModel){ 64 setModel(ListModel(listData)); 65 }else{ 66 var o = listData;//avoid Array casting 67 if(o instanceof Array){ 68 setListData(o); 69 }else{ 70 setListData(null); //create new 71 } 72 } 73 } 74 75 updateUI(); 76 } 77 78 public function setUI(ui:ComboBoxUI):Void{ 79 super.setUI(ui); 80 } 81 public function updateUI():Void{ 82 setUI(ComboBoxUI(UIManager.getUI(this))); 83 } 84 public function getUIClassID():String{ 85 return "ComboBoxUI"; 86 } 87 public function getUI():ComboBoxUI{ 88 return ComboBoxUI(ui); 89 } 90 91 /** 92 * addChangeListener(func:Function)<br> 93 * addChangeListener(func:Function, obj:Object) 94 * <p> 95 * The ActionListener will receive an ActionEvent when a selection has been made. 96 * If the combo box is editable, then an ActionEvent will be fired when editing has stopped. 97 * @return the listener added. 98 * @see #ON_ACT 99 * @see #addEventListener() 100 * @see #removeEventListener() 101 */ 102 public function addActionListener(func:Function, obj:Object):Object{ 103 return addEventListener(ON_ACT, func, obj); 104 } 105 106 private function fireActionPerformed():Void{ 107 dispatchEvent(ON_ACT, createEventObj(ON_ACT)); 108 } 109 110 /** 111 * Returns the popup list that display the items. 112 */ 113 public function getPopupList():JList{ 114 if(popupList == null){ 115 popupList = new JList(); 116 } 117 return popupList; 118 } 119 /** 120 * Sets the maximum number of rows the <code>JComboBox</code> displays. 121 * If the number of objects in the model is greater than count, 122 * the combo box uses a scrollbar. 123 * @param count an integer specifying the maximum number of items to 124 * display in the list before using a scrollbar 125 */ 126 public function setMaximumRowCount(count:Number):Void{ 127 maximumRowCount = count; 128 } 129 130 /** 131 * Returns the maximum number of items the combo box can display 132 * without a scrollbar 133 * @return an integer specifying the maximum number of items that are 134 * displayed in the list before using a scrollbar 135 */ 136 public function getMaximumRowCount():Number{ 137 return maximumRowCount; 138 } 139 140 141 /** 142 * @return the cellFactory for the popup List 143 */ 144 public function getListCellFactory():ListCellFactory{ 145 return getPopupList().getCellFactory(); 146 } 147 148 /** 149 * This will cause all cells recreating by new factory. 150 * @param newFactory the new cell factory for the popup List 151 */ 152 public function setListCellFactory(newFactory:ListCellFactory):Void{ 153 getPopupList().setCellFactory(newFactory); 154 } 155 156 /** 157 * Sets the editor used to paint and edit the selected item in the 158 * <code>JComboBox</code> field. The editor is used both if the 159 * receiving <code>JComboBox</code> is editable and not editable. 160 * @param anEditor the <code>ComboBoxEditor</code> that 161 * displays the selected item 162 */ 163 public function setEditor(anEditor:ComboBoxEditor):Void{ 164 if(anEditor == null) return; 165 166 var oldEditor:ComboBoxEditor = editor; 167 if (oldEditor != null) 168 { 169 oldEditor.removeEventListener(editorLisenter); 170 remove(oldEditor.getEditorComponent()); 171 } 172 editor = anEditor; 173 editor.setEditable(isEditable()); 174 append(editor.getEditorComponent()); 175 editorLisenter = editor.addActionListener(__editorActed, this); 176 revalidate(); 177 } 178 179 /** 180 * Returns the editor used to paint and edit the selected item in the 181 * <code>JComboBox</code> field. 182 * @return the <code>ComboBoxEditor</code> that displays the selected item 183 */ 184 public function getEditor():ComboBoxEditor{ 185 return editor; 186 } 187 188 /** 189 * Determines whether the <code>JComboBox</code> field is editable. 190 * An editable <code>JComboBox</code> allows the user to type into the 191 * field or selected an item from the list to initialize the field, 192 * after which it can be edited. (The editing affects only the field, 193 * the list item remains intact.) A non editable <code>JComboBox</code> 194 * displays the selected item in the field, 195 * but the selection cannot be modified. 196 * 197 * @param aFlag a boolean value, where true indicates that the 198 * field is editable 199 */ 200 public function setEditable(aFlag:Boolean):Void{ 201 editable = aFlag; 202 getEditor().setEditable(aFlag); 203 } 204 /** 205 * Returns true if the <code>JComboBox</code> is editable. 206 * By default, a combo box is not editable. 207 * @return true if the <code>JComboBox</code> is editable, else false 208 */ 209 public function isEditable():Boolean{ 210 return editable; 211 } 212 213 /** 214 * Enables the combo box so that items can be selected. When the 215 * combo box is disabled, items cannot be selected and values 216 * cannot be typed into its field (if it is editable). 217 * 218 * @param b a boolean value, where true enables the component and 219 * false disables it 220 */ 221 public function setEnabled(b:Boolean):Void{ 222 if(b != isEnabled()){ 223 repaint(); 224 } 225 super.setEnabled(b); 226 for(var i:Number=0; i<this.getComponentCount(); i++){ 227 var com:Component = getComponent(i); 228 if(com == getEditor().getEditorComponent()){ 229 getEditor().setEditable(b && isEditable()); 230 }else{ 231 com.setEnabled(b); 232 } 233 } 234 } 235 236 /** 237 * set a array to be the list data, but array is not a List Mode. 238 * So when the array content was changed, you should call updateListView 239 * to update the JList(the list for combo box).But this is not a good way, its slow. 240 * So suggest you to create a ListMode eg. VectorListMode, 241 * When you modify ListMode, it will automatic update JList. 242 * @see #setMode() 243 * @see org.aswing.ListModel 244 */ 245 public function setListData(ld:Array):Void{ 246 getPopupList().setListData(ld); 247 } 248 249 /** 250 * Set the list mode to provide the data to JList. 251 * @see org.aswing.ListModel 252 */ 253 public function setModel(m:ListModel):Void{ 254 getPopupList().setModel(m); 255 } 256 257 /** 258 * @return the model of this List 259 */ 260 public function getModel():ListModel{ 261 return getPopupList().getModel(); 262 } 263 /** 264 * Causes the combo box to display its popup window. 265 * @see #setPopupVisible() 266 */ 267 public function showPopup():Void{ 268 setPopupVisible(true); 269 } 270 /** 271 * Causes the combo box to close its popup window. 272 * @see #setPopupVisible() 273 */ 274 public function hidePopup():Void{ 275 setPopupVisible(false); 276 } 277 /** 278 * Sets the visibility of the popup, open or close. 279 */ 280 public function setPopupVisible(v:Boolean):Void{ 281 getUI().setPopupVisible(this, v); 282 } 283 /** 284 * Determines the visibility of the popup. 285 * 286 * @return true if the popup is visible, otherwise returns false 287 */ 288 public function isPopupVisible():Boolean{ 289 return getUI().isPopupVisible(this); 290 } 291 292 /** 293 * Sets the selected item in the combo box display area to the object in 294 * the argument. 295 * If <code>anObject</code> is in the list, the display area shows 296 * <code>anObject</code> selected. 297 * <p> 298 * If <code>anObject</code> is <i>not</i> in the list and the combo box is 299 * uneditable, it will not change the current selection. For editable 300 * combo boxes, the selection will change to <code>anObject</code>. 301 * <p> 302 * <code>ON_ACT</code> (<code>addActionListener()</code>)events added to the combo box will be notified 303 * when this method is called. 304 * 305 * @param anObject the list object to select; use <code>null</code> to 306 clear the selection 307 */ 308 public function setSelectedItem(anObject:Object):Void{ 309 getEditor().setValue(anObject); 310 var index:Number = indexInModel(anObject); 311 if(index >= 0){ 312 getPopupList().setSelectedIndex(index); 313 getPopupList().ensureIndexIsVisible(index); 314 } 315 fireActionPerformed(); 316 } 317 318 /** 319 * Returns the current selected item. 320 * <p> 321 * If the combo box is editable, then this value may not have been in 322 * the list model. 323 * @return the current selected Object 324 * @see #setSelectedItem() 325 */ 326 public function getSelectedItem():Object{ 327 if(isEditable()){ 328 return getEditor().getValue(); 329 }else{ 330 return getPopupList().getSelectedValue(); 331 } 332 } 333 /** 334 * Selects the item at index <code>anIndex</code>. 335 * 336 * @param anIndex an integer specifying the list item to select, 337 * where 0 specifies the first item in the list and -1 or greater than max index 338 * indicates empty selection 339 */ 340 public function setSelectedIndex(anIndex:Number):Void{ 341 var size:Number = getModel().getSize(); 342 if(anIndex < 0 || anIndex >= size){ 343 getEditor().setValue(null); 344 }else{ 345 getEditor().setValue(getModel().getElementAt(anIndex)); 346 getPopupList().setSelectedIndex(anIndex); 347 } 348 } 349 350 /** 351 * Returns the first item in the list that matches the given item. 352 * The result is not always defined if the <code>JComboBox</code> 353 * allows selected items that are not in the list. 354 * Returns -1 if there is no selected item or if the user specified 355 * an item which is not in the list. 356 * @return an integer specifying the currently selected list item, 357 * where 0 specifies 358 * the first item in the list; 359 * or -1 if no item is selected or if 360 * the currently selected item is not in the list 361 */ 362 public function getSelectedIndex():Number{ 363 if(isEditable()){ 364 return indexInModel(getEditor().getValue()); 365 }else{ 366 return getPopupList().getSelectedIndex(); 367 } 368 } 369 /** 370 * Returns the number of items in the list. 371 * @return an integer equal to the number of items in the list 372 */ 373 public function getItemCount():Number{ 374 return getModel().getSize(); 375 } 376 /** 377 * Returns the list item at the specified index. If <code>index</code> 378 * is out of range (less than zero or greater than or equal to size) 379 * it will return <code>undefined</code>. 380 * 381 * @param index an integer indicating the list position, where the first 382 * item starts at zero 383 * @return the <code>Object</code> at that list position; or 384 * <code>undefined</code> if out of range 385 */ 386 public function getItemAt(index:Number):Object{ 387 return getModel().getElementAt(index); 388 } 389 390 //---------------------------------------------------------- 391 private function __editorActed():Void{ 392 setSelectedItem(getEditor().getValue()); 393 } 394 395 private function indexInModel(value:Object):Number{ 396 var model:ListModel = getModel(); 397 var n:Number = model.getSize(); 398 for(var i:Number=0; i<n; i++){ 399 if(model.getElementAt(i) == value){ 400 return i; 401 } 402 } 403 return -1; 404 } 405 } 406