/*******************************************************************************
* Copyright 2011 Antti Havanko
*
* This file is part of Motiver.fi.
* Motiver.fi is licensed under one open source license and one commercial license.
*
* Commercial license: This is the appropriate option if you want to use Motiver.fi in
* commercial purposes. Contact license@motiver.fi for licensing options.
*
* Open source license: This is the appropriate option if you are creating an open source
* application with a license compatible with the GNU GPL license v3. Although the GPLv3 has
* many terms, the most important is that you must provide the source code of your application
* to your users so they can be free to modify your application for their own needs.
******************************************************************************/
/*
* Shows timeselect window below given textfield
*/
package com.delect.motiver.client.view;
import java.util.Date;
import com.google.gwt.user.client.Event;
import com.delect.motiver.client.AppController;
import com.delect.motiver.client.Motiver;
import com.delect.motiver.shared.util.CommonUtils;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.Popup;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.layout.TableLayout;
/**
* Shows timeselect textfield
*/
public class TimeSelectFieldView extends TextField<String> {
public interface TimeSelectFieldHandler {
void timeChanged(int time);
}
private TimeSelectFieldHandler handler;
//widgets
private Text[] labelHours = new Text[24];
private Listener<ComponentEvent> listenerLabelMouseOut = new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
if(be.getComponent() instanceof Text) {
Text l = ((Text)be.getComponent());
l.removeStyleName("label-time-select-sel");
}
setValue(CommonUtils.getTimeToString(origValue));
}
};
private int Hours = 0;
private int Minutes = 0;
private int origValue = 0;
private HorizontalPanel pMinutesBottom;
private HorizontalPanel pMinutesTop;
private Popup popup = null;
//Parameters: textfield containing time
@SuppressWarnings("deprecation")
public TimeSelectFieldView(int time, TimeSelectFieldHandler h) {
this.handler = h;
this.setMaxLength(10);
this.setWidth(65);
this.setAllowBlank(false);
if(AppController.User.getTimeFormat() == 0)
this.setRegex("(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9])");
else
this.setRegex("(0?[0-9]|1[0-9]|2[0-3]):([0-5][0-9]) [a-zA-z]{2}[.]?");
CommonUtils.setWarningMessages(this);
this.getMessages().setRegexText(AppController.Lang.FieldTimeFormat());
this.addListener(Events.OnKeyUp, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent event) {
try {
if(isValid()) {
int seconds = CommonUtils.getTimeToSeconds(getValue());
origValue = seconds;
Hours = origValue / 3600;
Minutes = (origValue - (Hours * 3600))/60;
//fire time selected event
if(handler != null) {
handler.timeChanged( seconds );
}
popup.hide();
popup = null;
}
} catch (Exception ignored) { }
}
});
this.setValue(CommonUtils.getTimeToString(time));
origValue = time;
//parse orig value
try {
Date d = new Date(time * 1000);
Hours = d.getHours();
Minutes = d.getMinutes();
} catch (Exception e) {
}
//open popup when clicked
this.addListener(Events.OnClick, new Listener<ComponentEvent>() {
@SuppressWarnings("unchecked")
@Override
public void handleEvent(ComponentEvent be) {
try {
if(popup == null) {
popup = new Popup();
popup.setWidth("370px");
popup.setHeight("105px");
initPopup();
}
final TextField<String> tf = (TextField<String>)be.getSource();
popup.show(tf.getElement(), "", new int[] {3, 22} );
} catch (Exception e) {
Motiver.showException(e);
}
}
});
sinkEvents(Event.ONCLICK);
}
private void initPopup() {
LayoutContainer panelContent = new LayoutContainer();
//bottom minutes
pMinutesTop = new HorizontalPanel();
pMinutesTop.setHeight(20);
pMinutesBottom = new HorizontalPanel();
//add minutes to top
panelContent.add(pMinutesTop);
//add times (before 12)
final LayoutContainer panel1 = panelHours(true, 0, 11);
panelContent.add(panel1);
//add times (after 12)
final LayoutContainer panel2 = panelHours(false, 12, 23);
panelContent.add(panel2);
//add minutes to bottom
panelContent.add(pMinutesBottom);
panelContent.layout();
popup.add(panelContent);
//reset orig value when popup is hidden
popup.addListener(Events.Hide, listenerLabelMouseOut);
}
protected void setHours(boolean setValue, int hours) {
try {
Hours = hours;
int seconds = Hours * 3600 + Minutes * 60;
setValue(CommonUtils.getTimeToString(seconds));
if(setValue) {
origValue = seconds;
popup.hide();
popup = null;
//fire time selected event
if(handler != null) {
handler.timeChanged( seconds );
}
}
} catch (Exception e) {
Motiver.showException(e);
}
}
/*
* Creates hours panel
* Parameters: which minutes are shown, hours min, max
*/
LayoutContainer panelHours(final boolean showTopMinutes, int start, int end) {
final LayoutContainer panelHour = new LayoutContainer();
panelHour.setLayout(new TableLayout(12));
for(int i=start; i <= end; i++) {
Text l = new Text(((i < 10)? "0" : "") + i);
l.setStyleName("label-time-select");
l.setData("h", i);
labelHours[i] = l;
l.addListener(Events.OnMouseOver, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
Text l = ((Text)be.getComponent());
l.addStyleName("label-time-select-sel");
int x = l.getAbsoluteLeft() - panelHour.getAbsoluteLeft();
if(showTopMinutes) {
pMinutesTop.removeAll();
pMinutesTop.add(panelMinutes());
pMinutesTop.setStyleAttribute("margin-left", x + "px");
pMinutesTop.layout();
pMinutesBottom.removeAll();
pMinutesBottom.layout();
}
else {
pMinutesBottom.removeAll();
pMinutesBottom.add(panelMinutes());
pMinutesBottom.setStyleAttribute("margin-left", x + "px");
pMinutesBottom.layout();
pMinutesTop.removeAll();
pMinutesTop.layout();
}
//remove style from other hours
for(int k=0; k < labelHours.length; k++) {
if(!labelHours[k].equals(l)) {
labelHours[k].removeStyleName("label-time-select-sel");
}
}
setHours(false, Integer.parseInt(be.getComponent().getData("h").toString()));
}
});
l.addListener(Events.OnMouseUp, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
setHours(true, Integer.parseInt(be.getComponent().getData("h").toString()));
}
});
l.sinkEvents(Event.MOUSEEVENTS);
panelHour.add(l);
}
return panelHour;
}
/*
* Creates minutes panel
*/
LayoutContainer panelMinutes() {
//top minutes
final LayoutContainer panelMinute = new LayoutContainer();
panelMinute.setLayout(new TableLayout(12));
for(int i=0; i <= 55; i+=5) {
Text l1 = new Text(((i < 10)? "0":"") + i);
l1.setStyleName("label-time-select-min");
l1.setData("m", i);
l1.addListener(Events.OnMouseOver, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
Text l = ((Text)be.getComponent());
l.addStyleName("label-time-select-sel");
setMinutes(false, Integer.parseInt(be.getComponent().getData("m").toString()));
}
});
l1.addListener(Events.OnMouseOut, listenerLabelMouseOut);
l1.addListener(Events.OnMouseUp, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
setMinutes(true, Integer.parseInt(be.getComponent().getData("m").toString()));
}
});
l1.sinkEvents(Event.MOUSEEVENTS);
panelMinute.add(l1);
}
return panelMinute;
}
void setMinutes(boolean setValue, int minutes) {
try {
Minutes = minutes;
int seconds = Hours * 3600 + Minutes * 60;
setValue(CommonUtils.getTimeToString(seconds));
if(setValue) {
origValue = seconds;
popup.hide();
popup = null;
//fire time selected event
if(handler != null) {
handler.timeChanged( seconds );
}
}
} catch (Exception e) {
Motiver.showException(e);
}
}
/**
* Returns current time
* @return time in seconds
*/
public int getTime() {
return Hours * 3600 + Minutes * 60;
}
}