blob: 6e8722cecc1369502a8f8f55ae4cdcef3fc73062 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2013 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.ui.internal.swt.bind;
import org.eclipse.jpt.common.ui.internal.listeners.SWTPropertyChangeListenerWrapper;
import org.eclipse.jpt.common.ui.internal.swt.events.DisposeAdapter;
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.PropertyValueModel;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Widget;
/**
* This binding can be used to keep a <em>label</em>
* synchronized with a image and text models.
*
* @see PropertyValueModel
* @see WidgetLabelAdapter
*/
class LabelModelBinding {
// ***** model
/** A value model on the underlying model image. */
private final PropertyValueModel<Image> imageModel;
/**
* A listener that allows us to synchronize the label's image with
* the model image.
*/
private final PropertyChangeListener imageListener;
/** A value model on the underlying model text. */
private final PropertyValueModel<String> textModel;
/**
* A listener that allows us to synchronize the label's text with
* the model text.
*/
private final PropertyChangeListener textListener;
// ***** UI
/** The <em>label</em> we synchronize with the image and text models. */
private final WidgetLabelAdapter labelAdapter;
/**
* A listener that allows us to stop listening to stuff when the widget
* is disposed. (Critical for preventing memory leaks.)
*/
private final DisposeListener widgetDisposeListener;
// ********** construction **********
/**
* Constructor - the models and label adapter are required.
*/
LabelModelBinding(PropertyValueModel<Image> imageModel, PropertyValueModel<String> textModel, WidgetLabelAdapter labelAdapter) {
super();
if ((imageModel == null) || (textModel == null) || (labelAdapter == null)) {
throw new NullPointerException();
}
this.imageModel = imageModel;
this.textModel = textModel;
this.labelAdapter = labelAdapter;
this.imageListener = this.buildImageListener();
this.imageModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.imageListener);
this.textListener = this.buildTextListener();
this.textModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
this.widgetDisposeListener = this.buildWidgetDisposeListener();
this.getWidget().addDisposeListener(this.widgetDisposeListener);
this.setImage(this.imageModel.getValue());
this.setText(this.textModel.getValue());
}
private PropertyChangeListener buildImageListener() {
return new SWTPropertyChangeListenerWrapper(new ImageListener());
}
/* CU private */ class ImageListener
extends PropertyChangeAdapter
{
@Override
public void propertyChanged(PropertyChangeEvent event) {
LabelModelBinding.this.setImage((Image) event.getNewValue());
}
}
private PropertyChangeListener buildTextListener() {
return new SWTPropertyChangeListenerWrapper(new TextListener());
}
/* CU private */ class TextListener
extends PropertyChangeAdapter
{
@Override
public void propertyChanged(PropertyChangeEvent event) {
LabelModelBinding.this.setText((String) event.getNewValue());
}
}
private DisposeListener buildWidgetDisposeListener() {
return new WidgetDisposeListener();
}
/* CU private */ class WidgetDisposeListener
extends DisposeAdapter
{
@Override
public void widgetDisposed(DisposeEvent event) {
LabelModelBinding.this.widgetDisposed();
}
}
// ********** model events **********
/* CU private */ void setImage(Image image) {
if ( ! this.getWidget().isDisposed()) {
this.labelAdapter.setImage(image);
}
}
/* CU private */ void setText(String text) {
if ( ! this.getWidget().isDisposed()) {
this.labelAdapter.setText((text != null) ? text : StringTools.EMPTY_STRING);
}
}
private Widget getWidget() {
return this.labelAdapter.getWidget();
}
// ********** UI events **********
/* CU private */ void widgetDisposed() {
// the widget is not yet "disposed" when we receive this event
// so we can still remove our listener
this.getWidget().removeDisposeListener(this.widgetDisposeListener);
this.imageModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.imageListener);
this.textModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
}
// ********** misc **********
@Override
public String toString() {
return ObjectTools.toString(this, this.textModel);
}
}