001package jmri.jmrix.loconet.sdfeditor;
002
003import java.awt.Dimension;
004import java.awt.FlowLayout;
005import java.util.List;
006import java.util.ResourceBundle;
007import javax.swing.BoxLayout;
008import javax.swing.JComponent;
009import javax.swing.JEditorPane;
010import javax.swing.JLabel;
011import javax.swing.JPanel;
012import javax.swing.JScrollPane;
013import javax.swing.JSeparator;
014import javax.swing.JSplitPane;
015import javax.swing.JTree;
016import javax.swing.event.TreeSelectionEvent;
017import javax.swing.event.TreeSelectionListener;
018import javax.swing.tree.DefaultMutableTreeNode;
019import javax.swing.tree.TreePath;
020import javax.swing.tree.TreeSelectionModel;
021import jmri.jmrix.loconet.sdf.SdfBuffer;
022import jmri.jmrix.loconet.sdf.SdfMacro;
023
024/**
025 * Pane for editing Digitrax SDF files.
026 * <p>
027 * The GUI consists of a tree of instructions on the left, and on the right an
028 * edit panel. The edit panel has a small detailed view of the instruction over
029 * a larger detailed view.
030 *
031 * @author Bob Jacobsen Copyright (C) 2007, 2008
032 */
033public class EditorPane extends javax.swing.JPanel implements TreeSelectionListener {
034
035    // GUI member declarations
036    static ResourceBundle res = ResourceBundle.getBundle("jmri.jmrix.loconet.sdfeditor.Editor");
037    static ResourceBundle exp = ResourceBundle.getBundle("jmri.jmrix.loconet.sdfeditor.Explanations");
038
039    public EditorPane() {
040        // start to configure GUI
041        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
042
043        // install left and right parts in split pane
044        split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, newTree(), newEditPane());
045        add(split);
046    }
047
048    JSplitPane split;
049    JTree tree;
050    DefaultMutableTreeNode topNode;
051
052    JComponent newTree() {
053        topNode = new DefaultMutableTreeNode("file"); // NOI18N
054        tree = new JTree(topNode);
055        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
056
057        // Listen for when the selection changes.
058        tree.addTreeSelectionListener(this);
059
060        // install in scroll area
061        JScrollPane treeView = new JScrollPane(tree);
062        treeView.setMinimumSize(new Dimension(250, 600));
063        treeView.setPreferredSize(new Dimension(250, 600));
064        return treeView;
065    }
066
067    SdfMacroEditor lastEditor = null;
068
069    /**
070     * Handle tree selection
071     */
072    @Override
073    public void valueChanged(TreeSelectionEvent e) {
074        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
075
076        if (node == null) {
077            return;
078        }
079
080        // get an editor
081        SdfMacroEditor nodeInfo = (SdfMacroEditor) node.getUserObject();
082
083        // use that editor to show the instruction
084        instruction.setText(nodeInfo.oneInstructionString());
085
086        // show the explanation text
087        explanation.setText(exp.getString(nodeInfo.getMacro().name()));
088
089        // make the correct editor visible
090        if (lastEditor != null) {
091            lastEditor.setVisible(false);
092        }
093        lastEditor = nodeInfo;
094        nodeInfo.update();
095        nodeInfo.setVisible(true);
096    }
097
098    public void updateSummary() {
099        if (lastEditor != null) {
100            instruction.setText(lastEditor.oneInstructionString());
101        }
102    }
103
104    JPanel newEditPane() {
105        JPanel p = new JPanel();
106        p.setMinimumSize(new Dimension(600, 400));
107        p.setPreferredSize(new Dimension(600, 400));
108        p.setMaximumSize(new Dimension(600, 400));
109
110        // layout is two vertical parts
111        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
112
113        // upper part of right window
114        p.add(newInstructionPane());
115
116        p.add(new JSeparator());
117
118        p.add(explanation);
119        explanation.setEditable(false);
120        explanation.setContentType("text/html"); // NOI18N
121        explanation.setMinimumSize(new Dimension(600, 200));
122        explanation.setPreferredSize(new Dimension(600, 200));
123        explanation.setMaximumSize(new Dimension(600, 200));
124        explanation.setBackground(new JLabel().getBackground());
125
126        p.add(new JSeparator());
127
128        // lower part of right window
129        p.add(newDetailPane());
130
131        return p;
132    }
133
134    MonitoringLabel instruction = new MonitoringLabel();
135    JEditorPane explanation = new JEditorPane();
136
137    JComponent newInstructionPane() {
138        instruction.setLineWrap(true);
139        instruction.setWrapStyleWord(true);
140        instruction.setText("Select an instruction in the tree to the left"); // NOI18N
141        instruction.setEditable(false);
142        instruction.setMinimumSize(new Dimension(600, 80));
143        instruction.setPreferredSize(new Dimension(600, 80));
144        instruction.setMaximumSize(new Dimension(600, 80));
145        instruction.setBackground(new JLabel().getBackground());
146        return instruction;
147    }
148
149    JPanel detailed = new JPanel(); // panel that contains the specific editors
150
151    JPanel newDetailPane() {
152
153        detailed.setLayout(new FlowLayout());
154
155        return detailed;
156    }
157
158    /**
159     * Add the instructions to the tree
160     * @param buff Buffer to add
161     */
162    void addSdf(SdfBuffer buff) {
163        //DefaultMutableTreeNode newNode = null;
164
165        // make the top elements at the top
166        List<SdfMacro> ops = buff.getMacroList();
167        for (int i = 0; i < ops.size(); i++) {
168            nestNodes(topNode, ops.get(i));
169        }
170
171        // don't show the top (single) node, 
172        // do show all the ones right under that.
173        tree.expandPath(new TreePath(topNode));
174        tree.setRootVisible(false);
175
176    }
177
178    void nestNodes(DefaultMutableTreeNode parent, SdfMacro macro) {
179        // put in the new topmost node
180        SdfMacroEditor e = SdfMacroEditor.attachEditor(macro);
181        detailed.add(e);
182        e.setVisible(false);
183        DefaultMutableTreeNode newNode
184                = new DefaultMutableTreeNode(e);
185        e.setNotify(newNode, this);
186        parent.add(newNode);
187
188        // recurse for kids
189        List<SdfMacro> children = macro.getChildren();
190        if (children == null) {
191            return;
192        }
193        for (int i = 0; i < children.size(); i++) {
194            nestNodes(newNode, children.get(i));
195        }
196    }
197
198    /**
199     * Get rid of held resources
200     */
201    void dispose() {
202    }
203
204}