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