blob: 750af7eb1614749233116aba5cdac917dca6af33 [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.jface;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jpt.common.ui.internal.swt.listeners.SWTListenerTools;
import org.eclipse.jpt.common.ui.jface.ItemLabelProvider;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
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.graphics.Image;
/**
* @param <M> the type of the provider's manager
*/
public abstract class AbstractModelItemLabelProvider<M extends ItemLabelProvider.Manager>
implements ItemLabelProvider
{
/* private-protected */ final Object item;
/* private-protected */ final M manager;
private final PropertyValueModel<ImageDescriptor> imageDescriptorModel;
private final PropertyChangeListener imageDescriptorListener;
private ImageDescriptor imageDescriptor;
private boolean refreshImage = true; // image can be null - must be accessed on the manager's UI thread
private Image image; // must be accessed on the manager's UI thread
private final PropertyValueModel<String> textModel;
private final PropertyChangeListener textListener;
private String text; // must be accessed on the manager's UI thread
private boolean disposed = false;
protected AbstractModelItemLabelProvider(Object item, M manager, PropertyValueModel<ImageDescriptor> imageDescriptorModel, PropertyValueModel<String> textModel) {
super();
if (item == null) {
throw new NullPointerException();
}
this.item = item;
if (manager == null) {
throw new NullPointerException();
}
this.manager = manager;
if (imageDescriptorModel == null) {
throw new NullPointerException();
}
this.imageDescriptorModel = imageDescriptorModel;
if (textModel == null) {
throw new NullPointerException();
}
this.textModel = textModel;
this.imageDescriptorListener = this.buildImageDescriptorListener();
this.imageDescriptorModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.imageDescriptorListener);
this.imageDescriptor = this.imageDescriptorModel.getValue();
this.textListener = this.buildTextListener();
this.textModel.addPropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
this.text = this.textModel.getValue();
}
// ********** image **********
/**
* Return the image (lazy-initialized).
* <p><strong>NB:</strong>
* Wait until the UI requests a new image to dispose of the old image;
* because the old image is held and used by the UI (i.e. the UI does not
* call this method <em>every</em> time it accesses the image).
* Also, there should be no chance of a concurrent access to the image
* (as held elsewhere) while this method is executing, as this method is
* called from the UI thread and the other references to the image are
* accessed only from the UI thread (and those references will be replaced
* by the image returned by this method, while continuing on the UI thread).
*/
public Image getImage() {
if (this.refreshImage) {
if (this.image != null) {
this.manager.getResourceManager().destroyImage(this.imageDescriptor);
}
this.image = this.buildImage();
this.refreshImage = false;
}
return this.image;
}
private Image buildImage() {
return (this.imageDescriptor == null) ? null : this.manager.getResourceManager().createImage(this.imageDescriptor);
}
private PropertyChangeListener buildImageDescriptorListener() {
return SWTListenerTools.wrap(this.buildImageDescriptorListener_(), this.manager.getViewer());
}
private PropertyChangeListener buildImageDescriptorListener_() {
return new ImageDescriptorListener();
}
/* CU private */ class ImageDescriptorListener
extends PropertyChangeAdapter
{
@Override
public void propertyChanged(PropertyChangeEvent event) {
AbstractModelItemLabelProvider.this.imageDescriptorChanged((ImageDescriptor) event.getNewValue());
}
}
/* CU private */ void imageDescriptorChanged(ImageDescriptor newValue) {
if (this.isAlive()) {
this.imageDescriptorChanged_(newValue);
}
}
private void imageDescriptorChanged_(ImageDescriptor newValue) {
this.refreshImage = true;
this.imageDescriptor = newValue;
this.manager.labelChanged(this.item);
}
// ********** text **********
public String getText() {
return this.text;
}
private PropertyChangeListener buildTextListener() {
return SWTListenerTools.wrap(this.buildTextListener_(), this.manager.getViewer());
}
private PropertyChangeListener buildTextListener_() {
return new TextListener();
}
/* CU private */ class TextListener
extends PropertyChangeAdapter
{
@Override
public void propertyChanged(PropertyChangeEvent event) {
AbstractModelItemLabelProvider.this.textChanged((String) event.getNewValue());
}
}
/* CU private */ void textChanged(String newValue) {
if (this.isAlive()) {
this.textChanged_(newValue);
}
}
private void textChanged_(String newValue) {
this.text = newValue;
this.manager.labelChanged(this.item);
}
// ********** dispose **********
public void dispose() {
this.textModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.textListener);
this.text = null;
if (this.image != null) {
this.manager.getResourceManager().destroyImage(this.imageDescriptor);
this.image = null;
}
this.refreshImage = true;
this.imageDescriptorModel.removePropertyChangeListener(PropertyValueModel.VALUE, this.imageDescriptorListener);
this.imageDescriptor = null;
this.disposed = true;
}
// ********** misc **********
/**
* @see org.eclipse.jface.viewers.StructuredViewer#update(Object, String[])
*/
public boolean isLabelProperty(String property) {
return true; // since the updates are triggered by this provider, this is probably always true
}
/**
* Check whether the provider was disposed between the time an event was
* fired and the time the event is handled on the UI thread.
*/
/* private-protected */ boolean isAlive() {
return ! this.disposed;
}
@Override
public String toString() {
return ObjectTools.toString(this, this.item);
}
}