/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui;
import java.util.*;
import malik.emulator.application.*;
import malik.emulator.media.graphics.*;
import malik.emulator.microedition.lcdui.*;
import malik.emulator.time.*;
public class DateField extends InteractiveItem
{
public static final int DATE = 1;
public static final int TIME = 2;
public static final int DATE_TIME = 3;
private static final int FIELD_YEAR = 0x0020ffff;
private static final int FIELD_MONTH = 0x001800ff;
private static final int FIELD_DAY = 0x001000ff;
private static final int FIELD_HOUR = 0x000800ff;
private static final int FIELD_MINUTE = 0x000000ff;
private static final int OFFSET_ZERO_INDEX;
private static final int[] OFFSET_VALUE;
static final String[] OFFSET_NAMES;
static final String[] DAY_NAMES;
static final Command SELECT;
static final Command BACK;
static final Font FONT;
static {
int len;
int zeroOffsetIndex;
int[] offsetValue;
String[] offsetNames = new String[] {
"UTC-12:00", "UTC-11:00", "UTC-10:00", "UTC-09:30", "UTC-09:00", "UTC-08:30", "UTC-08:00", "UTC-07:00",
"UTC-06:00", "UTC-05:00", "UTC-04:30", "UTC-04:00", "UTC-03:30", "UTC-03:00", "UTC-02:30", "UTC-02:00",
"UTC-01:00", "UTC-00:44", "UTC-00:25", "UTC+00:00", "UTC+00:20", "UTC+00:30", "UTC+01:00", "UTC+02:00",
"UTC+03:00", "UTC+03:30", "UTC+04:00", "UTC+04:30", "UTC+04:51", "UTC+05:00", "UTC+05:30", "UTC+05:40",
"UTC+05:45", "UTC+06:00", "UTC+06:30", "UTC+07:00", "UTC+07:20", "UTC+07:30", "UTC+08:00", "UTC+08:30",
"UTC+08:45", "UTC+09:00", "UTC+09:30", "UTC+10:00", "UTC+10:30", "UTC+11:00", "UTC+11:30", "UTC+12:00",
"UTC+12:45", "UTC+13:00", "UTC+13:45", "UTC+14:00"
};
zeroOffsetIndex = -1;
offsetValue = new int[len = offsetNames.length];
for(int i = len; i-- > 0; )
{
int offset;
String s;
if((s = offsetNames[i]) == null || s.length() < 9) continue;
offset = (s.charAt(4) - '0') * 36000000 + (s.charAt(5) - '0') * 3600000 + (s.charAt(7) - '0') * 600000 + (s.charAt(8) - '0') * 60000;
if(s.charAt(3) == '-') offset = -offset;
if(offset == 0 && zeroOffsetIndex < 0) zeroOffsetIndex = i;
offsetValue[i] = offset;
}
OFFSET_ZERO_INDEX = zeroOffsetIndex;
OFFSET_VALUE = offsetValue;
OFFSET_NAMES = offsetNames;
DAY_NAMES = new String[] { "пн", "вт", "ср", "чт", "пт", "сб", "вс" };
SELECT = new Command("Выбрать", Command.OK, Integer.MIN_VALUE);
BACK = new Command("Назад", Command.BACK, 0);
FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
}
private static void setLeft(Component[] list, int offset, int length, int startLeft) {
for(int lim = offset + length, i = offset; i < lim; i++)
{
Component cmp;
(cmp = list[i]).left = startLeft;
startLeft += cmp.width;
}
}
private static void setTop(Component[] list, int offset, int length, int rowHeight, int baseTop) {
for(int i = offset + length; i-- > offset; )
{
Component cmp;
(cmp = list[i]).top = baseTop + ((rowHeight - cmp.height) >> 1);
}
}
private static int indexOf(int offset) {
int[] offsetValue;
for(int i = (offsetValue = OFFSET_VALUE).length; i-- > 0; ) if(offsetValue[i] == offset) return i;
return OFFSET_ZERO_INDEX;
}
private static int getOffset(int index) {
return OFFSET_VALUE[index];
}
private static int getWidth(Component[] list, int offset, int length) {
int result = 0;
for(int i = offset + length; i-- > offset; result += list[i].width);
return result;
}
private static int getHeight(Component[] list, int offset, int length) {
int result = 0;
for(int i = offset + length; i-- > offset; )
{
int height;
if(result < (height = list[i].height)) result = height;
}
return result;
}
private static int getField(long fieldset, int field) {
return (int) (fieldset >> (field >> 16)) & field & 0xffff;
}
private static long setField(long fieldset, int field, int value) {
int shift = field >> 16;
int mask = field & 0xffff;
return fieldset & ~((long) mask << shift) | ((long) value & mask) << shift;
}
private abstract class Component extends Object
{
boolean visible;
int left;
int top;
int width;
int height;
final int field;
protected Component() {
this.field = 0;
}
protected Component(int field) {
this.field = field;
}
public abstract void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int value, String offset);
public abstract int getWidth();
public abstract int getHeight();
public void keyboardEvent(KeyboardEvent event) {
}
public void pointerEvent(PointerEvent event) {
}
public void selectEvent() {
}
public boolean hasSelectCommand() {
return false;
}
public boolean focusMove(int direction, boolean focused) {
return false;
}
public final void writeRectangle(int[] rect) {
rect[0] = left;
rect[1] = top;
rect[2] = width;
rect[3] = height;
}
public final void showTimeZoneList() {
(DateField.this).showTimeZoneList();
}
public final void repaint() {
(DateField.this).requestPaint();
}
public final void setFieldValue(int value) {
(DateField.this).setFieldValue(field, value);
}
public final int getFieldValue() {
return (DateField.this).getFieldValue(field);
}
public final int getFieldValue(int field) {
return (DateField.this).getFieldValue(field);
}
}
private class NumericComponent extends Component
{
private boolean newInput;
protected final int minValue;
protected final int maxValue;
public NumericComponent(int field, int minValue, int maxValue) {
(DateField.this).super(field);
this.newInput = true;
this.minValue = minValue;
this.maxValue = maxValue;
}
public void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int value, String offset) {
int x = focused && pressed ? width - 2 : width - 3;
int y = focused && pressed ? 4 : 3;
render.setFont(DateField.FONT);
render.setColor(RasterCanvas.getSystemColor(focused ? pressed ? 0x25 : 0x27 : 0x24));
render.drawElement(4, focused ? pressed ? 1 : 3 : 0, 0, 0, 0, width, height);
render.drawString(Integer.toString(value).concat("\u2195"), x, y, Graphics.RIGHT | Graphics.TOP);
}
public void keyboardEvent(KeyboardEvent event) {
int digit;
if((digit = event.getCharCode() - '0') >= 0 && digit <= 9)
{
long minValue = (long) this.minValue;
long maxValue = (long) this.maxValue;
long newValue;
if(newInput)
{
newInput = false;
if((newValue = (long) digit) < minValue) newValue = minValue;
if(newValue > maxValue) newValue = maxValue;
}
else if((newValue = (long) getFieldValue() * 10L + digit) > maxValue)
{
newInput = true;
newValue = maxValue;
}
setFieldValue((int) newValue);
}
}
public void pointerEvent(PointerEvent event) {
int x;
int y;
int h;
if(event.getAction() == PointerEvent.ACTION_POINTER_RELEASED && (x = event.getX()) >= 0 && x < width && (y = event.getY()) >= 0 && y < (h = height))
{
if(y >= (h >> 1))
{
decreaseFieldValue();
} else
{
increaseFieldValue();
}
}
}
public boolean focusMove(int direction, boolean focused) {
if(!focused) return newInput = true;
switch(direction)
{
case Item.DIR_NONE:
break;
case Item.DIR_UP:
newInput = true;
increaseFieldValue();
break;
case Item.DIR_DOWN:
newInput = true;
decreaseFieldValue();
break;
default:
return false;
}
return true;
}
public int getWidth() {
int result = 0;
int digits = 1;
Font font = DateField.FONT;
for(int val = maxValue; val > 9; val /= 10) digits++;
for(char digit = '0'; digit <= '9'; digit++)
{
int width;
if(result < (width = font.charWidth(digit))) result = width;
}
return result * digits + font.charWidth('\u2195') + 6;
}
public int getHeight() {
return DateField.FONT.getHeight() + 6;
}
public final void increaseFieldValue() {
int curValue;
setFieldValue((curValue = getFieldValue()) >= maxValue ? minValue : curValue + 1);
}
public final void decreaseFieldValue() {
int curValue;
setFieldValue((curValue = getFieldValue()) <= minValue ? maxValue : curValue - 1);
}
}
private class TextNumericComponent extends NumericComponent
{
private final String[] strings;
public TextNumericComponent(int field, int minValue, String[] strings) {
(DateField.this).super(field, minValue, minValue + strings.length - 1);
this.strings = strings;
}
public void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int value, String offset) {
int x = focused && pressed ? width - 2 : width - 3;
int y = focused && pressed ? 4 : 3;
render.setFont(DateField.FONT);
render.setColor(RasterCanvas.getSystemColor(focused ? pressed ? 0x25 : 0x27 : 0x24));
render.drawElement(4, focused ? pressed ? 1 : 3 : 0, 0, 0, 0, width, height);
render.drawString(strings[value - minValue], x, y, Graphics.RIGHT | Graphics.TOP);
}
public int getWidth() {
int result = 0;
String[] strings = this.strings;
Font font = DateField.FONT;
for(int i = strings.length; i-- > 0; )
{
int width;
if(result < (width = font.stringWidth(strings[i]))) result = width;
}
return result + 6;
}
}
private class StringComponent extends Component
{
private final Font font;
private final String text;
public StringComponent(String text, Font font) {
(DateField.this).super();
this.font = font == null ? Font.getDefaultFont() : font;
this.text = text == null ? "" : text;
}
public void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int value, String offset) {
render.setFont(font);
render.setColor(RasterCanvas.getSystemColor(0x28));
render.drawString(text, 0, 0, Graphics.LEFT | Graphics.TOP);
}
public int getWidth() {
return font.stringWidth(text);
}
public int getHeight() {
return font.getHeight();
}
}
private class DaySelectComponent extends Component
{
private int selectedDay;
public DaySelectComponent() {
(DateField.this).super(DateField.FIELD_DAY);
}
public void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int day, String offset) {
int dx = width / 7;
int dy = height / 7;
int daySelected = focused ? selectedDay : 0;
int year = getFieldValue(DateField.FIELD_YEAR);
int month = getFieldValue(DateField.FIELD_MONTH);
int firstWeekDay = CalendarSystem.gregorian.computeDayOfWeek(year, month, 1);
int numberOfDays = CalendarSystem.gregorian.computeNumberOfDays(year, month);
String[] days = DateField.DAY_NAMES;
Font font = DateField.FONT;
render.setFont(font);
render.setColor(RasterCanvas.getSystemColor(0x28));
for(int x = dx >> 1, i = 0; i < 7; x += dx, i++) render.drawString(days[i], x, 3, Graphics.HCENTER | Graphics.TOP);
if(firstWeekDay == 0) firstWeekDay = 7;
for(int dayCurrent = 2 - firstWeekDay, y = dy, i = 0; i < 6; y += dy, i++) for(int x = 0, j = 0; j < 7; dayCurrent++, x += dx, j++) if(dayCurrent >= 1 && dayCurrent <= numberOfDays)
{
if(dayCurrent == daySelected)
{
render.setColor(RasterCanvas.getSystemColor(focused ? pressed ? 0x25 : 0x27 : 0x24));
render.drawElement(4, focused ? pressed ? 1 : 3 : 0, 0, x, y, dx, dy);
render.drawString(Integer.toString(dayCurrent), x + (dx >> 1) + (focused && pressed ? 1 : 0), y + (focused && pressed ? 4 : 3), Graphics.HCENTER | Graphics.TOP);
continue;
}
if(dayCurrent == day)
{
render.drawElement(4, 0, 0, x, y, dx, dy);
render.setColor(RasterCanvas.getSystemColor(0x24));
} else
{
render.setColor(RasterCanvas.getSystemColor(0x28));
}
render.drawString(Integer.toString(dayCurrent), x + (dx >> 1), y + 3, Graphics.HCENTER | Graphics.TOP);
}
}
public void pointerEvent(PointerEvent event) {
int x = event.getX();
int y = event.getY();
int dx = width;
int dy = height;
if(x >= 0 && x < dx && y >= 0 && y < dy)
{
int col;
int row;
dx /= 7;
dy /= 7;
col = x / dx;
row = y / dy;
if(row-- > 0)
{
int day;
int year = getFieldValue(DateField.FIELD_YEAR);
int month = getFieldValue(DateField.FIELD_MONTH);
int firstWeekDay = CalendarSystem.gregorian.computeDayOfWeek(year, month, 1);
int numberOfDays = CalendarSystem.gregorian.computeNumberOfDays(year, month);
if(firstWeekDay == 0) firstWeekDay = 7;
if((day = 2 - firstWeekDay + row * 7 + col) < 1)
{
selectedDay = 1;
repaint();
}
else if(day > numberOfDays)
{
selectedDay = numberOfDays;
repaint();
}
else
{
selectedDay = day;
if(event.getAction() == PointerEvent.ACTION_POINTER_RELEASED)
{
setFieldValue(day);
} else
{
repaint();
}
}
}
}
}
public void selectEvent() {
setFieldValue(selectedDay);
}
public boolean hasSelectCommand() {
return true;
}
public boolean focusMove(int direction, boolean focused) {
int daySelected = selectedDay;
int year = getFieldValue(DateField.FIELD_YEAR);
int month = getFieldValue(DateField.FIELD_MONTH);
int numberOfDays = CalendarSystem.gregorian.computeNumberOfDays(year, month);
if(!focused)
{
switch(direction)
{
default:
selectedDay = 1;
break;
case Item.DIR_UP:
case Item.DIR_LEFT:
selectedDay = numberOfDays;
break;
}
return true;
}
switch(direction)
{
default:
return true;
case Item.DIR_LEFT:
if(--daySelected < 1) return false;
break;
case Item.DIR_RIGHT:
if(++daySelected > numberOfDays) return false;
break;
case Item.DIR_UP:
if((daySelected -= 7) < 1) return false;
break;
case Item.DIR_DOWN:
if((daySelected += 7) > numberOfDays) return false;
break;
}
selectedDay = daySelected;
repaint();
return true;
}
public int getWidth() {
int result = 0;
Font font = DateField.FONT;
for(char digit = '0'; digit <= '9'; digit++)
{
int width;
if(result < (width = font.charWidth(digit))) result = width;
}
return (2 * result + 6) * 7;
}
public int getHeight() {
return (DateField.FONT.getHeight() + 6) * 7;
}
}
private class TimeZoneComponent extends Component
{
public TimeZoneComponent() {
(DateField.this).super();
}
public void paint(Graphics render, int width, int height, boolean focused, boolean pressed, int value, String offset) {
int x = focused && pressed ? (width >> 1) + 1 : (width >> 1);
int y = focused && pressed ? 4 : 3;
render.setFont(DateField.FONT);
render.setColor(RasterCanvas.getSystemColor(focused ? pressed ? 0x25 : 0x27 : 0x24));
render.drawElement(4, focused ? pressed ? 1 : 3 : 0, 0, 0, 0, width, height);
render.drawString(offset, x, y, Graphics.HCENTER | Graphics.TOP);
}
public void pointerEvent(PointerEvent event) {
int x;
int y;
if(event.getAction() == PointerEvent.ACTION_POINTER_RELEASED && (x = event.getX()) >= 0 && x < width && (y = event.getY()) >= 0 && y < height) showTimeZoneList();
}
public void selectEvent() {
showTimeZoneList();
}
public boolean hasSelectCommand() {
return true;
}
public boolean focusMove(int direction, boolean focused) {
return !focused || direction == Item.DIR_NONE;
}
public int getWidth() {
int result = 0;
String[] names = DateField.OFFSET_NAMES;
Font font = DateField.FONT;
for(int i = names.length; i-- > 0; )
{
int width;
if(result < (width = font.stringWidth(names[i]))) result = width;
}
return result + 6;
}
public int getHeight() {
return DateField.FONT.getHeight() + 6;
}
}
private boolean needPlaceComponents;
private int mode;
private int width;
private int height;
private int current;
private int focused;
private int pressed;
private int ofsindex;
private long fieldset;
private final Component[] components;
private final StringList timeZoneList;
private final Object monitor;
public DateField(String label, int mode) {
this(label, mode, null);
}
public DateField(String label, int mode, TimeZone zone) {
super(label);
int index;
long fields;
long fieldset;
Component[] list;
CalendarSystem system;
StringList timeZoneList;
if(mode < DATE || mode > DATE_TIME)
{
throw new IllegalArgumentException("DateField: аргумент mode имеет недопустимое значение.");
}
index = indexOf((zone == null ? TimeZone.getDefault() : zone).getRawOffset());
fields = (system = CalendarSystem.gregorian).computeFields(System.currentTimeMillis(), DateField.getOffset(index));
fieldset = setField(0L, FIELD_YEAR, system.getYear(fields));
fieldset = setField(fieldset, FIELD_MONTH, system.getMonth(fields));
fieldset = setField(fieldset, FIELD_DAY, system.getDay(fields));
fieldset = setField(fieldset, FIELD_HOUR, system.getHour(fields));
fieldset = setField(fieldset, FIELD_MINUTE, system.getMinute(fields));
list = new Component[] {
this.new TextNumericComponent(FIELD_MONTH, 1, new String[] {
"Январь\u2195", "Февраль\u2195", "Март\u2195", "Апрель\u2195", "Май\u2195", "Июнь\u2195",
"Июль\u2195", "Август\u2195", "Сентябрь\u2195", "Октябрь\u2195", "Ноябрь\u2195", "Декабрь\u2195"
}),
this.new StringComponent(" ", FONT),
this.new NumericComponent(FIELD_YEAR, 0x0001, 0xffff),
this.new DaySelectComponent(),
this.new NumericComponent(FIELD_HOUR, 0, 23),
this.new StringComponent(" : ", FONT),
this.new NumericComponent(FIELD_MINUTE, 0, 59),
this.new StringComponent(" ", FONT),
this.new TimeZoneComponent()
};
(timeZoneList = new StringList(null, null, OFFSET_NAMES)).setCommandListener(new CommandListener() {
public void commandAction(Command command, Displayable screen) {
Display parent;
if(command == DateField.SELECT) (DateField.this).setOffsetIndex(((StringList) screen).getSelectedIndex());
if((parent = screen.getParentDisplay()) != null) parent.hideForeground();
}
});
timeZoneList.addCommand(SELECT);
timeZoneList.addCommand(BACK);
this.needPlaceComponents = true;
this.mode = mode;
this.focused = -1;
this.pressed = -1;
this.ofsindex = index;
this.fieldset = fieldset;
this.components = list;
this.timeZoneList = timeZoneList;
this.monitor = list;
}
public void setInputMode(int mode) {
boolean needed;
if(mode < DATE || mode > DATE_TIME)
{
throw new IllegalArgumentException("DateField.setInputMode: аргумент mode имеет недопустимое значение.");
}
needed = false;
synchronized(monitor)
{
if(this.mode != (this.mode = mode)) this.needPlaceComponents = needed = true;
}
if(needed) requestInvalidate();
}
public void setDate(Date date) {
boolean needed;
long time;
if(date == null) return;
needed = false;
time = date.getTime();
synchronized(monitor)
{
long fields;
long fieldset;
CalendarSystem system;
fields = (system = CalendarSystem.gregorian).computeFields(time, getOffset(ofsindex));
fieldset = setField(0L, FIELD_YEAR, system.getYear(fields));
fieldset = setField(fieldset, FIELD_MONTH, system.getMonth(fields));
fieldset = setField(fieldset, FIELD_DAY, system.getDay(fields));
fieldset = setField(fieldset, FIELD_HOUR, system.getHour(fields));
fieldset = setField(fieldset, FIELD_MINUTE, system.getMinute(fields));
if(this.fieldset != (this.fieldset = fieldset)) needed = true;
}
if(needed) requestPaint();
}
public int getInputMode() {
return mode;
}
public Date getDate() {
int year;
int month;
int day;
int hour;
int minute;
int index = this.ofsindex;
long fieldset = this.fieldset;
year = getField(fieldset, FIELD_YEAR);
month = getField(fieldset, FIELD_MONTH);
day = getField(fieldset, FIELD_DAY);
hour = getField(fieldset, FIELD_HOUR);
minute = getField(fieldset, FIELD_MINUTE);
return new Date(CalendarSystem.gregorian.computeTime(year, month, day, hour, minute, 0, 0, getOffset(index)));
}
void paint(Graphics render, int contentWidth, int contentHeight) {
int l = render.getClipX();
int t = render.getClipY();
int w = render.getClipWidth();
int h = render.getClipHeight();
int c = placeComponents();
int p = pressed;
long fieldset = this.fieldset;
Component[] list = components;
String ofs = OFFSET_NAMES[ofsindex];
if(!super.focused)
{
c = -1;
p = -1;
}
for(int i = list.length; i-- > 0; )
{
int cl;
int ct;
int cw;
int ch;
Component cmp;
if((cmp = list[i]).visible && (cl = cmp.left) < l + w && (ct = cmp.top) < t + h && cl + (cw = cmp.width) > l && ct + (ch = cmp.height) > t)
{
render.translate(cl - render.getTranslateX(), ct - render.getTranslateY());
cmp.paint(render, cw, ch, i == c, i == p, getField(fieldset, cmp.field), ofs);
}
}
}
void onCommandAction(Command command) {
if(command == SELECT)
{
components[current].selectEvent();
return;
}
super.onCommandAction(command);
}
void onKeyboardEvent(KeyboardEvent event) {
components[current].keyboardEvent(event);
}
void onPointerEvent(PointerEvent event) {
int f;
int x;
int y;
Component[] list = components;
switch(event.getAction())
{
case PointerEvent.ACTION_POINTER_PRESSED:
x = event.getX();
y = event.getY();
for(int len = list.length, i = 0; i < len; i++)
{
int cl;
int ct;
Component cmp;
if((cmp = list[i]).visible && x >= (cl = cmp.left) && x < cl + cmp.width && y >= (ct = cmp.top) && y < ct + cmp.height && cmp.focusMove(DIR_NONE, current == i))
{
setCurrent(i);
focused = pressed = i;
event.translate(cl, ct);
cmp.pointerEvent(event);
requestPaint();
break;
}
}
break;
case PointerEvent.ACTION_POINTER_RELEASED:
if((f = focused) >= 0)
{
Component cmp = list[f];
focused = pressed = -1;
event.translate(cmp.left, cmp.top);
cmp.pointerEvent(event);
requestPaint();
}
break;
default:
if((f = focused) >= 0)
{
int cl;
int ct;
Component cmp = list[f];
x = event.getX();
y = event.getY();
event.translate(cl = cmp.left, ct = cmp.top);
cmp.pointerEvent(event);
if(pressed != (pressed = x >= cl && x < cl + cmp.width && y >= ct && y < ct + cmp.height ? f : -1)) requestPaint();
}
break;
}
}
void onFocusLost() {
focused = -1;
pressed = -1;
super.onFocusLost();
}
boolean onFocusMove(int direction, int viewportWidth, int viewportHeight, int[] visibleRectangle) {
int c;
Component[] list = components;
Component cmp;
if(!super.onFocusMove(direction, viewportWidth, viewportHeight, visibleRectangle))
{
cmp = null;
switch(direction)
{
default:
for(int len = list.length, i = 0; i < len; i++) if((cmp = list[i]).visible && cmp.focusMove(direction, false))
{
setCurrent(i);
break;
}
break;
case DIR_UP:
case DIR_LEFT:
for(int i = list.length; i-- > 0; ) if((cmp = list[i]).visible && cmp.focusMove(direction, false))
{
setCurrent(i);
break;
}
break;
}
cmp.writeRectangle(visibleRectangle);
return true;
}
if((cmp = list[c = current]).focusMove(direction, true))
{
cmp.writeRectangle(visibleRectangle);
return true;
}
switch(direction)
{
case DIR_RIGHT:
case DIR_DOWN:
for(int len = list.length, i = c + 1; i < len; i++) if((cmp = list[i]).visible && cmp.focusMove(direction, false))
{
setCurrent(i);
cmp.writeRectangle(visibleRectangle);
return true;
}
break;
case DIR_LEFT:
case DIR_UP:
for(int i = c; i-- > 0; ) if((cmp = list[i]).visible && cmp.focusMove(direction, false))
{
setCurrent(i);
cmp.writeRectangle(visibleRectangle);
return true;
}
break;
default:
cmp.writeRectangle(visibleRectangle);
return true;
}
return false;
}
int getMinimumContentWidth() {
placeComponents();
return width;
}
int getMinimumContentHeight() {
placeComponents();
return height;
}
final void showTimeZoneList() {
Display parent;
Displayable owner;
if((owner = this.owner) != null && (parent = owner.getParentDisplay()) != null)
{
StringList list;
(list = timeZoneList).setSelectedIndex(ofsindex);
parent.setCurrent(list);
}
}
final void setOffsetIndex(int offsetIndex) {
boolean needed;
synchronized(monitor)
{
needed = this.ofsindex != (this.ofsindex = offsetIndex);
}
if(needed)
{
super.notifyStateChanged();
super.requestPaint();
}
}
final void setFieldValue(int field, int value) {
boolean needed;
synchronized(monitor)
{
long fieldsetOld;
long fieldsetNew = fieldsetOld = fieldset;
if(field == FIELD_YEAR)
{
int numberOfDays = CalendarSystem.gregorian.computeNumberOfDays(value, getField(fieldsetNew, FIELD_MONTH));
if(getField(fieldsetNew, FIELD_DAY) > numberOfDays) fieldsetNew = setField(fieldsetNew, FIELD_DAY, numberOfDays);
}
else if(field == FIELD_MONTH)
{
int numberOfDays = CalendarSystem.gregorian.computeNumberOfDays(getField(fieldsetNew, FIELD_YEAR), value);
if(getField(fieldsetNew, FIELD_DAY) > numberOfDays) fieldsetNew = setField(fieldsetNew, FIELD_DAY, numberOfDays);
}
fieldsetNew = setField(fieldsetNew, field, value);
needed = fieldsetOld != (fieldset = fieldsetNew);
}
if(needed)
{
super.notifyStateChanged();
super.requestPaint();
}
}
final int getOffsetIndex() {
return ofsindex;
}
final int getFieldValue(int field) {
return getField(fieldset, field);
}
private void setCurrent(int current) {
this.current = current;
super.removeCommand(SELECT);
if(components[current].hasSelectCommand()) super.setDefaultCommand(SELECT);
}
private int placeComponents() {
boolean date;
boolean time;
boolean needed;
int mode;
int result;
int row1Width;
int row2Width;
int row3Width;
int itemWidth;
int row1Height;
int row2Height;
int row3Height;
Component[] list;
synchronized(monitor)
{
if(needed = needPlaceComponents) needPlaceComponents = false;
}
if(!needed) return current;
mode = this.mode;
for(int i = (list = components).length; i-- > 0; )
{
Component cmp;
if((cmp = list[i]).visible = (mode & (i < 4 ? DATE : TIME)) != 0)
{
cmp.width = cmp.getWidth();
cmp.height = cmp.getHeight();
}
}
if(date = (mode & DATE) != 0)
{
Component cmp = list[3];
row1Width = getWidth(list, 0, 3);
row1Height = getHeight(list, 0, 3);
row2Width = cmp.width;
row2Height = cmp.height;
} else
{
row1Width = row1Height = row2Width = row2Height = 0;
}
if(time = (mode & TIME) != 0)
{
row3Width = getWidth(list, 4, 5);
row3Height = getHeight(list, 4, 5);
} else
{
row3Width = row3Height = 0;
}
width = itemWidth = Math.max(Math.max(row1Width, row2Width), row3Width);
height = row1Height + row2Height + row3Height;
if(date)
{
setLeft(list, 0, 3, (itemWidth - row1Width) >> 1);
setLeft(list, 3, 1, (itemWidth - row2Width) >> 1);
setTop(list, 0, 3, row1Height, 0);
setTop(list, 3, 1, row2Height, row1Height);
}
if(time)
{
setLeft(list, 4, 5, (itemWidth - row3Width) >> 1);
setTop(list, 4, 5, row3Height, row1Height + row2Height);
}
if(!list[result = current].visible) setCurrent(result = date ? 0 : 4);
return result;
}
}