at.spardat.xma.mdl.simple.SimpleUIDelegateClient Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
* 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:
* s IT Solutions AT Spardat GmbH - initial API and implementation
*******************************************************************************/
// @(#) $Id: SimpleUIDelegateClient.java 9374 2012-04-20 12:55:42Z hoenninger $
package at.spardat.xma.mdl.simple;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import at.spardat.enterprise.exc.SysException;
import at.spardat.enterprise.fmt.AParseException;
import at.spardat.enterprise.fmt.IFmt;
import at.spardat.enterprise.util.Types;
import at.spardat.xma.mdl.AttachmentExceptionClient;
import at.spardat.xma.mdl.ModelChangeEvent;
import at.spardat.xma.mdl.UIDelegateClient;
import at.spardat.xma.mdl.ValidationErrorClient;
import at.spardat.xma.mdl.WModel;
import at.spardat.xma.page.EventAdapter;
import at.spardat.xma.page.PageClient;
import at.spardat.xma.widgets.DatePicker;
/**
* The UIDelegateClient for a SimpleWM. Responsible for handling all UI-related stuff
* of a SimpleWidgetModel.
*
* The following attachements are eligible:
*
* SimpleWM SWT-Control
* -----------------------------------------------------
* T_BOOLEAN Button of types CHECK, RADIO, TOGGLE
* T_* every model may be attached to Text and Label controls.
*
*/
public class SimpleUIDelegateClient extends UIDelegateClient {
/**
* The attached SWT-control.
*/
private Control control_;
/**
* The opional label usually positioned at the left hand side of the control.
*/
private Label label_;
/**
* The widget model.
*/
private SimpleWMClient wModel_;
/**
* Keep track of whether we are updating the UI.
*/
private boolean updatingUI_ = false;
/**
* Editable-state
*/
private boolean editable_ = true;
/**
* The enabled-property
*/
private boolean enabled_ = true;
/**
* The validateUneditable-property
*/
private boolean validateUneditable_ = false;
/**
* Constructor
*/
public SimpleUIDelegateClient (SimpleWMClient model) {
wModel_ = model;
}
// see at.spardat.xma.mdl.UIDelegateClient.createControl()
public Object createControl(Object parent) {
Control control;
if(!(parent instanceof Composite)) throw new IllegalArgumentException("parent must be a composite");
Composite parentComp = (Composite)parent;
switch(wModel_.getType()) {
case Types.T_STRING:
case Types.T_BCD:
case Types.T_TIMESTAMP:
control = new Text(parentComp,SWT.SINGLE|SWT.BORDER|SWT.LEFT);
break;
case Types.T_DATE:
control = new DatePicker(parentComp, SWT.SINGLE|SWT.BORDER|SWT.LEFT,DatePicker.RED_WEEKEND);
((DatePicker)control).setDatePickerLocale(wModel_.getPageModelC().getComponent().getContext().getLocale());
break;
case Types.T_BOOLEAN:
control = new Button (parentComp, SWT.CHECK|SWT.LEFT);
break;
default:
throw new SysException("unsupported simple widget model type");
}
return control;
}
// see at.spardat.xma.mdl.UIDelegateClient.addListeners()
public void addListeners(Object control, EventAdapter adapter) {
if(control instanceof Text) {
((Text)control).addFocusListener(adapter);
((Text)control).addModifyListener(adapter);
((Text)control).addVerifyListener(adapter);
} else if(control instanceof Label) {
// no listener needed
} else if(control instanceof Button) {
((Button)control).addSelectionListener(adapter);
} else if(control instanceof DatePicker) {
((DatePicker)control).getDateTextField().addFocusListener(adapter);
((DatePicker)control).getDateTextField().addModifyListener(adapter);
((DatePicker)control).getDateTextField().addVerifyListener(adapter);
} else throw new IllegalArgumentException("unsupported control type: "+control.getClass().getName());
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#attachUI(java.lang.Object, java.lang.Object)
*/
public void attachUI (Object control, Object label) throws AttachmentExceptionClient {
boolean attach = false;
if (control instanceof Button) {
// radio boxes, check boxes and toggle buttons
// may be attached if the type of the WidgetModel is T_BOOLEAN
Button b = (Button) control;
int style = b.getStyle();
if ((style & SWT.TOGGLE) != 0 ||
(style & SWT.CHECK) != 0 ||
(style & SWT.RADIO) != 0) {
// the Button type is ok
if (wModel_.getType() == Types.T_BOOLEAN) attach = true;
}
} else if (control instanceof Text || control instanceof Label) {
// Text and Label controls may be attached to any kind of SimpleWM
attach = true;
} else if (control instanceof DatePicker) {
control = ((DatePicker)control).getDateTextField();
((Control)control).setData(this);
attach = true;
}
if (!attach) throw new AttachmentExceptionClient ("cannot attach " + control.getClass().getName() + " to SimpleWModel");
control_ = (Control) control;
if (label != null && label instanceof Label) {
label_ = (Label) label;
}
// move values to UI
updateUI();
// set the editable state on the control
if (control_ instanceof Text){
setControlEditable((Text)control_,editable_);
}
//if the control is already disabled, set this at enabled_ - otherwise do not change enabled_
//as in the Gen class the GUI designer disable property is set directly at the widget (only for some models)
enabled_ = control_.getEnabled()?enabled_:false;
setEnabled(enabled_); //set the model's enabled state at the control
updateErrorState();
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#detachUI()
*/
public void detachUI () {
// clear error state
wModel_.getPageModelC().clearValidationErrorImpl(control_);
wModel_.getPageModelC().clearError(control_);
wModel_.getPageModelC().getDialogPage().clearWarning(control_);
wModel_.getPageModelC().getDialogPage().clearInfo(control_);
if(control_!=null) {
enabled_=control_.getEnabled();
}
control_ = null;
label_ = null;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#getUIControl()
*/
public Object getUIControl () {
if (!isUIAttached()) throw new IllegalStateException ("not attached");
return control_;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#getUILabel()
*/
public Object getUILabel() {
if (!isUIAttached()) throw new IllegalStateException ("not attached");
return label_;
}
/**
* The following events must be notified from SWT widgets:
*
* Widget EVENT
* --------------------------------------------------------------------
* Button (RADIO, CHECK, TOGGLE) SelectionEvent
* Text VerifyEvent, ModifyEvent, FocusEvent from FocusListener.focusLost
* (important: do not call with FocusEvents from focusGained method).
*
*
* @see at.spardat.xma.mdl.UIDelegateClient#handleUIEvent(Object,int type)
*/
public void handleUIEvent (Object event, int type) {
if (!isUIAttached()) return;
if (updatingUI_) {
// this is very dangerous. We update the UI and although not finished yet,
// we receive an UI event.
// System.err.println ("got " + event + " while updating the UI; ignored ...");
return;
}
// sanity check: the Widget in the event must be control_
if (event instanceof TypedEvent) {
if (((TypedEvent)event).widget != control_) {
System.err.println ("widget in event differs from control in UIDelegate; event ignored ...");
return;
}
}
// SWT-VerifyEvent
if (event instanceof VerifyEvent) {
handleVerifyEvent ((VerifyEvent)event);
}
// SWT-ModifyEvent
else if (event instanceof ModifyEvent) {
handleModifyEvent ((ModifyEvent)event);
}
// SWT-SelectionEvent (with Buttons)
else if (event instanceof SelectionEvent) {
handleSelectionEvent ((SelectionEvent)event);
}
// SWT-FocusEvent (focusLost)
else if (event instanceof FocusEvent) {
handleFocusLostEvent ((FocusEvent)event);
}
}
/**
* Handles swt.events.VerifyEvent. Rejects the input characters if the formatter
* of the WidgetModel decides to do so.
*/
private void handleVerifyEvent (VerifyEvent ev) {
if (!wModel_.doUITransfer()) { ev.doit = false; return; }
IFmt fmt = wModel_.getFmtInternal();
// ask the formatter if the input characters are allowed
if (fmt != null) {
// check characters of the inserted text
for (int i=0; i 0 ) {
if ( evTextLength <= charsToMuch ) {
ev.doit = false;
return;
}
else {
ev.text = ev.text.substring(0,evTextLength - charsToMuch);
}
}
}
}
}
/**
* Handles swt.events.ModifyEvent. This tells us, that the control has been successfully changed
* by the user. The task here is to reflect the change in the WidgetModel.
*/
private void handleModifyEvent (ModifyEvent ev) {
UI2Model();
}
/**
* transfer the content of the widget into the model
*/
protected void UI2Model() {
if (control_ instanceof Text) {
String contents = ((Text)control_).getText();
SimpleWM.UserModifiedTextEvent modEvent = wModel_.new UserModifiedTextEvent (contents);
wModel_.handle(modEvent);
updateErrorState();
}
}
/**
* Handles swt.events.SelectionEvent. This event is notified by the UI if the state
* of a button changes.
*/
private void handleSelectionEvent (SelectionEvent ev) {
if (control_ instanceof Button) {
if (editable_) {
boolean selected = ((Button)control_).getSelection();
wModel_.handle(wModel_.new BooleanChangeEvent (selected, true));
} else {
// in the case a button is not editable, we cannot prevent the SWT-widget
// from getting input. So we restore the widget without changing the model.
updateUI();
}
}
}
/**
* When a Text field looses focus, its text is adjusted.
*/
private void handleFocusLostEvent (FocusEvent event) {
if (control_ instanceof Text && (control_.getStyle() & SWT.READ_ONLY) == 0 && editable_) {
IFmt fmt = wModel_.getFmtInternal();
if (fmt != null && !fmt.isOneWay() && wModel_.doUITransfer()) {
// in order to get a normalized representation, we first
// convert the text into the internal string encoding of
// the formatter, followed by a conversion back to the
// external encoding.
String uiText = ((Text)control_).getText();
String internal = null;
try {
internal = fmt.parse(uiText);
} catch (AParseException ex) {
}
if (internal != null) {
((Text)control_).setText(fmt.format(internal));
}
}
}
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#handleModelChangeEvent(ModelChangeEvent)
*/
public void handleModelChangeEvent (ModelChangeEvent event) {
// if the UI is not attached, do nothing
if (!isUIAttached()) return;
// otherwise update UI
updateUI();
updateErrorState();
}
/**
* Sets the widget to the current value of the model. The only situation where
* widget and model may differ, is if the widget contains a value not accepted by the
* validiator. In this case the model contains the last known valid value.
*/
public void resetWidgetFromModel() {
updatingUI_ = true;
try {
updateUI();
updateErrorState();
} finally {
updatingUI_ = false;
}
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#isUIAttached()
*/
public boolean isUIAttached () {
return control_ != null;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#getWModel()
*/
public WModel getWModel() {
return wModel_;
}
/**
* Transfers the value contained in the widget model to the UI-control.
*/
private void updateUI () {
updatingUI_ = true;
try {
// first the case with the Buttons and the T_BOOLEAN
if (control_ instanceof Button) {
((Button)control_).setSelection(wModel_.isTrue());
} else {
// the case with every kind of text
setTextOnUI (wModel_.getFormattedString());
}
} finally {
updatingUI_ = false;
}
}
/**
* Helper method to set the text in a Label or Text control, regardless of whether it
* is a Label or a Text.
*/
protected void setTextOnUI (String text) {
if (control_ instanceof Label) {
((Label)control_).setText(text);
} else if (control_ instanceof Text) {
((Text)control_).setText(text);
}
}
/**
* This method must be called after every change in an SWT Text control to update
* the error state information (i.e., keep track of the validation errors in
* entry fields).
*/
void updateErrorState () {
if (control_ instanceof Text && (isEditable() || isValidateIfUneditable())) {
// validation errors at Text widgets which are not read only.
String text = ((Text)control_).getText();
IFmt formatter = wModel_.getFmtInternal();
if (formatter == null || formatter.isOneWay()) {
// clear a previous error state
wModel_.getPageModelC().clearValidationErrorImpl(control_);
return;
}
// pass the text through the formatter to check if it is legitimate external
// input for the widget model
AParseException parseException = null;
try {
formatter.parse(text);
} catch (AParseException ex) {
parseException = ex;
}
PageClient pageModel = wModel_.getPageModelC();
if (parseException != null) {
// construct a ValidationErrorClient object and register it with the Page
pageModel.setValidationErrorImpl(new ValidationErrorClient (wModel_, control_, getLabelText(), parseException));
} else {
// clear a previous error state
pageModel.clearValidationErrorImpl(control_);
}
}
}
/**
* If inError, this method sets the background of the corresponding Control c
* to the error color defined in ComponentClient. If inError is false,
* the background is reset to the default color.
*/
public void setErrorColor (boolean inError) {
wModel_.getPageModelC().getPageEffects().errorStateChanged(control_,isEditable(),inError);
}
/**
* Returns the text of the label which may be null, if the label is unknown.
*/
private String getLabelText () {
String text = label_ != null ? label_.getText() : null;
return text;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#isEnabled()
*/
public boolean isEnabled () {
if (isUIAttached()) {
//always take the state from the widget (if it was set directly on it) as this is the old behavior
enabled_ = control_.isEnabled();
}
return enabled_;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#setEnabled(boolean)
*/
public void setEnabled (boolean what) {
enabled_ = what;
if (isUIAttached()){
if(control_.getParent() instanceof DatePicker){
control_.getParent().setEnabled(what);
}else{
control_.setEnabled(what);
}
}
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#isEditable()
*/
public boolean isEditable () {
return editable_;
}
/**
* @see at.spardat.xma.mdl.UIDelegateClient#setEditable(boolean)
*/
public void setEditable (boolean what) {
editable_ = what;
if (isUIAttached()) {
// with Text-widgets, use the editable property of the text
if (control_ instanceof Text){
setControlEditable((Text)control_,what);
}
if (!isEditable() && !isValidateIfUneditable()){
//Clear the validation-error if widget is not editable and not to validate in this state
wModel_.getPageModelC().clearValidationErrorImpl(control_);
}else{
//evaluate error if widget is editable or isValidateIfUneditable() is true
updateErrorState();
}
}
}
/**
* @see at.spardat.xma.mdl.simple.ISimpleWMClient#isValidateIfUneditable()
*
* @return the validateUneditable property
* @since version_number
* @author s3460
*/
public boolean isValidateIfUneditable() {
return validateUneditable_;
}
/**
* @see at.spardat.xma.mdl.simple.ISimpleWMClient#setValidateIfUneditable(boolean)
*
* @param what
* @since version_number
* @author s3460
*/
public void setValidateIfUneditable(boolean what) {
this.validateUneditable_ = what;
if (!isEditable() && !isValidateIfUneditable()){
//Clear the validation-error if widget is not editable and not to validate in this state
wModel_.getPageModelC().clearValidationErrorImpl(control_);
}else{
//evaluate error if widget is editable or isValidateIfUneditable() is true
updateErrorState();
}
}
/**
* Checks if the parent of the control has to be set editable too.
* @param text
* @param what
* @since version_number
* @author S3460
*/
private static void setControlEditable(Text text, boolean what){
if(text.getParent() instanceof DatePicker){
((DatePicker)text.getParent()).setEditable(what);
}else {
text.setEditable(what);
}
}
}