public class CalendarPopupScreen extends MainScreen {
private static SimpleDateFormat sdfWeekDay = new SimpleDateFormat("E");
private static SimpleDateFormat sdfMonth = new SimpleDateFormat("MMMM yyyy");
private static String SINGLE_BLANK = " ";
private static String FIELD_SIZE_STRING = " 30 ";
private int _selectedDay = -1;
private int _currentFocusDay;
private int _currentMonth;
private String _currentMonthString;
private int _currentYear;
private Calendar _cl = Calendar.getInstance();
private ButtonBorderedLabelField _prevMonthButton;
private LabelField _currentMonthField;
private ButtonBorderedLabelField _nextMonthButton;
private static int [] tableStyles = new int [] {
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH,
TableLayoutManager.FIXED_WIDTH
};
private int [] tableSizes = new int [7] ;
private TableLayoutManager _monthManager;
private Field _initialFocusField = null;
private Font _normalFont;
private Font _boldFont;
public CalendarPopupScreen() {
this(new Date());
}
public CalendarPopupScreen(long dateMilliSecs) {
this(new Date(dateMilliSecs));
}
public CalendarPopupScreen(Date selectedDate) {
_cl.setTime(selectedDate);
createScreen(_cl.get(Calendar.DAY_OF_MONTH), _cl.get(Calendar.MONTH) + 1, _cl.get(Calendar.YEAR));
}
public CalendarPopupScreen(int focusDay, int startMonth, int startYear) {
createScreen(focusDay, startMonth, startYear);
}
protected void onDisplay() {
if ( _initialFocusField != null ) {
_initialFocusField.setFocus();
_initialFocusField = null;
}
super.onDisplay();
}
private void createScreen(int focusDay, int startMonth, int startYear) {
_currentFocusDay = focusDay;
_currentMonth = startMonth;
_currentYear = startYear;
_normalFont = this.getFont().derive(Font.PLAIN);
if ( _normalFont.getAdvance(FIELD_SIZE_STRING) > Display.getWidth()/10 ) {
do {
_normalFont = _normalFont.derive(Font.PLAIN, _normalFont.getHeight()-1);
} while ( _normalFont.getAdvance(FIELD_SIZE_STRING) > Display.getWidth()/10 );
this.setFont(_normalFont);
}
_boldFont = _normalFont.derive(Font.BOLD);
HorizontalFieldManager hfm = new HorizontalFieldManager(HorizontalFieldManager.FIELD_HCENTER);
_prevMonthButton = new ButtonBorderedLabelField(SINGLE_BLANK + Characters.BLACK_LEFT_POINTING_TRIANGLE + SINGLE_BLANK,LabelField.FOCUSABLE);
hfm.add(_prevMonthButton);
_currentMonthField = new LabelField(SINGLE_BLANK + _currentMonthString + SINGLE_BLANK);
hfm.add(_currentMonthField);
_nextMonthButton = new ButtonBorderedLabelField(SINGLE_BLANK + Characters.BLACK_RIGHT_POINTING_TRIANGLE + SINGLE_BLANK,LabelField.FOCUSABLE);
hfm.add(_nextMonthButton);
this.add(hfm);
this.add(new VerticalSpacerField(3));
int columnSize = this.getFont().getAdvance(FIELD_SIZE_STRING);
for ( int i = 0; i < tableSizes.length; i++ ) {
tableSizes[i] = columnSize;
}
_monthManager = new TableLayoutManager(tableStyles, tableSizes, 0, TableLayoutManager.FIELD_HCENTER);
this.add(_monthManager);
this.setBorder(BorderFactory.createSimpleBorder(new XYEdges()));
displayMonth();
}
private void displayMonth() {
_monthManager.deleteAll();
_cl.set(Calendar.DAY_OF_MONTH, 1);
_cl.set(Calendar.MONTH, _currentMonth - 1);
_cl.set(Calendar.YEAR, _currentYear);
_cl.set(Calendar.HOUR_OF_DAY, 12);
_cl.set(Calendar.MINUTE, 0);
_cl.set(Calendar.SECOND, 0);
_cl.set(Calendar.MILLISECOND, 1);
long startOfMonth = _cl.getTime().getTime();
_currentMonthString = sdfMonth.formatLocal(_cl.getTime().getTime());
_currentMonthField.setText(SINGLE_BLANK + _currentMonthString + SINGLE_BLANK);
int workDay = _cl.get(Calendar.DAY_OF_WEEK);
int startAt = 0;
switch (workDay) {
case(Calendar.MONDAY): {
startAt = -1;
break;
}
case(Calendar.TUESDAY): {
startAt = -2;
break;
}
case(Calendar.WEDNESDAY): {
startAt = -3;
break;
}
case(Calendar.THURSDAY): {
startAt = -4;
break;
}
case(Calendar.FRIDAY): {
startAt = -5;
break;
}
case(Calendar.SATURDAY): {
startAt = -6;
break;
}
case(Calendar.SUNDAY): {
startAt = -6;
break;
}
}
Date workDate = _cl.getTime();
long workDateTime;
if(workDay==1){
workDateTime = workDate.getTime() + ((long)startAt);
}else{
workDateTime = workDate.getTime() + ((long)startAt) * ((long)DateTimeUtilities.ONEDAY);
}
long dayTime = workDateTime;
for ( int i = 0; i < 7; i++ ) {
String weekDay = sdfWeekDay.formatLocal(dayTime);
HeaderBorderedLabelField hblf = new HeaderBorderedLabelField(weekDay.substring(0,1), LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER);
hblf.setFont(_boldFont);
_monthManager.add(hblf);
dayTime = dayTime + DateTimeUtilities.ONEDAY;
}
for ( int i = 0; i < 42; i++ ) {
workDate.setTime(workDateTime);
_cl.setTime(workDate);
workDateTime = workDateTime + DateTimeUtilities.ONEDAY;
BorderedLabelField blf = null;
int actualDate = _cl.get(Calendar.DAY_OF_MONTH);
String tempDateString = Integer.toString(actualDate);
if ( _cl.get(Calendar.MONTH) == _currentMonth - 1 ) {
blf = new BorderedLabelField(tempDateString, LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER | LabelField.FOCUSABLE);
if ( _currentFocusDay == actualDate ) {
_initialFocusField = blf;
}
} else
if ( (i % 7 == 0) && (startOfMonth < _cl.getTime().getTime()) ) {
break;
} else {
blf = new UnfocusableBorderedLabelField(tempDateString, LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER);
}
_monthManager.add(blf);
}
if ( this.isDisplayed() && _initialFocusField != null ) {
_initialFocusField.setFocus();
_initialFocusField = null;
}
}
public boolean keyChar(char key, int status, int time) {
boolean retval = false;
switch (key) {
case Characters.ENTER: {
processFocus();
retval = true;
break;
}
case Characters.ESCAPE: {
close();
retval = true;
break;
}
default:
retval = super.keyChar(key, status, time);
break;
}
return retval;
}
private boolean processFocus() {
// Should deal with whatever the focsu is currently on
Field focusField = this.getDelegate().getLeafFieldWithFocus();
if ( focusField instanceof ButtonBorderedLabelField ) {
_currentFocusDay = -1; // Leave focus on 'button'
_initialFocusField = focusField;
int monthIncrement = 33;
if ( focusField == _prevMonthButton ) {
monthIncrement = -3;
}
_cl.set(Calendar.DAY_OF_MONTH, 1);
_cl.set(Calendar.MONTH, _currentMonth-1);
_cl.set(Calendar.YEAR, _currentYear);
Date workDate = _cl.getTime();
workDate.setTime(workDate.getTime() + (((long)monthIncrement) * ((long)DateTimeUtilities.ONEDAY)));
_cl.setTime(workDate);
_currentMonth = _cl.get(Calendar.MONTH) + 1;
_currentYear = _cl.get(Calendar.YEAR);
displayMonth();
return true;
} else
if ( focusField instanceof BorderedLabelField ) {
LabelField lab = (LabelField) focusField;
_selectedDay = Integer.parseInt(lab.getText());
close();
return true;
}
return false;
}
protected boolean trackwheelClick( int status, int time ) {
if ( processFocus() ) {
Field focusField = this.getDelegate().getLeafFieldWithFocus();
if ( focusField instanceof ButtonBorderedLabelField ) {
}else{
Dialog.alert( getSelectedDate().getTime()+"");
}
return true;
}
return super.trackwheelClick(status, time);
}
public void close() {
UiApplication.getUiApplication().popScreen(this);
}
public Date getSelectedDate() {
if ( _selectedDay == -1 ) {
return null;
}
Calendar cl = Calendar.getInstance();
cl.set(Calendar.YEAR, _currentYear);
cl.set(Calendar.MONTH, _currentMonth - 1);
cl.set(Calendar.DAY_OF_MONTH, _selectedDay);
cl.set(Calendar.HOUR_OF_DAY, 0);
cl.set(Calendar.MINUTE, 0);
cl.set(Calendar.SECOND, 0);
cl.set(Calendar.MILLISECOND, 1);
return cl.getTime();
}
}
class BorderedLabelField extends LabelField {
int width;
int height;
public BorderedLabelField(String text, long style) {
super(text, style);
}
public void paint(Graphics g) {
super.paint(g);
width = this.getWidth();
height = this.getHeight();
g.drawRect(0, 0, width, height);
}
}
class HeaderBorderedLabelField extends BorderedLabelField {
public HeaderBorderedLabelField(String text, long style) {
super(text, style | LabelField.NON_FOCUSABLE);
}
public void paint(Graphics g) {
g.setBackgroundColor(Color.LIGHTBLUE);
g.clear();
super.paint(g);
}
}
class UnfocusableBorderedLabelField extends BorderedLabelField {
public UnfocusableBorderedLabelField(String text, long style) {
super(text, style | LabelField.NON_FOCUSABLE);
}
public void paint(Graphics g) {
g.setBackgroundColor(Color.LIGHTGREY);
g.clear();
super.paint(g);
}
}
class ButtonBorderedLabelField extends BorderedLabelField {
public ButtonBorderedLabelField(String text, long style) {
super(text, style);
}
public void paint(Graphics g) {
g.setBackgroundColor(Color.LIGHTGREEN);
g.clear();
super.paint(g);
}
}
class VerticalSpacerField extends Field {
// Only for VerticalFieldManagers
private int _height;
public VerticalSpacerField(int height) {
super(Field.NON_FOCUSABLE);
_height = height;
}
public void layout(int widht, int hieght) {
setExtent(10, _height);
}
public void paint(Graphics g) {
}
}
The TableLayoutManager class is given below -
public class TableLayoutManager extends Manager {
int _columnWidths[];
int _suggestedColumnWidths[];
int _rowHeights[];
int _columnStyles[];
public static final int USE_PREFERRED_SIZE = 1;
public static final int USE_PREFERRED_WIDTH_WITH_MAXIMUM = 2;
public static final int SPLIT_REMAINING_WIDTH = 4;
public static final int FIXED_WIDTH = 8;
private static int BITMASK_USE_PREFERRED = USE_PREFERRED_WIDTH_WITH_MAXIMUM | USE_PREFERRED_SIZE;
public static int DEFAULT_PADDING = 5;
int _rows;
int _columns;
private int _horizPadding;
public TableLayoutManager(int columnStyles[], long style) {
this(columnStyles, null, DEFAULT_PADDING, style);
}
public TableLayoutManager(int columnStyles[], int columnWidths[], long style) {
this(columnStyles, columnWidths, DEFAULT_PADDING, style);
}
public TableLayoutManager(int columnStyles[], int columnWidths[], int horizontalPadding, long style) {
super(style);
_horizPadding = horizontalPadding;
_columnStyles = columnStyles;
if (_columnStyles == null)
throw new IllegalArgumentException("not column styles");
if (columnWidths != null) {
_suggestedColumnWidths = Arrays.copy(columnWidths, 0, columnWidths.length);
if (_suggestedColumnWidths.length < _columnStyles.length) {
int oldLength = _suggestedColumnWidths.length;
int increase = columnStyles.length - oldLength;
_suggestedColumnWidths = Arrays.copy(columnWidths, 0, columnStyles.length);
Arrays.fill(_suggestedColumnWidths, 0, oldLength, increase);
}
} else
_suggestedColumnWidths = new int[_columnStyles.length];
}
private Field getField(int x, int y) {
int i = x + (y * _columns);
if (i >= getFieldCount())
return null;
return getField(i);
}
private boolean isColumnStyle(int value, int flag) {
return ((value) & (flag)) > 0;
}
public int getPreferredWidth() {
int numberFields = getFieldCount();
if (numberFields == 0)
return 0;
int rows = numberFields / _columnStyles.length;
int prefferedWidth = 0;
int styles[] = _columnStyles;
int[] columnWidths = new int[_columns];
Arrays.fill(columnWidths, -1);
for (int i = 0; i < _columns; i++) {
if (isColumnStyle(styles[i], FIXED_WIDTH)) {
columnWidths[i] = _suggestedColumnWidths[i];
} else {
if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED)) {
for (int j = 0; j < rows; j++) {
Field field = getField(i, j);
if (field != null) {
int actualWidth = getPreferredWidthOfChild(field) + field.getMarginLeft() + field.getMarginRight();
if (isColumnStyle(styles[i], USE_PREFERRED_WIDTH_WITH_MAXIMUM)) {
actualWidth = Math.min(actualWidth, _suggestedColumnWidths[i]);
}
columnWidths[i] = Math.max(actualWidth, columnWidths[i]);
}
}
}
}
}
for (int n = 0; n < _columns; n++) {
prefferedWidth += columnWidths[n];
}
return prefferedWidth;
}
public int getPreferredHeight() {
int numberFields = getFieldCount();
if (numberFields == 0)
return 0;
int rows = numberFields / _columnStyles.length;
int prefferedHeight = 0;
int[] rowHeights = new int[rows];
Arrays.fill(rowHeights, -1);
for (int i = 0; i < _columns; i++) {
for (int j = 0; j < rows; j++) {
Field field = getField(i, j);
if (field != null) {
int actualHeight = getPreferredHeightOfChild(field) + field.getMarginBottom() + field.getMarginTop();
rowHeights[j] = Math.max(actualHeight, rowHeights[j]);
}
}
}
for (int n = 0; n < rows; n++) {
prefferedHeight += rowHeights[n];
}
return prefferedHeight;
}
protected void sublayout(int layoutWidth, int layoutHeight) {
int numberFields = getFieldCount();
if (numberFields == 0)
return;
layoutWidth -= getPaddingLeft() + getPaddingRight();
layoutHeight -= getPaddingTop() + getPaddingBottom();
_columns = _columnStyles.length;
int styles[] = _columnStyles;
if (isStyle(Field.USE_ALL_WIDTH)) {
boolean found = false;
for (int n = 0; n < _columns; n++) {
if (styles[n] == SPLIT_REMAINING_WIDTH) {
found = true;
break;
}
}
if (!found) {
styles[_columns - 1] = SPLIT_REMAINING_WIDTH;
}
}
_rows = numberFields / _columns;
if ((numberFields % _columns) > 0)
_rows++;
_columnWidths = new int[_columns];
_rowHeights = new int[_rows];
Arrays.fill(_columnWidths, -1);
Arrays.fill(_rowHeights, -1);
for (int i = 0; i < _columns; i++) {
if (isColumnStyle(styles[i], FIXED_WIDTH)) {
_columnWidths[i] = _suggestedColumnWidths[i];
} else {
if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED)) {
for (int j = 0; j < _rows; j++) {
Field field = getField(i, j);
if (field != null) {
layoutChild(field, Math.max(0, layoutWidth - (field.getMarginLeft() + field.getMarginRight())),
Math.max(0, layoutHeight - (field.getMarginBottom() + field.getMarginTop())));
int actualWidth = getPreferredWidthOfChild(field) + field.getMarginLeft() + field.getMarginRight();
int actualHeight = getPreferredHeightOfChild(field) + field.getMarginBottom() + field.getMarginTop();
if (isColumnStyle(styles[i], USE_PREFERRED_WIDTH_WITH_MAXIMUM)) {
actualWidth = Math.min(actualWidth, _suggestedColumnWidths[i]);
}
_columnWidths[i] = Math.max(actualWidth, _columnWidths[i]);
_rowHeights[j] = Math.max(actualHeight, _rowHeights[j]);
}
}
}
}
}
int usedColumnWidth = 0;
int numUnassignedColumnWidths = 0;
for (int i = 0; i < _columns; i++) {
if (_columnWidths[i] >= 0) {
usedColumnWidth += _columnWidths[i] + ((i < (_columns - 1)) ? _horizPadding : 0);
} else {
numUnassignedColumnWidths++;
}
}
if (numUnassignedColumnWidths > 0) {
int remainingWidthToAssign = layoutWidth - usedColumnWidth;
if (remainingWidthToAssign < 0) {
remainingWidthToAssign = 0;
}
int splitRemainingWidth = (remainingWidthToAssign - ((numUnassignedColumnWidths - 1) * _horizPadding))
/ numUnassignedColumnWidths;
for (int i = 0; i < _columns; i++) {
int assignedWidth = Math.min(remainingWidthToAssign,
splitRemainingWidth);
if (_columnWidths[i] < 0) {
_columnWidths[i] = assignedWidth;
remainingWidthToAssign -= assignedWidth;
}
}
}
int currentRow = 0;
int currentColumn = 0;
int y = getPaddingTop();
for (int n = 0; n < numberFields; n++) {
Field field = getField(n);
if (!isColumnStyle(styles[currentColumn], USE_PREFERRED_SIZE)) {
layoutChild( field,
Math.max(0, _columnWidths[currentColumn] - (field.getMarginLeft() + field.getMarginRight())),
Math.max(0, layoutHeight - y - (field.getMarginBottom() + field.getMarginTop())));
}
_rowHeights[currentRow] =Math.max(_rowHeights[currentRow], field.getExtent().height + field.getMarginBottom() + field.getMarginTop());
currentColumn++;
if ((n == (numberFields - 1)) || (currentColumn >= _columns)) {
int x = getPaddingLeft();
for (int i = 0; i < currentColumn; i++) {
Field field1 = getField(i, currentRow);
XYPoint offset = calcAlignmentOffset(field1,
Math.max( 0, _columnWidths[i] - (field1.getMarginLeft() + field1.getMarginRight())),
Math.max(0, _rowHeights[currentRow] - (field1.getMarginBottom() + field1.getMarginTop())));
setPositionChild(field1, x + offset.x + field1.getMarginLeft(), y + offset.y + field1.getMarginTop());
x += _columnWidths[i] + _horizPadding;
}
y += _rowHeights[currentRow];
currentColumn = 0;
currentRow++;
}
}
int totalWidth = 0;
if (isStyle(Field.USE_ALL_WIDTH)) {
totalWidth = layoutWidth;
} else {
for (int i = 0; i < _columns; i++) {
totalWidth += _columnWidths[i] + ((i < (_columns - 1)) ? _horizPadding : 0);
}
}
totalWidth += getPaddingLeft() + getPaddingRight();
y += getPaddingBottom();
setExtent(totalWidth, Math.min(y, layoutHeight));
}
protected boolean navigationMovement(int dx, int dy, int status, int time) {
int focusIndex = getFieldWithFocusIndex();
int dirY = (dy > 0) ? 1 : -1;
int absY = Math.abs(dy);
for (int y = 0; y < absY; y++) {
focusIndex += _columns * dirY;
if (focusIndex < 0 || focusIndex >= getFieldCount()) {
return false;
} else {
Field f = getField(focusIndex);
if (f.isFocusable()) {
f.setFocus();
} else
y--;
}
}
int dirX = (dx > 0) ? 1 : -1;
int absX = Math.abs(dx);
for (int x = 0; x < absX; x++) {
focusIndex += dirX;
if (focusIndex < 0 || focusIndex >= getFieldCount()) {
return false;
} else {
Field f = getField(focusIndex);
if (f.isFocusable()) {
f.setFocus();
} else
x--;
}
}
return true;
}
private XYPoint calcAlignmentOffset(Field field, int width, int height) {
XYPoint offset = new XYPoint(0, 0);
long fieldStyle = field.getStyle();
long field_x_style = fieldStyle & Field.FIELD_HALIGN_MASK;
if (field_x_style == Field.FIELD_RIGHT) {
offset.x = width - field.getExtent().width;
} else if (field_x_style == Field.FIELD_HCENTER) {
offset.x = (width - field.getExtent().width) / 2;
}
long field_y_style = fieldStyle & Field.FIELD_VALIGN_MASK;
if (field_y_style == Field.FIELD_BOTTOM) {
offset.y = height - field.getExtent().height;
} else if (field_y_style == Field.FIELD_VCENTER) {
offset.y = (height - field.getExtent().height) / 2;
}
return offset;
}
}