/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.sun.lwuit;
import com.sun.lwuit.animations.CommonTransitions;
import com.sun.lwuit.geom.Dimension;
import com.sun.lwuit.geom.Rectangle;
import com.sun.lwuit.plaf.Style;
import com.sun.lwuit.layouts.BorderLayout;
import com.sun.lwuit.list.DefaultListCellRenderer;
import com.sun.lwuit.list.DefaultListModel;
import com.sun.lwuit.list.ListCellRenderer;
import com.sun.lwuit.list.ListModel;
import com.sun.lwuit.plaf.UIManager;
import java.util.Vector;
/**
* A combo box is a list that allows only one selection at a time, when a user clicks
* the combo box a popup button with the full list of elements allows the selection of
* a single element. The combo box is driven by the list model and allows all the renderer
* features of the List as well.
*
* @see List
* @author Chen Fishbein
*/
public class ComboBox extends List {
private static boolean defaultActAsSpinnerDialog;
/**
* When this flag is active the combo box acts as a button that opens a dialog that looks like a spinner
* this allows creating user interfaces for touch devices where a spinner UI approach is more common than
* a combo box paradigm.
* @return the defaultActAsSpinnerDialog
*/
public static boolean isDefaultActAsSpinnerDialog() {
return defaultActAsSpinnerDialog;
}
/**
* When this flag is active the combo box acts as a button that opens a dialog that looks like a spinner
* this allows creating user interfaces for touch devices where a spinner UI approach is more common than
* a combo box paradigm.
* @param aDefaultActAsSpinnerDialog the defaultActAsSpinnerDialog to set
*/
public static void setDefaultActAsSpinnerDialog(boolean aDefaultActAsSpinnerDialog) {
defaultActAsSpinnerDialog = aDefaultActAsSpinnerDialog;
}
private boolean actAsSpinnerDialog = defaultActAsSpinnerDialog;
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box by default
*/
private static boolean defaultIncludeSelectCancel = true;
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box
*/
private boolean includeSelectCancel = defaultIncludeSelectCancel;
/**
* Creates a new instance of ComboBox
*
* @param items set of items placed into the combo box model
*/
public ComboBox(Vector items) {
this(new DefaultListModel(items));
}
/**
* Creates a new instance of ComboBox
*
* @param items set of items placed into the combo box model
*/
public ComboBox(Object[] items) {
this(new DefaultListModel(items));
}
/**
* Constructs an empty combo box
*/
public ComboBox() {
this(new DefaultListModel());
}
/**
* Creates a new instance of ComboBox
*
* @param model the model for the combo box elements and selection
*/
public ComboBox(ListModel model) {
super(model);
super.setUIID("ComboBox");
((DefaultListCellRenderer) super.getRenderer()).setShowNumbers(false);
setInputOnFocus(false);
setIsScrollVisible(false);
setFixedSelection(FIXED_NONE_CYCLIC);
ListCellRenderer r = getRenderer();
if(r instanceof Component) {
Component c = (Component) getRenderer();
c.setUIID("ComboBoxItem");
}
Component c = getRenderer().getListFocusComponent(this);
if(c != null){
c.setUIID("ComboBoxFocus");
}
}
/**
* @inheritDoc
*/
public void setUIID(String uiid) {
super.setUIID(uiid);
ListCellRenderer r = getRenderer();
if(r instanceof Component) {
Component c = (Component) getRenderer();
c.setUIID(uiid + "Item");
}
Component c = getRenderer().getListFocusComponent(this);
if(c != null){
c.setUIID(uiid + "Focus");
}
}
/**
* @inheritDoc
*/
public int getBaseline(int width, int height) {
Component selected;
if (getRenderingPrototype() != null) {
selected = getRenderer().getListCellRendererComponent(this, getRenderingPrototype(), 0, true);
}
if (getModel().getSize() > 0) {
selected = getRenderer().getListCellRendererComponent(this, getModel().getItemAt(0), 0, true);
} else {
selected = getRenderer().getListCellRendererComponent(this, "XXXXXXXXXXX", 0, true);
}
return getHeight() - getStyle().getPadding(false, BOTTOM) - selected.getStyle().getPadding(false, BOTTOM);
}
/**
* @inheritDoc
*/
protected void laidOut() {
}
/**
* @inheritDoc
*/
protected Rectangle getVisibleBounds() {
return getBounds();
}
/**
* @inheritDoc
*/
public void setSelectedIndex(int selection) {
super.setSelectedIndex(selection, false);
}
/**
* @inheritDoc
*/
public void setSelectedIndex(int selection, boolean scroll) {
super.setSelectedIndex(selection, false);
}
/**
* @inheritDoc
*/
public void pointerHover(int[] x, int[] y) {
}
/**
* @inheritDoc
*/
public void pointerHoverReleased(int[] x, int[] y) {
}
/**
* Subclasses can override this method to change the creation of the dialog
*
* @param l the list of the popup
* @return a dialog instance
*/
protected Dialog createPopupDialog(List l) {
Dialog popupDialog = new Dialog(getUIID() + "Popup", getUIID() + "PopupTitle");
popupDialog.setScrollable(false);
popupDialog.getContentPane().setAlwaysTensile(false);
popupDialog.setAlwaysTensile(false);
popupDialog.getContentPane().setUIID("PopupContentPane");
popupDialog.setDisposeWhenPointerOutOfBounds(true);
popupDialog.setTransitionInAnimator(CommonTransitions.createEmpty());
popupDialog.setTransitionOutAnimator(CommonTransitions.createEmpty());
popupDialog.setLayout(new BorderLayout());
popupDialog.addComponent(BorderLayout.CENTER, l);
return popupDialog;
}
/**
* Shows the popup dialog for the combo box and returns the resulting command.
* This method can be overriden by subclasses to modify the behavior of the class.
*
* @param popupDialog the popup dialog
* @param l the list within
* @return the selected command
*/
protected Command showPopupDialog(Dialog popupDialog, List l) {
if(UIManager.getInstance().isThemeConstant("popupTitleBool", false)) {
if(getLabelForComponent() != null) {
popupDialog.setTitle(getLabelForComponent().getText());
}
}
if(includeSelectCancel) {
popupDialog.setBackCommand(popupDialog.getMenuBar().getCancelMenuItem());
if(Display.getInstance().isTouchScreenDevice()) {
if(UIManager.getInstance().isThemeConstant("popupCancelBodyBool", false)) {
popupDialog.placeButtonCommands(new Command[] {popupDialog.getMenuBar().getCancelMenuItem()});
}
} else {
if (Display.getInstance().isThirdSoftButton()) {
popupDialog.addCommand(popupDialog.getMenuBar().getSelectMenuItem());
popupDialog.addCommand(popupDialog.getMenuBar().getCancelMenuItem());
} else {
popupDialog.addCommand(popupDialog.getMenuBar().getCancelMenuItem());
popupDialog.addCommand(popupDialog.getMenuBar().getSelectMenuItem());
}
}
}
if(actAsSpinnerDialog) {
l.setFixedSelection(List.FIXED_CENTER);
l.setUIID("Spinner");
l.spinnerOverlay = UIManager.getInstance().getComponentStyle("SpinnerOverlay");
l.spinnerOverlay.setMargin(0, 0, 0, 0);
l.setAlwaysTensile(false);
l.installDefaultPainter(l.spinnerOverlay);
popupDialog.setDialogUIID("Container");
popupDialog.setUIID("Container");
popupDialog.getTitleComponent().setUIID("Container");
popupDialog.setTransitionInAnimator(CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, true, 200));
popupDialog.setTransitionOutAnimator(CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, false, 200));
return popupDialog.show(Display.getInstance().getDisplayHeight() - popupDialog.getDialogComponent().getPreferredH(), 0, 0, 0, true, true);
}
if(UIManager.getInstance().isThemeConstant("centeredPopupBool", false)) {
return popupDialog.showPacked(BorderLayout.CENTER, true);
} else {
int top, bottom, left, right;
Form parentForm = getComponentForm();
int listW = Math.max(getWidth() , l.getPreferredW());
listW = Math.min(listW + UIManager.getInstance().getLookAndFeel().getVerticalScrollWidth(), parentForm.getContentPane().getWidth());
Component content = popupDialog.getDialogComponent();
Style contentStyle = content.getStyle();
int listH = content.getPreferredH()
+ contentStyle.getMargin(false, TOP)
+ contentStyle.getMargin(false, BOTTOM);
Component title = popupDialog.getTitleArea();
listH += title.getPreferredH()
+ title.getStyle().getMargin(false, TOP)
+ title.getStyle().getMargin(false, BOTTOM);
bottom = 0;
top = getAbsoluteY();
int formHeight = parentForm.getHeight();
if(parentForm.getSoftButtonCount() > 1) {
Component c = parentForm.getSoftButton(0).getParent();
formHeight -= c.getHeight();
Style s = c.getStyle();
formHeight -= (s.getMargin(TOP) + s.getMargin(BOTTOM));
}
if(listH < formHeight) {
// pop up or down?
if(top > formHeight / 2) {
bottom = formHeight - top;
top = top - listH;
} else {
top += getHeight();
bottom = formHeight - top - listH;
}
} else {
top = 0;
}
left = getAbsoluteX();
right = parentForm.getWidth() - left - listW;
if(right < 0) {
left += right;
right = 0;
}
popupDialog.setBackCommand(popupDialog.getMenuBar().getCancelMenuItem());
return popupDialog.show(Math.max(top, 0),
Math.max(bottom, 0),
Math.max(left, 0),
Math.max(right, 0), false, true);
}
}
/**
* @inheritDoc
*/
protected void fireClicked() {
List l = createPopupList();
l.dispatcher = dispatcher;
l.eventSource = this;
l.disposeDialogOnSelection = true;
Form parentForm = getComponentForm();
//l.getSelectedStyle().setBorder(null);
int tint = parentForm.getTintColor();
parentForm.setTintColor(0);
Dialog popupDialog = createPopupDialog(l);
int originalSel = getSelectedIndex();
Form.comboLock = includeSelectCancel;
Command result = showPopupDialog(popupDialog, l);
Form.comboLock = false;
parentForm.setTintColor(tint);
if(result == popupDialog.getMenuBar().getCancelMenuItem()) {
setSelectedIndex(originalSel);
}
}
/**
* Creates the list object used within the popup dialog. This method allows subclasses
* to customize the list creation for the popup dialog shown when the combo box is pressed.
*
* @return a newly created list object used when the user presses the combo box.
*/
protected List createPopupList() {
List l = new List(getModel());
l.setSmoothScrolling(isSmoothScrolling());
l.setFixedSelection(getFixedSelection());
l.setListCellRenderer(getRenderer());
l.setItemGap(getItemGap());
l.setUIID("ComboBoxList");
if(UIManager.getInstance().isThemeConstant("otherPopupRendererBool", false)) {
DefaultListCellRenderer renderer = new DefaultListCellRenderer();
renderer.setUIID("PopupItem");
renderer.getListFocusComponent(l).setUIID("PopupFocus");
l.setListCellRenderer(renderer);
}
return l;
}
/**
* @inheritDoc
*/
public void keyReleased(int keyCode) {
// other events are in keyReleased to prevent the next event from reaching the next form
int gameAction = Display.getInstance().getGameAction(keyCode);
if (gameAction == Display.GAME_FIRE) {
fireClicked();
return;
}
super.keyPressed(keyCode);
}
/**
* Prevent the combo box from losing selection in some use cases
*/
void selectElement(int selectedIndex) {
}
/**
* @inheritDoc
*/
public void pointerPressed(int x, int y) {
}
/**
* @inheritDoc
*/
public void pointerDragged(int x, int y) {
}
/**
* @inheritDoc
*/
public void pointerReleased(int x, int y) {
if(isEnabled()) {
fireClicked();
}
}
/**
* @inheritDoc
*/
public void paint(Graphics g) {
UIManager.getInstance().getLookAndFeel().drawComboBox(g, this);
}
/**
* @inheritDoc
*/
protected Dimension calcPreferredSize() {
return UIManager.getInstance().getLookAndFeel().getComboBoxPreferredSize(this);
}
/**
* @inheritDoc
*/
public int getOrientation() {
return COMBO;
}
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box
*
* @return true if the soft buttons for select/cancel should appear for the combo box
*/
public boolean isIncludeSelectCancel() {
return includeSelectCancel;
}
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box
*
* @param includeSelectCancel the new value
*/
public void setIncludeSelectCancel(boolean includeSelectCancel) {
this.includeSelectCancel = includeSelectCancel;
}
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box by default
*
* @return true if the soft buttons for select/cancel should appear for the combo box
*/
public static boolean isDefaultIncludeSelectCancel() {
return defaultIncludeSelectCancel;
}
/**
* Indicates whethe the soft buttons for select/cancel should appear for the combo box by default
*
* @param aDefaultIncludeSelectCancel the new value
*/
public static void setDefaultIncludeSelectCancel(boolean aDefaultIncludeSelectCancel) {
defaultIncludeSelectCancel = aDefaultIncludeSelectCancel;
}
/**
* When this flag is active the combo box acts as a button that opens a dialog that looks like a spinner
* this allows creating user interfaces for touch devices where a spinner UI approach is more common than
* a combo box paradigm.
* @return the actAsSpinnerDialog
*/
public boolean isActAsSpinnerDialog() {
return actAsSpinnerDialog;
}
/**
* When this flag is active the combo box acts as a button that opens a dialog that looks like a spinner
* this allows creating user interfaces for touch devices where a spinner UI approach is more common than
* a combo box paradigm.
* @param actAsSpinnerDialog the actAsSpinnerDialog to set
*/
public void setActAsSpinnerDialog(boolean actAsSpinnerDialog) {
this.actAsSpinnerDialog = actAsSpinnerDialog;
}
}