This time, including a SaveCapability for the Node:
public class ShipNode extends BeanNode implements PropertyChangeListener { private final InstanceContent ic; private final ShipSaveCapability saveCookie; public ShipNode(Ship bean) throws IntrospectionException { this(bean, new InstanceContent()); } public ShipNode(Ship bean, InstanceContent ic) throws IntrospectionException { super(bean, Children.LEAF, new ProxyLookup(new AbstractLookup(ic),
      Lookups.singleton(bean))); this.ic = ic; setDisplayName(bean.getType()); setShortDescription(String.valueOf(bean.getYear())); saveCookie = new ShipSaveCapability(bean); bean.addPropertyChangeListener(WeakListeners.propertyChange(this, bean)); } @Override public Action[] getActions(boolean context) { List<? extends Action> shipActions = Utilities.actionsForPath("Actions/Ship"); return shipActions.toArray(new Action[shipActions.size()]); } protected void fire(boolean modified) { if (modified)
      { ic.add(saveCookie); } else { ic.remove(saveCookie); } } private class ShipSaveCapability implements SaveCookie { private final Ship bean; public ShipSaveCapability(Ship bean) { this.bean = bean; } @Override public void save() throws IOException { StatusDisplayer.getDefault().setStatusText("Saving..."); fire(false); } } @Override public boolean canRename() { return true; } @Override public void setName(String s) { Ship c = getLookup().lookup(Ship.class); String oldDisplayName = c.getType();
      c.setType(s); fireNameChange(oldDisplayName, s); fire(true); } @Override public String getDisplayName() { Ship c = getLookup().lookup(Ship.class); if (null != c.getType()) { return c.getType(); } return super.getDisplayName(); } @Override public String getShortDescription() { Ship c = getLookup().lookup(Ship.class); if (null != String.valueOf(c.getYear())) { return String.valueOf(c.getYear()); } return super.getShortDescription(); } @Override public void propertyChange(PropertyChangeEvent evt) { if
      (evt.getPropertyName().equals("type")) { String oldDisplayName = evt.getOldValue().toString(); String newDisplayName = evt.getNewValue().toString(); fireDisplayNameChange(oldDisplayName, newDisplayName); } else if (evt.getPropertyName().equals("year")) { String oldToolTip = evt.getOldValue().toString(); String newToolTip = evt.getNewValue().toString(); fireShortDescriptionChange(oldToolTip, newToolTip); } fire(true); } }"
 
 




 - and it was received very well indeed! The message of the Calligra Engine as a kind of WebKit for office applications is clear and easily understood, and the audience seemed very interested in this. Not only that, people seemed very interested in the fact that Calligra isn't just working on mobile versions, they're right around the corner. So, yes, it sounds like Calligra is, indeed, the future of office suites as hinted by
 - and it was received very well indeed! The message of the Calligra Engine as a kind of WebKit for office applications is clear and easily understood, and the audience seemed very interested in this. Not only that, people seemed very interested in the fact that Calligra isn't just working on mobile versions, they're right around the corner. So, yes, it sounds like Calligra is, indeed, the future of office suites as hinted by 