/*
* Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org
* Use is subject to license terms. See license.txt.
*/
package org.beanfabrics.swing;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import org.beanfabrics.IModelProvider;
import org.beanfabrics.Link;
import org.beanfabrics.ModelProvider;
import org.beanfabrics.ModelSubscriber;
import org.beanfabrics.Path;
import org.beanfabrics.View;
import org.beanfabrics.event.WeakPropertyChangeListener;
import org.beanfabrics.model.AbstractPM;
import org.beanfabrics.model.IIconPM;
import org.beanfabrics.model.ITextPM;
import org.beanfabrics.model.IValuePM;
/**
* The <code>BnLabel</code> is a {@link JLabel} that can subscribe to an {@link ITextPM}.
*
* @author Michael Karneim
* @author Marcel Eyke
* @beaninfo
*/
@SuppressWarnings("serial")
public class BnLabel extends JLabel implements View<ITextPM>, ModelSubscriber {
private final Link link = new Link(this);
private final PropertyChangeListener listener = new MyWeakPropertyChangeListener();
private class MyWeakPropertyChangeListener implements WeakPropertyChangeListener, Serializable {
public void propertyChange(PropertyChangeEvent evt) {
refresh();
}
};
private ITextPM pModel;
private ErrorIconPainter errorIconPainter = createDefaultErrorIconPainter();
/**
* Constructs a <code>BnLabel</code>.
*/
public BnLabel() {
}
/**
* Constructs a <code>BnLabel</code> and binds it to the specified model.
*
* @param pModel
* the model
*/
public BnLabel(ITextPM pModel) {
this();
setPresentationModel(pModel);
}
/**
* Constructs a <code>BnLabel</code> and subscribes it for the model at the specified Path provided by the given
* provider.
*
* @param provider
* @param path
*/
public BnLabel(ModelProvider provider, Path path) {
this.setModelProvider(provider);
this.setPath(path);
}
/**
* Constructs a <code>BnLabel</code> and subscribes it for the model at the root level provided by the given
* provider.
*
* @param provider
*/
public BnLabel(ModelProvider provider) {
this.setModelProvider(provider);
this.setPath(new Path());
}
/**
* Returns whether this component is connected to the target {@link AbstractPM} to synchronize with.
*
* @return <code>true</code> when this component is connected, else <code>false</code>
*/
boolean isConnected() {
return this.pModel != null;
}
/**
* Configures this component depending on the target {@link AbstractPM} s attributes.
*/
private void refresh() {
refreshText();
refreshIcon();
refreshToolTip();
}
/**
* Configures the tool tip of this component on the depending on the target {@link IValuePM}s attributes.
*/
private void refreshToolTip() {
if (this.pModel == null) {
this.setToolTipText(null);
} else {
this.setToolTipText(pModel.isValid() == false ? pModel.getValidationState().getMessage() : pModel
.getDescription());
}
}
/**
* Configures the tool tip of this component on the depending on the target {@link IIconPM}s attributes.
*/
private void refreshIcon() {
if (this.pModel instanceof IIconPM) {
IIconPM iconEditor = (IIconPM) this.pModel;
this.setIcon(iconEditor.getIcon());
} else {
this.setIcon(null);
}
}
/**
* Configures the text of this component on the depending on the target {@link ITextPM}s attributes.
*/
private void refreshText() {
if (this.pModel == null) {
this.setText("");
} else {
this.setText(pModel.getText());
}
}
private ErrorIconPainter createDefaultErrorIconPainter() {
ErrorIconPainter result = new ErrorIconPainter();
result.setHorizontalAlignment(invertHorizontalAlignment(getHorizontalAlignment()));
return result;
}
public ErrorIconPainter getErrorIconPainter() {
return errorIconPainter;
}
public void setErrorIconPainter(ErrorIconPainter aErrorIconPainter) {
if (aErrorIconPainter == null) {
throw new IllegalArgumentException("aErrorIconPainter == null");
}
this.errorIconPainter = aErrorIconPainter;
}
/** {@inheritDoc} */
@Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
if (shouldPaintErrorIcon()) {
errorIconPainter.paint(g, this);
}
}
private boolean shouldPaintErrorIcon() {
ITextPM pModel = this.getPresentationModel();
if (pModel == null) {
return false;
}
return (pModel.isValid() == false);
}
@Override
public void setHorizontalAlignment(int alignment) {
super.setHorizontalAlignment(alignment);
if (errorIconPainter != null) {
this.errorIconPainter.setHorizontalAlignment(invertHorizontalAlignment(alignment));
}
}
private int invertHorizontalAlignment(int alignment) {
switch (alignment) {
case SwingConstants.LEFT:
return SwingConstants.RIGHT;
case SwingConstants.RIGHT:
return SwingConstants.LEFT;
case SwingConstants.LEADING:
return SwingConstants.TRAILING;
case SwingConstants.TRAILING:
return SwingConstants.LEADING;
default:
return alignment;
}
}
/** {@inheritDoc} */
public ITextPM getPresentationModel() {
return pModel;
}
/** {@inheritDoc} */
public void setPresentationModel(ITextPM newModel) {
ITextPM oldModel = this.pModel;
if (this.pModel != null) {
this.pModel.removePropertyChangeListener(listener);
}
this.pModel = newModel;
if (this.pModel != null) {
this.pModel.addPropertyChangeListener(listener);
}
refresh();
this.firePropertyChange("presentationModel", oldModel, newModel);
}
/** {@inheritDoc} */
public void setModelProvider(IModelProvider provider) {
this.link.setModelProvider(provider);
}
/** {@inheritDoc} */
public IModelProvider getModelProvider() {
return link.getModelProvider();
}
/** {@inheritDoc} */
public void setPath(Path path) {
this.link.setPath(path);
}
/** {@inheritDoc} */
public Path getPath() {
return link.getPath();
}
}