/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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.
*
* This program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.lcdui;
import java.util.Calendar;
import java.util.Date;
import com.sun.midp.i18n.Resource;
import com.sun.midp.i18n.ResourceConstants;
import com.sun.midp.configurator.Constants;
import com.sun.midp.chameleon.*;
import com.sun.midp.chameleon.skins.DateFieldSkin;
import com.sun.midp.chameleon.skins.resources.DateFieldResources;
import com.sun.midp.chameleon.skins.DateEditorSkin;
import com.sun.midp.chameleon.skins.resources.DateEditorResources;
import com.sun.midp.log.Logging;
import com.sun.midp.log.LogChannels;
/**
* This is the Look & Feel implementation for DateField.
*/
class DateFieldLFImpl extends ItemLFImpl implements DateFieldLF {
/**
* Creates DateFieldLF for the passed in DateField object.
* @param dateField the DateField object associated with this view
*/
DateFieldLFImpl(DateField dateField) {
super(dateField);
DateFieldResources.load();
DateEditorResources.load();
df = dateField;
if (editor == null) {
editor = new DateEditor(this);
}
}
// *****************************************************
// Package private methods
// *****************************************************
/**
* Notifies Look & Feel of a date change in the corresponding DateField.
* @param date - the new Date set in the DateField
*/
public void lSetDate(java.util.Date date) {
lRequestPaint();
}
/**
* Notifies Look & Feel of a new input mode set in the corresponding
* DateField.
* @param mode the new input mode set in the DateField.
*/
public void lSetInputMode(int mode) {
lRequestInvalidate(true, true);
}
/**
* Gets the date currently set on the date field widget.
* This method is called by Date only if Date is initialized.
* @return the date this widget is currently set to
*/
public Date lGetDate() {
return new java.util.Date(df.currentDate.getTime().getTime());
}
// *****************************************************
// Package private methods
// *****************************************************
/**
* Indicate whether or not traversing should occur.
*
* @return <code>true</code> if traversing should be skipped;
* </code>false</code>, if the field is editable.
*/
boolean shouldSkipTraverse() {
return false;
}
/**
* Sets the content size in the passed in array.
* Content is calculated based on the availableWidth.
* size[WIDTH] and size[HEIGHT] should be set by this method.
* @param size The array that holds Item content size and location
* in Item internal bounds coordinate system.
* @param availableWidth The width available for this Item
*/
void lGetContentSize(int size[], int availableWidth) {
Font f = DateFieldSkin.FONT;
size[HEIGHT] = f.getHeight() + (2 * DateFieldSkin.PAD_V);
int mode = df.mode;
size[WIDTH] =
f.stringWidth(toString(df.currentDate, mode, df.initialized)) +
(2 * DateFieldSkin.PAD_H);
switch (mode) {
case DateField.DATE:
if (DateFieldSkin.IMAGE_ICON_DATE != null) {
size[WIDTH] += DateFieldSkin.IMAGE_ICON_DATE.getWidth();
}
if (size[WIDTH] < DateEditorSkin.WIDTH_DATE) {
size[WIDTH] = DateEditorSkin.WIDTH_DATE;
}
break;
case DateField.TIME:
if (DateFieldSkin.IMAGE_ICON_TIME != null) {
size[WIDTH] += DateFieldSkin.IMAGE_ICON_TIME.getWidth();
}
if (size[WIDTH] < DateEditorSkin.WIDTH_TIME) {
size[WIDTH] = DateEditorSkin.WIDTH_TIME;
}
break;
case DateField.DATE_TIME:
if (DateFieldSkin.IMAGE_ICON_DATETIME != null) {
size[WIDTH] +=
DateFieldSkin.IMAGE_ICON_DATETIME.getWidth();
}
if (size[WIDTH] < DateEditorSkin.WIDTH_DATETIME) {
size[WIDTH] = DateEditorSkin.WIDTH_DATETIME;
}
break;
default:
// for safety/completeness.
Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
"DateFieldLFImpl: mode=" + mode);
break;
}
if (size[WIDTH] > availableWidth) {
size[WIDTH] = availableWidth;
}
}
/**
* Determine if this Item should have a newline after it
*
* @return true if it should have a newline after
*/
boolean equateNLA() {
if (super.equateNLA()) {
return true;
}
return ((df.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
}
/**
* Determine if this Item should have a newline before it
*
* @return true if it should have a newline before
*/
boolean equateNLB() {
if (super.equateNLB()) {
return true;
}
return ((df.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
}
/**
* Called from the Date Editor to save the selected Date.
*
* @param date The Date object to which current date should be set.
*/
void saveDate(java.util.Date date) {
synchronized (Display.LCDUILock) {
df.setDateImpl(date);
lSetDate(date);
}
}
/**
* Paints the content area of this DateField.
* Graphics is translated to contents origin.
* @param g The graphics where DateField content should be painted
* @param width The width available for the Item's content
* @param height The height available for the Item's content
*/
void lPaintContent(Graphics g, int width, int height) {
currentDate = df.currentDate;
mode = df.mode;
// draw background
if (DateFieldSkin.IMAGE_BG != null) {
CGraphicsUtil.draw9pcsBackground(g, 0, 0, width, height,
DateFieldSkin.IMAGE_BG);
} else {
// draw widget instead of using images
CGraphicsUtil.drawDropShadowBox(g, 0, 0, width, height,
DateFieldSkin.COLOR_BORDER,
DateFieldSkin.COLOR_BORDER_SHD,
DateFieldSkin.COLOR_BG);
}
// draw icon
int iconWidth = 0;
switch (mode) {
case DateField.DATE:
if (DateFieldSkin.IMAGE_ICON_DATE != null) {
iconWidth = DateFieldSkin.IMAGE_ICON_DATE.getWidth();
int yOffset = height -
DateFieldSkin.IMAGE_ICON_DATE.getHeight();
if (yOffset > 0) {
yOffset = (int)(yOffset / 2);
} else {
yOffset = 0;
}
drawButtonBG(g, width - iconWidth, 0, iconWidth, height);
g.drawImage(DateFieldSkin.IMAGE_ICON_DATE,
width - iconWidth, yOffset,
Graphics.LEFT | Graphics.TOP);
}
break;
case DateField.TIME:
if (DateFieldSkin.IMAGE_ICON_TIME != null) {
iconWidth = DateFieldSkin.IMAGE_ICON_TIME.getWidth();
int yOffset = height -
DateFieldSkin.IMAGE_ICON_DATE.getHeight();
if (yOffset > 0) {
yOffset = (int)(yOffset / 2);
} else {
yOffset = 0;
}
drawButtonBG(g, width - iconWidth, 0, iconWidth, height);
g.drawImage(DateFieldSkin.IMAGE_ICON_TIME,
width - iconWidth, yOffset,
Graphics.LEFT | Graphics.TOP);
}
break;
case DateField.DATE_TIME:
if (DateFieldSkin.IMAGE_ICON_DATETIME != null) {
iconWidth = DateFieldSkin.IMAGE_ICON_DATETIME.getWidth();
int yOffset = height -
DateFieldSkin.IMAGE_ICON_DATE.getHeight();
if (yOffset > 0) {
yOffset = (int)(yOffset / 2);
} else {
yOffset = 0;
}
drawButtonBG(g, width - iconWidth, 0, iconWidth, height);
g.drawImage(DateFieldSkin.IMAGE_ICON_DATETIME,
width - iconWidth, yOffset,
Graphics.LEFT | Graphics.TOP);
}
break;
default:
// for safety/completeness.
Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
"DateFieldLFImpl: mode=" + mode);
break;
}
// we clip in case our text is too long
g.clipRect(DateFieldSkin.PAD_H, DateFieldSkin.PAD_V,
width - (2 * DateFieldSkin.PAD_H) - iconWidth,
height - (2 * DateFieldSkin.PAD_V));
g.translate(DateFieldSkin.PAD_H, DateFieldSkin.PAD_V);
// paint value
g.setFont(DateFieldSkin.FONT);
g.setColor(DateFieldSkin.COLOR_FG);
g.drawString(toString(currentDate, mode, df.initialized),
0, 0, Graphics.LEFT | Graphics.TOP);
g.translate(-DateFieldSkin.PAD_H, -DateFieldSkin.PAD_V);
if (editor.isPopupOpen() && editor.isSizeChanged()) {
setPopupLocation();
}
}
/**
* Draw background of button
* @param g Graphics
* @param x x coordinate
* @param y y coordinate
* @param w width
* @param h height
*/
void drawButtonBG(Graphics g, int x, int y, int w, int h) {
if (DateFieldSkin.IMAGE_BUTTON_BG != null) {
CGraphicsUtil.draw9pcsBackground(g, x, y, w, h,
DateFieldSkin.IMAGE_BUTTON_BG);
}
}
/**
* Called by the system to traverse this DateField.
*
* @param dir the direction of traversal
* @param viewportWidth the width of the container's viewport
* @param viewportHeight the height of the container's viewport
* @param visRect passes the visible rectangle into the method, and
* returns the updated traversal rectangle from the method
* @return true if internal traversal had occurred, false if traversal
* should proceed out
*/
boolean lCallTraverse(int dir, int viewportWidth, int viewportHeight,
int[] visRect)
{
super.lCallTraverse(dir, viewportWidth, viewportHeight, visRect);
visRect[X] = 0;
visRect[Y] = 0;
visRect[HEIGHT] = bounds[HEIGHT];
visRect[WIDTH] = bounds[WIDTH];
if (!editor.isPopupOpen()) {
if (!traversedIn) {
traversedIn = true;
return true;
}
}
return false;
}
/**
* Called by the system to indicate traversal has left this Item.
*/
void lCallTraverseOut() {
super.lCallTraverseOut();
traversedIn = false;
if (editor.isPopupOpen()) {
editor.hideAllPopups();
getCurrentDisplay().hidePopup(editor);
}
}
/**
* Called by the system to signal a key press.
*
* @param keyCode the key code of the key that has been pressed
*/
void uCallKeyPressed(int keyCode) {
if (keyCode != Constants.KEYCODE_SELECT) {
return;
}
synchronized (Display.LCDUILock) {
if (!editor.isPopupOpen()) {
setPopupLocation();
editor.show();
} else {
editor.hideAllPopups();
getCurrentDisplay().hidePopup(editor);
}
} // synchronized
uRequestPaint();
}
/**
* Set location of popup layer
*/
private void setPopupLocation() {
ScreenLFImpl sLF = (ScreenLFImpl)df.owner.getLF();
// decide where to show popup: above, below or in
// the middle of the screen (if both above/below don't
// work out)
int[] avalibleBounds = sLF.lGetCurrentDisplay().getBodyLayerBounds();
int x = bounds[X] + contentBounds[X] + DateFieldSkin.PAD_V - sLF.viewable[X];
int y = bounds[Y] + contentBounds[Y] - sLF.viewable[Y];
if (y - DateEditorSkin.HEIGHT >= 0) {
// can fit above
y -= DateEditorSkin.HEIGHT - DateFieldSkin.PAD_V - avalibleBounds[Y];
} else if (y + contentBounds[HEIGHT] + DateEditorSkin.HEIGHT + 2 * DateFieldSkin.PAD_V < avalibleBounds[HEIGHT]) {
// can fit below
y += contentBounds[HEIGHT] + 2 * DateFieldSkin.PAD_V + avalibleBounds[Y];
} else {
// fit in the middle of screen
y = avalibleBounds[Y] + (avalibleBounds[HEIGHT] / 2) -
(DateEditorSkin.HEIGHT / 2);
}
editor.setLocation(x, y);
}
/**
* Called by the system to indicate the size available to this Item
* has changed
*
* @param w the new width of the item's content area
* @param h the new height of the item's content area
*/
void uCallSizeChanged(int w, int h) {
super.uCallSizeChanged(w,h);
synchronized (Display.LCDUILock) {
editor.setSizeChanged();
}
}
/**
* Get the localized day of the week text given a Calendar.
*
* @param calendar The Calendar object to retrieve the date from
* @return String The day of the week text based on the date in the
* calendar
*/
static String dayOfWeekString(Calendar calendar) {
String str;
switch (calendar.get(Calendar.DAY_OF_WEEK)) {
case Calendar.SUNDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_SUN);
break;
case Calendar.MONDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_MON);
break;
case Calendar.TUESDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_TUE);
break;
case Calendar.WEDNESDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_WED);
break;
case Calendar.THURSDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_THU);
break;
case Calendar.FRIDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_FRI);
break;
case Calendar.SATURDAY:
str = Resource.getString(ResourceConstants.LCDUI_DF_SAT);
break;
default:
str = Integer.toString(calendar.get(Calendar.DAY_OF_WEEK));
break;
}
return str;
}
/**
* A utility method to return a numerical digit as two digits
* if it is less than 10 (used to display time in 2 digits
* if required, eg. 6:09pm).
*
* @param n The number to convert
* @return String The String representing the number in two digits
*/
static String twoDigits(int n) {
if (n == 0) {
return "00";
} else if (n < 10) {
return "0" + n;
} else {
return "" + n;
}
}
/**
* Get the am/pm text given a Calendar.
*
* @param calendar The Calendar object to retrieve the time from
* @return String The am/pm text based on the time in the calendar
*/
static String ampmString(Calendar calendar) {
if (!CLOCK_USES_AM_PM) {
return null;
}
return (calendar.get(Calendar.AM_PM) == Calendar.AM) ?
Resource.getString(ResourceConstants.LCDUI_DF_AM) :
Resource.getString(ResourceConstants.LCDUI_DF_PM);
}
/**
* Get the hour given a Calendar, based on a 12-hour or 24-hour clock.
*
* @param calendar The Calendar object to retrieve the hour from
* @return String The hour based on whether it's a 12-hour/24-hour clock
*/
static String getHourString(Calendar calendar) {
if (CLOCK_USES_AM_PM) {
int hour = calendar.get(Calendar.HOUR);
return (hour == 0) ? "12" : "" + hour;
} else {
return Integer.toString(calendar.get(Calendar.HOUR_OF_DAY));
}
}
/**
* Translate the mode of a DateField into a readable string.
*
* @param currentDate The current date set in the DateField.
* @param mode The mode to translate.
* @param initialized <code>true</code> if the human-readable string has
* been initialized; <code>false</code>, otherwise.
* @return String A human-readable string representing the mode of the
* DateField.
*/
static String toString(Calendar currentDate, int mode,
boolean initialized)
{
String str = null;
if (!initialized) {
switch (mode) {
case DateField.DATE:
str = Resource.getString(ResourceConstants.LCDUI_DF_DATE);
break;
case DateField.TIME:
str = Resource.getString(ResourceConstants.LCDUI_DF_TIME);
break;
case DateField.DATE_TIME:
str = Resource.getString(
ResourceConstants.LCDUI_DF_DATETIME);
break;
default:
// for safety/completeness.
Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
"DateFieldLFImpl: mode=" + mode);
break;
}
} else {
switch (mode) {
case DateField.DATE:
str = Resource.getDateString(
dayOfWeekString(currentDate),
"" + currentDate.get(Calendar.DATE),
MONTH_NAMES[currentDate.get(Calendar.MONTH)].
substring(0, 3),
Integer.toString(currentDate.get(Calendar.YEAR)));
break;
case DateField.TIME:
str = Resource.getTimeString(getHourString(currentDate),
"" + twoDigits(currentDate.get(Calendar.MINUTE)),
"" + currentDate.get(Calendar.SECOND),
ampmString(currentDate));
break;
case DateField.DATE_TIME:
str = Resource.getDateTimeString(
dayOfWeekString(currentDate),
Integer.toString(currentDate.get(Calendar.DATE)),
MONTH_NAMES[currentDate.get(Calendar.MONTH)].
substring(0, 3),
Integer.toString(currentDate.get(Calendar.YEAR)),
getHourString(currentDate),
twoDigits(currentDate.get(Calendar.MINUTE)),
Integer.toString(currentDate.get(Calendar.SECOND)),
ampmString(currentDate));
break;
default:
// for safety/completeness.
Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
"DateFieldLFImpl: mode=" + mode);
break;
}
}
return str;
}
/**
* Static array holding the names of the 12 months.
*/
static final String[] MONTH_NAMES = {
Resource.getString(ResourceConstants.LCDUI_DF_JANUARY),
Resource.getString(ResourceConstants.LCDUI_DF_FEBRUARY),
Resource.getString(ResourceConstants.LCDUI_DF_MARCH),
Resource.getString(ResourceConstants.LCDUI_DF_APRIL),
Resource.getString(ResourceConstants.LCDUI_DF_MAY),
Resource.getString(ResourceConstants.LCDUI_DF_JUNE),
Resource.getString(ResourceConstants.LCDUI_DF_JULY),
Resource.getString(ResourceConstants.LCDUI_DF_AUGUST),
Resource.getString(ResourceConstants.LCDUI_DF_SEPTEMBER),
Resource.getString(ResourceConstants.LCDUI_DF_OCTOBER),
Resource.getString(ResourceConstants.LCDUI_DF_NOVEMBER),
Resource.getString(ResourceConstants.LCDUI_DF_DECEMBER)
};
/**
* Flag to signal the clock representation uses AM and PM notation.
* This is dummy right now, and always set to true since there is
* not easy to find out from the system if the clock is using a
* 12-hour or 24-hour mode.
*/
static final boolean CLOCK_USES_AM_PM = true;
/**
* DateField associated with this view.
*/
DateField df;
/**
* Current date being handled by this datefield impl.
*/
private Calendar currentDate;
/**
* Current input mode being handled by this datefield impl.
*/
int mode;
/**
* A flag indicating a prior call to uCallTraverse()
*/
private boolean traversedIn;
/**
* The editor for this DateField.
*/
DateEditor editor = null;
}
|