001package jmri.jmrit.beantable.oblock;
002
003import jmri.InstanceManager;
004import jmri.NamedBean;
005import jmri.jmrit.logix.OBlock;
006import jmri.jmrit.logix.OBlockManager;
007import jmri.jmrit.logix.Portal;
008import jmri.jmrit.logix.PortalManager;
009import jmri.swing.NamedBeanComboBox;
010import jmri.util.JmriJFrame;
011import jmri.util.swing.JComboBoxUtil;
012
013import javax.annotation.Nonnull;
014import javax.swing.*;
015import java.awt.*;
016import java.awt.event.ActionEvent;
017
018/**
019 * Defines a GUI for editing OBlocks - Portal objects in the _tabbed OBlock Table interface.
020 * Based on AudioSourceFrame.
021 *
022 * @author Matthew Harris copyright (c) 2009
023 * @author Egbert Broerse (C) 2020
024 */
025public class PortalEditFrame extends JmriJFrame {
026
027    JPanel main = new JPanel();
028    //private final JScrollPane scroll = new JScrollPane(main, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
029
030    PortalTableModel model;
031    PortalManager pm;
032    //private final Object lock = new Object();
033
034    // UI components for Add/Edit Portal
035    private final JLabel portalLabel = new JLabel(Bundle.getMessage("PortalNameLabel"), JLabel.TRAILING);
036    private final JTextField portalUserName = new JTextField(15);
037    private final JLabel fromBlockLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("FromBlockName")), JLabel.TRAILING);
038    private final JLabel toBlockLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("OppBlockName")), JLabel.TRAILING);
039    private final NamedBeanComboBox<OBlock> fromBlockComboBox = new NamedBeanComboBox<>(InstanceManager.getDefault(OBlockManager.class), null, NamedBean.DisplayOptions.DISPLAYNAME);
040    private final NamedBeanComboBox<OBlock> toBlockComboBox = new NamedBeanComboBox<>(InstanceManager.getDefault(OBlockManager.class), null, NamedBean.DisplayOptions.DISPLAYNAME);
041    private final JLabel statusBar = new JLabel(Bundle.getMessage("AddPortalStatusEnter"), JLabel.LEADING);
042
043    private final PortalEditFrame frame = this;
044    private Portal _portal;
045    private boolean _newPortal = false;
046
047//    @SuppressWarnings("OverridableMethodCallInConstructor")
048    public PortalEditFrame(@Nonnull String title, Portal portal, PortalTableModel model) {
049        super(title, true, true);
050        this.model = model;
051        pm = InstanceManager.getDefault(PortalManager.class);
052        layoutFrame();
053        if (portal == null) {
054            resetFrame();
055            setTitle(Bundle.getMessage("TitleAddPortal"));
056            _newPortal = true;
057        } else {
058            _portal = portal;
059            populateFrame(portal);
060        }
061    }
062
063    public void layoutFrame() {
064        frame.addHelpMenu("package.jmri.jmrit.beantable.OBlockTable", true);
065        frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS));
066        frame.setSize(425, 225);
067
068        JPanel p = new JPanel();
069        p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
070
071        JPanel configGrid = new JPanel();
072        GridLayout layout = new GridLayout(3, 2, 10, 0); // (int rows, int cols, int hgap, int vgap)
073        configGrid.setLayout(layout);
074
075        // row 1
076        configGrid.add(portalLabel);
077        JPanel p1 = new JPanel();
078        p1.add(portalUserName, JPanel.CENTER_ALIGNMENT);
079        configGrid.add(p1);
080        // row 2
081        fromBlockComboBox.addActionListener(e -> {
082            if ((toBlockComboBox.getItemCount() > 0) && (fromBlockComboBox.getSelectedItem() != null) &&
083                    (toBlockComboBox.getSelectedItem() != null) &&
084                    (toBlockComboBox.getSelectedItem().equals(fromBlockComboBox.getSelectedItem()))) {
085                log.debug("resetting ToBlock");
086                toBlockComboBox.setSelectedIndex(0); // clear the other one
087            }
088        });
089        configGrid.add(fromBlockLabel);
090        configGrid.add(fromBlockComboBox);
091        fromBlockComboBox.setAllowNull(true);
092        JComboBoxUtil.setupComboBoxMaxRows(fromBlockComboBox);
093        // row 3
094        toBlockComboBox.addActionListener(e -> {
095            if ((toBlockComboBox.getItemCount() > 0) && (fromBlockComboBox.getSelectedItem() != null) &&
096                    (toBlockComboBox.getSelectedItem() != null) &&
097                    (toBlockComboBox.getSelectedItem().equals(fromBlockComboBox.getSelectedItem()))) {
098                log.debug("resetting FromBlock");
099                fromBlockComboBox.setSelectedIndex(0); // clear the other one
100            }
101        });
102        configGrid.add(toBlockLabel);
103        configGrid.add(toBlockComboBox);
104        toBlockComboBox.setAllowNull(true);
105        JComboBoxUtil.setupComboBoxMaxRows(toBlockComboBox);
106
107        p.add(configGrid);
108        p.add(Box.createVerticalGlue());
109
110        p1 = new JPanel();
111        statusBar.setFont(statusBar.getFont().deriveFont(0.9f * portalUserName.getFont().getSize())); // a bit smaller
112        statusBar.setForeground(Color.gray);
113        p1.add(statusBar);
114        p.add(p1);
115
116        // put buttons at the bottom
117        JPanel p2 = new JPanel();
118        JButton cancel;
119        p2.add(cancel = new JButton(Bundle.getMessage("ButtonCancel")));
120        cancel.addActionListener((ActionEvent e) -> frame.dispose());
121        JButton ok;
122        p2.add(ok = new JButton(Bundle.getMessage("ButtonOK")));
123        ok.addActionListener((ActionEvent e) -> {
124            applyPressed(e);
125        });
126        p.add(p2, BorderLayout.SOUTH);
127
128        main.add(p);
129        frame.getContentPane().add(main);
130        frame.setEscapeKeyClosesWindow(true);
131        frame.getRootPane().setDefaultButton(ok);
132    }
133
134    /**
135     * Populate the Edit OBlock frame with default values.
136     */
137    public void resetFrame() {
138        portalUserName.setText(null);
139        portalUserName.setBackground(Color.white);
140        if (fromBlockComboBox.getItemCount() > 0) {
141            fromBlockComboBox.setSelectedIndex(0);
142            toBlockComboBox.setSelectedIndex(0); // the combos use the same list so 1 check is sufficient
143        }
144        // reset statusBar text
145        if (fromBlockComboBox.getItemCount() < 2) {
146            status(Bundle.getMessage("NotEnoughBlocks"), true);
147        } else {
148            status(Bundle.getMessage("AddPortalStatusEnter"), false);
149        }
150        _newPortal = true;
151    }
152
153    /**
154     * Populate the Edit Portal frame with current values.
155     *
156     * @param p existing Portal to copy the attributes from
157     */
158    public void populateFrame(Portal p) {
159        if (p == null) {
160            throw new IllegalArgumentException("Null OBlock object");
161        }
162        portalUserName.setText(p.getName());
163        if (p.getFromBlockName() != null) {
164            fromBlockComboBox.setSelectedItemByName(p.getFromBlockName());
165        }
166        if (p.getToBlockName() != null) {
167            toBlockComboBox.setSelectedItemByName(p.getToBlockName());
168        }
169        _newPortal = false;
170    }
171
172    private void applyPressed(ActionEvent e) {
173        String user = portalUserName.getText().trim();
174        if (user.equals("")) {
175            // warn/help bar red
176            status(Bundle.getMessage("WarningSysNameEmpty"), true);
177            portalUserName.setBackground(Color.red);
178            return;
179        }
180        portalUserName.setBackground(Color.white);
181        status(Bundle.getMessage("AddPortalStatusEnter"), false);
182        if (fromBlockComboBox.getSelectedIndex() == -1 || toBlockComboBox.getSelectedIndex() == -1) {
183            status(Bundle.getMessage("PortalNeedsBlock", user), true);
184            return;
185        }
186        if (_newPortal) {
187            _portal = pm.createNewPortal(user);
188            if (_portal == null) { // pm found an existing portal by the same name
189                // warn/help bar red
190                status(Bundle.getMessage("WarningSysNameInUse"), true);
191                portalUserName.setBackground(Color.red);
192                return;
193            }
194        } else {
195            String msg = _portal.setName(user); // will check for duplicates
196            if (msg != null) {
197                status(msg, true);
198                return;
199            }
200        }
201        try {
202            OBlock block = fromBlockComboBox.getSelectedItem();
203            if (block != null) { // could have been deleted in JMRI by now?
204                // SametoFromBlock is prevented between comboboxes
205                if (!_portal.setFromBlock(block, false)) {
206                    String msg = Bundle.getMessage("BlockPathsConflict", fromBlockComboBox.getSelectedItemDisplayName(), _portal.getFromBlockName());
207                    int val = model.verifyWarning(msg);
208                    if (val == 2) {
209                        status(msg, true);
210                        return;
211                    } else {
212                        status(Bundle.getMessage("AddPortalStatusEnter"), false);
213                    }
214                }
215                _portal.setFromBlock(block, true);
216            }
217            block = toBlockComboBox.getSelectedItem();
218            if (block != null) {
219                if (!_portal.setToBlock(block, false)) {
220                    String msg = Bundle.getMessage("BlockPathsConflict", fromBlockComboBox.getSelectedItemDisplayName(), _portal.getFromBlockName());
221                    int val = model.verifyWarning(msg);
222                    if (val == 2) {
223                        status(msg, true);
224                        return;
225                    } else {
226                        status(Bundle.getMessage("AddPortalStatusEnter"), false);
227                    }
228                }
229                _portal.setToBlock(block, true);
230            }
231        } catch (IllegalArgumentException ex) {
232            jmri.util.swing.JmriJOptionPane.showMessageDialog(null, ex.getMessage(),
233                Bundle.getMessage("PortalCreateErrorTitle"), jmri.util.swing.JmriJOptionPane.ERROR_MESSAGE);
234            status(Bundle.getMessage("AddPortalFailed", user), true);
235            return;
236        }
237        // Notify changes
238        model.fireTableDataChanged();
239        dispose();
240    }
241
242    void status(String message, boolean warn){
243        statusBar.setText(message);
244        statusBar.setForeground(warn ? Color.red : Color.gray);
245    }
246
247    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PortalEditFrame.class);
248
249}