001package jmri.jmrit.operations.locations.tools;
002
003import java.awt.*;
004import java.util.List;
005
006import javax.swing.*;
007
008import jmri.jmrit.operations.OperationsFrame;
009import jmri.jmrit.operations.OperationsXml;
010import jmri.jmrit.operations.locations.*;
011import jmri.jmrit.operations.locations.gui.TrackEditFrame;
012import jmri.jmrit.operations.setup.Control;
013import jmri.jmrit.operations.setup.Setup;
014import jmri.util.swing.JmriJOptionPane;
015
016/**
017 *
018 * Things to test with this frame:
019 *
020 * - Adding a new Pool name to the available pools list
021 *
022 * - What happens when a null track is passed to the frame
023 *
024 * - Selecting an existing pool and saving it to the track
025 *
026 * - Selecting a minimum length and saving it to the track
027 *
028 * - Not sure if we want to test the status display panel, as it doesn't do
029 * anything.
030 *
031 * @author Daniel Boudreau Copyright (C) 2011
032 * @author Gregory Madsen Copyright (C) 2012
033 *
034 *
035 */
036class PoolTrackFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
037
038    // labels
039    JLabel name = new JLabel(Bundle.getMessage("Name"));
040    JLabel minimum = new JLabel(Bundle.getMessage("Minimum"));
041    JLabel maximum = new JLabel(Bundle.getMessage("Maximum"));
042    JLabel length = new JLabel(Bundle.getMessage("Length"));
043
044    // text field
045    JTextField trackPoolNameTextField = new JTextField(20);
046    JTextField trackMinLengthTextField = new JTextField(5);
047
048    // combo box
049    JComboBox<Pool> comboBoxPools = new JComboBox<>();
050    
051    // train departure order out of staging
052    JRadioButton orderNormal = new JRadioButton(Bundle.getMessage("Normal"));
053    JRadioButton orderFIFO = new JRadioButton(Bundle.getMessage("DescriptiveFIFO"));
054    JRadioButton orderLIFO = new JRadioButton(Bundle.getMessage("DescriptiveLIFO"));
055
056    // major buttons
057    JButton addButton = new JButton(Bundle.getMessage("Add"));
058    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
059
060    // pool status
061    JPanel poolStatus = new JPanel();
062
063    private TrackEditFrame _tefx;
064    protected Track _track;
065    protected Pool _pool;
066
067    public PoolTrackFrame(TrackEditFrame tef) {
068        super();
069
070        _tefx = tef;
071        _track = _tefx._track;
072    }
073
074    public PoolTrackFrame(Track track) {
075        super();
076        _track = track;
077    }
078
079    @Override
080    public void initComponents() {
081        if (_track == null) {
082            log.debug("track is null, pools can not be created");
083            return;
084        }
085        // the following code sets the frame's initial state
086        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
087
088        _track.addPropertyChangeListener(this);
089        _track.getLocation().addPropertyChangeListener(this);
090
091        _pool = _track.getPool();
092
093        if (_pool != null) {
094            _pool.addPropertyChangeListener(this);
095        }
096
097        // load the panel
098        JPanel p1 = new JPanel();
099        p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS));
100        JScrollPane p1Pane = new JScrollPane(p1);
101        p1Pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
102        p1Pane.setBorder(BorderFactory.createTitledBorder(""));
103        
104        // row 1
105        JPanel pt = new JPanel();
106        pt.setLayout(new BoxLayout(pt, BoxLayout.X_AXIS));
107        pt.setMaximumSize(new Dimension(2000, 250));
108
109        // row 1a
110        JPanel pTrackName = new JPanel();
111        pTrackName.setLayout(new GridBagLayout());
112        pTrackName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Track")));
113        addItem(pTrackName, new JLabel(_track.getName()), 0, 0);
114
115        // row 1b
116        JPanel pLocationName = new JPanel();
117        pLocationName.setLayout(new GridBagLayout());
118        pLocationName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Location")));
119        addItem(pLocationName, new JLabel(_track.getLocation().getName()), 0, 0);
120
121        pt.add(pTrackName);
122        pt.add(pLocationName);
123
124        JPanel poolName = new JPanel();
125        poolName.setLayout(new GridBagLayout());
126        poolName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PoolName")));
127        addItem(poolName, trackPoolNameTextField, 0, 0);
128        addItem(poolName, addButton, 1, 0);
129
130        JPanel selectPool = new JPanel();
131        selectPool.setLayout(new GridBagLayout());
132        selectPool.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PoolSelect")));
133        addItem(selectPool, comboBoxPools, 0, 0);
134
135        JPanel minLengthTrack = new JPanel();
136        minLengthTrack.setLayout(new GridBagLayout());
137        minLengthTrack
138                .setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PoolTrackMinimum", _track.getName())));
139        addItem(minLengthTrack, trackMinLengthTextField, 0, 0);
140
141        trackMinLengthTextField.setText(Integer.toString(_track.getMinimumLength()));
142        
143        // row 4, train service order panel
144        JPanel panelOrder = new JPanel();
145        panelOrder.setLayout(new GridBagLayout());
146        panelOrder.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainPickupOrder")));
147        panelOrder.add(orderNormal);
148        panelOrder.add(orderFIFO);
149        panelOrder.add(orderLIFO);
150        
151        ButtonGroup orderGroup = new ButtonGroup();
152        orderGroup.add(orderNormal);
153        orderGroup.add(orderFIFO);
154        orderGroup.add(orderLIFO);
155        
156        updateRadioButtons();
157        
158        addRadioButtonAction(orderNormal);
159        addRadioButtonAction(orderFIFO);
160        addRadioButtonAction(orderLIFO);
161
162        JPanel savePool = new JPanel();
163        savePool.setLayout(new GridBagLayout());
164        savePool.setBorder(BorderFactory.createTitledBorder(""));
165        addItem(savePool, saveButton, 0, 0);
166
167        p1.add(pt);
168        p1.add(poolName);
169        p1.add(selectPool);
170        p1.add(minLengthTrack);
171        if (_track.isStaging()) {
172            p1.add(panelOrder);
173        }
174        p1.add(savePool);
175
176        JPanel p2 = new JPanel();
177        p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
178        JScrollPane p2Pane = new JScrollPane(p2);
179        p2Pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
180        p2Pane.setBorder(BorderFactory.createTitledBorder(""));
181
182        // pool status panel
183        poolStatus.setLayout(new GridBagLayout());
184
185        p2.add(poolStatus);
186
187        getContentPane().add(p1Pane);
188        getContentPane().add(p2Pane);
189        setTitle(Bundle.getMessage("MenuItemPoolTrack"));
190
191        // load comboBox
192        updatePoolsComboBox();
193        updatePoolStatus();
194
195        // button action - These use a convention in the OperationsFrame base
196        // class that requires the events to be sorted out in
197        // buttonActionPerformed.
198        addButtonAction(addButton);
199        addButtonAction(saveButton);
200        
201        // add help menu to window
202        addHelpMenu("package.jmri.jmrit.operations.Operations_Pools", true); // NOI18N
203        
204        initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight300));
205    }
206
207    private void updatePoolsComboBox() {
208        _track.getLocation().updatePoolComboBox(comboBoxPools);
209        comboBoxPools.setSelectedItem(_track.getPool());
210    }
211
212    private void updatePoolStatus() {
213        // This shows the details of the current member tracks in the Pool.
214        poolStatus.removeAll();
215
216        addItemLeft(poolStatus, name, 0, 0);
217        addItem(poolStatus, maximum, 1, 0);
218        addItem(poolStatus, minimum, 2, 0);
219        addItem(poolStatus, length, 3, 0);
220
221        String poolName = "";
222        if (_track.getPool() != null) {
223            Pool pool = _track.getPool();
224            poolName = pool.getName();
225            List<Track> tracks = pool.getTracks();
226            int totalMinLength = 0;
227            int totalLength = 0;
228            for (int i = 0; i < tracks.size(); i++) {
229                Track track = tracks.get(i);
230                JLabel name = new JLabel();
231                name.setText(track.getName());
232                
233                JLabel maximum = new JLabel();
234                maximum.setText(Integer.toString(pool.getMaxLengthTrack(track)));
235
236                JLabel minimum = new JLabel();
237                minimum.setText(Integer.toString(track.getMinimumLength()));
238                totalMinLength = totalMinLength + track.getMinimumLength();
239
240                JLabel length = new JLabel();
241                length.setText(Integer.toString(track.getLength()));
242                totalLength = totalLength + track.getLength();
243
244                addItemLeft(poolStatus, name, 0, i + 1);
245                addItem(poolStatus, maximum, 1, i + 1);
246                addItem(poolStatus, minimum, 2, i + 1);
247                addItem(poolStatus, length, 3, i + 1);
248            }
249            // Summary
250            int totalLine = tracks.size() + 1;
251            JLabel total = new JLabel(Bundle.getMessage("Totals"));
252            addItem(poolStatus, total, 0, totalLine);
253            if (totalMinLength > totalLength) {
254                JLabel error = new JLabel(Bundle.getMessage("ErrorMinLen"));
255                error.setForeground(Color.RED);
256                addItem(poolStatus, error, 1, totalLine);
257            }
258            JLabel totalMin = new JLabel();
259            totalMin.setText(Integer.toString(totalMinLength));
260            addItem(poolStatus, totalMin, 2, totalLine);
261            JLabel totalLen = new JLabel();
262            totalLen.setText(Integer.toString(totalLength));
263            addItem(poolStatus, totalLen, 3, totalLine);
264        }
265        poolStatus.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("PoolTracks", poolName)));
266        poolStatus.repaint();
267        poolStatus.revalidate();
268        setPreferredSize(null); // kill JMRI window size
269        pack();
270    }
271
272    @Override
273    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
274        if (ae.getSource() == addButton) {
275            Location location = _track.getLocation();
276            location.addPool(trackPoolNameTextField.getText().trim());
277        }
278
279        if (ae.getSource() == saveButton) {
280            try {
281                _track.setMinimumLength(Integer.parseInt(trackMinLengthTextField.getText()));
282            } catch (NumberFormatException e) {
283                JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackMustBeNumber"), Bundle
284                        .getMessage("ErrorTrackLength"), JmriJOptionPane.ERROR_MESSAGE);
285                return;
286            }
287
288            if (_pool != null) {
289                _pool.removePropertyChangeListener(this);
290            }
291            _pool = (Pool) comboBoxPools.getSelectedItem();
292            if (_pool != null) {
293                _pool.addPropertyChangeListener(this);
294            }
295            _track.setPool(_pool); // this causes a property change to this frame
296            updateServiceOrder();
297
298            // save location file
299            OperationsXml.save();
300            if (Setup.isCloseWindowOnSaveEnabled()) {
301                dispose();
302            }
303        }
304    }
305    
306    @Override
307    public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) {
308        log.debug("radio button activated");
309        if (_track.getPool() != null) {
310            for (Track track : _track.getPool().getTracks()) {
311                if (ae.getSource() == orderNormal) {
312                    track.setServiceOrder(Track.NORMAL);
313                }
314                if (ae.getSource() == orderFIFO) {
315                    track.setServiceOrder(Track.FIFO);
316                }
317                if (ae.getSource() == orderLIFO) {
318                    track.setServiceOrder(Track.LIFO);
319                }
320            }
321        }
322    }
323    
324    private void updateServiceOrder() {
325        if (_track.isStaging() && _track.getPool() != null) {
326            for (Track track : _track.getPool().getTracks()) {
327                if (track != _track) {
328                    _track.setServiceOrder(track.getServiceOrder());
329                    updateRadioButtons();
330                    break;
331                }
332            }
333        }
334    }
335    
336    private void updateRadioButtons() {
337        orderNormal.setSelected(_track.getServiceOrder().equals(Track.NORMAL));
338        orderFIFO.setSelected(_track.getServiceOrder().equals(Track.FIFO));
339        orderLIFO.setSelected(_track.getServiceOrder().equals(Track.LIFO));
340    }
341
342    @Override
343    public void dispose() {
344        if (_track != null) {
345            _track.removePropertyChangeListener(this);
346            _track.getLocation().removePropertyChangeListener(this);
347        }
348        if (_pool != null) {
349            _pool.removePropertyChangeListener(this);
350        }
351        super.dispose();
352    }
353
354    @Override
355    public void propertyChange(java.beans.PropertyChangeEvent e) {
356        // This should move to the base class
357        // Just call LogEvent(e); instead. It will figure out if logging is
358        // enabled, etc.
359        if (Control.SHOW_PROPERTY) {
360            log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e
361                    .getNewValue());
362        }
363        if (e.getPropertyName().equals(Location.POOL_LENGTH_CHANGED_PROPERTY)) {
364            updatePoolsComboBox();
365        }
366
367        if (e.getPropertyName().equals(Pool.LISTCHANGE_CHANGED_PROPERTY)
368                || e.getPropertyName().equals(Location.LENGTH_CHANGED_PROPERTY)
369                || e.getPropertyName().equals(Track.POOL_CHANGED_PROPERTY)
370                || e.getPropertyName().equals(Track.MIN_LENGTH_CHANGED_PROPERTY)) {
371            updatePoolStatus();
372        }
373    }
374
375    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PoolTrackFrame.class);
376}