001package jmri.jmrit.signalling; 002 003import java.awt.BorderLayout; 004import java.awt.Component; 005import java.awt.Container; 006import java.awt.Dimension; 007import java.awt.FlowLayout; 008import java.awt.GridLayout; 009import java.awt.event.ActionEvent; 010import java.beans.PropertyChangeListener; 011import java.util.ArrayList; 012import java.util.Hashtable; 013import java.util.List; 014import java.util.Vector; 015 016import javax.swing.BorderFactory; 017import javax.swing.Box; 018import javax.swing.BoxLayout; 019import javax.swing.ButtonGroup; 020import javax.swing.JButton; 021import javax.swing.JCheckBox; 022import javax.swing.JComboBox; 023import javax.swing.JFrame; 024import javax.swing.JLabel; 025import javax.swing.JPanel; 026import javax.swing.JRadioButton; 027import javax.swing.JScrollPane; 028import javax.swing.JTabbedPane; 029import javax.swing.JTable; 030import javax.swing.SortOrder; 031import javax.swing.SwingUtilities; 032import javax.swing.table.AbstractTableModel; 033import javax.swing.table.TableColumn; 034import javax.swing.table.TableColumnModel; 035import javax.swing.table.TableRowSorter; 036 037import jmri.*; 038import jmri.NamedBean.DisplayOptions; 039import jmri.implementation.SignalSpeedMap; 040import jmri.jmrit.beantable.RowComboBoxPanel; 041import jmri.jmrit.display.layoutEditor.LayoutBlockConnectivityTools; 042import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 043import jmri.swing.NamedBeanComboBox; 044import jmri.swing.RowSorterUtil; 045import jmri.util.AlphanumComparator; 046import jmri.util.swing.JComboBoxUtil; 047import jmri.util.swing.JmriJOptionPane; 048import jmri.util.swing.JmriPanel; 049 050/** 051 * Create a JFrame to configure Signal Mast Logic Pairs (Source + Destination 052 * Masts). 053 * 054 * @author Kevin Dickerson Copyright (C) 2011 055 * @author Egbert Broerse Copyright (C) 2017, 2018, 2019 056 */ 057public class SignallingPanel extends JmriPanel { 058 059 private final NamedBeanComboBox<SignalMast> sourceMastBox; 060 private final NamedBeanComboBox<SignalMast> destMastBox; 061 private JLabel fixedSourceMastLabel = new JLabel(); 062 private JLabel fixedDestMastLabel = new JLabel(); 063 private static final JLabel sourceMastLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("SourceMast")), JLabel.TRAILING); // NOI18N 064 private static final JLabel destMastLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("DestMast")), JLabel.TRAILING); // NOI18N 065 private final JCheckBox useLayoutEditor = new JCheckBox(Bundle.getMessage("UseLayoutEditorPaths")); // NOI18N 066 private final JCheckBox useLayoutEditorTurnout = new JCheckBox(Bundle.getMessage("UseTurnoutDetails")); // NOI18N 067 private final JCheckBox useLayoutEditorBlock = new JCheckBox(Bundle.getMessage("UseBlockDetails")); // NOI18N 068 private final JCheckBox allowAutoMastGeneration = new JCheckBox(Bundle.getMessage("AllowAutomaticSignalMast")); // NOI18N 069 private final JCheckBox lockTurnouts = new JCheckBox(Bundle.getMessage("LockTurnouts")); // NOI18N 070 private static final JButton sizer = new JButton("Sizer"); // NOI18N 071 072 // fields to store the items currently being configured 073 private SignalMast sourceMast; 074 private SignalMast destMast; 075 private SignalMastLogic sml; 076 077 private final jmri.NamedBeanHandleManager nbhm = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class); 078 079 private JFrame jFrame; 080 081 // Size of the individual bean tables inside the shared pane 082 private static final Dimension TABLESIZEPREFERRED = new Dimension(720, 200); 083 084 /** 085 * Create an empty JPanel to configure a new Signal Mast Logic. 086 * 087 * @param frame Name for the enclosing JFrame 088 */ 089 public SignallingPanel(JFrame frame) { 090 this(null, null, frame); 091 } 092 093 /** 094 * Create and fill in the JPanel to edit an existing Signal Mast Logic. 095 * 096 * @see SignallingFrame 097 * @param source Bean of Source Signal Mast 098 * @param dest Bean of Destination Signal Mast 099 * @param frame Name for the enclosing JFrame 100 */ 101 public SignallingPanel(SignalMast source, SignalMast dest, JFrame frame) { 102 super(); 103 jFrame = frame; 104 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); // NOI18N 105 JButton updateButton = new JButton(Bundle.getMessage("UpdateLogicButton")); // NOI18N 106 JButton applyButton = new JButton(Bundle.getMessage("ButtonApply")); // NOI18N 107 JLabel mastSpeed = new JLabel(); 108 109 if (source != null) { 110 this.sourceMast = source; 111 this.sml = InstanceManager.getDefault(jmri.SignalMastLogicManager.class).getSignalMastLogic(source); 112 fixedSourceMastLabel = new JLabel(sourceMast.getDisplayName()); 113 // if (dest != null) { 114 // frame.setTitle(source.getDisplayName() + " to " + dest.getDisplayName()); 115 // } 116 } 117 if ((dest != null) && (sml != null)) { 118 this.destMast = dest; 119 if (!sml.isDestinationValid(dest)) { 120 sml.setDestinationMast(dest); 121 } 122 fixedDestMastLabel = new JLabel(destMast.getDisplayName()); 123 useLayoutEditor.setSelected(sml.useLayoutEditor(destMast)); 124 useLayoutEditorTurnout.setSelected(sml.useLayoutEditorTurnouts(destMast)); 125 useLayoutEditorBlock.setSelected(sml.useLayoutEditorBlocks(destMast)); 126 allowAutoMastGeneration.setSelected(sml.allowAutoMaticSignalMastGeneration(destMast)); 127 lockTurnouts.setSelected(sml.isTurnoutLockAllowed(destMast)); 128 129 float pathSpeed = sml.getMaximumSpeed(dest); 130 if (pathSpeed == 0.0f) { 131 mastSpeed.setText(Bundle.getMessage("MakeLabel", Bundle.getMessage("PathSpeed")) + " " + Bundle.getMessage("NoneSet")); // NOI18N 132 } else { 133 String speed = jmri.InstanceManager.getDefault(SignalSpeedMap.class).getNamedSpeed(pathSpeed); 134 if (speed != null) { 135 mastSpeed.setText(Bundle.getMessage("MakeLabel", Bundle.getMessage("PathSpeed")) + " " + speed); // NOI18N 136 } else { 137 mastSpeed.setText(Bundle.getMessage("MakeLabel", Bundle.getMessage("PathSpeed")) + " " + pathSpeed); // NOI18N 138 } 139 } 140 } else if (dest == null) { 141 sml = null; 142 } 143 144 SignalMastManager smm = InstanceManager.getDefault(jmri.SignalMastManager.class); 145 sourceMastBox = new NamedBeanComboBox<>(smm, sourceMast, DisplayOptions.DISPLAYNAME); 146 sourceMastBox.setMaximumSize(sourceMastBox.getPreferredSize()); 147 destMastBox = new NamedBeanComboBox<>(smm, destMast, DisplayOptions.DISPLAYNAME); 148 destMastBox.setMaximumSize(destMastBox.getPreferredSize()); 149 150 JComboBoxUtil.setupComboBoxMaxRows(sourceMastBox); 151 JComboBoxUtil.setupComboBoxMaxRows(destMastBox); 152 153 // directly add sub-panes onto JFrame's content pane to allow resizing (2018) 154 Container contentPane = frame.getContentPane(); 155 156 JPanel header = new JPanel(); 157 header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS)); 158 159 JPanel mastGrid = new JPanel(); 160 GridLayout layout = new GridLayout(2, 2, 10, 0); // (int rows, int cols, int hgap, int vgap) 161 mastGrid.setLayout(layout); 162 // row 1 163 mastGrid.add(sourceMastLabel); 164 165 JPanel sourcePanel = new JPanel(); 166 sourcePanel.setLayout(new BoxLayout(sourcePanel, BoxLayout.X_AXIS)); 167 sourcePanel.add(sourceMastBox); 168 sourcePanel.add(fixedSourceMastLabel); 169 mastGrid.add(sourcePanel); 170 // row 2 171 mastGrid.add(destMastLabel); 172 173 JPanel destPanel = new JPanel(); 174 destPanel.setLayout(new BoxLayout(destPanel, BoxLayout.X_AXIS)); 175 destPanel.add(destMastBox); 176 destPanel.add(fixedDestMastLabel); 177 178 destMastBox.addActionListener(e -> { 179 if (useLayoutEditor.isSelected()) { 180 try { 181 boolean valid = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlockConnectivityTools().checkValidDest(sourceMastBox.getSelectedItem(), 182 destMastBox.getSelectedItem(), LayoutBlockConnectivityTools.Routing.MASTTOMAST); 183 if (!valid) { 184 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorUnReachableDestination")); 185 } 186 } catch (jmri.JmriException je) { 187 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("WarningUnableToValidate")); 188 } 189 } 190 }); 191 192 mastGrid.add(destPanel); 193 header.add(mastGrid); 194 195 header.add(mastSpeed); 196 197 JPanel editor = new JPanel(); 198 editor.setLayout(new BoxLayout(editor, BoxLayout.Y_AXIS)); 199 useLayoutEditor.setAlignmentX(Component.LEFT_ALIGNMENT); 200 editor.add(useLayoutEditor); 201 202 JPanel useLayoutEditorSubPanel = new JPanel(); // indent 2 options connected to LayoutEditor choice 203 useLayoutEditorSubPanel.setLayout(new BoxLayout(useLayoutEditorSubPanel, BoxLayout.Y_AXIS)); 204 useLayoutEditorSubPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); 205 useLayoutEditorSubPanel.add(useLayoutEditorTurnout); 206 useLayoutEditorSubPanel.add(useLayoutEditorBlock); 207 editor.add(useLayoutEditorSubPanel); 208 useLayoutEditorSubPanel.setVisible(false); 209 210 useLayoutEditor.addActionListener(e -> { 211 212 useLayoutEditorSubPanel.setVisible(useLayoutEditor.isSelected()); 213 // Setup for display of all Turnouts, if needed 214 boolean valid; 215 if (useLayoutEditor.isSelected()) { 216 jFrame.pack(); 217 if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) { 218 int response = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("EnableLayoutBlockRouting"), 219 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.QUESTION_MESSAGE); 220 if (response == JmriJOptionPane.YES_OPTION) { 221 InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true); 222 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LayoutBlockRoutingEnabled")); // NOI18N 223 } 224 } 225 226 if ((sml != null) && (destMast != null)) { 227 try { 228 sml.useLayoutEditor(useLayoutEditor.isSelected(), destMast); 229 } catch (jmri.JmriException je) { 230 JmriJOptionPane.showMessageDialog(this, je.toString()); 231 } 232 try { 233 valid = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlockConnectivityTools().checkValidDest(sourceMastBox.getSelectedItem(), 234 destMastBox.getSelectedItem(), LayoutBlockConnectivityTools.Routing.MASTTOMAST); 235 if (!valid) { 236 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorUnReachableDestination")); 237 } 238 } catch (jmri.JmriException je) { 239 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("WarningUnableToValidate")); 240 } 241 } 242 } 243 }); 244 header.add(editor); 245 header.add(allowAutoMastGeneration); 246 header.add(lockTurnouts); 247 248 // selection radiobuttons for All/Included items 249 JPanel py = new JPanel(); 250 py.add(new JLabel(Bundle.getMessage("Show"))); // NOI18N 251 ButtonGroup selGroup = new ButtonGroup(); 252 allButton = new JRadioButton(Bundle.getMessage("All"), true); // NOI18N 253 selGroup.add(allButton); 254 py.add(allButton); 255 allButton.addActionListener(e -> { 256 // Setup for display of all Turnouts, if needed 257 if (!showAll) { 258 showAll = true; 259 _blockModel.fireTableDataChanged(); 260 _turnoutModel.fireTableDataChanged(); 261 _signalMastModel.fireTableDataChanged(); 262 _sensorModel.fireTableDataChanged(); 263 } 264 }); 265 JRadioButton includedButton = new JRadioButton(Bundle.getMessage("Included"), false); // NOI18N 266 selGroup.add(includedButton); 267 py.add(includedButton); 268 includedButton.addActionListener(e -> { 269 // Setup for display of included Turnouts only, if needed 270 if (showAll) { 271 showAll = false; 272 initializeIncludedList(); 273 _blockModel.fireTableDataChanged(); 274 _turnoutModel.fireTableDataChanged(); 275 _signalMastModel.fireTableDataChanged(); 276 _sensorModel.fireTableDataChanged(); 277 } 278 }); 279 py.add(new JLabel(" " + Bundle.getMessage("Elements"))); // NOI18N 280 header.add(py); 281 contentPane.add(header); 282 283 // build_x_Panel() returns a JScrollFrame 284 JTabbedPane detailsTab = new JTabbedPane(); 285 detailsTab.add(Bundle.getMessage("Blocks"), buildBlocksPanel()); // NOI18N 286 detailsTab.add(Bundle.getMessage("Turnouts"), buildTurnoutPanel()); // NOI18N 287 detailsTab.add(Bundle.getMessage("Sensors"), buildSensorPanel()); // NOI18N 288 detailsTab.add(Bundle.getMessage("SignalMasts"), buildSignalMastPanel()); // NOI18N 289 290 JScrollPane detailsScrollPane = new JScrollPane(detailsTab); // make set of 1-2 tables scrollable on smaller screens 291 contentPane.add(detailsScrollPane); 292 293 JPanel footer = new JPanel(); 294 footer.setLayout(new FlowLayout(FlowLayout.TRAILING)); 295 296 // Cancel button 297 footer.add(cancelButton); 298 cancelButton.addActionListener(this::cancelPressed); 299 300 // Update button 301 footer.add(updateButton); 302 updateButton.addActionListener(this::updatePressed); 303 updateButton.setToolTipText(Bundle.getMessage("UpdateButtonToolTip")); // NOI18N 304 updateButton.setVisible(true); 305 306 // Apply (and Close) button 307 footer.add(applyButton); 308 applyButton.addActionListener(this::applyPressed); 309 applyButton.setToolTipText(Bundle.getMessage("ApplyButtonToolTip")); // NOI18N 310 applyButton.setVisible(true); 311 312 contentPane.add(Box.createVerticalGlue()); // glue above buttons 313 contentPane.add(footer); 314 315 if (sourceMast != null) { // edit an existing SML, fix source mast 316 fixedSourceMastLabel.setVisible(true); 317 sourceMastBox.setVisible(false); 318 } else { // source mast selectable for a new SML 319 fixedSourceMastLabel.setVisible(false); 320 sourceMastBox.setVisible(true); 321 } 322 if ((sml != null) && (destMast != null)) { // edit an existing SML, fix destination mast 323 fixedDestMastLabel.setVisible(true); 324 destMastBox.setVisible(false); 325 useLayoutEditorSubPanel.setVisible(useLayoutEditor.isSelected()); 326 initializeIncludedList(); 327 editDetails(); // pick up details for an existing SML configuration 328 } else { 329 useLayoutEditorSubPanel.setVisible(useLayoutEditor.isSelected()); 330 fixedDestMastLabel.setVisible(false); 331 destMastBox.setVisible(true); 332 } 333 } 334 335 private JScrollPane _manualBlockScrollPane; 336 private JScrollPane _manualSignalMastScrollPane; 337 private JScrollPane _manualSensorScrollPane; 338 339 private BlockModel _blockModel; 340 private AutoBlockModel _autoBlockModel; 341 private List<ManualBlockList> _manualBlockList; 342 private List<AutoBlockList> _automaticBlockList = new ArrayList<>(); 343 344 private TurnoutModel _turnoutModel; 345 private AutoTurnoutModel _autoTurnoutModel; 346 private List<ManualTurnoutList> _manualTurnoutList; 347 private List<AutoTurnoutList> _automaticTurnoutList = new ArrayList<>(); 348 349 private SensorModel _sensorModel; 350 private List<ManualSensorList> _manualSensorList; 351 352 private SignalMastModel _signalMastModel; 353 private AutoMastModel _autoSignalMastModel; 354 private List<ManualSignalMastList> _manualSignalMastList; 355 private List<AutoSignalMastList> _automaticSignalMastList = new ArrayList<>(); 356 357 private final JPanel p2xb = new JPanel(); 358 359 /** 360 * Compose GUI for setting up Blocks tab for an SML. 361 * 362 * @return a JPanel containing the SML control blocks configuration 363 * interface 364 */ 365 private JPanel buildBlocksPanel() { 366 JPanel blockPanel = new JPanel(); 367 blockPanel.setLayout(new BoxLayout(blockPanel, BoxLayout.Y_AXIS)); 368 369 jmri.BlockManager bm = jmri.InstanceManager.getDefault(jmri.BlockManager.class); 370 _manualBlockList = new ArrayList<>(); 371 for (Block b : bm.getNamedBeanSet()) { 372 _manualBlockList.add(new ManualBlockList(b)); 373 } 374 375 if ((sml != null) && (destMast != null)) { 376 List<Block> blkList = sml.getAutoBlocks(destMast); 377 _automaticBlockList = new ArrayList<>(blkList.size()); 378 for (Block blk : blkList) { 379 AutoBlockList blockitem = new AutoBlockList(blk); 380 blockitem.setState(sml.getAutoBlockState(blk, destMast)); 381 _automaticBlockList.add(blockitem); 382 } 383 } 384 JPanel p2xc = new JPanel(); // this hides a field 385 JPanel p2xcSpace = new JPanel(); 386 p2xcSpace.setLayout(new BoxLayout(p2xcSpace, BoxLayout.Y_AXIS)); 387 p2xcSpace.add(new JLabel("XXX")); // NOI18N 388 p2xc.add(p2xcSpace); 389 390 JPanel p21c = new JPanel(); 391 p21c.setLayout(new BoxLayout(p21c, BoxLayout.Y_AXIS)); 392 p21c.add(new JLabel(Bundle.getMessage("LabelSelectChecked", Bundle.getMessage("Blocks")))); // NOI18N 393 p2xc.add(p21c); 394 395 _blockModel = new BlockModel(); 396 JTable manualBlockTable = new JTable(_blockModel); 397 TableRowSorter<BlockModel> manualBlockSorter = new TableRowSorter<>(_blockModel); 398 // configure row height for comboBox 399 manualBlockTable.setRowHeight(sizer.getPreferredSize().height - 2); // row height has to be greater than for plain tables 400 manualBlockSorter.setComparator(BlockModel.SNAME_COLUMN, new jmri.util.AlphanumComparator()); 401 manualBlockSorter.setComparator(BlockModel.UNAME_COLUMN, new jmri.util.AlphanumComparator()); 402 RowSorterUtil.setSortOrder(manualBlockSorter, BlockModel.SNAME_COLUMN, SortOrder.ASCENDING); 403 _blockModel.configStateColumn(manualBlockTable); // create static comboBox in State column 404 manualBlockTable.setRowSorter(manualBlockSorter); 405 manualBlockTable.setRowSelectionAllowed(false); 406 manualBlockTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 407 // JComboBox<String> stateCCombo = new JComboBox<>(); // moved to ManualBlockTable class 408 409 TableColumnModel _manualBlockColumnModel = manualBlockTable.getColumnModel(); 410 TableColumn includeColumnC = _manualBlockColumnModel. 411 getColumn(BlockModel.INCLUDE_COLUMN); 412 includeColumnC.setResizable(false); 413 includeColumnC.setMinWidth(9 * Bundle.getMessage("Include").length()); // was fixed 60 // NOI18N 414 includeColumnC.setMaxWidth(includeColumnC.getMinWidth() + 5); 415 416 TableColumn sNameColumnC = _manualBlockColumnModel. 417 getColumn(BlockModel.SNAME_COLUMN); 418 sNameColumnC.setResizable(true); 419 sNameColumnC.setMinWidth(75); 420 421 TableColumn stateColumnC = _manualBlockColumnModel. 422 getColumn(BlockModel.STATE_COLUMN); 423 //stateColumnC.setCellEditor(new DefaultCellEditor(stateCCombo)); // moved to ManualBlockTable class 424 stateColumnC.setResizable(false); 425 stateColumnC.setMinWidth(9 * Math.max(SET_TO_UNOCCUPIED.length(), SET_TO_OCCUPIED.length()) + 40); 426 stateColumnC.setMaxWidth(stateColumnC.getMinWidth() + 10); // was fixed 100 427 // remaining space is filled by UserName 428 _manualBlockScrollPane = new JScrollPane(manualBlockTable); 429 p2xc.add(_manualBlockScrollPane, BorderLayout.CENTER); 430 blockPanel.add(p2xc); 431 p2xc.setVisible(true); 432 433 setRowHeight(manualBlockTable.getRowHeight()); 434 p2xcSpace.setVisible(false); 435 436 JPanel p2xaSpace = new JPanel(); 437 p2xaSpace.setLayout(new BoxLayout(p2xaSpace, BoxLayout.Y_AXIS)); 438 p2xaSpace.add(new JLabel("XXX")); // NOI18N 439 p2xb.add(p2xaSpace); 440 441 JPanel p21a = new JPanel(); 442 p21a.setLayout(new BoxLayout(p21a, BoxLayout.Y_AXIS)); 443 p21a.add(new JLabel(Bundle.getMessage("LabelAutogenerated", Bundle.getMessage("Blocks")))); // NOI18N 444 p2xb.add(p21a); 445 446 _autoBlockModel = new AutoBlockModel(); 447 JTable autoBlockTable = new JTable(_autoBlockModel); 448 TableRowSorter<AutoBlockModel> autoBlockSorter = new TableRowSorter<>(_autoBlockModel); 449 autoBlockSorter.setComparator(AutoBlockModel.SNAME_COLUMN, new jmri.util.AlphanumComparator()); 450 autoBlockSorter.setComparator(AutoBlockModel.UNAME_COLUMN, new jmri.util.AlphanumComparator()); 451 RowSorterUtil.setSortOrder(autoBlockSorter, AutoBlockModel.SNAME_COLUMN, SortOrder.ASCENDING); 452 autoBlockTable.setRowSorter(autoBlockSorter); 453 autoBlockTable.setRowSelectionAllowed(false); 454 autoBlockTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 455 456 TableColumnModel _autoBlockColumnModel = autoBlockTable.getColumnModel(); 457 TableColumn sNameColumnA = _autoBlockColumnModel. 458 getColumn(AutoBlockModel.SNAME_COLUMN); 459 sNameColumnA.setResizable(true); 460 sNameColumnA.setMinWidth(75); 461 462 TableColumn stateColumnA = _autoBlockColumnModel. 463 getColumn(AutoBlockModel.STATE_COLUMN); 464 stateColumnA.setResizable(false); 465 stateColumnA.setMinWidth(90); 466 stateColumnA.setMaxWidth(100); 467 468 JScrollPane _autoBlockScrollPane = new JScrollPane(autoBlockTable); 469 p2xb.add(_autoBlockScrollPane, BorderLayout.CENTER); 470 blockPanel.add(p2xb); 471 p2xb.setVisible(true); 472 473 setRowHeight(autoBlockTable.getRowHeight()); 474 p2xaSpace.setVisible(false); 475 476 return blockPanel; 477 } 478 479 private final JPanel p2xa = new JPanel(); 480 481 /** 482 * Compose GUI for setting up the Turnouts tab for an SML. 483 * 484 * @return a JPanel containing the SML control turnouts configuration 485 * interface 486 */ 487 private JPanel buildTurnoutPanel() { 488 JPanel turnoutPanel = new JPanel(); 489 turnoutPanel.setLayout(new BoxLayout(turnoutPanel, BoxLayout.Y_AXIS)); 490 491 jmri.TurnoutManager bm = jmri.InstanceManager.turnoutManagerInstance(); 492 _manualTurnoutList = new ArrayList<>(); 493 for (Turnout b : bm.getNamedBeanSet()) { 494 String systemName = b.getSystemName(); 495 String userName = b.getUserName(); 496 _manualTurnoutList.add(new ManualTurnoutList(systemName, userName)); 497 } 498 499 if ((sml != null) && (destMast != null)) { 500 List<Turnout> turnList = sml.getAutoTurnouts(destMast); 501 _automaticTurnoutList = new ArrayList<>(turnList.size()); 502 for (Turnout turn : turnList) { 503 String systemName = turn.getSystemName(); 504 String userName = turn.getUserName(); 505 AutoTurnoutList turnItem = new AutoTurnoutList(systemName, userName); 506 turnItem.setState(sml.getAutoTurnoutState(turn, destMast)); 507 _automaticTurnoutList.add(turnItem); 508 } 509 } 510 511 JPanel p2xt = new JPanel(); 512 JPanel p2xcSpace = new JPanel(); 513 p2xcSpace.setLayout(new BoxLayout(p2xcSpace, BoxLayout.Y_AXIS)); 514 p2xcSpace.add(new JLabel("XXX")); // NOI18N 515 p2xt.add(p2xcSpace); 516 517 JPanel p21c = new JPanel(); 518 p21c.setLayout(new BoxLayout(p21c, BoxLayout.Y_AXIS)); 519 p21c.add(new JLabel(Bundle.getMessage("LabelSelectChecked", Bundle.getMessage("Turnouts")))); // NOI18N 520 p2xt.add(p21c); 521 522 _turnoutModel = new TurnoutModel(); 523 JTable manualTurnoutTable = new JTable(_turnoutModel); 524 TableRowSorter<TurnoutModel> manualTurnoutSorter = new TableRowSorter<>(_turnoutModel); 525 // configure row height for comboBox 526 manualTurnoutTable.setRowHeight(sizer.getPreferredSize().height - 2); // row height has to be greater than for plain tables 527 manualTurnoutSorter.setComparator(TurnoutModel.SNAME_COLUMN, new AlphanumComparator()); 528 manualTurnoutSorter.setComparator(TurnoutModel.UNAME_COLUMN, new AlphanumComparator()); 529 RowSorterUtil.setSortOrder(manualTurnoutSorter, TurnoutModel.SNAME_COLUMN, SortOrder.ASCENDING); 530 _turnoutModel.configStateColumn(manualTurnoutTable); // create static comboBox in State column 531 manualTurnoutTable.setRowSorter(manualTurnoutSorter); 532 manualTurnoutTable.setRowSelectionAllowed(false); 533 manualTurnoutTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 534 // JComboBox<String> stateCCombo = new JComboBox<>(); // moved to ManualTurnoutTable class 535 536 TableColumnModel _manualTurnoutColumnModel = manualTurnoutTable.getColumnModel(); 537 TableColumn includeColumnC = _manualTurnoutColumnModel. 538 getColumn(TurnoutModel.INCLUDE_COLUMN); 539 includeColumnC.setResizable(false); 540 includeColumnC.setMinWidth(9 * Bundle.getMessage("Include").length()); // was fixed 60 // NOI18N 541 includeColumnC.setMaxWidth(includeColumnC.getMinWidth() + 5); 542 543 TableColumn sNameColumnC = _manualTurnoutColumnModel. 544 getColumn(TurnoutModel.SNAME_COLUMN); 545 sNameColumnC.setResizable(true); 546 sNameColumnC.setMinWidth(75); 547 548 TableColumn stateColumnC = _manualTurnoutColumnModel. 549 getColumn(TurnoutModel.STATE_COLUMN); 550 // stateColumnC.setCellEditor(new DefaultCellEditor(stateCCombo)); // moved to ManualTurnoutTable class 551 stateColumnC.setResizable(false); 552 log.debug("L = {}", SET_TO_ANY.length()); 553 stateColumnC.setMinWidth(9 * Math.max(SET_TO_ANY.length(), SET_TO_CLOSED.length()) + 30); 554 stateColumnC.setMaxWidth(stateColumnC.getMinWidth() + 10); // was fixed 100 555 // remaining space is filled by UserName 556 JScrollPane _manualTurnoutScrollPane = new JScrollPane(manualTurnoutTable); 557 p2xt.add(_manualTurnoutScrollPane, BorderLayout.CENTER); 558 turnoutPanel.add(p2xt); 559 p2xt.setVisible(true); 560 561 ROW_HEIGHT = manualTurnoutTable.getRowHeight(); 562 p2xcSpace.setVisible(false); 563 564 JPanel p2xaSpace = new JPanel(); 565 p2xaSpace.setLayout(new BoxLayout(p2xaSpace, BoxLayout.Y_AXIS)); 566 p2xaSpace.add(new JLabel("XXX")); // NOI18N 567 p2xa.add(p2xaSpace); 568 569 JPanel p21a = new JPanel(); 570 p21a.setLayout(new BoxLayout(p21a, BoxLayout.Y_AXIS)); 571 p21a.add(new JLabel(Bundle.getMessage("LabelAutogenerated", Bundle.getMessage("Turnouts")))); // NOI18N 572 p2xa.add(p21a); 573 574 _autoTurnoutModel = new AutoTurnoutModel(); 575 JTable autoTurnoutTable = new JTable(_autoTurnoutModel); 576 TableRowSorter<AutoTurnoutModel> autoTurnoutSorter = new TableRowSorter<>(_autoTurnoutModel); 577 autoTurnoutSorter.setComparator(AutoTurnoutModel.SNAME_COLUMN, new AlphanumComparator()); 578 autoTurnoutSorter.setComparator(AutoTurnoutModel.UNAME_COLUMN, new AlphanumComparator()); 579 RowSorterUtil.setSortOrder(autoTurnoutSorter, AutoTurnoutModel.SNAME_COLUMN, SortOrder.ASCENDING); 580 autoTurnoutTable.setRowSorter(autoTurnoutSorter); 581 autoTurnoutTable.setRowSelectionAllowed(false); 582 autoTurnoutTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 583 584 TableColumnModel _autoTurnoutColumnModel = autoTurnoutTable.getColumnModel(); 585 TableColumn sNameColumnA = _autoTurnoutColumnModel. 586 getColumn(AutoTurnoutModel.SNAME_COLUMN); 587 sNameColumnA.setResizable(true); 588 sNameColumnA.setMinWidth(75); 589 590 TableColumn stateColumnA = _autoTurnoutColumnModel. 591 getColumn(AutoTurnoutModel.STATE_COLUMN); 592 stateColumnA.setResizable(false); 593 stateColumnA.setMinWidth(90); 594 stateColumnA.setMaxWidth(100); 595 596 JScrollPane _autoTurnoutScrollPane = new JScrollPane(autoTurnoutTable); 597 p2xa.add(_autoTurnoutScrollPane, BorderLayout.CENTER); 598 turnoutPanel.add(p2xa); 599 p2xa.setVisible(true); 600 601 ROW_HEIGHT = autoTurnoutTable.getRowHeight(); 602 p2xaSpace.setVisible(false); 603 604 return turnoutPanel; 605 } 606 607 /** 608 * Compose GUI for setting up the Sensors tab for an SML. 609 * 610 * @return a JPanel containing the SML control sensors configuration 611 * interface 612 */ 613 private JPanel buildSensorPanel() { 614 JPanel sensorPanel = new JPanel(); 615 sensorPanel.setLayout(new BoxLayout(sensorPanel, BoxLayout.Y_AXIS)); 616 617 jmri.SensorManager bm = jmri.InstanceManager.sensorManagerInstance(); 618 _manualSensorList = new ArrayList<>(); 619 for (Sensor ss : bm.getNamedBeanSet()) { 620 String systemName = ss.getSystemName(); 621 String userName = ss.getUserName(); 622 _manualSensorList.add(new ManualSensorList(systemName, userName)); 623 } 624 625 JPanel p2xs = new JPanel(); 626 JPanel p2xsSpace = new JPanel(); 627 p2xsSpace.setLayout(new BoxLayout(p2xsSpace, BoxLayout.Y_AXIS)); 628 p2xsSpace.add(new JLabel("XXX")); // NOI18N 629 p2xs.add(p2xsSpace); 630 631 JPanel p21c = new JPanel(); 632 p21c.setLayout(new BoxLayout(p21c, BoxLayout.Y_AXIS)); 633 p21c.add(new JLabel(Bundle.getMessage("LabelSelectChecked", Bundle.getMessage("Sensors")))); // NOI18N 634 p2xs.add(p21c); 635 636 _sensorModel = new SensorModel(); 637 JTable manualSensorTable = new JTable(_sensorModel); 638 TableRowSorter<SensorModel> manualSensorSorter = new TableRowSorter<>(_sensorModel); 639 // configure row height for comboBox 640 manualSensorTable.setRowHeight(sizer.getPreferredSize().height - 2); // row height has to be greater than for plain tables 641 manualSensorSorter.setComparator(SensorModel.SNAME_COLUMN, new AlphanumComparator()); 642 manualSensorSorter.setComparator(SensorModel.UNAME_COLUMN, new AlphanumComparator()); 643 RowSorterUtil.setSortOrder(manualSensorSorter, SensorModel.SNAME_COLUMN, SortOrder.ASCENDING); 644 _sensorModel.configStateColumn(manualSensorTable); // create static comboBox in State column 645 manualSensorTable.setRowSorter(manualSensorSorter); 646 manualSensorTable.setRowSelectionAllowed(false); 647 manualSensorTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 648 //stateCCombo = new JComboBox<>(); // moved to ManualSensorTable class 649 650 TableColumnModel _manualSensorColumnModel = manualSensorTable.getColumnModel(); 651 TableColumn includeColumnC = _manualSensorColumnModel. 652 getColumn(SensorModel.INCLUDE_COLUMN); 653 includeColumnC.setResizable(false); 654 includeColumnC.setMinWidth(9 * Bundle.getMessage("Include").length()); // was fixed 60 // NOI18N 655 includeColumnC.setMaxWidth(includeColumnC.getMinWidth() + 5); 656 657 TableColumn sNameColumnC = _manualSensorColumnModel. 658 getColumn(SensorModel.SNAME_COLUMN); 659 sNameColumnC.setResizable(true); 660 sNameColumnC.setMinWidth(75); 661 662 TableColumn stateColumnC = _manualSensorColumnModel. 663 getColumn(SensorModel.STATE_COLUMN); 664 stateColumnC.setResizable(false); 665 stateColumnC.setMinWidth(9 * SET_TO_INACTIVE.length() + 30); 666 stateColumnC.setMaxWidth(stateColumnC.getMinWidth() + 10); // was fixed 100 667 // remaining space is filled by UserName 668 _manualSensorScrollPane = new JScrollPane(manualSensorTable); 669 p2xs.add(_manualSensorScrollPane, BorderLayout.CENTER); 670 671 sensorPanel.add(p2xs); 672 p2xs.setVisible(true); 673 674 ROW_HEIGHT = manualSensorTable.getRowHeight(); 675 p2xsSpace.setVisible(false); 676 677 return sensorPanel; 678 } 679 680 private final JPanel p2xsm = new JPanel(); 681 682 /** 683 * Compose GUI for setting up the Signal Masts tab for an SML. 684 * 685 * @return a JPanel containing the SML control signal masts configuration 686 * interface 687 */ 688 private JPanel buildSignalMastPanel() { 689 JPanel SignalMastPanel = new JPanel(); // TODO make this a shared variable 690 SignalMastPanel.setLayout(new BoxLayout(SignalMastPanel, BoxLayout.Y_AXIS)); 691 692 jmri.SignalMastManager bm = jmri.InstanceManager.getDefault(jmri.SignalMastManager.class); 693 _manualSignalMastList = new ArrayList<>(); 694 for (SignalMast m : bm.getNamedBeanSet()) { 695 _manualSignalMastList.add(new ManualSignalMastList(m)); 696 } 697 698 JPanel p2xm = new JPanel(); 699 JPanel p2xmSpace = new JPanel(); 700 p2xmSpace.setLayout(new BoxLayout(p2xmSpace, BoxLayout.Y_AXIS)); 701 p2xmSpace.add(new JLabel("XXX")); // NOI18N 702 p2xm.add(p2xmSpace); 703 704 JPanel p21c = new JPanel(); 705 p21c.setLayout(new BoxLayout(p21c, BoxLayout.Y_AXIS)); 706 p21c.add(new JLabel(Bundle.getMessage("LabelSelectChecked", Bundle.getMessage("SignalMasts")))); // NOI18N 707 p2xm.add(p21c); 708 709 _signalMastModel = new SignalMastModel(); 710 TableRowSorter<SignalMastModel> manualMastSorter = new TableRowSorter<>(_signalMastModel); 711 JTable manualSignalMastTable = new JTable(_signalMastModel); 712 // configure (extra) row height for comboBox 713 manualSignalMastTable.setRowHeight(sizer.getPreferredSize().height - 2); 714 // row height has to be greater than plain tables to properly show comboBox shape, but tightened a bit over preferred 715 _signalMastModel.configStateColumn(manualSignalMastTable); // create mast (row) specific comboBox in Aspect column 716 manualMastSorter.setComparator(SignalMastModel.SNAME_COLUMN, new jmri.util.AlphanumComparator()); 717 manualMastSorter.setComparator(SignalMastModel.UNAME_COLUMN, new jmri.util.AlphanumComparator()); 718 RowSorterUtil.setSortOrder(manualMastSorter, SignalMastModel.SNAME_COLUMN, SortOrder.ASCENDING); 719 manualSignalMastTable.setRowSorter(manualMastSorter); 720 manualSignalMastTable.setRowSelectionAllowed(false); 721 manualSignalMastTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 722 723 TableColumnModel _manualSignalMastColumnModel = manualSignalMastTable.getColumnModel(); 724 TableColumn includeColumnC = _manualSignalMastColumnModel. 725 getColumn(SignalMastModel.INCLUDE_COLUMN); 726 includeColumnC.setResizable(false); 727 includeColumnC.setMinWidth(9 * Bundle.getMessage("Include").length()); // was fixed 60 // NOI18N 728 includeColumnC.setMaxWidth(includeColumnC.getMinWidth() + 5); 729 TableColumn sNameColumnC = _manualSignalMastColumnModel. 730 getColumn(SignalMastModel.SNAME_COLUMN); 731 sNameColumnC.setResizable(true); 732 sNameColumnC.setMinWidth(75); 733 734 TableColumn stateColumnC = _manualSignalMastColumnModel. 735 getColumn(SensorModel.STATE_COLUMN); 736 stateColumnC.setResizable(false); 737 stateColumnC.setMinWidth(9 * ("Diverging Approach Medium").length() + 20); // NOI18N 738 stateColumnC.setMaxWidth(stateColumnC.getMinWidth() + 10); // was fixed 100 739 // remaining space is filled by UserName 740 _manualSignalMastScrollPane = new JScrollPane(manualSignalMastTable); 741 p2xm.add(_manualSignalMastScrollPane, BorderLayout.CENTER); 742 SignalMastPanel.add(p2xm); 743 p2xm.setVisible(true); 744 745 ROW_HEIGHT = manualSignalMastTable.getRowHeight(); 746 p2xmSpace.setVisible(false); 747 748 JPanel p2xaSpace = new JPanel(); 749 p2xaSpace.setLayout(new BoxLayout(p2xaSpace, BoxLayout.Y_AXIS)); 750 p2xaSpace.add(new JLabel("XXX")); 751 p2xsm.add(p2xaSpace); 752 753 JPanel p21a = new JPanel(); 754 p21a.setLayout(new BoxLayout(p21a, BoxLayout.Y_AXIS)); 755 p21a.add(new JLabel(Bundle.getMessage("LabelAutogenerated", Bundle.getMessage("SignalMasts")))); // NOI18N 756 p2xsm.add(p21a); 757 758 _autoSignalMastModel = new AutoMastModel(); 759 JTable autoMastTable = new JTable(_autoSignalMastModel); 760 TableRowSorter<AutoMastModel> autoMastSorter = new TableRowSorter<>(_autoSignalMastModel); 761 autoMastSorter.setComparator(AutoMastModel.SNAME_COLUMN, new jmri.util.AlphanumComparator()); 762 autoMastSorter.setComparator(AutoMastModel.UNAME_COLUMN, new jmri.util.AlphanumComparator()); 763 RowSorterUtil.setSortOrder(autoMastSorter, AutoMastModel.SNAME_COLUMN, SortOrder.ASCENDING); 764 autoMastTable.setRowSorter(autoMastSorter); 765 autoMastTable.setRowSelectionAllowed(false); 766 autoMastTable.setPreferredScrollableViewportSize(TABLESIZEPREFERRED); 767 768 TableColumnModel _autoMastColumnModel = autoMastTable.getColumnModel(); 769 TableColumn sNameColumnA = _autoMastColumnModel. 770 getColumn(AutoMastModel.SNAME_COLUMN); 771 sNameColumnA.setResizable(true); 772 sNameColumnA.setMinWidth(75); 773 774 TableColumn stateColumnA = _autoMastColumnModel. 775 getColumn(AutoMastModel.STATE_COLUMN); 776 stateColumnA.setResizable(false); 777 stateColumnA.setMinWidth(90); 778 stateColumnA.setMaxWidth(100); 779 780 JScrollPane _autoSignalMastScrollPane = new JScrollPane(autoMastTable); 781 p2xsm.add(_autoSignalMastScrollPane, BorderLayout.CENTER); 782 SignalMastPanel.add(p2xsm); 783 p2xsm.setVisible(true); 784 785 ROW_HEIGHT = autoMastTable.getRowHeight(); 786 p2xaSpace.setVisible(false); 787 788 return SignalMastPanel; 789 } 790 791 java.beans.PropertyChangeSupport pcs = new java.beans.PropertyChangeSupport(this); 792 793 /** 794 * Update changes in SML when Update button is pressed in the Edit Logic - 795 * Add Logic pane. 796 * 797 * @param e the event heard 798 */ 799 private void updatePressed(ActionEvent e) { 800 sourceMast = sourceMastBox.getSelectedItem(); 801 destMast = destMastBox.getSelectedItem(); 802 boolean smlPairAdded = false; 803 destOK = true; 804 805 if ((sourceMastBox.getSelectedItem() == null) || (destMastBox.getSelectedItem() == null)) { 806 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorSignalMastNull", 807 Bundle.getMessage("SourceMast"), Bundle.getMessage("DestMast"))); 808 destOK = false; 809 log.debug("No Source or Destination Mast selected, keep pane open"); // NOI18N 810 return; 811 } 812 if (sourceMast == destMast || fixedSourceMastLabel.getText().equals(destMast.getDisplayName())) { 813 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorSignalMastIdentical")); 814 destOK = false; 815 log.debug("Destination Mast check failed, keep pane open"); // NOI18N 816 return; 817 } 818 if ((sml == null) && (useLayoutEditor.isSelected())) { 819 boolean valid; 820 try { 821 valid = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlockConnectivityTools().checkValidDest(sourceMast, 822 destMast, LayoutBlockConnectivityTools.Routing.MASTTOMAST); 823 if (!valid) { 824 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ErrorUnReachableDestination")); 825 return; 826 } 827 } catch (jmri.JmriException je) { 828 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("WarningUnableToValidate")); 829 } 830 } 831 832 if (sml == null) { // a new SML directly from the SML Table 833 sml = InstanceManager.getDefault(jmri.SignalMastLogicManager.class).newSignalMastLogic(sourceMast); 834 // check if a similar SML pair already exists when in Add New session 835 if (!sml.getDestinationList().contains(destMast)) { // not yet defined as a pair 836 smlPairAdded = true; 837 sml.setDestinationMast(destMast); 838 } else { 839 // show replace/update dialog 840 int mes = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("WarningExistingPair"), 841 Bundle.getMessage("WarningTitle"), // NOI18N 842 JmriJOptionPane.YES_NO_OPTION); 843 if (mes != JmriJOptionPane.YES_OPTION) { 844 return; 845 } 846 } 847 fixedSourceMastLabel.setText(sourceMast.getDisplayName()); 848 fixedDestMastLabel.setText(destMast.getDisplayName()); 849 sourceMastBox.setVisible(false); 850 destMastBox.setVisible(false); 851 fixedSourceMastLabel.setVisible(true); 852 fixedDestMastLabel.setVisible(true); 853 _autoTurnoutModel.smlValid(); 854 _autoBlockModel.smlValid(); 855 _autoSignalMastModel.smlValid(); 856 } 857 initializeIncludedList(); 858 sml.allowAutoMaticSignalMastGeneration(allowAutoMastGeneration.isSelected(), destMast); 859 boolean layoutEditorGen = true; 860 try { 861 sml.useLayoutEditor(useLayoutEditor.isSelected(), destMast); 862 } catch (jmri.JmriException je) { 863 JmriJOptionPane.showMessageDialog(this, je.toString()); 864 layoutEditorGen = false; 865 } 866 867 try { 868 if (useLayoutEditor.isSelected()) { 869 sml.useLayoutEditorDetails(useLayoutEditorTurnout.isSelected(), useLayoutEditorBlock.isSelected(), destMast); 870 } 871 } catch (jmri.JmriException ji) { 872 if (layoutEditorGen) { 873 JmriJOptionPane.showMessageDialog(this, ji.toString()); 874 } 875 } 876 Hashtable<Block, Integer> hashBlocks = new Hashtable<>(); 877 for (ManualBlockList mbl : _includedManualBlockList) { 878 Block blk = jmri.InstanceManager.getDefault(jmri.BlockManager.class).getBlock(mbl.getSysName()); 879 if (blk != null) { 880 hashBlocks.put(blk, mbl.getState()); 881 } 882 } 883 sml.setBlocks(hashBlocks, destMast); 884 885 Hashtable<NamedBeanHandle<Turnout>, Integer> hashTurnouts = new Hashtable<>(); 886 for (ManualTurnoutList mtl : _includedManualTurnoutList) { 887 String turnoutName = mtl.getDisplayName(); 888 Turnout turnout = jmri.InstanceManager.turnoutManagerInstance().getTurnout(turnoutName); 889 if (turnout != null) { 890 NamedBeanHandle<Turnout> namedTurnout = nbhm.getNamedBeanHandle(turnoutName, turnout); 891 hashTurnouts.put(namedTurnout, mtl.getState()); 892 } 893 // no specific value, just show the current turnout state as selection in comboBox. 894 // for existing SML pair, will be updated to show present setting by editDetails() 895 } 896 sml.setTurnouts(hashTurnouts, destMast); 897 898 Hashtable<NamedBeanHandle<Sensor>, Integer> hashSensors = new Hashtable<>(); 899 for (ManualSensorList msl : _includedManualSensorList) { 900 String sensorName = msl.getDisplayName(); 901 Sensor sensor = jmri.InstanceManager.sensorManagerInstance().getSensor(msl.getDisplayName()); 902 if (sensor != null) { 903 NamedBeanHandle<Sensor> namedSensor = nbhm.getNamedBeanHandle(sensorName, sensor); 904 hashSensors.put(namedSensor, msl.getState()); 905 } 906 // no specific value, just show the current sensor state as selection in comboBox. 907 // for existing SML pair, will be updated to show present setting by editDetails() 908 } 909 sml.setSensors(hashSensors, destMast); 910 911 Hashtable<SignalMast, String> hashSignalMasts = new Hashtable<>(); 912 for (ManualSignalMastList msml : _includedManualSignalMastList) { 913 if (msml.getMast() == sourceMast || msml.getMast() == destMast) { 914 // warn user that control mast is either source or destination mast of this pair, but allow as a valid choice 915 int mes = JmriJOptionPane.showConfirmDialog(null, java.text.MessageFormat.format(Bundle.getMessage("SignalMastCriteriaOwn"), // NOI18N 916 msml.getMast().getDisplayName()), 917 Bundle.getMessage("SignalMastCriteriaOwnTitle"), // NOI18N 918 JmriJOptionPane.YES_NO_OPTION ); 919 if (mes == JmriJOptionPane.YES_OPTION ) { 920 hashSignalMasts.put(msml.getMast(), msml.getSetToState()); 921 } else { // No 922 msml.setIncluded(false); // deselect "Included" checkBox for signal mast in manualSignalList 923 initializeIncludedList(); 924 _signalMastModel.fireTableDataChanged(); 925 } 926 } else { 927 hashSignalMasts.put(msml.getMast(), msml.getSetToState()); 928 } 929 } 930 sml.setMasts(hashSignalMasts, destMast); 931 932 sml.allowTurnoutLock(lockTurnouts.isSelected(), destMast); 933 934 //required to set up transits using Layout Panel 935 //this.setAssociatedSection(destMast); 936 937 sml.initialise(destMast); 938 if (smlPairAdded) { 939 log.debug("New SML"); // NOI18N 940 firePropertyChange("newDestination", null, destMastBox.getSelectedItem()); // to show new SML in underlying table // NOI18N 941 } 942 } 943 944 void setAssociatedSection(SignalMast destMast){ 945 SectionManager sm = InstanceManager.getDefault(SectionManager.class); 946 if (!sml.getAutoBlocksBetweenMasts(destMast).isEmpty()) { 947 String secUserName = sml.getSourceMast().getDisplayName() + ":" + destMast.getDisplayName(); 948 Section sec = sm.getSection(secUserName); 949 if (sec != null) { 950 //A Section already exists, lets check that it is one used with the SML, if so carry on using that. 951 if (sec.getSectionType() != Section.SIGNALMASTLOGIC) { 952 return; 953 } 954 } 955 else { 956 try { 957 sec = sm.createNewSection(secUserName); 958 } 959 catch(IllegalArgumentException ex){ 960 log.warn("Could not create Section for {} {}",secUserName,ex.getMessage()); 961 } 962 } 963 sml.setAssociatedSection(sec, destMast); 964 } 965 } 966 967 private boolean destOK = true; // false indicates destMast and sourceMast are identical 968 969 /** 970 * When Apply button is pressed, call updatePressed and afterwards close the 971 * edit pane. 972 * 973 * @param e the event heard 974 */ 975 void applyPressed(ActionEvent e) { 976 updatePressed(e); // store edits 977 if (destOK) { // enable user to correct configuration if warned the destMast is incorrect by skipping pane closing 978 cancelPressed(e); // close panel signaling acceptance of edits/Apply to the user 979 } 980 } 981 982 /** 983 * Clean up when Cancel button is pressed. 984 * 985 * @param e the event heard 986 */ 987 void cancelPressed(ActionEvent e) { 988 if (jFrame != null) { 989 jFrame.setVisible(false); 990 jFrame.dispose(); 991 } 992 jFrame = null; 993 } 994 995 int blockModeFromBox(JComboBox<String> box) { 996 String mode = (String) box.getSelectedItem(); 997 int result = jmri.util.StringUtil.getStateFromName(mode, blockInputModeValues, blockInputModes); 998 999 if (result < 0) { 1000 log.warn("unexpected mode string in blockMode: {}", mode); // NOI18N 1001 throw new IllegalArgumentException(); 1002 } 1003 return result; 1004 } 1005 1006 void setBlockModeBox(int mode, JComboBox<String> box) { 1007 String result = jmri.util.StringUtil.getNameFromState(mode, blockInputModeValues, blockInputModes); 1008 box.setSelectedItem(result); 1009 } 1010 1011 private static final String[] blockInputModes = new String[]{Bundle.getMessage("UnOccupied"), Bundle.getMessage("Occupied")}; // NOI18N 1012 private static final int[] blockInputModeValues = new int[]{Block.UNOCCUPIED, Block.OCCUPIED}; 1013 1014 /** 1015 * Create new lists of control items configured as part of an SML. 1016 */ 1017 private void initializeIncludedList() { 1018 _includedManualBlockList = new ArrayList<>(); 1019 for (ManualBlockList mbl : _manualBlockList) { 1020 if (mbl.isIncluded()) { 1021 _includedManualBlockList.add(mbl); 1022 } 1023 } 1024 1025 if ((sml != null) && (destMast != null)) { 1026 List<Block> blkList = sml.getAutoBlocks(destMast); 1027 _automaticBlockList = new ArrayList<>(blkList.size()); 1028 for (Block blk : blkList) { 1029 AutoBlockList newABlk = new AutoBlockList(blk); 1030 _automaticBlockList.add(newABlk); 1031 newABlk.setState(sml.getAutoBlockState(blk, destMast)); 1032 } 1033 } 1034 1035 _includedManualTurnoutList = new ArrayList<>(); 1036 for (ManualTurnoutList mtl : _manualTurnoutList) { 1037 if (mtl.isIncluded()) { 1038 _includedManualTurnoutList.add(mtl); 1039 } 1040 } 1041 1042 if ((sml != null) && (destMast != null)) { 1043 List<Turnout> turnList = sml.getAutoTurnouts(destMast); 1044 _automaticTurnoutList = new ArrayList<>(turnList.size()); 1045 for (Turnout turn : turnList) { 1046 String systemName = turn.getSystemName(); 1047 String userName = turn.getUserName(); 1048 AutoTurnoutList newAturn = new AutoTurnoutList(systemName, userName); 1049 _automaticTurnoutList.add(newAturn); 1050 newAturn.setState(sml.getAutoTurnoutState(turn, destMast)); 1051 } 1052 } 1053 1054 _includedManualSensorList = new ArrayList<>(); 1055 for (ManualSensorList msl : _manualSensorList) { 1056 if (msl.isIncluded()) { 1057 _includedManualSensorList.add(msl); 1058 } 1059 } 1060 1061 _includedManualSignalMastList = new ArrayList<>(); 1062 for (ManualSignalMastList msml : _manualSignalMastList) { 1063 if (msml.isIncluded()) { 1064 _includedManualSignalMastList.add(msml); 1065 } 1066 } 1067 1068 if ((sml != null) && (destMast != null)) { 1069 List<SignalMast> mastList = sml.getAutoMasts(destMast); 1070 _automaticSignalMastList = new ArrayList<>(mastList.size()); 1071 for (SignalMast mast : mastList) { 1072 AutoSignalMastList newAmast = new AutoSignalMastList(mast); 1073 _automaticSignalMastList.add(newAmast); 1074 newAmast.setState(sml.getAutoSignalMastState(mast, destMast)); 1075 } 1076 } 1077 } 1078 1079 private final JRadioButton allButton; 1080 1081 private boolean showAll = true; // false indicates show only included items 1082 1083 private static final String SET_TO_ACTIVE = Bundle.getMessage("SensorStateActive"); // NOI18N 1084 private static final String SET_TO_INACTIVE = Bundle.getMessage("SensorStateInactive"); // NOI18N 1085 private static final String SET_TO_CLOSED = jmri.InstanceManager.turnoutManagerInstance().getClosedText(); 1086 private static final String SET_TO_THROWN = jmri.InstanceManager.turnoutManagerInstance().getThrownText(); 1087 1088 private static final String SET_TO_UNOCCUPIED = Bundle.getMessage("UnOccupied"); // NOI18N 1089 private static final String SET_TO_OCCUPIED = Bundle.getMessage("Occupied"); // NOI18N 1090 private static final String SET_TO_ANY = Bundle.getMessage("AnyState"); // NOI18N 1091 1092 private static int ROW_HEIGHT; 1093 1094 private static void setRowHeight(int newHeight) { 1095 ROW_HEIGHT = newHeight; 1096 } 1097 1098 /** 1099 * Cancels "Show Included Only" option 1100 */ 1101 void cancelIncludedOnly() { 1102 if (!showAll) { 1103 allButton.doClick(); 1104 } 1105 } 1106 1107 /** 1108 * Fill in existing SML configuration on the edit panel 1109 */ 1110 private void editDetails() { 1111 int setRow = 0; 1112 for (int i = _manualBlockList.size() - 1; i >= 0; i--) { 1113 ManualBlockList block = _manualBlockList.get(i); 1114 String tSysName = block.getSysName(); 1115 Block blk = InstanceManager.getDefault(jmri.BlockManager.class).getBlock(tSysName); 1116 if (sml.isBlockIncluded(blk, destMast)) { 1117 block.setIncluded(true); 1118 block.setState(sml.getBlockState(blk, destMast)); 1119 setRow = i; 1120 } else { 1121 block.setIncluded(false); 1122 block.setState(Block.UNOCCUPIED); 1123 } 1124 } 1125 setRow -= 1; 1126 if (setRow < 0) { 1127 setRow = 0; 1128 } 1129 _manualBlockScrollPane.getVerticalScrollBar().setValue(setRow * ROW_HEIGHT); 1130 _blockModel.fireTableDataChanged(); 1131 1132 setRow = 0; 1133 for (int i = _manualTurnoutList.size() - 1; i >= 0; i--) { 1134 ManualTurnoutList turnout = _manualTurnoutList.get(i); 1135 String tSysName = turnout.getSysName(); 1136 Turnout turn = InstanceManager.turnoutManagerInstance().getTurnout(tSysName); 1137 if (sml.isTurnoutIncluded(turn, destMast)) { 1138 turnout.setIncluded(true); 1139 turnout.setState(sml.getTurnoutState(turn, destMast)); 1140 setRow = i; 1141 } else { 1142 turnout.setIncluded(false); 1143 turnout.setState(Turnout.CLOSED); 1144 } 1145 } 1146 setRow -= 1; 1147 if (setRow < 0) { 1148 setRow = 0; 1149 } 1150 _manualSensorScrollPane.getVerticalScrollBar().setValue(setRow * ROW_HEIGHT); 1151 _sensorModel.fireTableDataChanged(); 1152 1153 setRow = 0; 1154 for (int i = _manualSensorList.size() - 1; i >= 0; i--) { 1155 ManualSensorList sensor = _manualSensorList.get(i); 1156 String tSysName = sensor.getSysName(); 1157 Sensor sen = InstanceManager.sensorManagerInstance().getSensor(tSysName); 1158 if (sml.isSensorIncluded(sen, destMast)) { 1159 sensor.setIncluded(true); 1160 sensor.setState(sml.getSensorState(sen, destMast)); 1161 setRow = i; 1162 } else { 1163 sensor.setIncluded(false); 1164 sensor.setState(Sensor.INACTIVE); 1165 } 1166 } 1167 setRow -= 1; 1168 if (setRow < 0) { 1169 setRow = 0; 1170 } 1171 _manualSensorScrollPane.getVerticalScrollBar().setValue(setRow * ROW_HEIGHT); 1172 _sensorModel.fireTableDataChanged(); 1173 1174 setRow = 0; 1175 for (int i = _manualSignalMastList.size() - 1; i >= 0; i--) { 1176 ManualSignalMastList mast = _manualSignalMastList.get(i); 1177 SignalMast sigMast = _manualSignalMastList.get(i).getMast(); 1178 if (sml.isSignalMastIncluded(sigMast, destMast)) { 1179 mast.setIncluded(true); 1180 mast.setSetToState(sml.getSignalMastState(sigMast, destMast)); 1181 setRow = i; 1182 } else { 1183 mast.setIncluded(false); 1184 } 1185 } 1186 setRow -= 1; 1187 if (setRow < 0) { 1188 setRow = 0; 1189 } 1190 _manualSignalMastScrollPane.getVerticalScrollBar().setValue(setRow * ROW_HEIGHT); 1191 _signalMastModel.fireTableDataChanged(); 1192 1193 } 1194 1195 private List<ManualBlockList> _includedManualBlockList; 1196 private List<ManualTurnoutList> _includedManualTurnoutList; 1197 private List<ManualSensorList> _includedManualSensorList; 1198 private List<ManualSignalMastList> _includedManualSignalMastList; 1199 1200 /** 1201 * Abstract class implemented during edit of an SML. 1202 */ 1203 private abstract static class SignalMastElement { 1204 1205 String _sysName; 1206 String _userName; 1207 boolean _included; 1208 int _setToState; 1209 1210 SignalMastElement() { 1211 1212 } 1213 1214 SignalMastElement(String sysName, String userName) { 1215 _sysName = sysName; 1216 _userName = userName; 1217 _included = false; 1218 _setToState = Sensor.INACTIVE; 1219 } 1220 1221 String getSysName() { 1222 return _sysName; 1223 } 1224 1225 String getUserName() { 1226 return _userName; 1227 } 1228 1229 String getDisplayName() { 1230 String name = getUserName(); 1231 if (name != null && name.length() > 0) { 1232 return name; 1233 } else { 1234 return getSysName(); 1235 } 1236 } 1237 1238 boolean isIncluded() { 1239 return _included; 1240 } 1241 1242 void setIncluded(boolean include) { 1243 _included = include; 1244 } 1245 1246 abstract String getSetToState(); 1247 1248 abstract void setSetToState(String state); 1249 1250 int getState() { 1251 return _setToState; 1252 } 1253 1254 void setState(int state) { 1255 _setToState = state; 1256 } 1257 } 1258 1259 /* 1260 * A series of Lists to store all SML properties during Edit. 1261 */ 1262 1263 /** 1264 * A paired list of manually configurable Layout Blocks and a corresponding 1265 * Set To State used during edit of an SML. 1266 */ 1267 private static class ManualBlockList extends SignalMastElement { 1268 1269 ManualBlockList(Block block) { 1270 this.block = block; 1271 } 1272 Block block; 1273 1274 @Override 1275 String getSysName() { 1276 return block.getSystemName(); 1277 } 1278 1279 @Override 1280 String getUserName() { 1281 return block.getUserName(); 1282 } 1283 1284 boolean getPermissiveWorking() { 1285 return block.getPermissiveWorking(); 1286 } 1287 1288 String getBlockSpeed() { 1289 return block.getBlockSpeed(); 1290 } 1291 1292 @Override 1293 String getSetToState() { 1294 switch (_setToState) { 1295 case Block.OCCUPIED: 1296 return SET_TO_OCCUPIED; 1297 case Block.UNOCCUPIED: 1298 return SET_TO_UNOCCUPIED; 1299 default: 1300 // fall out 1301 break; 1302 } 1303 return SET_TO_ANY; 1304 } 1305 1306 @Override 1307 void setSetToState(String state) { 1308 if (SET_TO_UNOCCUPIED.equals(state)) { 1309 _setToState = Block.UNOCCUPIED; 1310 } else if (SET_TO_OCCUPIED.equals(state)) { 1311 _setToState = Block.OCCUPIED; 1312 } else { 1313 _setToState = 0x03; // AnyState 1314 } 1315 } 1316 } 1317 1318 /** 1319 * A paired list of automatically configured Layout Blocks and a 1320 * corresponding Set To State used during edit of an SML. 1321 */ 1322 private static class AutoBlockList extends ManualBlockList { 1323 1324 AutoBlockList(Block block) { 1325 super(block); 1326 } 1327 1328 @Override 1329 void setSetToState(String state) { 1330 } 1331 } 1332 1333 /** 1334 * A paired list of manually configurable Turnouts and a corresponding Set 1335 * To State used during edit of an SML. 1336 */ 1337 private static class ManualTurnoutList extends SignalMastElement { 1338 1339 ManualTurnoutList(String sysName, String userName) { 1340 super(sysName, userName); 1341 } 1342 1343 @Override 1344 String getSetToState() { 1345 switch (_setToState) { 1346 case Turnout.THROWN: 1347 return SET_TO_THROWN; 1348 case Turnout.CLOSED: 1349 return SET_TO_CLOSED; 1350 default: 1351 // fall out 1352 break; 1353 } 1354 return SET_TO_ANY; 1355 } 1356 1357 @Override 1358 void setSetToState(String state) { 1359 if (SET_TO_THROWN.equals(state)) { 1360 _setToState = Turnout.THROWN; 1361 } else if (SET_TO_CLOSED.equals(state)) { 1362 _setToState = Turnout.CLOSED; 1363 } else { 1364 _setToState = 0x00; // AnyState is not correctly returned with Turnouts 1365 } 1366 } 1367 } 1368 1369 /** 1370 * A paired list of automatically configured Turnouts and a corresponding 1371 * Set To State used during edit of an SML. 1372 */ 1373 private static class AutoTurnoutList extends ManualTurnoutList { 1374 1375 AutoTurnoutList(String sysName, String userName) { 1376 super(sysName, userName); 1377 } 1378 1379 @Override 1380 void setSetToState(String state) { 1381 } 1382 } 1383 1384 /** 1385 * A paired list of manually configured Sensors and a corresponding Set To 1386 * State used during edit of an SML. 1387 */ 1388 private static class ManualSensorList extends SignalMastElement { 1389 1390 ManualSensorList(String sysName, String userName) { 1391 super(sysName, userName); 1392 } 1393 1394 @Override 1395 String getSetToState() { 1396 switch (_setToState) { 1397 case Sensor.INACTIVE: 1398 return SET_TO_INACTIVE; 1399 case Sensor.ACTIVE: 1400 return SET_TO_ACTIVE; 1401 default: 1402 // fall out 1403 break; 1404 } 1405 return ""; 1406 } 1407 1408 @Override 1409 void setSetToState(String state) { 1410 if (SET_TO_INACTIVE.equals(state)) { 1411 _setToState = Sensor.INACTIVE; 1412 } else if (SET_TO_ACTIVE.equals(state)) { 1413 _setToState = Sensor.ACTIVE; 1414 } // do not provide other choices like "OnChange" 1415 } 1416 } 1417 1418 /** 1419 * A paired list of manually configured Signal Masts and a corresponding Set To 1420 * State used during edit of an SML. 1421 */ 1422 private static class ManualSignalMastList extends SignalMastElement { 1423 1424 ManualSignalMastList(SignalMast s) { 1425 mast = s; 1426 } 1427 1428 String _setToAspect = ""; 1429 1430 SignalMast mast; 1431 1432 SignalMast getMast() { 1433 return mast; 1434 } 1435 1436 @Override 1437 String getSysName() { 1438 return mast.getSystemName(); 1439 } 1440 1441 @Override 1442 String getUserName() { 1443 return mast.getUserName(); 1444 } 1445 1446 @Override 1447 String getSetToState() { 1448 return _setToAspect; 1449 } 1450 1451 @Override 1452 void setSetToState(String state) { 1453 _setToAspect = state; 1454 } 1455 } 1456 1457 /** 1458 * A paired list of automatically configured Signal Masts and a 1459 * corresponding Set To State used during edit of an SML. 1460 */ 1461 private static class AutoSignalMastList extends ManualSignalMastList { 1462 1463 AutoSignalMastList(SignalMast s) { 1464 super(s); 1465 } 1466 1467 @Override 1468 void setSetToState(String state) { 1469 } 1470 1471 void setState(String state) { 1472 _setToAspect = state; 1473 } 1474 } 1475 1476 /** 1477 * A series of TableModels to display and edit configurations for 1478 * SignalMastLogic (SML) on the Tabs. 1479 */ 1480 abstract class TableModel extends AbstractTableModel implements PropertyChangeListener { 1481 1482 @Override 1483 public Class<?> getColumnClass(int c) { 1484 switch (c) { 1485 case INCLUDE_COLUMN: 1486 return Boolean.class; 1487 case STATE_COLUMN: 1488 return RowComboBoxPanel.class; // Use a JPanel containing a custom State ComboBox 1489 default: 1490 return String.class; 1491 } 1492 } 1493 1494 /** 1495 * Respond to change from bean. Prevent State change during edit. 1496 * 1497 * @param e A property change of any bean 1498 */ 1499 @Override 1500 public void propertyChange(java.beans.PropertyChangeEvent e) { 1501 if (e.getPropertyName().equals("length")) { // NOI18N 1502 // a new NamedBean is available in the manager 1503 fireTableDataChanged(); 1504 } 1505 } 1506 1507 /** 1508 * Remove references to and from this object, so that it can eventually 1509 * be garbage-collected. 1510 */ 1511 public void dispose() { 1512 jmri.InstanceManager.turnoutManagerInstance().removePropertyChangeListener(this); 1513 } 1514 1515 @Override 1516 public String getColumnName(int col) { 1517 switch (col) { 1518 case SNAME_COLUMN: 1519 return Bundle.getMessage("ColumnSystemName"); // NOI18N 1520 case UNAME_COLUMN: 1521 return Bundle.getMessage("ColumnUserName"); // NOI18N 1522 case INCLUDE_COLUMN: 1523 return Bundle.getMessage("Include"); // NOI18N 1524 case STATE_COLUMN: 1525 return Bundle.getMessage("ColumnState"); // pick up via SignallingBundle as it is a different "State" label than non-signal tables // NOI18N 1526 default: 1527 return "unknown"; // NOI18N 1528 } 1529 } 1530 1531 @Override 1532 public int getColumnCount() { 1533 return 4; 1534 } 1535 1536 @Override 1537 public boolean isCellEditable(int r, int c) { 1538 return ((c == INCLUDE_COLUMN) || (c == STATE_COLUMN)); 1539 } 1540 1541 /** 1542 * Customize the State column to show an appropriate ComboBox of 1543 * available options. 1544 * 1545 * @param table a JTable of beans 1546 */ 1547 protected void configStateColumn(JTable table) { 1548 // have the state column hold a JPanel with a JComboBox for States 1549 // add extras, override BeanTableDataModel 1550 log.debug("Bean configStateColumn (I am {})", super.toString()); // NOI18N 1551 table.setDefaultEditor(RowComboBoxPanel.class, new StateComboBoxPanel()); 1552 table.setDefaultRenderer(RowComboBoxPanel.class, new StateComboBoxPanel()); // use same class for the renderer 1553 // Set more things? 1554 } 1555 1556 /** 1557 * Provide a table cell renderer looking like a JComboBox as an 1558 * editor/renderer for the manual tables on all except the Masts tab. 1559 * <p> 1560 * This is a lightweight version of the 1561 * {@link jmri.jmrit.beantable.RowComboBoxPanel} RowComboBox cell editor 1562 * class, some of the hashtables not needed here since we only need 1563 * identical options for all rows in a column. 1564 * 1565 * @see SignalMastModel.AspectComboBoxPanel for a full application with 1566 * row specific comboBox choices. 1567 */ 1568 public class StateComboBoxPanel extends RowComboBoxPanel { 1569 1570 @Override 1571 protected final void eventEditorMousePressed() { 1572 this.editor.add(getEditorBox(table.convertRowIndexToModel(this.currentRow))); // add editorBox to JPanel 1573 this.editor.revalidate(); 1574 SwingUtilities.invokeLater(this.comboBoxFocusRequester); 1575 log.debug("eventEditorMousePressed in row: {})", this.currentRow); // NOI18N 1576 } 1577 1578 /** 1579 * Call the method in the surrounding method for the 1580 * SignalHeadTable. 1581 * 1582 * @param row the user clicked on in the table 1583 * @return an appropriate combobox for this signal head 1584 */ 1585 @Override 1586 protected JComboBox<String> getEditorBox(int row) { 1587 return getStateEditorBox(row); 1588 } 1589 1590 } 1591 1592 // Methods to display STATE_COLUMN ComboBox in tables. 1593 // All row values are in terms of the Model, not the Table as displayed. 1594 // Hashtables for Editors; none used for Renderers 1595 /** 1596 * Provide a static JComboBox element to display inside the JPanel 1597 * CellEditor. When not yet present, create, store and return a new one. 1598 * 1599 * @param row Index number (in TableDataModel) 1600 * @return A combobox containing the valid aspect names for this mast 1601 */ 1602 JComboBox<String> getStateEditorBox(int row) { 1603 // create dummy comboBox, override in extended classes for each bean 1604 JComboBox<String> editCombo = new JComboBox<>(); 1605 editCombo.addItem(Bundle.getMessage("None")); // NOI18N 1606 return editCombo; 1607 } 1608 // end of methods to display STATE_COLUMN ComboBox 1609 1610 public static final int SNAME_COLUMN = 0; 1611 public static final int UNAME_COLUMN = 1; 1612 static final int INCLUDE_COLUMN = 2; 1613 public static final int STATE_COLUMN = 3; 1614 } 1615 1616 /** 1617 * TableModel for selecting SML control Blocks and Block Set To State. 1618 */ 1619 class BlockModel extends TableModel { 1620 1621 BlockModel() { 1622 jmri.InstanceManager.getDefault(jmri.BlockManager.class).addPropertyChangeListener(this); 1623 } 1624 1625 @Override 1626 public int getRowCount() { 1627 if (showAll) { 1628 return _manualBlockList.size(); 1629 } else { 1630 return _includedManualBlockList.size(); 1631 } 1632 } 1633 1634 private static final int SPEED_COLUMN = 4; 1635 private static final int PERMISSIVE_COLUMN = 5; 1636 1637 @Override 1638 public int getColumnCount() { 1639 return 6; 1640 } 1641 1642 @Override 1643 public Object getValueAt(int r, int c) { 1644 List<ManualBlockList> blockList; 1645 if (showAll) { 1646 blockList = _manualBlockList; 1647 } else { 1648 blockList = _includedManualBlockList; 1649 } 1650 // some error checking 1651 if (r >= blockList.size()) { 1652 log.debug("row index is greater than block list"); // NOI18N 1653 return "error"; // NOI18N 1654 } 1655 switch (c) { 1656 case INCLUDE_COLUMN: 1657 return blockList.get(r).isIncluded(); 1658 case SNAME_COLUMN: 1659 return blockList.get(r).getSysName(); 1660 case UNAME_COLUMN: 1661 return blockList.get(r).getUserName(); 1662 case STATE_COLUMN: 1663 return blockList.get(r).getSetToState(); 1664 case SPEED_COLUMN: 1665 return blockList.get(r).getBlockSpeed(); 1666 case PERMISSIVE_COLUMN: 1667 return blockList.get(r).getPermissiveWorking(); 1668 default: 1669 return ""; 1670 } 1671 } 1672 1673 @Override 1674 public Class<?> getColumnClass(int c) { 1675 if (c == PERMISSIVE_COLUMN) { 1676 return Boolean.class; 1677 } 1678 return super.getColumnClass(c); 1679 } 1680 1681 @Override 1682 public String getColumnName(int col) { 1683 switch (col) { 1684 case SPEED_COLUMN: 1685 return Bundle.getMessage("ColumnSpeed"); // NOI18N 1686 case PERMISSIVE_COLUMN: 1687 return Bundle.getMessage("ColumnPermissive"); // NOI18N 1688 default: 1689 // fall out 1690 break; 1691 } 1692 return super.getColumnName(col); 1693 } 1694 1695 @Override 1696 public void setValueAt(Object type, int r, int c) { 1697 List<ManualBlockList> blockList; 1698 if (showAll) { 1699 blockList = _manualBlockList; 1700 } else { 1701 blockList = _includedManualBlockList; 1702 } 1703 switch (c) { 1704 case INCLUDE_COLUMN: 1705 blockList.get(r).setIncluded((Boolean) type); 1706 break; 1707 case STATE_COLUMN: 1708 log.debug("State = {}", type); // NOI18N 1709 blockList.get(r).setSetToState((String) type); 1710 break; 1711 default: 1712 break; 1713 } 1714 } 1715 1716 /** 1717 * Provide a static JComboBox element to display inside the JPanel 1718 * CellEditor. When not yet present, create, store and return a new one. 1719 * 1720 * @param row Index number (in TableDataModel) 1721 * @return A combobox containing the valid aspect names for this mast 1722 */ 1723 @Override 1724 JComboBox<String> getStateEditorBox(int row) { 1725 // create dummy comboBox, override in extended classes for each bean 1726 JComboBox<String> editCombo = new JComboBox<>(); 1727 editCombo.addItem(SET_TO_UNOCCUPIED); 1728 editCombo.addItem(SET_TO_OCCUPIED); 1729 editCombo.addItem(SET_TO_ANY); 1730 return editCombo; 1731 } 1732 1733 } 1734 1735 /** 1736 * TableModel for selecting SML control Turnouts and Turnout Set To State. 1737 */ 1738 class TurnoutModel extends TableModel { 1739 1740 TurnoutModel() { 1741 jmri.InstanceManager.turnoutManagerInstance().addPropertyChangeListener(this); 1742 } 1743 1744 @Override 1745 public int getRowCount() { 1746 if (showAll) { 1747 return _manualTurnoutList.size(); 1748 } else { 1749 return _includedManualTurnoutList.size(); 1750 } 1751 } 1752 1753 @Override 1754 public Object getValueAt(int r, int c) { 1755 List<ManualTurnoutList> turnoutList; 1756 if (showAll) { 1757 turnoutList = _manualTurnoutList; 1758 } else { 1759 turnoutList = _includedManualTurnoutList; 1760 } 1761 // some error checking 1762 if (r >= turnoutList.size()) { 1763 log.debug("row index is greater than turnout list"); // NOI18N 1764 return "error"; // NOI18N 1765 } 1766 switch (c) { 1767 case INCLUDE_COLUMN: 1768 return turnoutList.get(r).isIncluded(); 1769 case SNAME_COLUMN: 1770 return turnoutList.get(r).getSysName(); 1771 case UNAME_COLUMN: 1772 return turnoutList.get(r).getUserName(); 1773 case STATE_COLUMN: 1774 // initial answer is 'Thrown', never null or empty 1775 return turnoutList.get(r).getSetToState(); 1776 default: 1777 return null; 1778 } 1779 } 1780 1781 @Override 1782 public void setValueAt(Object type, int r, int c) { 1783 List<ManualTurnoutList> turnoutList; 1784 if (showAll) { 1785 turnoutList = _manualTurnoutList; 1786 } else { 1787 turnoutList = _includedManualTurnoutList; 1788 } 1789 switch (c) { 1790 case INCLUDE_COLUMN: 1791 turnoutList.get(r).setIncluded((Boolean) type); 1792 break; 1793 case STATE_COLUMN: 1794 log.debug("State = {}", type); // NOI18N 1795 if (type != null) { 1796 turnoutList.get(r).setSetToState((String) type); 1797 fireTableRowsUpdated(r, r); // use new value 1798 } 1799 break; 1800 default: 1801 break; 1802 } 1803 } 1804 1805 /** 1806 * Provide a static JComboBox element to display inside the JPanel 1807 * CellEditor. When not yet present, create, store and return a new one. 1808 * 1809 * @param row Index number (in TableDataModel) 1810 * @return A combobox containing the valid aspect names for this mast 1811 */ 1812 @Override 1813 JComboBox<String> getStateEditorBox(int row) { 1814 // create dummy comboBox, override in extended classes for each bean 1815 JComboBox<String> editCombo = new JComboBox<>(); 1816 editCombo.addItem(SET_TO_THROWN); 1817 editCombo.addItem(SET_TO_CLOSED); 1818 editCombo.addItem(SET_TO_ANY); 1819 return editCombo; 1820 } 1821 1822 } 1823 1824 /** 1825 * TableModel for selecting SML control Sensors and Sensor Set To State. 1826 */ 1827 class SensorModel extends TableModel { 1828 1829 SensorModel() { 1830 InstanceManager.sensorManagerInstance().addPropertyChangeListener(this); 1831 } 1832 1833 @Override 1834 public int getRowCount() { 1835 if (showAll) { 1836 return _manualSensorList.size(); 1837 } else { 1838 return _includedManualSensorList.size(); 1839 } 1840 } 1841 1842 @Override 1843 public Object getValueAt(int r, int c) { 1844 List<ManualSensorList> sensorList; 1845 if (showAll) { 1846 sensorList = _manualSensorList; 1847 } else { 1848 sensorList = _includedManualSensorList; 1849 } 1850 // some error checking 1851 if (r >= sensorList.size()) { 1852 log.debug("row index is greater than sensor list"); // NOI18N 1853 return null; 1854 } 1855 switch (c) { 1856 case INCLUDE_COLUMN: 1857 return sensorList.get(r).isIncluded(); 1858 case SNAME_COLUMN: 1859 return sensorList.get(r).getSysName(); 1860 case UNAME_COLUMN: 1861 return sensorList.get(r).getUserName(); 1862 case STATE_COLUMN: 1863 return sensorList.get(r).getSetToState(); 1864 default: 1865 return null; 1866 } 1867 } 1868 1869 @Override 1870 public void setValueAt(Object type, int r, int c) { 1871 List<ManualSensorList> sensorList; 1872 if (showAll) { 1873 sensorList = _manualSensorList; 1874 } else { 1875 sensorList = _includedManualSensorList; 1876 } 1877 switch (c) { 1878 case INCLUDE_COLUMN: 1879 sensorList.get(r).setIncluded((Boolean) type); 1880 break; 1881 case STATE_COLUMN: 1882 sensorList.get(r).setSetToState((String) type); 1883 break; 1884 default: 1885 break; 1886 } 1887 } 1888 1889 /** 1890 * Provide a static JComboBox element to display inside the JPanel 1891 * CellEditor. When not yet present, create, store and return a new one. 1892 * 1893 * @param row Index number (in TableDataModel) 1894 * @return A combobox containing the valid aspect names for this mast 1895 */ 1896 @Override 1897 JComboBox<String> getStateEditorBox(int row) { 1898 // create dummy comboBox, override in extended classes for each bean 1899 JComboBox<String> editCombo = new JComboBox<>(); 1900 editCombo.addItem(SET_TO_INACTIVE); 1901 editCombo.addItem(SET_TO_ACTIVE); 1902 return editCombo; 1903 } 1904 1905 } 1906 1907 /** 1908 * Set up table for selecting Signal Masts and an Aspect on each mast 1909 * Updated for TableRowSorter 1910 */ 1911 class SignalMastModel extends TableModel { 1912 1913 SignalMastModel() { 1914 jmri.InstanceManager.getDefault(jmri.SignalMastManager.class).addPropertyChangeListener(this); 1915 } 1916 1917 @Override 1918 public int getRowCount() { 1919 if (showAll) { 1920 return _manualSignalMastList.size(); 1921 } else { 1922 return _includedManualSignalMastList.size(); 1923 } 1924 } 1925 1926 @Override 1927 public Object getValueAt(int r, int c) { // get values from objects to display in table cells 1928 List<ManualSignalMastList> signalMastList; 1929 if (showAll) { 1930 signalMastList = _manualSignalMastList; 1931 } else { 1932 signalMastList = _includedManualSignalMastList; 1933 } 1934 // some error checking 1935 if (r >= signalMastList.size()) { 1936 log.debug("row index is greater than mast list"); // NOI18N 1937 return "error"; // NOI18N 1938 } 1939 switch (c) { 1940 case INCLUDE_COLUMN: 1941 return signalMastList.get(r).isIncluded(); 1942 case SNAME_COLUMN: 1943 return signalMastList.get(r).getSysName(); 1944 case UNAME_COLUMN: 1945 return signalMastList.get(r).getUserName(); 1946 case STATE_COLUMN: 1947 try { 1948 return signalMastList.get(r).getSetToState(); 1949 } catch (java.lang.NullPointerException e) { 1950 //Aspect not set 1951 log.debug("Aspect for mast {} not set", r); // NOI18N 1952 return Bundle.getMessage("BeanStateUnknown"); // use place holder string in table // NOI18N 1953 } 1954 default: 1955 return null; 1956 } 1957 } 1958 1959 @Override 1960 public void setValueAt(Object type, int r, int c) { // store (new) choices in mast 1961 List<ManualSignalMastList> signalMastList; 1962 if (showAll) { 1963 signalMastList = _manualSignalMastList; 1964 } else { 1965 signalMastList = _includedManualSignalMastList; 1966 } 1967 switch (c) { 1968 case STATE_COLUMN: 1969 if (type != null) { 1970 //convertRowIndexToModel(row) not needed 1971 log.debug("setValueAt (rowConverted={}; value={})", r, type); // NOI18N 1972 signalMastList.get(r).setSetToState((String) type); 1973 fireTableRowsUpdated(r, r); 1974 } 1975 break; 1976 case INCLUDE_COLUMN: 1977 signalMastList.get(r).setIncluded((Boolean) type); 1978 break; 1979 default: 1980 break; 1981 } 1982 } 1983 1984 @Override 1985 public Class<?> getColumnClass(int c) { 1986 if (c == STATE_COLUMN) { 1987 return RowComboBoxPanel.class; // Use a JPanel containing a custom State ComboBox 1988 } 1989 return super.getColumnClass(c); 1990 } 1991 1992 public String getValue(String name) { // called by Table Cell Renderer 1993 SignalMast sm = InstanceManager.getDefault(jmri.SignalMastManager.class).getBySystemName(name); 1994 if (sm != null) { 1995 return sm.getAspect(); // return _manualSignalMastList.get(sm).getSetToState(); // unspecific, have to translate sm to index in model 1996 } else { 1997 return null; // reporting "Unknown" seems useless for this application 1998 } 1999 } 2000 2001 @Override 2002 public String getColumnName(int col) { 2003 if (col == STATE_COLUMN) { 2004 return Bundle.getMessage("ColumnAspect"); // cf. line 1356 for general/other bean types // NOI18N 2005 } else { 2006 return super.getColumnName(col); 2007 } 2008 } 2009 2010 /** 2011 * Customize the SignalMast State (Appearance) column to show an 2012 * appropriate ComboBox of available Aspects. 2013 * 2014 * @param table a JTable of Signal Masts 2015 */ 2016 @Override 2017 protected void configStateColumn(JTable table) { 2018 // have the state column hold a JPanel with a JComboBox for Aspects 2019 // add extras, override BeanTableDataModel 2020 log.debug("Mast configStateColumn (I am {})", super.toString()); // NOI18N 2021 table.setDefaultEditor(RowComboBoxPanel.class, new AspectComboBoxPanel()); 2022 table.setDefaultRenderer(RowComboBoxPanel.class, new AspectComboBoxPanel()); // use same class for the renderer 2023 // Set more things? 2024 } 2025 2026 /** 2027 * A row specific Aspect combobox cell editor/renderer. 2028 * <p> 2029 * This is a full version of the 2030 * {@link jmri.jmrit.beantable.RowComboBoxPanel} RowComboBox cell editor 2031 * class, including all hashtables and row specific comboBox choices. 2032 * 2033 * @see StateComboBoxPanel for a lightweight application when all that's 2034 * needed are identical options for all rows in a colomn. 2035 */ 2036 public class AspectComboBoxPanel extends RowComboBoxPanel { 2037 2038 @Override 2039 protected final void eventEditorMousePressed() { 2040 this.editor.add(getEditorBox(table.convertRowIndexToModel(this.currentRow))); // add eb to JPanel 2041 this.editor.revalidate(); 2042 SwingUtilities.invokeLater(this.comboBoxFocusRequester); 2043 log.debug("eventEditorMousePressed in row: {}; me = {})", this.currentRow, this.toString()); // NOI18N 2044 } 2045 2046 /** 2047 * Call method {@link #getAspectEditorBox(int)} in the surrounding 2048 * method for the SignalMastTable 2049 * 2050 * @param row Index of the row clicked in the table 2051 * @return an appropriate combobox for this signal mast 2052 */ 2053 @Override 2054 protected JComboBox<String> getEditorBox(int row) { 2055 return getAspectEditorBox(row); 2056 } 2057 } 2058 2059 // Methods to display STATE_COLUMN (aspect) ComboBox in the Signal Mast Manual Table 2060 // All row values are in terms of the Model, not the Table as displayed. 2061 2062 /** 2063 * Provide a JComboBox element to display inside the JPanel CellEditor. 2064 * When not yet present, create, store and return a new one. 2065 * 2066 * @param row Index number (in TableDataModel) 2067 * @return A combobox containing the valid aspect names for this mast 2068 */ 2069 JComboBox<String> getAspectEditorBox(int row) { 2070 JComboBox<String> editCombo = editorMap.get(this.getValueAt(row, SNAME_COLUMN)); 2071 if (editCombo == null) { 2072 // create a new one with correct aspects 2073 editCombo = new JComboBox<>(getAspectVector(row)); // show it 2074 editorMap.put(this.getValueAt(row, SNAME_COLUMN), editCombo); // and store it 2075 } 2076 return editCombo; 2077 } 2078 2079 // Hashtables for Editors; none used for Renderers 2080 Hashtable<Object, JComboBox<String>> editorMap = new Hashtable<>(); 2081 2082 /** 2083 * Holds a Hashtable of valid aspects per signal mast used by 2084 * getAspectEditorBox() 2085 * 2086 * @param row Index number (in TableDataModel) 2087 * @return The Vector of valid aspect names for this mast to show in the 2088 * JComboBox 2089 */ 2090 Vector<String> getAspectVector(int row) { 2091 Vector<String> comboaspects = boxMap.get(this.getValueAt(row, SNAME_COLUMN)); 2092 if (comboaspects == null) { 2093 // create a new one with correct aspects 2094 SignalMast mast = InstanceManager.getDefault(jmri.SignalMastManager.class) 2095 .getSignalMast((String) this.getValueAt(row, SNAME_COLUMN)); 2096 if (mast!=null) { 2097 comboaspects = mast.getValidAspects(); 2098 boxMap.put(this.getValueAt(row, SNAME_COLUMN), comboaspects); // and store it 2099 } 2100 } 2101 return comboaspects; 2102 } 2103 2104 private final Hashtable<Object, Vector<String>> boxMap = new Hashtable<>(); 2105 2106 // end of methods to display STATE_COLUMN (Aspect) ComboBox 2107 2108 } 2109 2110 /** 2111 * A series of autoTableModels to display - but not edit - configurations on 2112 * the Edit SML Tabs that are autogenerated from layout Editor information. 2113 */ 2114 abstract class AutoTableModel extends AbstractTableModel implements PropertyChangeListener { 2115 2116 AutoTableModel() { 2117 smlValid(); 2118 } 2119 2120 final void smlValid() { 2121 if (sml != null) { 2122 sml.addPropertyChangeListener(this); 2123 } 2124 } 2125 2126 @Override 2127 public Class<?> getColumnClass(int c) { 2128 return String.class; 2129 } 2130 2131 /** 2132 * Remove references to and from this object, so that it can eventually 2133 * be garbage-collected. 2134 */ 2135 public void dispose() { 2136 jmri.InstanceManager.turnoutManagerInstance().removePropertyChangeListener(this); 2137 } 2138 2139 @Override 2140 public String getColumnName(int col) { 2141 switch (col) { 2142 case SNAME_COLUMN: 2143 return Bundle.getMessage("ColumnSystemName"); // NOI18N 2144 case UNAME_COLUMN: 2145 return Bundle.getMessage("ColumnUserName"); // NOI18N 2146 case STATE_COLUMN: 2147 return Bundle.getMessage("ColumnAspect"); // pick up via SignallingBundle as it is a different "State" label than non-signal tables // NOI18N 2148 2149 default: 2150 return "unknown"; // NOI18N 2151 } 2152 } 2153 2154 @Override 2155 public int getColumnCount() { 2156 return 3; 2157 } 2158 2159 @Override 2160 public boolean isCellEditable(int r, int c) { 2161 return false; 2162 } 2163 2164 public static final int SNAME_COLUMN = 0; 2165 public static final int UNAME_COLUMN = 1; 2166 public static final int STATE_COLUMN = 2; 2167 } 2168 2169 /** 2170 * TableModel to display - but not edit - Auto Layout Blocks on the Edit SML 2171 * Blocks Tab. 2172 */ 2173 class AutoBlockModel extends AutoTableModel { 2174 2175 AutoBlockModel() { 2176 if (sml != null) { 2177 sml.addPropertyChangeListener(this); 2178 } 2179 } 2180 2181 static final int SPEED_COLUMN = 3; 2182 static final int PERMISSIVE_COLUMN = 4; 2183 2184 @Override 2185 public int getColumnCount() { 2186 return 5; 2187 } 2188 2189 @Override 2190 public String getColumnName(int col) { 2191 switch (col) { 2192 case SPEED_COLUMN: 2193 return Bundle.getMessage("ColumnSpeed"); // NOI18N 2194 case PERMISSIVE_COLUMN: 2195 return Bundle.getMessage("ColumnPermissive"); // NOI18N 2196 default: 2197 // fall out 2198 break; 2199 } 2200 return super.getColumnName(col); 2201 } 2202 2203 @Override 2204 public void propertyChange(java.beans.PropertyChangeEvent e) { 2205 if (e.getPropertyName().equals("autoblocks")) { // NOI18N 2206 // a new NamedBean is available in the manager 2207 initializeIncludedList(); 2208 fireTableDataChanged(); 2209 } 2210 } 2211 2212 @Override 2213 public Class<?> getColumnClass(int c) { 2214 if (c == PERMISSIVE_COLUMN) { 2215 return Boolean.class; 2216 } 2217 return super.getColumnClass(c); 2218 } 2219 2220 @Override 2221 public int getRowCount() { 2222 return _automaticBlockList.size(); 2223 } 2224 2225 @Override 2226 public Object getValueAt(int r, int c) { 2227 switch (c) { 2228 case SNAME_COLUMN: 2229 return _automaticBlockList.get(r).getSysName(); 2230 case UNAME_COLUMN: 2231 return _automaticBlockList.get(r).getUserName(); 2232 case STATE_COLUMN: 2233 return _automaticBlockList.get(r).getSetToState(); 2234 case SPEED_COLUMN: 2235 return _automaticBlockList.get(r).getBlockSpeed(); 2236 case PERMISSIVE_COLUMN: 2237 return _automaticBlockList.get(r).getPermissiveWorking(); 2238 default: 2239 return null; 2240 } 2241 } 2242 2243 @Override 2244 public void setValueAt(Object type, int r, int c) { 2245 } 2246 2247 @Override 2248 public boolean isCellEditable(int r, int c) { 2249 return false; 2250 } 2251 } 2252 2253 /** 2254 * TableModel to display - but not edit - Auto Turnouts on the Edit SML 2255 * Turnouts Tab. 2256 */ 2257 class AutoTurnoutModel extends AutoTableModel { 2258 2259 AutoTurnoutModel() { 2260 super(); 2261 } 2262 2263 @Override 2264 public int getRowCount() { 2265 return _automaticTurnoutList.size(); 2266 } 2267 2268 @Override 2269 public void propertyChange(java.beans.PropertyChangeEvent e) { 2270 if (e.getPropertyName().equals("autoturnouts")) { // NOI18N 2271 // a new NamedBean is available in the manager 2272 initializeIncludedList(); 2273 fireTableDataChanged(); 2274 } 2275 } 2276 2277 @Override 2278 public Object getValueAt(int r, int c) { 2279 switch (c) { 2280 case SNAME_COLUMN: 2281 return _automaticTurnoutList.get(r).getSysName(); 2282 case UNAME_COLUMN: 2283 return _automaticTurnoutList.get(r).getUserName(); 2284 case STATE_COLUMN: 2285 return _automaticTurnoutList.get(r).getSetToState(); 2286 default: 2287 return null; 2288 } 2289 } 2290 } 2291 2292 /** 2293 * TableModel to display - but not edit - Auto Signal Masts on the Edit SML 2294 * Signal Masts Tab. 2295 */ 2296 class AutoMastModel extends AutoTableModel { 2297 2298 AutoMastModel() { 2299 super(); 2300 } 2301 2302 @Override 2303 public int getRowCount() { 2304 return _automaticSignalMastList.size(); 2305 } 2306 2307 @Override 2308 public void propertyChange(java.beans.PropertyChangeEvent e) { 2309 if (e.getPropertyName().equals("automasts")) { // NOI18N 2310 // a new NamedBean is available in the manager 2311 initializeIncludedList(); 2312 fireTableDataChanged(); 2313 } 2314 } 2315 2316 @Override 2317 public Object getValueAt(int r, int c) { 2318 switch (c) { 2319 case SNAME_COLUMN: 2320 return _automaticSignalMastList.get(r).getSysName(); 2321 case UNAME_COLUMN: 2322 return _automaticSignalMastList.get(r).getUserName(); 2323 case STATE_COLUMN: 2324 return _automaticSignalMastList.get(r).getSetToState(); 2325 default: 2326 return null; 2327 } 2328 } 2329 } 2330 2331 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SignallingPanel.class); 2332 2333}