blob: cfb1fd2215e1cb7203a0cd53a67f41af901c1f9e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*******************************************************************************/
package org.eclipse.scout.rt.ui.rap.form.fields.datefield;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
import org.eclipse.scout.commons.CompareUtility;
import org.eclipse.scout.commons.holders.Holder;
import org.eclipse.scout.commons.job.JobEx;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.datefield.IDateField;
import org.eclipse.scout.rt.ui.rap.LogicalGridLayout;
import org.eclipse.scout.rt.ui.rap.ext.ButtonEx;
import org.eclipse.scout.rt.ui.rap.ext.StatusLabelEx;
import org.eclipse.scout.rt.ui.rap.ext.StyledTextEx;
import org.eclipse.scout.rt.ui.rap.ext.custom.StyledText;
import org.eclipse.scout.rt.ui.rap.form.fields.IPopupSupport;
import org.eclipse.scout.rt.ui.rap.form.fields.LogicalGridDataBuilder;
import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutValueFieldComposite;
import org.eclipse.scout.rt.ui.rap.form.fields.datefield.chooser.TimeChooserDialog;
import org.eclipse.scout.rt.ui.rap.internal.TextFieldEditableSupport;
import org.eclipse.scout.rt.ui.rap.keystroke.RwtKeyStroke;
import org.eclipse.scout.rt.ui.rap.util.RwtLayoutUtility;
import org.eclipse.scout.rt.ui.rap.util.RwtUtility;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
//TODO RAP 2.0 Migration
//check shell listener removel
public class RwtScoutTimeField extends RwtScoutValueFieldComposite<IDateField> implements IRwtScoutTimeField, IPopupSupport {
private Button m_dropDownButton;
private TextFieldEditableSupport m_editableSupport;
private Set<IPopupSupportListener> m_popupEventListeners;
private Object m_popupEventListenerLock;
private boolean m_ignoreLabel = false;
private Composite m_timeContainer;
private boolean m_dateTimeCompositeMember;
private String m_displayTextToVerify;
private TimeChooserDialog m_timeChooserDialog = null;
private FocusAdapter m_textFieldFocusAdapter = null;
private P_TimeChooserDisposeListener m_disposeListener;
@Override
public void setIgnoreLabel(boolean ignoreLabel) {
m_ignoreLabel = ignoreLabel;
if (ignoreLabel) {
getUiLabel().setVisible(false);
}
else {
getUiLabel().setVisible(getScoutObject().isLabelVisible());
}
}
public boolean isIgnoreLabel() {
return m_ignoreLabel;
}
public boolean isDateTimeCompositeMember() {
return m_dateTimeCompositeMember;
}
@Override
public void setDateTimeCompositeMember(boolean dateTimeCompositeMember) {
m_dateTimeCompositeMember = dateTimeCompositeMember;
}
@Override
protected void initializeUi(Composite parent) {
m_popupEventListeners = new HashSet<IPopupSupportListener>();
m_popupEventListenerLock = new Object();
Composite container = getUiEnvironment().getFormToolkit().createComposite(parent);
StatusLabelEx label = getUiEnvironment().getFormToolkit().createStatusLabel(container, getScoutObject());
m_timeContainer = getUiEnvironment().getFormToolkit().createComposite(container, SWT.BORDER);
m_timeContainer.setData(WidgetUtil.CUSTOM_VARIANT, VARIANT_TIMEFIELD);
StyledText textField = new StyledTextEx(m_timeContainer, SWT.SINGLE);
getUiEnvironment().getFormToolkit().adapt(textField, false, false);
textField.setData(WidgetUtil.CUSTOM_VARIANT, VARIANT_TIMEFIELD);
ButtonEx timeChooserButton = getUiEnvironment().getFormToolkit().createButtonEx(m_timeContainer, SWT.PUSH | SWT.NO_FOCUS);
timeChooserButton.setData(WidgetUtil.CUSTOM_VARIANT, VARIANT_TIMEFIELD);
m_timeContainer.setTabList(new Control[]{textField});
container.setTabList(new Control[]{m_timeContainer});
// key strokes on container
getUiEnvironment().addKeyStroke(container, new P_TimeChooserOpenKeyStroke(), false);
// key strokes on field
getUiEnvironment().addKeyStroke(textField, new P_ShiftNextQuarterHourKeyStroke(), false);
getUiEnvironment().addKeyStroke(textField, new P_ShiftPreviousQuarterHourKeyStroke(), false);
getUiEnvironment().addKeyStroke(textField, new P_ShiftNextHourKeyStroke(), false);
getUiEnvironment().addKeyStroke(textField, new P_ShiftPreviousHourKeyStroke(), false);
// listener
timeChooserButton.addListener(ButtonEx.SELECTION_ACTION, new P_RwtBrowseButtonListener());
textField.addMouseListener(new MouseAdapter() {
private static final long serialVersionUID = 1L;
@Override
public void mouseUp(MouseEvent e) {
handleUiTimeChooserAction();
}
});
//
setUiContainer(container);
setUiLabel(label);
setDropDownButton(timeChooserButton);
setUiField(textField);
// layout
container.setLayout(new LogicalGridLayout(1, 0));
m_timeContainer.setLayoutData(LogicalGridDataBuilder.createField(((IFormField) getScoutObject()).getGridData()));
m_timeContainer.setLayout(RwtLayoutUtility.createGridLayoutNoSpacing(2, false));
GridData textLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
textField.setLayoutData(textLayoutData);
GridData buttonLayoutData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
buttonLayoutData.heightHint = 20;
buttonLayoutData.widthHint = 20;
timeChooserButton.setLayoutData(buttonLayoutData);
}
@Override
public Button getDropDownButton() {
return m_dropDownButton;
}
public void setDropDownButton(ButtonEx b) {
m_dropDownButton = b;
}
@Override
public StyledTextEx getUiField() {
return (StyledTextEx) super.getUiField();
}
public boolean isFocusInTimePicker() {
Control focusControl = getUiEnvironment().getDisplay().getFocusControl();
boolean isFocusInDatePicker = RwtUtility.isAncestorOf(m_timeChooserDialog.getShell(), focusControl);
return isFocusInDatePicker;
}
private void installFocusListenerOnTextField() {
if (getUiField().isDisposed()) {
return;
}
getUiField().setFocus();
if (m_textFieldFocusAdapter == null) {
m_textFieldFocusAdapter = new FocusAdapter() {
private static final long serialVersionUID = 1L;
@Override
public void focusLost(FocusEvent e) {
handleUiFocusLostOnDatePickerPopup(e);
}
};
}
getUiField().addFocusListener(m_textFieldFocusAdapter);
}
/**
* The event is fired only if the time picker popup is open.
* <p>
* The default sets the focus on the ui field if the new focus is inside the time picker. <br/>
* If the new focus is outside the time picker it makes sure the time picker popup will be closed.
* </p>
*/
protected void handleUiFocusLostOnDatePickerPopup(FocusEvent event) {
if (isFocusInTimePicker()) {
getUiEnvironment().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
getUiField().setFocus();
}
});
}
else {
getUiEnvironment().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
makeSureTimeChooserIsClosed();
}
});
}
}
private void uninstallFocusListenerOnTextField() {
if (!getUiField().isDisposed() && m_textFieldFocusAdapter != null) {
getUiField().removeFocusListener(m_textFieldFocusAdapter);
}
}
@Override
protected void setEnabledFromScout(boolean b) {
super.setEnabledFromScout(b);
m_dropDownButton.setEnabled(b);
getUiField().setEnabled(b);
if (b) {
m_timeContainer.setData(WidgetUtil.CUSTOM_VARIANT, VARIANT_TIMEFIELD);
}
else {
m_timeContainer.setData(WidgetUtil.CUSTOM_VARIANT, VARIANT_TIMEFIELD_DISABLED);
}
}
@Override
protected void setLabelVisibleFromScout() {
if (!isIgnoreLabel()) {
super.setLabelVisibleFromScout();
}
}
@Override
protected void setFieldEnabled(Control rwtField, boolean enabled) {
if (m_editableSupport == null) {
m_editableSupport = new TextFieldEditableSupport(getUiField());
}
m_editableSupport.setEditable(enabled);
}
@Override
protected void setDisplayTextFromScout(String s) {
IDateField scoutField = getScoutObject();
if (s == null) {
s = "";
}
m_displayTextToVerify = s;
Date value = scoutField.getValue();
if (value != null) {
DateFormat format = scoutField.getIsolatedTimeFormat();
if (format != null) {
m_displayTextToVerify = format.format(value);
}
}
getUiField().setText(m_displayTextToVerify);
getUiField().setCaretOffset(0);
}
@Override
protected void setBackgroundFromScout(String scoutColor) {
setBackgroundFromScout(scoutColor, m_timeContainer);
}
@Override
protected void handleUiInputVerifier(boolean doit) {
if (!doit) {
return;
}
final String text = getUiField().getText();
// only handle if text has changed
if (CompareUtility.equals(text, m_displayTextToVerify) && (isDateTimeCompositeMember() || getScoutObject().getErrorStatus() == null)) {
return;
}
m_displayTextToVerify = text;
final Holder<Boolean> result = new Holder<Boolean>(Boolean.class, false);
// notify Scout
Runnable t = new Runnable() {
@Override
public void run() {
boolean b = getScoutObject().getUIFacade().setTimeTextFromUI(text);
result.setValue(b);
}
};
JobEx job = getUiEnvironment().invokeScoutLater(t, 0);
try {
job.join(2345);
}
catch (InterruptedException e) {
//nop
}
getUiEnvironment().dispatchImmediateUiJobs();
// end notify
return;
}
@Override
protected void handleUiFocusGained() {
if (isSelectAllOnFocusEnabled()) {
getUiField().setSelection(0, getUiField().getText().length());
}
}
protected void makeSureTimeChooserIsClosed() {
if (m_timeChooserDialog != null
&& m_timeChooserDialog.getShell() != null
&& !m_timeChooserDialog.getShell().isDisposed()) {
m_timeChooserDialog.getShell().close();
}
uninstallFocusListenerOnTextField();
}
private void handleUiTimeChooserAction() {
if (!getDropDownButton().isVisible() || !getDropDownButton().isEnabled()) {
return;
}
Date oldTime = getScoutObject().getValue();
if (oldTime == null) {
oldTime = new Date();
}
notifyPopupEventListeners(IPopupSupportListener.TYPE_OPENING);
makeSureTimeChooserIsClosed();
m_timeChooserDialog = createTimeChooserDialog(getUiField().getShell(), oldTime);
if (m_timeChooserDialog != null) {
m_disposeListener = new P_TimeChooserDisposeListener();
m_timeChooserDialog.getShell().addDisposeListener(m_disposeListener);
m_timeChooserDialog.openTimeChooser(getUiField());
installFocusListenerOnTextField();
}
}
protected TimeChooserDialog createTimeChooserDialog(Shell parentShell, Date currentTime) {
return new TimeChooserDialog(parentShell, currentTime);
}
private void getTimeFromClosedDateChooserDialog() {
if (m_disposeListener != null) {
m_timeChooserDialog.getShell().removeDisposeListener(m_disposeListener);
}
boolean setFocusToUiField = false;
try {
final Date newDate = m_timeChooserDialog.getReturnTime();
if (newDate != null) {
setFocusToUiField = true;
// notify Scout
Runnable t = new Runnable() {
@Override
public void run() {
getScoutObject().getUIFacade().setTimeFromUI(newDate);
}
};
getUiEnvironment().invokeScoutLater(t, 0);
// end notify
}
}
finally {
notifyPopupEventListeners(IPopupSupportListener.TYPE_CLOSED);
uninstallFocusListenerOnTextField();
if (setFocusToUiField
&& !getUiField().isDisposed()) {
getUiField().setFocus();
}
}
}
private void notifyPopupEventListeners(int eventType) {
IPopupSupportListener[] listeners;
synchronized (m_popupEventListenerLock) {
listeners = m_popupEventListeners.toArray(new IPopupSupportListener[m_popupEventListeners.size()]);
}
for (IPopupSupportListener listener : listeners) {
listener.handleEvent(eventType);
}
}
@Override
public void addPopupEventListener(IPopupSupportListener listener) {
synchronized (m_popupEventListenerLock) {
m_popupEventListeners.add(listener);
}
}
@Override
public void removePopupEventListener(IPopupSupportListener listener) {
synchronized (m_popupEventListenerLock) {
m_popupEventListeners.remove(listener);
}
}
/**
*
*/
private final class P_TimeChooserDisposeListener implements DisposeListener {
private static final long serialVersionUID = 1L;
@Override
public void widgetDisposed(DisposeEvent event) {
getTimeFromClosedDateChooserDialog();
}
}
private class P_RwtBrowseButtonListener implements Listener {
private static final long serialVersionUID = 1L;
public P_RwtBrowseButtonListener() {
}
@Override
public void handleEvent(Event event) {
switch (event.type) {
case ButtonEx.SELECTION_ACTION:
getUiField().forceFocus();
handleUiTimeChooserAction();
break;
default:
break;
}
}
} // end class P_RwtBrowseButtonListener
private void shiftTime(final int level, final int value) {
if (getUiField().isDisposed()) {
return;
}
if (getUiField().isEnabled()
&& getUiField().getEditable()
&& getUiField().isVisible()) {
if (level >= 0) {
// notify Scout
Runnable t = new Runnable() {
@Override
public void run() {
getScoutObject().getUIFacade().fireTimeShiftActionFromUI(level, value);
}
};
getUiEnvironment().invokeScoutLater(t, 0);
// end notify
}
}
}
private class P_ShiftNextQuarterHourKeyStroke extends RwtKeyStroke {
public P_ShiftNextQuarterHourKeyStroke() {
super(SWT.ARROW_UP);
}
@Override
public void handleUiAction(Event e) {
int level = 0;
int value = 1;
shiftTime(level, value);
}
}
private class P_ShiftPreviousQuarterHourKeyStroke extends RwtKeyStroke {
public P_ShiftPreviousQuarterHourKeyStroke() {
super(SWT.ARROW_DOWN);
}
@Override
public void handleUiAction(Event e) {
int level = 0;
int value = -1;
shiftTime(level, value);
}
}
private class P_ShiftNextHourKeyStroke extends RwtKeyStroke {
public P_ShiftNextHourKeyStroke() {
super(SWT.ARROW_UP, SWT.SHIFT);
}
@Override
public void handleUiAction(Event e) {
int level = 1;
int value = 1;
shiftTime(level, value);
}
}
private class P_ShiftPreviousHourKeyStroke extends RwtKeyStroke {
public P_ShiftPreviousHourKeyStroke() {
super(SWT.ARROW_DOWN, SWT.SHIFT);
}
@Override
public void handleUiAction(Event e) {
int level = 1;
int value = -1;
shiftTime(level, value);
}
}
private class P_TimeChooserOpenKeyStroke extends RwtKeyStroke {
public P_TimeChooserOpenKeyStroke() {
super(SWT.F2);
}
@Override
public void handleUiAction(Event e) {
handleUiTimeChooserAction();
}
}
}