blob: f0c9ac3cddd5d8371baf6b463c7979cdb28a5bd3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2013 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0, which accompanies this distribution
* and is available at https://www.eclipse.org/legal/epl-2.0/.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.ui.internal.swt.bindings;
import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter;
import org.eclipse.jpt.common.ui.internal.swt.events.ModifyAdapter;
import org.eclipse.jpt.common.ui.internal.swt.listeners.SWTListenerTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
import org.eclipse.jpt.common.utility.model.listener.PropertyChangeAdapter;
import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Text;
/**
* This binding can be used to keep a text field
* synchronized with a model text/string.
* <p>
* <strong>NB:</strong> This binding is bi-directional.
*
* @see ModifiablePropertyValueModel
* @see Text
*/
final class TextFieldModelBinding {
/**
* The text model we keep synchronized with the text field.
*/
private final ModifiablePropertyValueModel<String> textModel;
/**
* A listener that allows us to synchronize the text field's contents with
* the text model.
*/
private final PropertyChangeListener textListener;
/**
* The text field we keep synchronized with the text model.
*/
private final Text textField;
/**
* A listener that allows us to synchronize our text model
* with the text field's contents.
*/
private final ModifyListener textFieldModifyListener;
/**
* A listener that allows us to stop listening to stuff when the text field
* is disposed.
*/
private final DisposeListener textFieldDisposeListener;
// ********** constructor **********
/**
* Constructor - the text model and text field are required.
*/
TextFieldModelBinding(ModifiablePropertyValueModel<String> textModel, Text textField) {
super();
if ((textModel == null) || (textField == null)) {
throw new NullPointerException();
}
this.textModel = textModel;
this.textField = textField;
this.textListener = this.buildTextListener();
this.textModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
this.textFieldModifyListener = this.buildTextFieldModifyListener();
this.textField.addModifyListener(this.textFieldModifyListener);
this.textFieldDisposeListener = this.buildTextFieldDisposeListener();
this.textField.addDisposeListener(this.textFieldDisposeListener);
this.setTextFieldText(textModel.getValue());
}
// ********** initialization **********
private PropertyChangeListener buildTextListener() {
return SWTListenerTools.wrap(new TextListener(), this.textField);
}
/* CU private */ class TextListener
extends PropertyChangeAdapter
{
@Override
public void propertyChanged(PropertyChangeEvent event) {
TextFieldModelBinding.this.textChanged(event);
}
}
private ModifyListener buildTextFieldModifyListener() {
return new TextFieldModifyListener();
}
/* CU private */ class TextFieldModifyListener
extends ModifyAdapter
{
@Override
public void modifyText(ModifyEvent event) {
TextFieldModelBinding.this.textFieldModified();
}
}
private DisposeListener buildTextFieldDisposeListener() {
return new TextFieldDisposeListener();
}
/* CU private */ class TextFieldDisposeListener
extends DisposeAdapter
{
@Override
public void widgetDisposed(DisposeEvent event) {
TextFieldModelBinding.this.textFieldDisposed();
}
}
// ********** text model events **********
/* CU private */ void textChanged(PropertyChangeEvent event) {
if ( ! this.textField.isDisposed()) {
this.setTextFieldText((String) event.getNewValue());
}
}
private void setTextFieldText(String text) {
// the text model can be null, but the text field cannot
this.setTextFieldText_((text == null) ? StringTools.EMPTY_STRING : text);
}
private void setTextFieldText_(String text) {
if ( ! text.equals(this.textField.getText())) { // text field does not short-circuit
this.textField.setText(text);
}
}
// ********** text field events **********
/* CU private */ void textFieldModified() {
this.textModel.setValue(this.textField.getText());
}
/* CU private */ void textFieldDisposed() {
// the text field is not yet "disposed" when we receive this event
// so we can still remove our listeners
this.textField.removeDisposeListener(this.textFieldDisposeListener);
this.textField.removeModifyListener(this.textFieldModifyListener);
this.textModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
}
// ********** misc **********
@Override
public String toString() {
return ObjectTools.toString(this, this.textModel);
}
}