001package jmri.jmrit.display.palette;
002
003import java.awt.event.FocusAdapter;
004import java.awt.event.FocusEvent;
005import java.util.ArrayList;
006
007import javax.swing.BorderFactory;
008import javax.swing.Box;
009import javax.swing.BoxLayout;
010import javax.swing.JButton;
011import javax.swing.JCheckBox;
012import javax.swing.JFrame;
013import javax.swing.JLabel;
014import javax.swing.JPanel;
015import javax.swing.JTextField;
016
017import jmri.InstanceManager;
018import jmri.Sensor;
019import jmri.jmrit.logix.OBlock;
020import jmri.jmrit.logix.OPath;
021import jmri.jmrit.picker.PickListModel;
022import jmri.jmrit.picker.PickPanel;
023import jmri.util.swing.JmriJOptionPane;
024
025/**
026 * Panel for Occupancy and Error detection.
027 */
028public class DetectionPanel extends JPanel {
029
030    private final JTextField _occDetectorName = new JTextField(); // can be either a Sensor or OBlock name
031    private JFrame _pickFrame;
032    private final JButton _openPicklistButton;
033    private final JPanel _trainIdPanel;
034    private JCheckBox _showTrainName;
035    private OBlock _block;
036    private final JPanel _blockPathPanel;
037    private final JPanel _sensorBlurbPanel;
038    private final ItemPanel _parent;
039    private ArrayList<JCheckBox> _pathBoxes;
040    private JPanel _checkBoxPanel;
041
042    /**
043     * Add _blockPathPanel to this ItemPanel.
044     * @param parent the indicator track item panel
045     */
046    public DetectionPanel(ItemPanel parent) {
047        super();
048        _parent = parent;
049        _occDetectorName.addActionListener(e -> checkDetection());
050        _occDetectorName.addFocusListener(new FocusAdapter() {
051            @Override
052            public void focusLost(FocusEvent e) {
053                checkDetection();
054            }
055        });
056        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
057        JPanel panel = new JPanel();
058        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
059        panel.add(makeSensorPanel(_occDetectorName, "OccupancySensor", "ToolTipOccupancySensor"));
060        _openPicklistButton = new JButton(Bundle.getMessage("OpenPicklist"));
061        _openPicklistButton.addActionListener(a -> {
062            if (_pickFrame == null) {
063                openPickList();
064            } else {
065                closePickList();
066            }
067        });
068        JPanel p = new JPanel();
069        p.add(_openPicklistButton);
070        panel.add(p);
071        add(panel);
072
073        _trainIdPanel = makeTrainIdPanel();
074        add(_trainIdPanel);
075
076        _blockPathPanel = new JPanel();
077        _blockPathPanel.setLayout(new BoxLayout(_blockPathPanel, BoxLayout.Y_AXIS));
078        p = new JPanel();
079        p.add(new JLabel(Bundle.getMessage("SelectPathIcons")));
080        _blockPathPanel.add(p);
081        _checkBoxPanel = new JPanel();
082        _blockPathPanel.add(_checkBoxPanel);
083        _blockPathPanel.add(Box.createVerticalStrut(ItemPalette.STRUT_SIZE));
084        _blockPathPanel.setToolTipText(Bundle.getMessage("ToolTipSelectPathIcons"));
085        add(_blockPathPanel);
086
087        _sensorBlurbPanel = new JPanel();
088        JPanel blurb = new JPanel();
089        blurb.setLayout(new BoxLayout(blurb, BoxLayout.Y_AXIS));
090        blurb.add(Box.createVerticalStrut(ItemPalette.STRUT_SIZE));
091        blurb.add(new JLabel(Bundle.getMessage("DetectorNote")));
092        blurb.add(Box.createVerticalStrut(ItemPalette.STRUT_SIZE));
093        _sensorBlurbPanel.add(blurb);
094        add(_sensorBlurbPanel);
095    }
096
097    JPanel makeSensorPanel(JTextField field, String text, String toolTip) {
098        JPanel panel = new JPanel();
099        JLabel label = new JLabel(Bundle.getMessage(text));
100        panel.add(label);
101        java.awt.Dimension dim = field.getPreferredSize();
102        dim.width = 500;
103        field.setMaximumSize(dim);
104        dim.width = 200;
105        field.setMinimumSize(dim);
106        field.setColumns(20);
107        field.setDragEnabled(true);
108        field.setTransferHandler(new jmri.util.DnDStringImportHandler());
109        label.setToolTipText(Bundle.getMessage(toolTip));
110        field.setToolTipText(Bundle.getMessage(toolTip));
111        panel.setToolTipText(Bundle.getMessage(toolTip));
112        panel.add(field);
113        return panel;
114    }
115
116//    @SuppressWarnings("raw")
117    void openPickList() {
118        _pickFrame = new JFrame();
119        JPanel content = new JPanel();
120        content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
121
122        JPanel blurb = new JPanel();
123        blurb.setLayout(new BoxLayout(blurb, BoxLayout.Y_AXIS));
124        blurb.add(Box.createVerticalStrut(ItemPalette.STRUT_SIZE));
125        blurb.add(new JLabel(Bundle.getMessage("DragOccupancyName", Bundle.getMessage("OccupancySensor"))));
126        blurb.add(new JLabel(Bundle.getMessage("DetectorNote")));
127//        blurb.add(new JLabel(Bundle.getMessage("DragErrorName", Bundle.getMessage("ErrorSensor"))));
128        blurb.add(Box.createVerticalStrut(ItemPalette.STRUT_SIZE));
129        JPanel panel = new JPanel();
130        panel.add(blurb);
131        content.add(panel);
132        PickListModel<?>[] models = {PickListModel.oBlockPickModelInstance(),
133            PickListModel.sensorPickModelInstance()
134        };
135        content.add(new PickPanel(models));
136
137        _pickFrame.setContentPane(content);
138        _pickFrame.addWindowListener(new java.awt.event.WindowAdapter() {
139            @Override
140            public void windowClosing(java.awt.event.WindowEvent e) {
141                closePickList();
142            }
143        });
144        _pickFrame.setLocationRelativeTo(this);
145        _pickFrame.toFront();
146        _pickFrame.setVisible(true);
147        _pickFrame.pack();
148        _openPicklistButton.setText(Bundle.getMessage("ClosePicklist"));
149    }
150
151    void closePickList() {
152        _pickFrame.dispose();
153        _pickFrame = null;
154        _openPicklistButton.setText(Bundle.getMessage("OpenPicklist"));
155    }
156
157    private JPanel makeTrainIdPanel() {
158        JPanel panel = new JPanel();
159        _showTrainName = new JCheckBox(Bundle.getMessage("ShowTrainName"));
160        _showTrainName.setToolTipText(Bundle.getMessage("ToolTipShowTrainName"));
161        JPanel p = new JPanel();
162        p.add(_showTrainName);
163        p.setToolTipText(Bundle.getMessage("ToolTipShowTrainName"));
164        panel.add(p);
165        return panel;
166    }
167
168    public void dispose() {
169        if (_pickFrame != null) {
170            _pickFrame.dispose();
171            _pickFrame = null;
172        }
173    }
174
175    /*
176     * **************** Getters & Setters **************************
177     */
178    public boolean getShowTrainName() {
179        return _showTrainName.isSelected();
180    }
181
182    public void setShowTrainName(boolean show) {
183        _showTrainName.setSelected(show);
184    }
185
186    public String getOccSensor() {
187        String name = _occDetectorName.getText();
188        if (name != null && name.trim().length() > 0) {
189            if (InstanceManager.sensorManagerInstance().getSensor(name) != null) {
190                return name;
191            }
192        }
193        return null;
194    }
195
196    public String getOccBlock() {
197        String name = _occDetectorName.getText();
198        if (name != null && name.trim().length() > 0) {
199            if (InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(name) != null) {
200                return name;
201            }
202        }
203        return null;
204    }
205
206    /**
207     * Name of either Sensor or OBlock for detection
208     * @param name detector name
209     */
210    public void setOccDetector(String name) {
211        _occDetectorName.setText(name);
212        checkDetection();
213    }
214
215    public ArrayList<String> getPaths() {
216        ArrayList<String> paths = new ArrayList<>();
217        if (_pathBoxes != null) {
218            for (JCheckBox pathBox : _pathBoxes) {
219                if (pathBox.isSelected()) {
220                    // displayed path names are padded to 25 charts
221                    paths.add(pathBox.getName().trim());
222                }
223            }
224        }
225        return paths;
226    }
227
228    public void setPaths(ArrayList<String> iconPath) {
229        if (iconPath == null || _block == null) {
230            _pathBoxes = null;
231            return;
232        }
233        for (String s : iconPath) {
234            for (JCheckBox pathBox : _pathBoxes) {
235                // displayed path names are padded to 25 chars
236                String name = pathBox.getName().trim();
237                if (s.equals(name)) {
238                    pathBox.setSelected(true);
239                }
240            }
241        }
242    }
243
244    /*
245     * ******************************************
246     */
247    private void checkDetection() {
248        String name = _occDetectorName.getText();
249        if (name != null && name.trim().length() > 0) {
250            OBlock block = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(name);
251            if (block != null) {
252                if (block.equals(_block)) {
253                    return;
254                }
255                makePathList(block);
256                showPanels(true);
257           } else {
258                Sensor sensor = InstanceManager.sensorManagerInstance().getSensor(name);
259                if (sensor == null) {
260                    JmriJOptionPane.showMessageDialog(_parent._frame,
261                            Bundle.getMessage("InvalidOccDetector", name),
262                            Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE);
263                    _occDetectorName.setText(null);
264                }
265                showPanels(false);
266            }
267        } else {
268            showPanels(false);
269        }
270    }
271
272    private void showPanels(boolean hasOBlock) {
273        _trainIdPanel.setVisible(hasOBlock);
274        _blockPathPanel.setVisible(hasOBlock);
275        _sensorBlurbPanel.setVisible(!hasOBlock);
276        if (!hasOBlock) {
277            _block = null;
278        }
279        invalidate();
280        _parent.hideIcons();    // resizes panel properly
281    }
282
283    private void makePathList(OBlock block) {
284        _blockPathPanel.remove(_checkBoxPanel);
285        _checkBoxPanel = new JPanel();
286        _checkBoxPanel.setLayout(new BoxLayout(_checkBoxPanel, BoxLayout.Y_AXIS));
287        _checkBoxPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(java.awt.Color.black),
288                Bundle.getMessage("circuitPaths")));
289        _checkBoxPanel.add(Box.createHorizontalStrut(100));
290        _block = block;
291        _pathBoxes = new ArrayList<>();
292        _block.getPaths().stream().filter(o -> o instanceof OPath)
293                      .map(o -> ((OPath) o).getName()).forEach( name -> {
294            if (name.length() < 25) {
295                char[] ca = new char[25];
296                for (int j = 0; j < name.length(); j++) {
297                    ca[j] = name.charAt(j);
298                }
299                for (int j = name.length(); j < 25; j++) {
300                    ca[j] = ' ';
301                }
302                name = new String(ca);
303            }
304            JCheckBox box = new JCheckBox(name);
305            box.setName(name);
306            _pathBoxes.add(box);
307            _checkBoxPanel.add(box);
308        });
309        _blockPathPanel.add(_checkBoxPanel, 1);
310    }
311
312}