package nl.fontys.sofa.limo.view.node.bean; import java.awt.Image; import java.beans.IntrospectionException; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import javax.swing.ImageIcon; import nl.fontys.sofa.limo.api.dao.DAO; import nl.fontys.sofa.limo.domain.BaseEntity; import nl.fontys.sofa.limo.domain.component.Icon; import nl.fontys.sofa.limo.view.node.DetachableNode; import nl.fontys.sofa.limo.view.node.Deletable; import nl.fontys.sofa.limo.view.node.property.StupidProperty; import nl.fontys.sofa.limo.view.node.property.StupidProperty.PropertyGuard; import nl.fontys.sofa.limo.view.node.property.editor.IconPropertyEditor; import nl.fontys.sofa.limo.view.util.IconUtil; import nl.fontys.sofa.limo.view.util.LIMOResourceBundle; import org.openide.ErrorManager; import org.openide.nodes.BeanNode; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.lookup.AbstractLookup; import org.openide.util.lookup.InstanceContent; /** * AbstractBeanNode class which defines basic Node actions and creates a lookup * for the underlying bean. * * @author Sebastiaan Heijmann */ public abstract class AbstractBeanNode<T extends BaseEntity> extends BeanNode<T> implements DetachableNode, Deletable { private Class entityClass; private PropertyChangeListener listener; protected InstanceContent ic; protected T bean; /** * Abstract class which defines basic implementations for nodes and binds * the data model. The data model is available through the * AbstractBeanNode's lookup. * <p> * Override getActions and getNewTypes methods to define actions associated * with this Node. * * @param bean the underlying data model * @throws IntrospectionException */ public AbstractBeanNode(T bean, Class entityClass) throws IntrospectionException { this(bean, new InstanceContent()); this.entityClass = entityClass; } private AbstractBeanNode(T bean, InstanceContent ic) throws IntrospectionException { super(bean, Children.LEAF, new AbstractLookup(ic)); this.ic = ic; ic.add(bean); String description = bean.getDescription(); String name = bean.getName(); setShortDescription(description); setDisplayName(name); } @Override public Image getIcon(int type) { Image icon = IconUtil.getIcon(entityClass, type); if (icon == null) { return super.getIcon(type); } return icon; } @Override public void destroy() throws IOException { fireNodeDestroyed(); } /** * Get the property change listener. * * @return the property change listener. */ protected PropertyChangeListener getListener() { if (this.listener == null) { this.listener = (PropertyChangeEvent evt) -> { DAO service = (DAO) Lookup.getDefault().lookup(getServiceClass()); service.update(getBean()); firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); switch (evt.getPropertyName()) { case "name": setDisplayName((String) evt.getNewValue()); break; case "description": setShortDescription((String) evt.getNewValue()); break; case "icon": createProperties(getBean(), null); setSheet(getSheet()); break; } }; } return this.listener; } /** * Get the propertysheet for name and description. * * @return the propertysheet set. */ protected Sheet.Set getNameDescriptionPropertySheet() { Sheet.Set set = Sheet.createPropertiesSet(); set.setName("properties"); set.setDisplayName("General properties"); try { StupidProperty name = new StupidProperty<>(getBean(), String.class, "name"); // do not allow empty names name.setPropertyGuard((Object value) -> !((String)value).isEmpty()); name.addPropertyChangeListener(getListener()); name.setDisplayName(LIMOResourceBundle.getString("NAME")); name.setShortDescription(LIMOResourceBundle.getString("NAME_OF", LIMOResourceBundle.getString("EVENT"))); StupidProperty description = new StupidProperty<>(getBean(), String.class, "description"); description.addPropertyChangeListener(getListener()); description.setDisplayName(LIMOResourceBundle.getString("DESCRIPTION")); description.setShortDescription(LIMOResourceBundle.getString("DESCRIPTION_OF", LIMOResourceBundle.getString("EVENT"))); set.put(name); set.put(description); } catch (NoSuchMethodException ex) { ErrorManager.getDefault(); } return set; } /** * Get the propertysheet for the base entity. * * @return the propertysheet set. */ protected Sheet.Set getBaseEntityPropertySheet() { Sheet.Set set = this.getNameDescriptionPropertySheet(); try { StupidProperty iconProp = new StupidProperty(getBean(), Icon.class, "icon"); iconProp.addPropertyChangeListener(getListener()); iconProp.setPropertyEditorClass(IconPropertyEditor.HubIconPropertyEditor.class); iconProp.setDisplayName(LIMOResourceBundle.getString("ICON")); iconProp.setShortDescription(LIMOResourceBundle.getString("ICON_OF", LIMOResourceBundle.getString("HUB_TYPE"))); iconProp.setValue("valueIcon", new ImageIcon(getBeanIcon().getImage())); iconProp.setValue("canEditAsText", false); set.put(iconProp); } catch (NoSuchMethodException ex) { ErrorManager.getDefault(); } return set; } /** * Get the entity class name. * * @return Class - the class from this entity. */ public Class getEntityClass() { return entityClass; } /** * Get the service class of this bean. * * @return Class - the service class. */ abstract Class getServiceClass(); /** * Get the icon for this bean. * * @return the icon of the bean. */ protected abstract Icon getBeanIcon(); @Override public boolean canDestroy() { return false; } @Override public boolean canCut() { return false; } @Override public boolean canCopy() { return false; } @Override public boolean canRename() { return false; } }