001package jmri.jmrix.openlcb.swing.networktree;
002
003import java.awt.Dimension;
004import javax.swing.JTree;
005import javax.swing.event.TreeSelectionEvent;
006import javax.swing.tree.DefaultMutableTreeNode;
007
008import jmri.*;
009import jmri.jmrix.can.CanListener;
010import jmri.jmrix.can.CanMessage;
011import jmri.jmrix.can.CanReply;
012import jmri.jmrix.can.CanSystemConnectionMemo;
013import jmri.jmrix.can.swing.CanPanelInterface;
014import jmri.jmrix.openlcb.swing.ClientActions;
015import jmri.util.JmriJFrame;
016
017import org.openlcb.Connection;
018import org.openlcb.MimicNodeStore;
019import org.openlcb.NodeID;
020import org.openlcb.OlcbInterface;
021import org.openlcb.SimpleNodeIdent;
022import org.openlcb.implementations.MemoryConfigurationService;
023import org.openlcb.swing.memconfig.MemConfigDescriptionPane;
024import org.openlcb.swing.memconfig.MemConfigReadWritePane;
025import org.openlcb.swing.networktree.NodeTreeRep;
026import org.openlcb.swing.networktree.TreePane;
027
028/**
029 * Frame displaying tree of OpenLCB nodes.
030 *
031 * @author Bob Jacobsen Copyright (C) 2009, 2010, 2012
032 */
033public class NetworkTreePane extends jmri.util.swing.JmriPanel implements CanListener, CanPanelInterface {
034
035    public NetworkTreePane() {
036        super();
037    }
038
039    private transient CanSystemConnectionMemo memo;
040
041    @Override
042    public void initContext(Object context) {
043        if (context instanceof CanSystemConnectionMemo) {
044            initComponents((CanSystemConnectionMemo) context);
045        }
046    }
047
048    @Override
049    public void initComponents(CanSystemConnectionMemo memo) {
050        this.memo = memo;
051
052        memo.getTrafficController().addCanListener(this);
053
054        // add GUI components
055        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
056
057        treePane = new TreePane(){
058            UserPreferencesManager pref = jmri.InstanceManager.getDefault(UserPreferencesManager.class);
059            String sortPreferenceName = NetworkTreePane.class.getName() + ".selectedSortOrder";
060
061            @Override
062            public void initComponents(MimicNodeStore store, final Connection connection,
063                            final NodeID node, final NodeTreeRep.SelectionKeyLoader loader) {
064                super.initComponents(store, connection, node, loader);
065                // finally handle sort-by JComboBox preferences WITHOUT setting preferences
066                var name = pref.getProperty(this.getClass().getName(), sortPreferenceName);
067                if (name == null) name = "BY_NAME";
068                SortOrder order;
069                try {
070                    order = SortOrder.valueOf((String)name);
071                } catch (IllegalArgumentException e) {
072                    order = SortOrder.BY_NAME;
073                }
074                super.setSortOrder(order);
075                // and do it a little later to make sure the table has been shown
076                final var localOrder = order;
077                jmri.util.ThreadingUtil.runOnLayoutDelayed( () -> {
078                    super.setSortOrder(localOrder);
079                }, 750
080                );
081            }
082            
083            // This overrides setOrder to preserve the order
084            @Override
085            public void setSortOrder(SortOrder order) {
086                pref.setProperty(this.getClass().getName(), sortPreferenceName, order.name());
087                super.setSortOrder(order);
088            }
089        };
090        treePane.setPreferredSize(new Dimension(300, 300));
091
092        treePane.initComponents(memo.get(MimicNodeStore.class), memo.get(Connection.class), memo.get(NodeID.class), new ActionLoader(memo)
093        );
094        add(treePane);
095
096        treePane.addTreeSelectionListener((TreeSelectionEvent e) -> {
097            JTree tree = (JTree) e.getSource();
098            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
099
100            if (node == null) {
101                return;
102            }
103
104            if (node.getUserObject() instanceof NodeTreeRep.SelectionKey) {
105                ((NodeTreeRep.SelectionKey) node.getUserObject()).select(node);
106            }
107        });
108    }
109
110    TreePane treePane;
111
112    @Override
113    public String getTitle() {
114        if (memo != null) {
115            return (memo.getUserName() + " Network Tree");
116        }
117        return "LCC / OpenLCB Network Tree";
118    }
119
120    @Override
121    public void dispose() {
122        memo.getTrafficController().removeCanListener(this);
123    }
124
125    @Override
126    public synchronized void message(CanMessage l) {  // receive a message and log it
127    }
128
129    @Override
130    public synchronized void reply(CanReply l) {  // receive a reply and log it
131    }
132
133    //private final static Logger log = LoggerFactory.getLogger(NetworkTreePane.class);
134
135    /**
136     * Nested class to open specific windows when proper tree element is picked.
137     */
138    private static class ActionLoader extends NodeTreeRep.SelectionKeyLoader {
139
140        private final ClientActions actions;
141
142        ActionLoader(CanSystemConnectionMemo memo) {
143            OlcbInterface iface = memo.get(OlcbInterface.class);
144            actions = new ClientActions(iface, memo);
145            this.store = iface.getNodeStore();
146            this.mcs = iface.getMemoryConfigurationService();
147        }
148
149        final MimicNodeStore store;
150        final MemoryConfigurationService mcs;
151
152        @Override
153        public NodeTreeRep.SelectionKey cdiKey(String name, NodeID node) {
154            return new NodeTreeRep.SelectionKey(name, node) {
155                @Override
156                public void select(DefaultMutableTreeNode rep) {
157                    MimicNodeStore.NodeMemo memo = store.findNode(node);
158                    SimpleNodeIdent ident = memo.getSimpleNodeIdent();
159                    StringBuilder description = new StringBuilder();
160                    if (ident.getUserName() != null) {
161                        description.append(ident.getUserName());
162                    }
163                    if (ident.getUserDesc() != null && ident.getUserDesc().length() > 0) {
164                        if (description.length() > 0) {
165                            description.append(" - ");
166                        }
167                        description.append(ident.getUserDesc());
168                    }
169                    if (description.length() == 0) {
170                        if (ident.getMfgName() != null && ident.getMfgName().length() > 0) {
171                            description.append(ident.getMfgName());
172                        }
173                        if (ident.getModelName() != null && ident.getModelName().length() > 0) {
174                            if (description.length() > 0) {
175                                description.append(" - ");
176                            }
177                            description.append(ident.getModelName());
178                        }
179                    }
180                    if (description.length() == 0) {
181                        description.append(node.toString());
182                    } else {
183                        description.append(" (");
184                        description.append(node.toString());
185                        description.append(")");
186                    }
187                    openCdiPane(node, description.toString());
188                }
189            };
190        }
191
192        @Override
193        public NodeTreeRep.SelectionKey configurationKey(String name, NodeID node) {
194            return new NodeTreeRep.SelectionKey(name, node) {
195                @Override
196                public void select(DefaultMutableTreeNode rep) {
197                    openConfigurePane(node);
198                }
199            };
200        }
201
202        void openConfigurePane(NodeID node) {
203            {
204                JmriJFrame f = new JmriJFrame();
205                f.setTitle("Configuration Capabilities " + node);
206                MemConfigDescriptionPane mc = new MemConfigDescriptionPane(node, store, mcs);
207                f.add(mc);
208                mc.initComponents();
209                f.pack();
210                f.setVisible(true);
211            }
212            {
213                JmriJFrame f = new JmriJFrame();
214                f.setTitle("Configuration R/W Tool " + node);
215                MemConfigReadWritePane mc = new MemConfigReadWritePane(node, store, mcs);
216                f.add(mc);
217                mc.initComponents();
218                f.pack();
219                f.setVisible(true);
220            }
221        }
222
223        public void openCdiPane(final NodeID destNode, String description) {
224            actions.openCdiWindow(destNode, description);
225        }
226    }
227
228}