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