/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package de.cismet.cids.editors;
import Sirius.navigator.tools.MetaObjectCache;
import Sirius.server.middleware.types.MetaClass;
import Sirius.server.middleware.types.MetaClassStore;
import Sirius.server.middleware.types.MetaObject;
import org.jdesktop.beansbinding.Converter;
import org.jdesktop.beansbinding.Validator;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingWorker;
import de.cismet.cids.dynamics.CidsBean;
import de.cismet.tools.CismetThreadPool;
/**
* DOCUMENT ME!
*
* @author therter
* @version $Revision$, $Date$
*/
public class DefaultBindableRadioButtonField extends JPanel implements Bindable, MetaClassStore, ActionListener {
//~ Static fields/initializers ---------------------------------------------
private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
DefaultBindableRadioButtonField.class);
private static final String BINDING_PROPERTY = "selectedElements";
//~ Instance fields --------------------------------------------------------
private boolean enableLabels = true;
private HashMap<Object, Icon> icons = null;
private String iconProperty = null;
private ButtonGroup bg = new ButtonGroup();
private CidsBean selectedElements = null;
private MetaClass mc = null;
private Map<JRadioButton, MetaObject> boxToObjectMapping = new HashMap<JRadioButton, MetaObject>();
private PropertyChangeSupport support = new PropertyChangeSupport(this);
private volatile boolean threadRunning = false;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new CustomReferencedCheckboxField object.
*/
public DefaultBindableRadioButtonField() {
}
//~ Methods ----------------------------------------------------------------
@Override
public void addPropertyChangeListener(final PropertyChangeListener listener) {
if (this.support != null) {
this.support.addPropertyChangeListener(listener);
}
}
@Override
public void removePropertyChangeListener(final PropertyChangeListener listener) {
if (this.support != null) {
this.support.removePropertyChangeListener(listener);
}
}
/**
* DOCUMENT ME!
*
* @param element DOCUMENT ME!
*/
public void setSelectedElements(final Object element) {
if (element instanceof CidsBean) {
this.selectedElements = (CidsBean)element;
} else {
if (element != null) {
LOG.error("Selected element is not a CidsBean.");
}
}
if (setThreadRunning()) {
activateElement();
threadRunning = false;
}
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Object getSelectedElements() {
return selectedElements;
}
@Override
public String getBindingProperty() {
return BINDING_PROPERTY;
}
@Override
public Validator getValidator() {
return null;
}
@Override
public Converter getConverter() {
return null;
}
@Override
public Object getNullSourceValue() {
return null;
}
@Override
public Object getErrorSourceValue() {
return null;
}
@Override
public MetaClass getMetaClass() {
return this.mc;
}
@Override
public void setMetaClass(final MetaClass metaClass) {
if (LOG.isDebugEnabled()) {
LOG.debug("set meta class " + ((metaClass != null) ? metaClass.getName() : "null"));
}
CismetThreadPool.execute(new SwingWorker<MetaObject[], Void>() {
@Override
protected MetaObject[] doInBackground() throws Exception {
Thread.currentThread().setName("DefaultBindableRadioButtonField setMetaClass()");
while (!setThreadRunning()) {
try {
Thread.sleep(50);
} catch (final InterruptedException e) {
// nothing to do
}
}
bg = new ButtonGroup();
boxToObjectMapping = new HashMap<JRadioButton, MetaObject>();
mc = metaClass;
if (mc != null) {
final String query = "select " + mc.getID() + ", " + mc.getPrimaryKey() + " from "
+ mc.getTableName();
return MetaObjectCache.getInstance().getMetaObjectsByQuery(query, mc.getDomain());
} else {
LOG.error("Meta class is null.", new Throwable());
}
return null;
}
@Override
protected void done() {
try {
DefaultBindableRadioButtonField.this.removeAll();
JRadioButton button = null;
final MetaObject[] metaObjects = get();
if (icons == null) {
DefaultBindableRadioButtonField.this.setLayout(new GridLayout(metaObjects.length, 1));
} else {
DefaultBindableRadioButtonField.this.setLayout(new GridLayout(metaObjects.length, 2));
}
if (LOG.isDebugEnabled()) {
LOG.debug(metaObjects.length + " objects found.");
}
for (final MetaObject tmpMc : metaObjects) {
button = new JRadioButton();
button.addActionListener(DefaultBindableRadioButtonField.this);
button.setOpaque(false);
button.setContentAreaFilled(false);
if (enableLabels) {
button.setText(tmpMc.getBean().toString());
}
bg.add(button);
if (icons != null) {
final Icon i = icons.get(tmpMc.getBean().getProperty(iconProperty));
final JLabel l = new JLabel();
if (i != null) {
l.setIcon(i);
}
l.setSize(i.getIconWidth(), i.getIconHeight());
add(l);
}
add(button);
boxToObjectMapping.put(button, tmpMc);
if (Thread.currentThread().isInterrupted()) {
return;
}
}
activateElement();
} catch (final Exception e) {
LOG.error("Exception while filling a radio button field.", e);
} finally {
threadRunning = false;
}
}
});
}
/**
* DOCUMENT ME!
*/
private synchronized void activateElement() {
if (selectedElements != null) {
final Iterator<JRadioButton> it = boxToObjectMapping.keySet().iterator();
while (it.hasNext()) {
final JRadioButton tmp = it.next();
final MetaObject mo = boxToObjectMapping.get(tmp);
if ((mo != null) && selectedElements.equals(mo.getBean())) {
bg.setSelected(tmp.getModel(), true);
}
}
} else {
this.bg.clearSelection();
}
}
/**
* DOCUMENT ME!
*
* @param decider DOCUMENT ME!
* @param removeSelectedElements DOCUMENT ME!
*/
public void refreshCheckboxState(final FieldStateDecider decider, final boolean removeSelectedElements) {
CismetThreadPool.execute(new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
Thread.currentThread().setName("DefaultBindableRadioButtonField refreshCheckboxState");
while (!setThreadRunning()) {
try {
Thread.sleep(50);
} catch (final InterruptedException e) {
// nothing to do
}
}
return null;
}
@Override
protected void done() {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("refresh CheckboxState", new Exception());
}
final Iterator<JRadioButton> it = boxToObjectMapping.keySet().iterator();
if (removeSelectedElements) {
selectedElements = null;
}
while (it.hasNext()) {
final JRadioButton button = it.next();
button.setEnabled(
decider.isCheckboxForClassActive(boxToObjectMapping.get(button)));
button.setSelected(false);
if (Thread.currentThread().isInterrupted()) {
return;
}
}
activateElement();
} finally {
threadRunning = false;
}
}
});
}
/**
* DOCUMENT ME!
*/
public void dispose() {
}
@Override
public void actionPerformed(final ActionEvent ae) {
final MetaObject mo = boxToObjectMapping.get((JRadioButton)ae.getSource());
final Object old = selectedElements;
selectedElements = mo.getBean();
support.firePropertyChange(BINDING_PROPERTY, old, mo.getBean());
}
/**
* DOCUMENT ME!
*
* @return the icons
*/
public HashMap<Object, Icon> getIcons() {
return icons;
}
/**
* DOCUMENT ME!
*
* @param icons the icons to set
* @param iconProperty DOCUMENT ME!
*/
public void setIcons(final HashMap<Object, Icon> icons, final String iconProperty) {
this.icons = icons;
this.iconProperty = iconProperty;
}
/**
* DOCUMENT ME!
*
* @return the enableLabels
*/
public boolean isEnableLabels() {
return enableLabels;
}
/**
* DOCUMENT ME!
*
* @param enableLabels the enableLabels to set
*/
public void setEnableLabels(final boolean enableLabels) {
this.enableLabels = enableLabels;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
private synchronized boolean setThreadRunning() {
if (threadRunning) {
return false;
} else {
threadRunning = true;
return true;
}
}
}