Edit node property causes deselection?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Edit node property causes deselection?

ogeva
Hi,
I have a problem with nodes properties.
I have a simple nodes tree view, where nodes (representing server appliances) can be created and set with basic parameters such as ip, username/password etc.
They are displayed by a simple tree view, and are edited by the built in property viewer. These are all simple BeanNodes wrapping simple pojo ApplianceEntity objects.

The problem is that whenever I am editing a node's property, it gets deselected, and the next node is selected.
I could not find any hint as to why this could happen in the very simple code....

The nodes are persisted to filespace.
ApplianceEntity:

Code:

@ConvertAsJavaBean()
public class ApplianceEntity {
private final Logger log = LoggerFactory.getLogger("Appliance Tools");
    private String address;
    private String sshUserName;
    private String sshPassword;
    private String dbAddress;
    private String dbUserName;
    private String dbPassword;
    private ApplianceType applianceType = ApplianceType.UNKNOWN;
       
    public enum ApplianceType {
        VAPP, APPX, UNKNOWN
    };


    private final PropertyChangeSupport propertyChangeSupport;

    public ApplianceEntity() {
        propertyChangeSupport = new PropertyChangeSupport(this);
    }

    public ApplianceEntity(String address) {
        propertyChangeSupport = new PropertyChangeSupport(this);
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        String old = this.address;
        this.address=address;
        propertyChangeSupport.firePropertyChange("address", old, address);
    }

    public String getSshUserName() {
        return sshUserName;
    }

    public void setSshUserName(String sshUserName) {
        String old = this.sshUserName;
        this.sshUserName = sshUserName;
        propertyChangeSupport.firePropertyChange("sshUserName", old, sshUserName);
    }

    public String getSshPassword() {
        return sshPassword;
    }

    public void setSshPassword(String sshPassword) {
        String old = this.sshPassword;
        this.sshPassword = sshPassword;
        propertyChangeSupport.firePropertyChange("sshPassword", old, sshPassword);
    }

    public String getDbAddress() {
        return this.dbAddress;
    }

    public void setDbAddress(String dbAddress) {
        String old = this.dbAddress;
        this.dbAddress=dbAddress;
        propertyChangeSupport.firePropertyChange("dbAddress", old, dbAddress);
    }

    public String getDbUserName() {
        return this.dbUserName;
    }

    public void setDbUserName(String dbUserName) {
        String old = this.dbUserName;
        this.dbUserName=dbUserName;
        propertyChangeSupport.firePropertyChange("dbUserName", old, dbUserName);
    }

    public String getDbPassword() {
        return this.dbPassword;
    }

    public void setDbPassword(String dbPassword) {
        String old = this.dbPassword;
        this.dbPassword=dbPassword;
        propertyChangeSupport.firePropertyChange("dbPassword", old, dbPassword);
    }
    public ApplianceType getApplianceType() {
        return applianceType;
    }
    public void setApplianceType(ApplianceType applianceType) {
        ApplianceType old = this.applianceType;
        this.applianceType = applianceType;
        propertyChangeSupport.firePropertyChange("applianceType", old, applianceType);
    }
   

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[")
                .append("address:" + address + ",")
                .append("]");
        return sb.toString();
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.propertyChangeSupport.removePropertyChangeListener(listener);
    }

}






RootNode:

Code:

public class AppliancesRootNode extends AbstractNode {

    Logger log = LoggerFactory.getLogger("Appliance Tools");

    public AppliancesRootNode(Children applianceChildren) throws IntrospectionException {
        super(applianceChildren);
        setName("Appliances");
        if (FileUtil.getConfigFile("Appliances") == null) {
            try {
                FileUtil.getConfigRoot().createFolder("Appliances");
            } catch (IOException ex) {
                log.log(QALevel.FAIL, ex.getMessage(), ex);
            }
        }
    }

    @Override
    public Action[] getActions(boolean context) {
        return new Action[]{SystemAction.get(NewAction.class)};
    }

    @Override
    public NewType[] getNewTypes() {
        return new NewType[]{new NewType() {
            @Override
            public String getName() {
                return "Appliance";
            }

            @Override
            public void create() throws IOException {

                NotifyDescriptor.InputLine msg
                        = new NotifyDescriptor.InputLine(
                                "New Appliance",
                                "Address");
                DialogDisplayer.getDefault().notify(msg);
                ApplianceEntity bean = new ApplianceEntity(msg.getInputText());
                InstanceDataObject.create(
                        DataFolder.findFolder(FileUtil.getConfigFile("Appliances")),
                        bean.getAddress(),
                        bean,
                        null,
                        true
                );
            }
        }};
    }

}




AppliaceEntityNode

Code:

public class ApplianceEntityNode extends BeanNode<ApplianceEntity> {

    public ApplianceEntityNode(ApplianceEntity obj) throws IntrospectionException {
        super(obj, Children.LEAF, Lookups.singleton(obj));
        setDisplayName(obj.getAddress());
    }

    @Override
    public Action[] getActions(boolean context) {
        return new Action[]{(SystemAction.get(DeleteAction.class))};
    }

    @Override
    public boolean canDestroy() {
        return true;
    }

    @Override
    public void destroy() throws IOException {
        fireNodeDestroyed();
    }
   
}



ChildFactory:

Code:

class ApplianceChildFactory extends ChildFactory.Detachable<ApplianceEntity> implements LookupListener, NodeListener {

    Result<ApplianceEntity> result;
    Logger log = LoggerFactory.getLogger("Appliance Tools");

    public ApplianceChildFactory() {
    }

    @Override
    protected void addNotify() {
        result = Lookups.forPath("Appliances").lookupResult(ApplianceEntity.class);
        result.addLookupListener(this);
    }

    @Override
    protected void removeNotify() {
        result.removeLookupListener(this);
    }

    @Override
    protected boolean createKeys(List<ApplianceEntity> list) {
        if(!result.allInstances().isEmpty()) {
        list.addAll(result.allInstances());
    }
        return true;
    }

    @Override
    protected Node createNodeForKey(ApplianceEntity key) {
        ApplianceEntityNode applianceNode = null;

        try {
//            NodeOperation.getDefault().showProperties(new ApplianceEntityNode(key));
            applianceNode = new ApplianceEntityNode(key);

            applianceNode.addNodeListener(this);
        } catch (IntrospectionException ex) {
            Exceptions.printStackTrace(ex);
        }
        return applianceNode;
    }

    @Override
    public void resultChanged(LookupEvent le) {
        refresh(true);
    }
   
   

    @Override
    public void nodeDestroyed(NodeEvent ev) {
       
        ApplianceEntity removedAppliance = ev.getNode().getLookup().lookup(ApplianceEntity.class);
        for (FileObject fo : FileUtil.getConfigFile("Appliances").getChildren()) {
            ApplianceEntity appliance = FileUtil.getConfigObject(fo.getPath(), ApplianceEntity.class);
            if (removedAppliance == appliance) {
                try {
                    fo.delete();
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        }
        refresh(true);
    }
   
   

    @Override
    public void childrenAdded(NodeMemberEvent nme) {

    }

    @Override
    public void childrenRemoved(NodeMemberEvent nme) {

    }

    @Override
    public void childrenReordered(NodeReorderEvent nre) {

    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {

    }

}





The top component has an explorer manager, and is initialized like this:


Code:

   public ApplianceExplorerTopComponent() throws IntrospectionException {
        initComponents();
        setName(Bundle.CTL_ApplianceEditorTopComponent());
        setToolTipText(Bundle.HINT_ApplianceEditorTopComponent());

        //open properties window
        TopComponent t = WindowManager.getDefault().findTopComponent("properties");
        if (t != null) {
            WindowManager wm = WindowManager.getDefault();
            t.open();
        }

        //add delete action
        ActionMap map = getActionMap();
        map.put("delete", ExplorerUtils.actionDelete(mgr, true));
        associateLookup(ExplorerUtils.createLookup(mgr, map));

        setLayout(new BorderLayout());
        BeanTreeView view = new BeanTreeView();
       
        add(view, BorderLayout.CENTER);

        mgr.setRootContext(new AppliancesRootNode(Children.create(new ApplianceChildFactory(), true)));
    }




Thanks




Reply | Threaded
Open this post in threaded view
|

Edit node property causes deselection?

ogeva
Hmm. Apparently removed the property change support from the Entity bean did the trick.
But it makes it harder to bind JavaFX controls this way.

Is there any way to avoid that effect? What registers there?




Reply | Threaded
Open this post in threaded view
|

Re: Edit node property causes deselection?

Tim Boudreau-3
If you want to know what is causing the selection change, your best bet is to instrument your PropertyChangeListener to print a stack trace when editing is aborted because selection is changing.  Somewhere in that stack trace will be the culprit.

-Tim

On Sun, Jan 1, 2017 at 4:05 AM, ogeva <[hidden email]> wrote:
Hmm. Apparently removed the property change support from the Entity bean did the trick.
But it makes it harder to bind JavaFX controls this way.

Is there any way to avoid that effect? What registers there?







--
Reply | Threaded
Open this post in threaded view
|

Edit node property causes deselection?

ogeva
In reply to this post by ogeva
Yes, but I didn't implement the property change listener.
I added PropertyChangeSupport to allow @ConvertAsJavaBean to work, persisting the object to xml when changed and reloading it.
It's a netbeans platform feature of the settings api...

I could implement it manually probably, just drop the annotation and serialize the objects manually on change without reading them back.
And only read them on start up or module load...

But it would have been a neat feature, had it worked as expected.




Reply | Threaded
Open this post in threaded view
|

Edit node property causes deselection?

ogeva
In reply to this post by ogeva
Oh well. It's working as expected.
The problematic line was

Code:
    @Override
    public void resultChanged(LookupEvent le) {
        refresh(true);
    }



In the child factory class.
It would refresh the nodes collection on any change, and a change was triggered by the property change. then the selected node would get deselected...
I am not sure why it was there. It was probably copied early on when working with a tutorial or something.