/* * 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; } }