Spinner.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:19k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit.spinner;
  26. import com.sun.lwuit.Component;
  27. import com.sun.lwuit.Display;
  28. import com.sun.lwuit.Graphics;
  29. import com.sun.lwuit.Image;
  30. import com.sun.lwuit.List;
  31. import com.sun.lwuit.TextArea;
  32. import com.sun.lwuit.TextField;
  33. import com.sun.lwuit.geom.Dimension;
  34. import com.sun.lwuit.list.DefaultListCellRenderer;
  35. import com.sun.lwuit.list.ListCellRenderer;
  36. import com.sun.lwuit.list.ListModel;
  37. import com.sun.lwuit.plaf.Style;
  38. import java.util.Calendar;
  39. import java.util.Date;
  40. /**
  41.  * A spinner allows us to select a numeric, date or time value using the arrow keys
  42.  * in a similar way to a list or a combo box.
  43.  *
  44.  * @author Shai Almog
  45.  */
  46. public class Spinner extends List {
  47.     /**
  48.      * Value for create date renderer represnting Day-Month-4 Digit Year
  49.      */
  50.     public static final int DATE_FORMAT_DD_MM_YYYY = 1;
  51.     /**
  52.      * Value for create date renderer represnting Month-Day-4 Digit Year
  53.      */
  54.     public static final int DATE_FORMAT_MM_DD_YYYY = 2;
  55.     /**
  56.      * Value for create date renderer represnting Day-Month-2 Digit Year
  57.      */
  58.     public static final int DATE_FORMAT_DD_MM_YY = 11;
  59.     /**
  60.      * Value for create date renderer represnting Month-Day-2 Digit Year
  61.      */
  62.     public static final int DATE_FORMAT_MM_DD_YY = 12;
  63.     /**
  64.      * The image appearing on the side of the spinner widget to indicate its "spinnability"
  65.      */
  66.     private static Image spinnerHandle;
  67.     private long lastKeyInteraction;
  68.     private TextField quickType = new TextField();
  69.     private boolean monthFirst;
  70.     private int currentInputAlign = LEFT;
  71.     private static int inputSkipDelay = 2000;
  72.     /**
  73.      * Creates a new time spinner instance, time is an integer represented in seconds
  74.      * since mindnight
  75.      *
  76.      * @param min lowest value allowed in seconds since midnight
  77.      * @param max maximum value allowed in seconds since midnight
  78.      * @param currentValue the starting value in seconds since midnight
  79.      * @param step increments in the spinner (in seconds)
  80.      * @param twentyFourHours show the value as 24 hour values or AM/PM
  81.      * @param showSeconds show the value of the seconds as well or hide it
  82.      * @return new spinner instance
  83.      */
  84.     public static Spinner createTime(int min, int max, int currentValue, int step, boolean twentyFourHours, boolean showSeconds) {
  85.         Spinner s = new Spinner(new SpinnerNumberModel(min, max, currentValue, step),
  86.                 DateTimeRenderer.createTimeRenderer(twentyFourHours, showSeconds));
  87.         return s;
  88.     }
  89.     /**
  90.      * Creates a new date spinner instance
  91.      *
  92.      * @param min lowest value allowed
  93.      * @param max maximum value allowed
  94.      * @param currentValue the starting value for the mode
  95.      * @param separatorChar character to separate the entries during rendering
  96.      * @param format formatting type for the field
  97.      * @return new spinner instance
  98.      */
  99.     public static Spinner createDate(long min, long max, long currentValue, char separatorChar, int format) {
  100.         Spinner s = new Spinner(new SpinnerDateModel(min, max, currentValue), DateTimeRenderer.createDateRenderer(separatorChar, format));
  101.         s.monthFirst = format == DATE_FORMAT_MM_DD_YY || format == DATE_FORMAT_MM_DD_YYYY;
  102.         return s;
  103.     }
  104.     /**
  105.      * Creates a new numeric spinner instance
  106.      *
  107.      * @param min lowest value allowed
  108.      * @param max maximum value allowed
  109.      * @param currentValue the starting value for the mode
  110.      * @param step the value by which we increment the entries in the model
  111.      * @return new spinner instance
  112.      */
  113.     public static Spinner create(int min, int max, int currentValue, int step) {
  114.         return new Spinner(new SpinnerNumberModel(min, max, currentValue, step), new DefaultListCellRenderer(false));
  115.     }
  116.     /**
  117.      * Creates a new numeric spinner instance
  118.      *
  119.      * @param min lowest value allowed
  120.      * @param max maximum value allowed
  121.      * @param currentValue the starting value for the mode
  122.      * @param step the value by which we increment the entries in the model
  123.      * @return new spinner instance
  124.      */
  125.     public static Spinner create(double min, double max, double currentValue, double step) {
  126.         return new Spinner(new SpinnerNumberModel(min, max, currentValue, step), new DefaultListCellRenderer(false));
  127.     }
  128.     /**
  129.      * Creates a new spinner instance with the given spinner model
  130.      *
  131.      * @param spinner model such as SpinnerDateModel or SpinnerNumberModel
  132.      */
  133.     private Spinner(ListModel model, ListCellRenderer rendererInstance) {
  134.         super(model);
  135.         setListCellRenderer(rendererInstance);
  136.         setUIID("Spinner");
  137.         setFixedSelection(FIXED_CENTER);
  138.         setOrientation(2);
  139.         setInputOnFocus(false);
  140.         setIsScrollVisible(false);
  141.         DefaultListCellRenderer render = ((DefaultListCellRenderer) super.getRenderer());
  142.         render.setRTL(false);
  143.         render.setShowNumbers(false);
  144.         render.setUIID("SpinnerRenderer");
  145.         Component bgFocus = render.getListFocusComponent(this);
  146.         bgFocus.getSelectedStyle().setBgTransparency(0);
  147.         bgFocus.getUnselectedStyle().setBgTransparency(0);
  148.         quickType.setReplaceMenu(false);
  149.         quickType.setInputModeOrder(new String[]{"123"});
  150.         quickType.setFocus(true);
  151.         quickType.setRTL(false);
  152.         quickType.setAlignment(LEFT);
  153.         setIgnoreFocusComponentWhenUnfocused(true);
  154.         setRenderingPrototype(model.getItemAt(model.getSize() - 1));
  155.         if (getRenderer() instanceof DateTimeRenderer) {
  156.             quickType.setColumns(2);
  157.         }
  158.     }
  159.     /**
  160.      * @inheritDoc
  161.      */
  162.     protected void initComponent() {
  163.         getComponentForm().registerAnimated(this);
  164.     }
  165.     /**
  166.      * @inheritDoc
  167.      */
  168.     protected Dimension calcScrollSize() {
  169.         return super.calcPreferredSize();
  170.     }
  171.     /**
  172.      * @inheritDoc
  173.      */
  174.     protected Dimension calcPreferredSize() {
  175.         int boxWidth = 0;
  176.         int verticalPadding = getStyle().getPadding(false, Component.TOP) + getStyle().getPadding(false, Component.BOTTOM);
  177.         int horizontalPadding = getStyle().getPadding(isRTL(), Component.RIGHT) + getStyle().getPadding(isRTL(), Component.LEFT);
  178.         Object prototype = getRenderingPrototype();
  179.         int selectedHeight;
  180.         ListCellRenderer renderer = getRenderer();
  181.         Component cmp;
  182.         if (prototype != null) {
  183.             cmp = renderer.getListCellRendererComponent(this, prototype, 0, true);
  184.         } else {
  185.             if (getModel().getSize() > 0) {
  186.                 cmp = renderer.getListCellRendererComponent(this, getModel().getItemAt(0), 0, true);
  187.             } else {
  188.                 cmp = renderer.getListCellRendererComponent(this, null, 0, true);
  189.             }
  190.         }
  191.         selectedHeight = cmp.getPreferredH();
  192.         if(spinnerHandle != null) {
  193.             if(spinnerHandle.getHeight() > selectedHeight) {
  194.                 selectedHeight = spinnerHandle.getHeight();
  195.             }
  196.             boxWidth += spinnerHandle.getWidth();
  197.         }
  198.         return new Dimension(cmp.getPreferredW() + boxWidth + horizontalPadding, (selectedHeight + verticalPadding));
  199.     }
  200.     /**
  201.      * @inheritDoc
  202.      */
  203.     public void keyPressed(int code) {
  204.         int game = Display.getInstance().getGameAction(code);
  205.         if (game > 0) {
  206.             super.keyPressed(code);
  207.         } else {
  208.             quickType.keyPressed(code);
  209.             lastKeyInteraction = System.currentTimeMillis();
  210.         }
  211.     }
  212.     /**
  213.      * Set the value of the spinner to a number or a date based on the spinner type
  214.      *
  215.      * @param o a number or a date
  216.      */
  217.     public void setValue(Object o) {
  218.         ListModel m = getModel();
  219.         if (m instanceof SpinnerDateModel) {
  220.             ((SpinnerDateModel) m).setValue((Date) o);
  221.         } else {
  222.             ((SpinnerNumberModel) m).setValue(o);
  223.         }
  224.     }
  225.     /**
  226.      * Returns the value of the spinner to a number or a date based on the spinner type
  227.      *
  228.      * @return a number or a date
  229.      */
  230.     public Object getValue() {
  231.         ListModel m = getModel();
  232.         if (m instanceof SpinnerDateModel) {
  233.             return ((SpinnerDateModel) m).getValue();
  234.         }
  235.         return ((SpinnerNumberModel) m).getValue();
  236.     }
  237.     /**
  238.      * @inheritDoc
  239.      */
  240.     public void keyReleased(int code) {
  241.         int game = Display.getInstance().getGameAction(code);
  242.         if (game > 0) {
  243.             super.keyReleased(code);
  244.         } else {
  245.             try {
  246.                 quickType.keyReleased(code);
  247.                 lastKeyInteraction = System.currentTimeMillis();
  248.                 String t = quickType.getText();
  249.                 if (getRenderer() instanceof DateTimeRenderer) {
  250.                     // is this is a time input or a date input?
  251.                     if(getModel() instanceof SpinnerNumberModel) {
  252.                         int time = ((Integer)getValue()).intValue();
  253.                         int seconds = time % 60;
  254.                         int minutes = time / 60;
  255.                         int hours = minutes / 60;
  256.                         minutes %= 60;
  257.                         switch (currentInputAlign) {
  258.                             case LEFT:
  259.                                 hours = Integer.parseInt(t);
  260.                                 if(((DateTimeRenderer)getRenderer()).isTwentyFourHours()) {
  261.                                     if(hours > 24) {
  262.                                         return;
  263.                                     }
  264.                                 } else {
  265.                                     if(hours > 12) {
  266.                                         return;
  267.                                     }
  268.                                 }
  269.                                 break;
  270.                             case CENTER:
  271.                                 minutes = Integer.parseInt(t);
  272.                                 if(minutes > 59) {
  273.                                     return;
  274.                                 }
  275.                                 break;
  276.                             case RIGHT:
  277.                                 seconds = Integer.parseInt(t);
  278.                                 if(seconds > 59) {
  279.                                     return;
  280.                                 }
  281.                                 break;
  282.                         }
  283.                         int actual = seconds + minutes * 60 + hours * 60 * 60;
  284.                         setValue(new Integer(actual));
  285.                         // update the spinner positioning if we have two characters
  286.                         if (quickType.getText().length() > 1) {
  287.                             quickType.setText("");
  288.                             switch (currentInputAlign) {
  289.                                 case LEFT:
  290.                                     currentInputAlign = CENTER;
  291.                                     break;
  292.                                 case CENTER:
  293.                                     if(((DateTimeRenderer)getRenderer()).isShowSeconds()) {
  294.                                         currentInputAlign = RIGHT;
  295.                                     } else {
  296.                                         currentInputAlign = LEFT;
  297.                                         lastKeyInteraction = -1;
  298.                                     }
  299.                                     break;
  300.                                 case RIGHT:
  301.                                     currentInputAlign = LEFT;
  302.                                     lastKeyInteraction = -1;
  303.                                     break;
  304.                             }
  305.                         }
  306.                     } else {
  307.                         Calendar c = Calendar.getInstance();
  308.                         c.setTime((Date) getValue());
  309.                         switch (currentInputAlign) {
  310.                             case LEFT:
  311.                                 if (monthFirst) {
  312.                                     c.set(Calendar.MONTH, Integer.parseInt(t) - 1);
  313.                                 } else {
  314.                                     c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(t));
  315.                                 }
  316.                                 break;
  317.                             case CENTER:
  318.                                 if (monthFirst) {
  319.                                     c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(t));
  320.                                 } else {
  321.                                     c.set(Calendar.MONTH, Integer.parseInt(t) - 1);
  322.                                 }
  323.                                 break;
  324.                             case RIGHT:
  325.                                 int y = c.get(Calendar.YEAR);
  326.                                 c.set(Calendar.YEAR, y - (y % 100) + Integer.parseInt(t));
  327.                                 break;
  328.                         }
  329.                         setValue(c.getTime());
  330.                         // update the spinner positioning if we have two characters
  331.                         if (quickType.getText().length() > 1) {
  332.                             quickType.setText("");
  333.                             switch (currentInputAlign) {
  334.                                 case LEFT:
  335.                                     currentInputAlign = CENTER;
  336.                                     break;
  337.                                 case CENTER:
  338.                                     currentInputAlign = RIGHT;
  339.                                     break;
  340.                                 case RIGHT:
  341.                                     currentInputAlign = LEFT;
  342.                                     lastKeyInteraction = -1;
  343.                                     break;
  344.                             }
  345.                         }
  346.                     }
  347.                     return;
  348.                 } else {
  349.                     SpinnerNumberModel n = (SpinnerNumberModel) getModel();
  350.                     if (n.realValues) {
  351.                         double val = Double.parseDouble(t);
  352.                         if(val > ((SpinnerNumberModel)getModel()).getMax() ||
  353.                                 val < ((SpinnerNumberModel)getModel()).getMin()) {
  354.                             return;
  355.                         }
  356.                         setValue(new Double(val));
  357.                     } else {
  358.                         int val = Integer.parseInt(t);
  359.                         if(val > ((SpinnerNumberModel)getModel()).getMax() ||
  360.                                 val < ((SpinnerNumberModel)getModel()).getMin()) {
  361.                             return;
  362.                         }
  363.                         setValue(new Integer(val));
  364.                     }
  365.                 }
  366.                 int modelSize = getModel().getSize();
  367.                 for (int iter = 0; iter < modelSize; iter++) {
  368.                     String v = getModel().getItemAt(iter).toString();
  369.                     if (v.startsWith(t)) {
  370.                         setSelectedIndex(iter);
  371.                         return;
  372.                     }
  373.                 }
  374.             // easier to ignore exceptions than build "proper" error handling
  375.             } catch(IllegalArgumentException ignore) {
  376.                 ignore.printStackTrace();
  377.             } 
  378.         }
  379.     }
  380.     /**
  381.      * @inheritDoc
  382.      */
  383.     public boolean isRTL() {
  384.         // Since spinner is numeric it shouldn't be affected by RTL and should naturally be right aligned
  385.         return false;
  386.     }
  387.     /**
  388.      * @inheritDoc
  389.      */
  390.     public void setRTL(boolean rtl) {
  391.         // Since spinner is numeric it shouldn't be affected by RTL and should naturally be right aligned
  392.     }
  393.     /**
  394.      * @inheritDoc
  395.      */
  396.     public void paint(Graphics g) {
  397.         super.paint(g);
  398.         if(spinnerHandle != null) {
  399.             Style s = getStyle();
  400.             g.drawImage(spinnerHandle, getX() + getWidth() - spinnerHandle.getWidth() - s.getPadding(isRTL(), LEFT) - s.getPadding(isRTL(), RIGHT),
  401.                     getY() + s.getPadding(false, TOP));
  402.         }
  403.         if (System.currentTimeMillis() - inputSkipDelay < lastKeyInteraction || quickType.isPendingCommit()) {
  404.             quickType.setWidth(Math.min(getWidth(), quickType.getPreferredW()));
  405.             quickType.setHeight(Math.min(getHeight(), quickType.getPreferredH()));
  406.             Style s = quickType.getStyle();
  407.             quickType.setY(getScrollY() + getY());
  408.             // positioning based on date/time
  409.             if (getRenderer() instanceof DateTimeRenderer) {
  410.                 switch (currentInputAlign) {
  411.                     case LEFT:
  412.                         quickType.setX(getX());
  413.                         break;
  414.                     case RIGHT:
  415.                         quickType.setX(getX() + quickType.getStyle().getFont().charWidth(TextArea.getWidestChar()) * 4 + s.getMargin(false, RIGHT));
  416.                         break;
  417.                     default:
  418.                         quickType.setX(getX() + quickType.getStyle().getFont().charWidth(TextArea.getWidestChar()) * 2 + s.getMargin(false, RIGHT));
  419.                         break;
  420.                 }
  421.             } else {
  422.                 quickType.setX(getX());
  423.             }
  424.             quickType.paintComponent(g, true);
  425.         }
  426.     }
  427.     /**
  428.      * @inheritDoc
  429.      */
  430.     public boolean animate() {
  431.         boolean val = super.animate();
  432.         if (lastKeyInteraction != -1) {
  433.             quickType.animate();
  434.             if (System.currentTimeMillis() - inputSkipDelay > lastKeyInteraction && !quickType.isPendingCommit()) {
  435.                 lastKeyInteraction = -1;
  436.                 quickType.clear();
  437.                 currentInputAlign = LEFT;
  438.             }
  439.             return true;
  440.         }
  441.         return val;
  442.     }
  443.     /**
  444.      * The image appearing on the side of the spinner widget to indicate its "spinnability"
  445.      *
  446.      * @return the spinnerHandle
  447.      */
  448.     public static Image getSpinnerHandle() {
  449.         return spinnerHandle;
  450.     }
  451.     /**
  452.      * The image appearing on the side of the spinner widget to indicate its "spinnability"
  453.      *
  454.      * @param aSpinnerHandle the spinnerHandle to set
  455.      */
  456.     public static void setSpinnerHandle(Image aSpinnerHandle) {
  457.         spinnerHandle = aSpinnerHandle;
  458.     }
  459.     /**
  460.      * Indicates the time after which the skip input area for entering spinner values manually will disappear
  461.      *
  462.      * @return the inputSkipDelay
  463.      */
  464.     public static int getInputSkipDelay() {
  465.         return inputSkipDelay;
  466.     }
  467.     /**
  468.      * Indicates the time after which the skip input area for entering spinner values manually will disappear
  469.      *
  470.      * @param aInputSkipDelay the time for disappearing
  471.      */
  472.     public static void setInputSkipDelay(int aInputSkipDelay) {
  473.         inputSkipDelay = aInputSkipDelay;
  474.     }
  475. }