001package jmri.jmrit.display.controlPanelEditor;
002
003import java.awt.Dimension;
004import java.awt.FlowLayout;
005import java.awt.event.ActionEvent;
006import java.beans.PropertyChangeEvent;
007import java.beans.PropertyChangeListener;
008
009import javax.swing.Box;
010import javax.swing.BoxLayout;
011import javax.swing.JButton;
012import javax.swing.JLabel;
013import javax.swing.JPanel;
014import javax.swing.JTextField;
015
016import jmri.InstanceManager;
017import jmri.Sensor;
018import jmri.NamedBean.DisplayOptions;
019import jmri.jmrit.display.IndicatorTrack;
020import jmri.jmrit.display.IndicatorTrackIcon;
021import jmri.jmrit.display.IndicatorTurnoutIcon;
022import jmri.jmrit.display.Positionable;
023import jmri.jmrit.display.ToolTip;
024import jmri.jmrit.display.TurnoutIcon;
025import jmri.jmrit.logix.OBlock;
026import jmri.jmrit.logix.OBlockManager;
027import jmri.jmrit.logix.Portal;
028import jmri.jmrit.picker.PickListModel;
029import jmri.util.swing.JmriJOptionPane;
030
031/**
032 * @author Pete Cressman Copyright: Copyright (c) 2011
033 */
034public class EditCircuitFrame extends EditFrame implements PropertyChangeListener {
035
036    private JTextField _systemName;
037    private JTextField _blockName;
038    private JTextField _detectorSensorName;
039    private JTextField _errorSensorName;
040    private JTextField _blockState;
041    private JTextField _numTrackSeg;
042    private JTextField _numTurnouts;
043    private LengthPanel _lengthPanel;
044    private JPanel _namePanel;
045    private boolean _create;
046
047    // Sensor list
048    OpenPickListButton<Sensor> _pickTable;
049
050    public EditCircuitFrame(String title, CircuitBuilder parent, OBlock block) {
051        super(title, parent, block);
052        _create = (block == null);
053        updateContentPanel(_create);
054        _homeBlock.addPropertyChangeListener("deleted", this);
055        pack();
056    }
057
058    @Override
059    protected JPanel makeContentPanel() {
060        JPanel contentPane = new JPanel();
061        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
062        _blockName = new JTextField();
063        _detectorSensorName = new JTextField();
064        _errorSensorName = new JTextField();
065        _blockState = new JTextField();
066        _numTrackSeg = new JTextField();
067        _numTurnouts = new JTextField();
068        JPanel p = new JPanel();
069        
070        p.add(new JLabel(Bundle.getMessage("AddRemoveIcons")));
071        contentPane.add(p);
072        contentPane.add(Box.createVerticalStrut(STRUT_SIZE));
073
074        JPanel panel = new JPanel();
075        // panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
076        panel.add(CircuitBuilder.makeTextBoxPanel(false, _blockState, "blockState", false, null));
077        _blockState.setPreferredSize(new Dimension(150, _blockState.getPreferredSize().height));
078        contentPane.add(panel);
079
080        _namePanel = new JPanel();
081        _namePanel.setLayout(new BoxLayout(_namePanel, BoxLayout.Y_AXIS));
082        contentPane.add(_namePanel);
083
084        panel = new JPanel();
085        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
086        JPanel _buttonPanel = new JPanel();
087        _buttonPanel.setLayout(new FlowLayout());
088        panel.add(_buttonPanel);
089        contentPane.add(panel);
090        
091        contentPane.add(Box.createVerticalStrut(STRUT_SIZE));
092        p = new JPanel();
093        p.add(new JLabel(Bundle.getMessage("numTrackElements")));
094        contentPane.add(p);
095
096        panel = new JPanel();
097        // panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
098        panel.add(Box.createHorizontalGlue());
099        panel.add(CircuitBuilder.makeTextBoxPanel(
100                false, _numTrackSeg, "Segments", false, null));
101        _numTrackSeg.setPreferredSize(new Dimension(20, _numTrackSeg.getPreferredSize().height));
102        panel.add(Box.createHorizontalStrut(STRUT_SIZE));
103
104        panel.add(CircuitBuilder.makeTextBoxPanel(
105                false, _numTurnouts, "Turnouts", false, null));
106        _numTurnouts.setPreferredSize(new Dimension(20, _numTurnouts.getPreferredSize().height));
107        panel.add(Box.createHorizontalStrut(STRUT_SIZE));
108        contentPane.add(panel);
109        contentPane.add(Box.createVerticalStrut(STRUT_SIZE));
110
111        panel = new JPanel();
112        // panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
113        _detectorSensorName.setPreferredSize(new Dimension(300, _detectorSensorName.getPreferredSize().height));
114        panel.add(CircuitBuilder.makeTextBoxPanel(
115                false, _detectorSensorName, "DetectionSensor", true, "detectorSensorName"));
116        _detectorSensorName.setToolTipText(Bundle.getMessage("detectorSensorName"));
117        contentPane.add(panel);
118
119        panel = new JPanel();
120        // panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
121        _errorSensorName.setPreferredSize(new Dimension(300, _errorSensorName.getPreferredSize().height));
122        panel.add(CircuitBuilder.makeTextBoxPanel(
123                false, _errorSensorName, "ErrorSensor", true, "detectorErrorName"));
124        _errorSensorName.setToolTipText(Bundle.getMessage("detectorErrorName"));
125        contentPane.add(panel);
126
127        String[] blurbLines = { Bundle.getMessage("DragOccupancySensor", Bundle.getMessage("DetectionSensor")),
128                                Bundle.getMessage("DragErrorName", Bundle.getMessage("ErrorSensor"))};
129        _pickTable = new OpenPickListButton<>(blurbLines, PickListModel.sensorPickModelInstance(),
130                this, Bundle.getMessage("OpenPicklist", Bundle.getMessage("BeanNameSensor")));
131        contentPane.add(_pickTable.getButtonPanel());
132        contentPane.add(Box.createVerticalStrut(STRUT_SIZE));
133
134        _lengthPanel = new LengthPanel(_homeBlock, LengthPanel.BLOCK_LENGTH, "TooltipPathLength");
135        _lengthPanel.changeUnits();
136        _lengthPanel.setLength(_homeBlock.getLengthMm());
137        contentPane.add(_lengthPanel);
138        contentPane.add(Box.createVerticalStrut(STRUT_SIZE));
139
140        contentPane.add(makeDoneButtonPanel());
141        return contentPane;
142    }
143    private JPanel makeCreateBlockPanel() {
144        _systemName = new JTextField();
145        _systemName.setText(_homeBlock.getSystemName());
146        _blockName.setText(_homeBlock.getUserName());
147        JPanel panel = new JPanel();
148        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
149        panel.add(CircuitBuilder.makeTextBoxPanel(
150                false, _systemName, "ColumnSystemName", true, "TooltipBlockName"));
151        _systemName.setPreferredSize(new Dimension(300, _systemName.getPreferredSize().height));
152        panel.add(CircuitBuilder.makeTextBoxPanel(
153                false, _blockName, "blockName", true, "TooltipBlockName"));
154        _blockName.setPreferredSize(new Dimension(300, _blockName.getPreferredSize().height));
155
156        JPanel buttonPanel = new JPanel();
157        buttonPanel.setLayout(new FlowLayout());
158        JButton createButton = new JButton(Bundle.getMessage("buttonCreate"));
159        createButton.addActionListener((ActionEvent a) -> createBlock());
160        createButton.setToolTipText(Bundle.getMessage("createOBlock"));
161        buttonPanel.add(createButton);
162        
163        panel.add(buttonPanel);
164        panel.add(Box.createVerticalStrut(STRUT_SIZE));
165        return panel;
166    }
167
168    private JPanel makeEditBlockPanel() {
169        _blockName.setText(_homeBlock.getUserName());
170        JPanel panel = new JPanel();
171        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
172        panel.add(CircuitBuilder.makeTextBoxPanel(
173                false, _blockName, "blockName", true, "TooltipBlockName"));
174        _blockName.setPreferredSize(new Dimension(300, _blockName.getPreferredSize().height));
175
176        JPanel buttonPanel = new JPanel();
177        buttonPanel.setLayout(new FlowLayout());
178
179        JButton changeButton = new JButton(Bundle.getMessage("buttonChangeName"));
180        changeButton.addActionListener((ActionEvent a) -> changeBlockName());
181        changeButton.setToolTipText(Bundle.getMessage("ToolTipChangeName"));
182        buttonPanel.add(changeButton);
183
184        JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete"));
185        deleteButton.addActionListener((ActionEvent a) -> deleteCircuit());
186        deleteButton.setToolTipText(Bundle.getMessage("ToolTipDeleteCircuit"));
187        buttonPanel.add(deleteButton);
188
189        panel.add(buttonPanel);
190        panel.add(Box.createVerticalStrut(STRUT_SIZE));
191        return panel;
192     }
193
194    @Override
195    protected JPanel makeDoneButtonPanel() {
196        JPanel buttonPanel = new JPanel();
197        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
198        JPanel panel = new JPanel();
199        panel.setLayout(new FlowLayout());
200
201        JButton convertButton = new JButton(Bundle.getMessage("ButtonConvertIcon"));
202        convertButton.addActionListener((ActionEvent a) -> convertIcons());
203        convertButton.setToolTipText(Bundle.getMessage("ToolTipConvertIcon"));
204        panel.add(convertButton);
205
206        JButton doneButton = new JButton(Bundle.getMessage("ButtonDone"));
207        doneButton.addActionListener((ActionEvent a) -> {
208            if (_create) {
209                closeCreate();
210            } else {
211                closingEvent(false);
212            }
213        });
214        panel.add(doneButton);
215        buttonPanel.add(panel);
216
217        return buttonPanel;
218    }
219
220    private void convertIcons() {
221        _parent.setIconGroup(_homeBlock);
222        _parent.queryConvertTrackIcons(_homeBlock, "PortalOrPath");
223        this.toFront();
224    }
225
226    /*
227     * *********************** end setup *************************
228     */
229
230    private void createBlock() {
231        String userName = _blockName.getText().trim();
232        String systemName = _systemName.getText().trim();
233        OBlockManager mgr = InstanceManager.getDefault(OBlockManager.class);
234        StringBuilder  sb = new StringBuilder ();
235        if (userName.length() > 0) {
236             OBlock block = mgr.getByUserName(userName);
237            if (block != null) {
238                sb.append(Bundle.getMessage("duplicateName", userName, block.getSystemName()));
239                sb.append("\n");
240            }
241        }
242        if (!mgr.isValidSystemNameFormat(systemName)) {
243            sb.append(Bundle.getMessage("sysnameOBlock"));
244            sb.append("\n");
245        } else {
246            OBlock block = mgr.getBySystemName(systemName);
247            if (block != null) {
248                sb.append(Bundle.getMessage("duplicateName", systemName, block.getUserName()));
249                sb.append("\n");
250            }
251        }
252        if (sb.toString().length() > 0) {
253            JmriJOptionPane.showMessageDialog(this, sb.toString(),
254                    Bundle.getMessage("editCiruit"), JmriJOptionPane.INFORMATION_MESSAGE);
255            _systemName.setText(_homeBlock.getSystemName());
256            return;
257        }
258        _homeBlock = mgr.createNewOBlock(systemName, userName);
259        updateContentPanel(false);
260    }
261
262    private void changeBlockName() {
263        String name = _blockName.getText().trim();
264        String msg = null;
265        if (name.length() == 0) {
266            msg = Bundle.getMessage("TooltipBlockName");
267        } else {
268            OBlock block = InstanceManager.getDefault(OBlockManager.class).getByUserName(name);
269            if (block != null) {
270                msg = Bundle.getMessage("duplicateName", name, block.getDisplayName(DisplayOptions.QUOTED_USERNAME_SYSTEMNAME));
271            }
272        }
273        if (msg != null) {
274            JmriJOptionPane.showMessageDialog(this, msg,
275                    Bundle.getMessage("editCiruit"), JmriJOptionPane.INFORMATION_MESSAGE);
276            return;
277            
278        }
279        _homeBlock.setUserName(name);
280        // block user name change will change portal names.  Change PortalIcon names to match
281        for (Positionable p : _parent.getCircuitIcons(_homeBlock)) {
282            if (p instanceof PortalIcon) {
283                PortalIcon icon = (PortalIcon)p;
284                Portal portal = icon.getPortal();
285                icon.setName(portal.getName());
286                icon.setToolTip(new ToolTip(portal.getDescription(), 0, 0, icon));
287            }
288        }
289    }
290
291    private void deleteCircuit() {
292        int result = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("confirmBlockDelete"),
293                Bundle.getMessage("editCiruit"), JmriJOptionPane.YES_NO_OPTION,
294                JmriJOptionPane.QUESTION_MESSAGE);
295        if (result == JmriJOptionPane.YES_OPTION) {
296            _parent.removeBlock(_homeBlock);
297            closingEvent(true, null);   // No Messages, just close
298        }
299    }
300
301    private void updateContentPanel(boolean create) {
302        updateIconList(_parent._editor.getSelectionGroup());
303        String name = "";
304        Sensor sensor = _homeBlock.getSensor();
305        if (sensor != null) {
306            name = sensor.getDisplayName();
307            _detectorSensorName.setText(name);
308        }
309
310        sensor = _homeBlock.getErrorSensor();
311        if (sensor != null) {
312            name = sensor.getDisplayName();
313            _errorSensorName.setText(name);
314        }
315
316        int state = _homeBlock.getState();
317        StringBuilder stateText = new StringBuilder();
318        if ((state & OBlock.UNKNOWN) != 0) {
319            stateText.append("Unknown ");
320        }
321        if ((state & OBlock.OCCUPIED) != 0) {
322            stateText.append("Occupied ");
323        }
324        if ((state & OBlock.UNOCCUPIED) != 0) {
325            stateText.append("Unoccupied ");
326        }
327        if ((state & OBlock.INCONSISTENT) != 0) {
328            stateText.append("Inconsistent ");
329        }
330        if ((state & OBlock.ALLOCATED) != 0) {
331            stateText.append("Allocated ");
332        }
333        if ((state & OBlock.RUNNING) != 0) {
334            stateText.append("Positioned ");
335        }
336        if ((state & OBlock.OUT_OF_SERVICE) != 0) {
337            stateText.append("OutOf Service ");
338        }
339        if ((state & OBlock.UNDETECTED) != 0) {
340            stateText.append("Dark ");
341        }
342        if ((state & OBlock.TRACK_ERROR) != 0) {
343            stateText.append("TrackError ");
344        }
345        if (state == 0) {
346            stateText.append("Not Initialized");
347        }
348        if (log.isDebugEnabled()) {
349            log.debug("updateContentPanel: state= {}", stateText);
350        }
351        _blockState.setText(stateText.toString());
352
353        JPanel panel;
354        if (create) {
355            panel = makeCreateBlockPanel();
356        } else {
357            panel = makeEditBlockPanel();
358            _create = false;
359        }
360        _namePanel.removeAll();
361        _namePanel.add(panel);
362        _namePanel.invalidate();
363        pack();
364    }
365
366    private void closeCreate() {
367        StringBuilder  sb = new StringBuilder ();
368        String sysName = _homeBlock.getSystemName();
369        OBlock block = InstanceManager.getDefault(OBlockManager.class).getBySystemName(sysName);
370        if (block == null) {
371            // get rid of icon selections
372            for (Positionable pos : _parent.getCircuitIcons(_homeBlock)) {
373                if (pos instanceof IndicatorTrack) {
374                    ((IndicatorTrack) pos).setOccBlockHandle(null);
375                }
376            }
377            _parent._editor.getSelectionGroup().clear();
378            sb.append( Bundle.getMessage("notCreated", _systemName.getText().trim()));
379            closingEvent(false, sb.toString());
380            if (_pickTable != null) {
381                _pickTable.closePickList();
382            }
383        } else {
384            closingEvent(false);
385        }
386    }
387
388    @Override
389    protected void closingEvent(boolean close) {
390        StringBuffer sb = new StringBuffer();
391        String msg = checkForSensors();
392        if (msg != null) {
393            sb.append(msg);
394            sb.append("\n");
395        }
396        String name = _blockName.getText().trim();
397        if (name.length() == 0) {
398            msg = Bundle.getMessage("blankUserName");
399            if (msg != null) {
400                sb.append(msg);
401                sb.append("\n");
402            }
403        } else if (!name.equals(_homeBlock.getUserName())) {
404            msg = Bundle.getMessage("changeBlockName", name, _homeBlock.getDisplayName(DisplayOptions.QUOTED_USERNAME_SYSTEMNAME));
405            if (msg != null) {
406                sb.append(msg);
407                sb.append("\n");
408            }
409        }
410        _parent.setIconGroup(_homeBlock);
411        msg = _parent.checkForTrackIcons(_homeBlock, "PortalOrPath");
412        if (msg.length() > 0) {
413            sb.append(msg);
414            sb.append("\n");
415        }
416        if (_lengthPanel.getLength() <= 0.001) {
417            msg = Bundle.getMessage("noBlockLength");
418            if (msg != null) {
419                sb.append(msg);
420                sb.append("\n");
421            }
422        } else {
423            _homeBlock.setLength(_lengthPanel.getLength());
424        }
425
426        closingEvent(close, sb.toString());
427        if (_pickTable != null) {
428            _pickTable.closePickList();
429        }
430    }
431    
432    private String checkForSensors() {
433        String name = _detectorSensorName.getText();
434        String errName = _errorSensorName.getText();
435        if (!_homeBlock.setSensor(name)) {
436           return java.text.MessageFormat.format(Bundle.getMessage("badSensorName"), name);
437        }
438        if (errName.length() > 2) {
439            if (_homeBlock.getSensor() == null) {
440                int result = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("mixedSensors"),
441                        Bundle.getMessage("noSensor"), JmriJOptionPane.YES_NO_OPTION,
442                        JmriJOptionPane.QUESTION_MESSAGE);
443                if (result == JmriJOptionPane.YES_OPTION) {
444                    if (!_homeBlock.setSensor(errName)) {
445                        return java.text.MessageFormat.format(Bundle.getMessage("badSensorName"), errName);
446                    } else {
447                        _homeBlock.setErrorSensor(null);
448                        _detectorSensorName.setText(_homeBlock.getSensor().getDisplayName());
449                        _errorSensorName.setText(null);
450                    }
451                } else {
452                    if (!_homeBlock.setErrorSensor(errName)) {
453                        return java.text.MessageFormat.format(Bundle.getMessage("badSensorName"), errName);
454                    }
455                }
456            } else {
457                if (!_homeBlock.setErrorSensor(errName)) {
458                    return java.text.MessageFormat.format(Bundle.getMessage("badSensorName"), errName);
459                }
460            }
461        } else if (errName.trim().length() == 0){ {
462            _homeBlock.setErrorSensor(null);
463        }
464            
465        }
466        Sensor sensor = _homeBlock.getSensor();
467        if (sensor == null) {
468            return Bundle.getMessage("noDetecterSensor");
469        } else if (sensor.equals(_homeBlock.getErrorSensor())) {
470            _homeBlock.setErrorSensor(null);
471            _errorSensorName.setText(null);
472            return java.text.MessageFormat.format(Bundle.getMessage("DuplSensorRemoved"),
473                    sensor.getDisplayName(DisplayOptions.QUOTED_DISPLAYNAME));
474        }
475        return null;
476    }
477
478    protected void updateIconList(java.util.List<Positionable> icons) {
479        //if (log.isDebugEnabled()) log.debug(
480        int segments = 0;
481        int turnouts = 0;
482        if (icons != null) {
483            if (log.isDebugEnabled()) {
484                log.debug("updateIconList: icons.size()= {}", icons.size());
485            }
486            for (Positionable pos : icons) {
487                if (pos instanceof IndicatorTurnoutIcon) {
488                    turnouts++;
489                } else if (pos instanceof IndicatorTrackIcon) {
490                    segments++;
491                } else if (pos instanceof TurnoutIcon) {
492                    turnouts++;
493                } else {
494                    segments++;
495                }
496            }
497        }
498        _numTrackSeg.setText(String.valueOf(segments));
499        _numTurnouts.setText(String.valueOf(turnouts));
500    }
501
502    @Override
503    public void propertyChange(PropertyChangeEvent e) {
504        if (e.getPropertyName().equals("deleted")) {
505            closingEvent(true, null);   // No Messages, just close
506        }
507    }
508
509    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EditCircuitFrame.class);
510
511}