001package jmri.jmrit.beantable.signalmast;
002
003import java.awt.*;
004import java.awt.event.*;
005import java.text.DecimalFormat;
006import java.util.*;
007
008import javax.annotation.Nonnull;
009import javax.swing.*;
010import javax.swing.border.TitledBorder;
011
012import jmri.*;
013import jmri.implementation.TurnoutSignalMast;
014import jmri.util.swing.BeanSelectCreatePanel;
015
016import org.openide.util.lookup.ServiceProvider;
017
018/**
019 * A pane for configuring TurnoutSignalMast objects.
020 *
021 * @see jmri.jmrit.beantable.signalmast.SignalMastAddPane
022 * @author Bob Jacobsen Copyright (C) 2017, 2018
023 * @since 4.11.2
024 */
025public class TurnoutSignalMastAddPane extends SignalMastAddPane {
026
027    public TurnoutSignalMastAddPane() {
028        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
029        // lit/unlit controls
030        JPanel p = new JPanel();
031        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
032        p.add(new JLabel(Bundle.getMessage("AllowUnLitLabel") + ": "));
033        p.add(allowUnLit);
034        p.setAlignmentX(Component.LEFT_ALIGNMENT);
035        add(p);
036        
037        turnoutMastScroll = new JScrollPane(turnoutMastPanel);
038        turnoutMastScroll.setBorder(BorderFactory.createEmptyBorder());
039        add(turnoutMastScroll);
040    }
041
042    /** {@inheritDoc} */
043    @Override
044    @Nonnull public String getPaneName() {
045        return Bundle.getMessage("TurnCtlMast");
046    }
047
048    JPanel turnoutMastPanel = new JPanel();
049    JScrollPane turnoutMastScroll;
050    JCheckBox resetPreviousState = new JCheckBox(Bundle.getMessage("ResetPrevious"));
051
052    JCheckBox allowUnLit = new JCheckBox();
053    
054    LinkedHashMap<String, TurnoutAspectPanel> turnoutAspect = new LinkedHashMap<>(NOTIONAL_ASPECT_COUNT); // only used once, see updateTurnoutAspectPanel()
055    JPanel disabledAspectsPanel = new JPanel();
056    
057    TurnoutSignalMast currentMast = null;
058
059    /** {@inheritDoc} */
060    @Override
061    public void setAspectNames(@Nonnull SignalAppearanceMap map, @Nonnull SignalSystem sigSystem) {
062        Enumeration<String> aspects = map.getAspects();
063        log.debug("setAspectNames(...)");
064
065        turnoutAspect.clear();
066        while (aspects.hasMoreElements()) {
067            String aspect = aspects.nextElement();
068            TurnoutAspectPanel aPanel = new TurnoutAspectPanel(aspect);
069            turnoutAspect.put(aspect, aPanel);
070        }
071
072        turnoutMastPanel.removeAll();
073        for (Map.Entry<String, TurnoutAspectPanel> entry : turnoutAspect.entrySet()) {
074            log.trace("   aspect: {}", entry.getKey());
075            turnoutMastPanel.add(entry.getValue().getPanel());
076        }
077
078        turnoutMastPanel.add(resetPreviousState);
079        resetPreviousState.setToolTipText(Bundle.getMessage("ResetPreviousToolTip"));
080
081        turnoutMastPanel.setLayout(new jmri.util.javaworld.GridLayout2(0, 2)); // 0 means enough
082        
083        turnoutMastPanel.revalidate();
084        turnoutMastScroll.revalidate();
085    }
086
087    /** {@inheritDoc} */
088    @Override
089    public boolean canHandleMast(@Nonnull SignalMast mast) {
090        return mast instanceof TurnoutSignalMast;
091    }
092
093    /** {@inheritDoc} */
094    @Override
095    public void setMast(SignalMast mast) { 
096        log.trace("setMast({}) start", mast);
097        if (mast == null) { 
098            currentMast = null; 
099            return; 
100        }
101        
102        if (! (mast instanceof TurnoutSignalMast) ) {
103            log.error("mast was wrong type: {} {}", mast.getSystemName(), mast.getClass().getName());
104            return;
105        }
106
107        currentMast = (TurnoutSignalMast) mast;
108        SignalAppearanceMap appMap = mast.getAppearanceMap();
109
110        if (appMap != null) {
111            Enumeration<String> aspects = appMap.getAspects();
112            while (aspects.hasMoreElements()) {
113                String key = aspects.nextElement();
114                Objects.requireNonNull(key, "only non-null keys are expected");
115                TurnoutAspectPanel turnPanel = turnoutAspect.get(key);
116                Objects.requireNonNull(turnPanel, "a panel should exist for each aspect");
117                turnPanel.setSelectedTurnout(currentMast.getTurnoutName(key));
118                turnPanel.setTurnoutState(currentMast.getTurnoutState(key));
119                turnPanel.setAspectDisabled(currentMast.isAspectDisabled(key));
120            }
121        }
122        if (currentMast.resetPreviousStates()) {
123            resetPreviousState.setSelected(true);
124        }
125        if (currentMast.allowUnLit()) {
126            turnoutUnLitBox.setDefaultNamedBean(currentMast.getUnLitTurnout());
127            if (currentMast.getUnLitTurnoutState() == Turnout.CLOSED) {
128                turnoutUnLitState.setSelectedItem(stateClosed);
129            } else {
130                turnoutUnLitState.setSelectedItem(stateThrown);
131            }
132
133        }
134
135        allowUnLit.setSelected(currentMast.allowUnLit());
136
137        log.trace("setMast({}) end", mast);
138    }
139
140    /** {@inheritDoc} */
141    @Override
142    public boolean createMast(@Nonnull String sigsysname, @Nonnull String mastname, @Nonnull String username) {
143        log.debug("createMast({},{})", sigsysname, mastname);
144        String name;
145        if (currentMast == null) {
146            name = "IF$tsm:"
147                    + sigsysname
148                    + ":" + mastname.substring(11, mastname.length() - 4);
149            name += "($" + (paddedNumber.format(TurnoutSignalMast.getLastRef() + 1)) + ")";
150            currentMast = new TurnoutSignalMast(name);
151
152            InstanceManager.getDefault(jmri.SignalMastManager.class).register(currentMast);
153        }
154        name = currentMast.getSystemName();
155        
156        // load a new or existing mast
157        for (Map.Entry<String, TurnoutAspectPanel> entry : turnoutAspect.entrySet()) {
158            entry.getValue().setReference(name + ":" + entry.getKey());
159            turnoutMastPanel.add(entry.getValue().getPanel());
160            if (entry.getValue().isAspectDisabled()) {
161                currentMast.setAspectDisabled(entry.getKey());
162            } else {
163                currentMast.setAspectEnabled(entry.getKey());
164                currentMast.setTurnout(entry.getKey(), entry.getValue().getTurnoutName(), entry.getValue().getTurnoutState());
165            }
166        }
167        currentMast.resetPreviousStates(resetPreviousState.isSelected());
168        if (!username.isEmpty()) {
169            currentMast.setUserName(username);
170        }
171        currentMast.setAllowUnLit(allowUnLit.isSelected());
172        if (allowUnLit.isSelected()) {
173            currentMast.setUnLitTurnout(turnoutUnLitBox.getDisplayName(), turnoutStateValues[turnoutUnLitState.getSelectedIndex()]);
174        }
175        return true;
176    }
177
178    String stateThrown = InstanceManager.turnoutManagerInstance().getThrownText();
179    String stateClosed = InstanceManager.turnoutManagerInstance().getClosedText();
180    
181    String[] turnoutStates = new String[]{stateClosed, stateThrown};
182    int[] turnoutStateValues = new int[]{Turnout.CLOSED, Turnout.THROWN};
183
184    BeanSelectCreatePanel<Turnout> turnoutUnLitBox = new BeanSelectCreatePanel<>(InstanceManager.turnoutManagerInstance(), null);
185    JComboBox<String> turnoutUnLitState = new JComboBox<>(turnoutStates);
186    DecimalFormat paddedNumber = new DecimalFormat("0000");
187
188    @ServiceProvider(service = SignalMastAddPane.SignalMastAddPaneProvider.class)
189    static public class SignalMastAddPaneProvider extends SignalMastAddPane.SignalMastAddPaneProvider {
190        /** {@inheritDoc} */
191        @Override
192        @Nonnull public String getPaneName() {
193            return Bundle.getMessage("TurnCtlMast");
194        }
195        /** {@inheritDoc} */
196        @Override
197        @Nonnull public SignalMastAddPane getNewPane() {
198            return new TurnoutSignalMastAddPane();
199        }
200    }
201
202    /**
203     * JPanel to define properties of an Aspect for a Turnout Signal Mast.
204     * <p>
205     * Invoked from the AddSignalMastPanel class when a Turnout Signal Mast is
206     * selected.
207     */
208    class TurnoutAspectPanel {
209
210        BeanSelectCreatePanel<Turnout> beanBox = new BeanSelectCreatePanel<>(InstanceManager.turnoutManagerInstance(), null);
211        JCheckBox disabledCheck = new JCheckBox(Bundle.getMessage("DisableAspect"));
212        JLabel turnoutStateLabel = new JLabel(Bundle.getMessage("SetState"));
213        JComboBox<String> turnoutState = new JComboBox<>(turnoutStates);
214
215        String aspect = "";
216
217        TurnoutAspectPanel(String aspect) {
218            this.aspect = aspect;
219        }
220
221        TurnoutAspectPanel(String turnoutName, int state) {
222            if (turnoutName == null || turnoutName.isEmpty()) {
223                return;
224            }
225            beanBox.setDefaultNamedBean(InstanceManager.turnoutManagerInstance().getTurnout(turnoutName));
226        }
227
228        /**
229         * Store the mast name as comment in the turnout.
230         *
231         * @param reference Text to use as comment
232         */
233        void setReference(String reference) {
234            beanBox.setReference(reference);
235        }
236
237        int getTurnoutState() {
238            return turnoutStateValues[turnoutState.getSelectedIndex()];
239        }
240
241        void setSelectedTurnout(String name) {
242            if (name == null || name.isEmpty()) {
243                return;
244            }
245            beanBox.setDefaultNamedBean(InstanceManager.turnoutManagerInstance().getTurnout(name));
246        }
247
248        void setTurnoutState(int state) {
249            if (state == Turnout.CLOSED) {
250                turnoutState.setSelectedItem(stateClosed);
251            } else {
252                turnoutState.setSelectedItem(stateThrown);
253            }
254        }
255
256        void setAspectDisabled(boolean boo) {
257            disabledCheck.setSelected(boo);
258            if (boo) {
259                beanBox.setEnabled(false);
260                turnoutStateLabel.setEnabled(false);
261                turnoutState.setEnabled(false);
262            } else {
263                beanBox.setEnabled(true);
264                turnoutStateLabel.setEnabled(true);
265                turnoutState.setEnabled(true);
266            }
267        }
268
269        boolean isAspectDisabled() {
270            return disabledCheck.isSelected();
271        }
272
273        String getTurnoutName() {
274            return beanBox.getDisplayName();
275        }
276
277        NamedBean getTurnout() {
278            try {
279                return beanBox.getNamedBean();
280            } catch (jmri.JmriException ex) {
281                log.warn("skipping creation of turnout");
282                return null;
283            }
284        }
285
286        JPanel panel;
287
288        JPanel getPanel() {
289            if (panel == null) {
290                panel = new JPanel();
291                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
292                JPanel turnDetails = new JPanel();
293                turnDetails.add(beanBox);
294                turnDetails.add(turnoutStateLabel);
295                turnDetails.add(turnoutState);
296                panel.add(turnDetails);
297                panel.add(disabledCheck);
298                TitledBorder border = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black));
299                border.setTitle(aspect);
300                panel.setBorder(border);
301
302                disabledCheck.addActionListener((ActionEvent e) -> {
303                    setAspectDisabled(disabledCheck.isSelected());
304                });
305
306            }
307            return panel;
308        }
309
310    }
311
312    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TurnoutSignalMastAddPane.class);
313
314}