001package jmri.jmrit.display.layoutEditor.LayoutEditorDialogs; 002 003import java.awt.*; 004import java.awt.event.*; 005import java.text.DecimalFormat; 006import java.util.ArrayList; 007import java.util.List; 008 009import javax.annotation.Nonnull; 010import javax.swing.*; 011import javax.swing.border.EtchedBorder; 012import javax.swing.border.TitledBorder; 013 014import jmri.NamedBean.DisplayOptions; 015import jmri.*; 016import jmri.jmrit.display.layoutEditor.*; 017import jmri.jmrit.display.Positionable; 018import jmri.jmrit.display.SignalMastIcon; 019import jmri.swing.NamedBeanComboBox; 020import jmri.util.JmriJFrame; 021import jmri.util.swing.JmriJOptionPane; 022 023/** 024 * MVC Editor component for PositionablePoint objects. 025 * 026 * @author Bob Jacobsen Copyright (c) 2020 027 * 028 */ 029public class LayoutTurntableEditor extends LayoutTrackEditor { 030 031 /** 032 * constructor method. 033 * @param layoutEditor main layout editor. 034 */ 035 public LayoutTurntableEditor(@Nonnull LayoutEditor layoutEditor) { 036 super(layoutEditor); 037 } 038 039 /*==============*\ 040 | Edit Turntable | 041 \*==============*/ 042 // variables for Edit Turntable pane 043 private LayoutTurntable layoutTurntable = null; 044 private LayoutTurntableView layoutTurntableView = null; 045 046 private JmriJFrame editLayoutTurntableFrame = null; 047 private final JTextField editLayoutTurntableRadiusTextField = new JTextField(8); 048 private final JTextField editLayoutTurntableAngleTextField = new JTextField(8); 049 private final NamedBeanComboBox<Block> editLayoutTurntableBlockNameComboBox = new NamedBeanComboBox<>( 050 InstanceManager.getDefault(BlockManager.class), null, DisplayOptions.DISPLAYNAME); 051 private JButton editLayoutTurntableSegmentEditBlockButton; 052 053 private JPanel editLayoutTurntableRayPanel; 054 private JButton editLayoutTurntableAddRayTrackButton; 055 private JCheckBox editLayoutTurntableDccControlledCheckBox; 056 private JCheckBox editLayoutTurntableUseSignalMastsCheckBox; 057 private JPanel signalMastParametersPanel; 058 private NamedBeanComboBox<SignalMast> exitMastComboBox; 059 private NamedBeanComboBox<SignalMast> bufferMastComboBox; 060 061 private String editLayoutTurntableOldRadius = ""; 062 private final List<NamedBeanComboBox<SignalMast>> approachMastComboBoxes = new ArrayList<>(); 063 private final java.util.Set<SignalMast> mastsUsedElsewhere = new java.util.HashSet<>(); 064 private boolean editLayoutTurntableOpen = false; 065 private boolean editLayoutTurntableNeedsRedraw = false; 066 067 private JRadioButton doNotPlaceIcons; 068 private JRadioButton placeIconsLeft; 069 private JRadioButton placeIconsRight; 070 071 private final List<Turnout> turntableTurnouts = new ArrayList<>(); 072 073 /** 074 * Edit a Turntable. 075 */ 076 @Override 077 public void editLayoutTrack(@Nonnull LayoutTrackView layoutTrackView) { 078 if ( layoutTrackView instanceof LayoutTurntableView ) { 079 this.layoutTurntableView = (LayoutTurntableView) layoutTrackView; 080 this.layoutTurntable = this.layoutTurntableView.getTurntable(); 081 } else { 082 log.error("editLayoutTrack called with wrong type {}", layoutTrackView, new Exception("traceback")); 083 } 084 sensorList.clear(); 085 086 if (editLayoutTurntableOpen) { 087 editLayoutTurntableFrame.setVisible(true); 088 } else // Initialize if needed 089 if (editLayoutTurntableFrame == null) { 090 editLayoutTurntableFrame = new JmriJFrame(Bundle.getMessage("EditTurntable"), false, true); // NOI18N 091 editLayoutTurntableFrame.addHelpMenu("package.jmri.jmrit.display.EditTurntable", true); // NOI18N 092 editLayoutTurntableFrame.setLocation(50, 30); 093 094 Container contentPane = editLayoutTurntableFrame.getContentPane(); 095 JPanel headerPane = new JPanel(); 096 JPanel footerPane = new JPanel(); 097 headerPane.setLayout(new BoxLayout(headerPane, BoxLayout.Y_AXIS)); 098 footerPane.setLayout(new BoxLayout(footerPane, BoxLayout.Y_AXIS)); 099 contentPane.setLayout(new BorderLayout()); 100 contentPane.add(headerPane, BorderLayout.NORTH); 101 contentPane.add(footerPane, BorderLayout.SOUTH); 102 103 // setup radius text field 104 JPanel panel1 = new JPanel(); 105 panel1.setLayout(new FlowLayout()); 106 JLabel radiusLabel = new JLabel(Bundle.getMessage("TurntableRadius")); // NOI18N 107 panel1.add(radiusLabel); 108 radiusLabel.setLabelFor(editLayoutTurntableRadiusTextField); 109 panel1.add(editLayoutTurntableRadiusTextField); 110 editLayoutTurntableRadiusTextField.setToolTipText(Bundle.getMessage("TurntableRadiusHint")); // NOI18N 111 headerPane.add(panel1); 112 113 // setup ray track angle text field 114 JPanel panel2 = new JPanel(); 115 panel2.setLayout(new FlowLayout()); 116 JLabel rayAngleLabel = new JLabel(Bundle.getMessage("RayAngle")); // NOI18N 117 panel2.add(rayAngleLabel); 118 rayAngleLabel.setLabelFor(editLayoutTurntableAngleTextField); 119 panel2.add(editLayoutTurntableAngleTextField); 120 editLayoutTurntableAngleTextField.setToolTipText(Bundle.getMessage("RayAngleHint")); // NOI18N 121 headerPane.add(panel2); 122 123 // setup block name 124 JPanel panel2a = new JPanel(); 125 panel2a.setLayout(new FlowLayout()); 126 JLabel blockNameLabel = new JLabel(Bundle.getMessage("BlockID")); // NOI18N 127 panel2a.add(blockNameLabel); 128 blockNameLabel.setLabelFor(editLayoutTurntableBlockNameComboBox); 129 LayoutEditor.setupComboBox(editLayoutTurntableBlockNameComboBox, false, true, true); 130 editLayoutTurntableBlockNameComboBox.setToolTipText(Bundle.getMessage("EditBlockNameHint")); // NOI18N 131 panel2a.add(editLayoutTurntableBlockNameComboBox); 132 133 // Edit Block 134 panel2a.add(editLayoutTurntableSegmentEditBlockButton = new JButton(Bundle.getMessage("EditBlock", ""))); // NOI18N 135 editLayoutTurntableSegmentEditBlockButton.addActionListener(this::editLayoutTurntableEditBlockPressed); 136 editLayoutTurntableSegmentEditBlockButton.setToolTipText(Bundle.getMessage("EditBlockHint", "")); // empty value for block 1 // NOI18N 137 headerPane.add(panel2a); 138 139 // setup add ray track button 140 JPanel panel3 = new JPanel(); 141 panel3.setLayout(new FlowLayout()); 142 panel3.add(editLayoutTurntableAddRayTrackButton = new JButton(Bundle.getMessage("AddRayTrack"))); // NOI18N 143 editLayoutTurntableAddRayTrackButton.setToolTipText(Bundle.getMessage("AddRayTrackHint")); // NOI18N 144 editLayoutTurntableAddRayTrackButton.addActionListener((ActionEvent e) -> { 145 addRayTrackPressed(e); 146 updateRayPanel(); 147 }); 148 149 panel3.add(editLayoutTurntableDccControlledCheckBox = new JCheckBox(Bundle.getMessage("TurntableDCCControlled"))); // NOI18N 150 headerPane.add(panel3); 151 152 JPanel panel4 = new JPanel(); 153 panel4.setLayout(new FlowLayout()); 154 panel4.add(editLayoutTurntableUseSignalMastsCheckBox = new JCheckBox(Bundle.getMessage("TurntableUseSignalMasts"))); // NOI18N 155 headerPane.add(panel4); 156 157 // setup signal mast parameters panel 158 signalMastParametersPanel = new JPanel(); 159 signalMastParametersPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TurntableSignalMastAssignmentsTitle"))); // NOI18N 160 exitMastComboBox = new NamedBeanComboBox<>(InstanceManager.getDefault(SignalMastManager.class), null, DisplayOptions.DISPLAYNAME); 161 LayoutEditor.setupComboBox(exitMastComboBox, false, true, true); 162 exitMastComboBox.setEditable(false); 163 exitMastComboBox.setAllowNull(true); 164 bufferMastComboBox = new NamedBeanComboBox<>(InstanceManager.getDefault(SignalMastManager.class), null, DisplayOptions.DISPLAYNAME); 165 LayoutEditor.setupComboBox(bufferMastComboBox, false, true, true); 166 bufferMastComboBox.setEditable(false); 167 bufferMastComboBox.setAllowNull(true); 168 169 // set up Done and Cancel buttons 170 JPanel panel5 = new JPanel(); 171 panel5.setLayout(new FlowLayout()); 172 addDoneCancelButtons(panel5, editLayoutTurntableFrame.getRootPane(), 173 this::editLayoutTurntableDonePressed, this::turntableEditCancelPressed); 174 footerPane.add(panel5); 175 176 editLayoutTurntableRayPanel = new JPanel(); 177 editLayoutTurntableRayPanel.setLayout(new BoxLayout(editLayoutTurntableRayPanel, BoxLayout.Y_AXIS)); 178 JScrollPane rayScrollPane = new JScrollPane(editLayoutTurntableRayPanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 179 contentPane.add(rayScrollPane, BorderLayout.CENTER); 180 } 181 182 editLayoutTurntableBlockNameComboBox.setSelectedIndex(-1); 183 LayoutBlock lb = layoutTurntable.getLayoutBlock(); 184 if (lb != null) { 185 Block blk = lb.getBlock(); 186 if (blk != null) { 187 editLayoutTurntableBlockNameComboBox.setSelectedItem(blk); 188 } 189 } 190 191 editLayoutTurntableDccControlledCheckBox.setSelected(layoutTurntable.isTurnoutControlled()); 192 editLayoutTurntableUseSignalMastsCheckBox.setSelected(layoutTurntable.isDispatcherManaged()); 193 editLayoutTurntableDccControlledCheckBox.addActionListener((ActionEvent e) -> { 194 layoutTurntable.setTurnoutControlled(editLayoutTurntableDccControlledCheckBox.isSelected()); 195 196 for (Component comp : editLayoutTurntableRayPanel.getComponents()) { 197 if (comp instanceof TurntableRayPanel) { 198 TurntableRayPanel trp = (TurntableRayPanel) comp; 199 trp.showTurnoutDetails(); 200 } 201 } 202 editLayoutTurntableFrame.pack(); 203 }); 204 205 signalMastParametersPanel.setVisible(layoutTurntable.isDispatcherManaged()); 206 editLayoutTurntableUseSignalMastsCheckBox.addActionListener((ActionEvent e) -> { 207 boolean isSelected = editLayoutTurntableUseSignalMastsCheckBox.isSelected(); 208 layoutTurntable.setDispatcherManaged(isSelected); // Update the model 209 signalMastParametersPanel.setVisible(layoutTurntable.isDispatcherManaged()); 210 updateRayPanel(); // Rebuild to show/hide mast details, which also handles visibility 211 editLayoutTurntableFrame.pack(); 212 }); 213 214 // Cache the list of masts used on other parts of the layout. 215 // This is the performance-critical change, preventing a full layout scan on every click. 216 mastsUsedElsewhere.clear(); 217 layoutEditor.getLETools().createListUsedSignalMasts(); 218 mastsUsedElsewhere.addAll(layoutEditor.getLETools().usedMasts); 219 220 // Remove masts assigned to the current turntable from the "used elsewhere" list 221 if (layoutTurntable.getBufferMast() != null) { 222 mastsUsedElsewhere.remove(layoutTurntable.getBufferMast()); 223 } 224 if (layoutTurntable.getExitSignalMast() != null) { 225 mastsUsedElsewhere.remove(layoutTurntable.getExitSignalMast()); 226 } 227 for (LayoutTurntable.RayTrack ray : layoutTurntable.getRayTrackList()) { 228 if (ray.getApproachMast() != null) { 229 mastsUsedElsewhere.remove(ray.getApproachMast()); 230 } 231 } 232 233 exitMastComboBox.setExcludedItems(mastsUsedElsewhere); 234 exitMastComboBox.addActionListener(e -> { 235 SignalMast newMast = exitMastComboBox.getSelectedItem(); 236 layoutTurntable.setExitSignalMast( (newMast != null) ? newMast.getSystemName() : null ); 237 }); 238 239 bufferMastComboBox.setExcludedItems(mastsUsedElsewhere); 240 bufferMastComboBox.addActionListener(e -> { 241 SignalMast newMast = bufferMastComboBox.getSelectedItem(); 242 layoutTurntable.setBufferSignalMast( (newMast != null) ? newMast.getSystemName() : null ); 243 }); 244 245 // Set up for Edit 246 editLayoutTurntableRadiusTextField.setText(" " + layoutTurntable.getRadius()); 247 editLayoutTurntableOldRadius = editLayoutTurntableRadiusTextField.getText(); 248 editLayoutTurntableAngleTextField.setText("0"); 249 editLayoutTurntableFrame.addWindowListener(new java.awt.event.WindowAdapter() { 250 @Override 251 public void windowClosing(java.awt.event.WindowEvent e) { 252 turntableEditCancelPressed(null); 253 } 254 }); 255 updateRayPanel(); 256 SignalMast exitMast = layoutTurntable.getExitSignalMast(); 257 SignalMast bufferMast = layoutTurntable.getBufferMast(); 258 if (exitMast != null) { 259 exitMastComboBox.setSelectedItem(exitMast); 260 } 261 if (bufferMast != null) { 262 bufferMastComboBox.setSelectedItem(bufferMast); 263 } 264 265 editLayoutTurntableFrame.pack(); 266 editLayoutTurntableFrame.setVisible(true); 267 editLayoutTurntableOpen = true; 268 } // editLayoutTurntable 269 270 @InvokeOnGuiThread 271 private void editLayoutTurntableEditBlockPressed(ActionEvent a) { 272 // check if a block name has been entered 273 String newName = editLayoutTurntableBlockNameComboBox.getSelectedItemDisplayName(); 274 if (newName == null) { 275 newName = ""; 276 } 277 if ((layoutTurntable.getBlockName().isEmpty()) 278 || !layoutTurntable.getBlockName().equals(newName)) { 279 // get new block, or null if block has been removed 280 layoutTurntable.setLayoutBlock(layoutEditor.provideLayoutBlock(newName)); 281 editLayoutTurntableNeedsRedraw = true; 282 ///layoutEditor.getLEAuxTools().setBlockConnectivityChanged(); 283 ///layoutTurntable.updateBlockInfo(); 284 } 285 // check if a block exists to edit 286 LayoutBlock blockToEdit = layoutTurntable.getLayoutBlock(); 287 if (blockToEdit == null) { 288 JmriJOptionPane.showMessageDialog(editLayoutTurntableFrame, 289 Bundle.getMessage("Error1"), // NOI18N 290 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 291 return; 292 } 293 blockToEdit.editLayoutBlock(editLayoutTurntableFrame); 294 layoutEditor.setDirty(); 295 editLayoutTurntableNeedsRedraw = true; 296 } 297 298 // Remove old rays and add them back in 299 private void updateRayPanel() { 300 // Create list of turnouts to be retained in the NamedBeanComboBox 301 turntableTurnouts.clear(); 302 layoutTurntable.getRayTrackList().forEach(rt -> turntableTurnouts.add(rt.getTurnout())); 303 304 editLayoutTurntableRayPanel.removeAll(); 305 editLayoutTurntableRayPanel.setLayout(new BoxLayout(editLayoutTurntableRayPanel, BoxLayout.Y_AXIS)); 306 for (LayoutTurntable.RayTrack rt : layoutTurntable.getRayTrackList()) { 307 editLayoutTurntableRayPanel.add(new TurntableRayPanel(rt)); 308 } 309 310 // Rebuild signal mast panel 311 signalMastParametersPanel.removeAll(); 312 approachMastComboBoxes.clear(); 313 314 if (layoutTurntable.isDispatcherManaged()) { 315 signalMastParametersPanel.setLayout(new BoxLayout(signalMastParametersPanel, BoxLayout.Y_AXIS)); 316 317 // Add approach masts for each ray 318 for (LayoutTurntable.RayTrack rt : layoutTurntable.getRayTrackList()) { 319 JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT)); 320 p.add(new JLabel(Bundle.getMessage("ApproachMastRay", rt.getConnectionIndex() + 1))); 321 NamedBeanComboBox<SignalMast> combo = new NamedBeanComboBox<>( 322 InstanceManager.getDefault(SignalMastManager.class), rt.getApproachMast(), DisplayOptions.DISPLAYNAME); 323 LayoutEditor.setupComboBox(combo, false, true, true); 324 combo.setEditable(false); 325 combo.setAllowNull(true); 326 p.add(combo); 327 signalMastParametersPanel.add(p); 328 approachMastComboBoxes.add(combo); 329 } 330 331 // Add action listeners now that the list is complete 332 for (int i = 0; i < approachMastComboBoxes.size(); i++) { 333 final int index = i; // final variable for use in lambda 334 approachMastComboBoxes.get(i).setExcludedItems(mastsUsedElsewhere); 335 approachMastComboBoxes.get(i).addActionListener(e -> { 336 SignalMast newMast = approachMastComboBoxes.get(index).getSelectedItem(); 337 layoutTurntable.getRayTrackList().get(index).setApproachMast( (newMast != null) ? newMast.getSystemName() : null ); 338 }); 339 } 340 if (!approachMastComboBoxes.isEmpty()) { 341 signalMastParametersPanel.add(new JSeparator()); 342 } 343 344 // Add shared icon placement controls 345 JPanel placementPanel = new JPanel(); 346 placementPanel.setLayout(new BoxLayout(placementPanel, BoxLayout.Y_AXIS)); // NOI18N 347 placementPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TurntableAddMastIconsTitle"))); 348 349 doNotPlaceIcons = new JRadioButton(Bundle.getMessage("DoNotPlace")); // NOI18N 350 placeIconsLeft = new JRadioButton(Bundle.getMessage("LeftHandSide")); // NOI18N 351 placeIconsRight = new JRadioButton(Bundle.getMessage("RightHandSide")); // NOI18N 352 ButtonGroup bg = new ButtonGroup(); 353 bg.add(doNotPlaceIcons); 354 bg.add(placeIconsLeft); 355 bg.add(placeIconsRight); 356 switch (layoutTurntable.getSignalIconPlacement()) { 357 case 1: 358 placeIconsLeft.setSelected(true); 359 break; 360 case 2: 361 placeIconsRight.setSelected(true); 362 break; 363 default: doNotPlaceIcons.setSelected(true); 364 } 365 366 JPanel radioPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); 367 radioPanel.add(doNotPlaceIcons); 368 radioPanel.add(placeIconsLeft); 369 radioPanel.add(placeIconsRight); 370 placementPanel.add(radioPanel); 371 signalMastParametersPanel.add(placementPanel); 372 373 signalMastParametersPanel.add(new JSeparator()); 374 375 JPanel mastPanel = new JPanel(new GridBagLayout()); 376 GridBagConstraints c = new GridBagConstraints(); 377 c.gridx = 0; 378 c.gridy = 0; 379 c.anchor = GridBagConstraints.LINE_START; 380 c.insets = new Insets(2, 2, 2, 2); // Default insets 381 mastPanel.add(new JLabel(Bundle.getMessage("TurntableExitMastLabel")), c); 382 c.gridx = 1; 383 c.insets = new Insets(2, 5, 2, 2); // Add left padding 384 mastPanel.add(exitMastComboBox, c); 385 386 c.gridx = 0; 387 c.gridy = 1; 388 c.insets = new Insets(2, 2, 2, 2); // Reset for label 389 mastPanel.add(new JLabel(Bundle.getMessage("TurntableBufferMastLabel")), c); 390 c.gridx = 1; 391 c.insets = new Insets(2, 5, 2, 2); // Add left padding 392 mastPanel.add(bufferMastComboBox, c); 393 394 signalMastParametersPanel.add(mastPanel); 395 editLayoutTurntableRayPanel.add(signalMastParametersPanel); 396 } 397 editLayoutTurntableRayPanel.revalidate(); 398 editLayoutTurntableRayPanel.repaint(); 399 editLayoutTurntableFrame.pack(); 400 } 401 402 private void saveRayPanelDetail() { 403 for (Component comp : editLayoutTurntableRayPanel.getComponents()) { 404 if (comp instanceof TurntableRayPanel) { 405 TurntableRayPanel trp = (TurntableRayPanel) comp; 406 trp.updateDetails(); 407 } 408 } 409 } 410 411 private void addRayTrackPressed(ActionEvent a) { 412 double ang = 0.0; 413 try { 414 ang = Float.parseFloat(editLayoutTurntableAngleTextField.getText()); 415 } catch (Exception e) { 416 JmriJOptionPane.showMessageDialog(editLayoutTurntableFrame, Bundle.getMessage("EntryError") + ": " 417 + e + Bundle.getMessage("TryAgain"), Bundle.getMessage("ErrorTitle"), 418 JmriJOptionPane.ERROR_MESSAGE); 419 return; 420 } 421 layoutTurntable.addRay(ang); 422 layoutEditor.redrawPanel(); 423 layoutEditor.setDirty(); 424 editLayoutTurntableNeedsRedraw = false; 425 } 426 427 private void editLayoutTurntableDonePressed(ActionEvent a) { 428 // check if Block changed 429 String newName = editLayoutTurntableBlockNameComboBox.getSelectedItemDisplayName(); 430 if (newName == null) { 431 newName = ""; 432 } 433 434 if ((layoutTurntable.getBlockName().isEmpty()) || !layoutTurntable.getBlockName().equals(newName)) { 435 // get new block, or null if block has been removed 436 layoutTurntable.setLayoutBlock(layoutEditor.provideLayoutBlock(newName)); 437 editLayoutTurntableNeedsRedraw = true; 438 ///layoutEditor.getLEAuxTools().setBlockConnectivityChanged(); 439 ///layoutTurntable.updateBlockInfo(); 440 } 441 442 layoutTurntable.setDispatcherManaged(editLayoutTurntableUseSignalMastsCheckBox.isSelected()); 443 if (editLayoutTurntableUseSignalMastsCheckBox.isSelected()) { 444 String exitMastName = exitMastComboBox.getSelectedItemDisplayName(); 445 String bufferMastName = bufferMastComboBox.getSelectedItemDisplayName(); 446 layoutTurntable.setExitSignalMast(exitMastName); 447 layoutTurntable.setBufferSignalMast(bufferMastName); 448 449 for (int i = 0; i < approachMastComboBoxes.size(); i++) { 450 LayoutTurntable.RayTrack ray = layoutTurntable.getRayTrackList().get(i); 451 NamedBeanComboBox<SignalMast> combo = approachMastComboBoxes.get(i); 452 ray.setApproachMast(combo.getSelectedItemDisplayName()); 453 } 454 455 // Always remove any existing icons for this turntable's approach masts first. 456 // This ensures that moving icons from right-to-left works correctly. 457 List<SignalMastIcon> iconsToRemove = new ArrayList<>(); 458 for (Positionable p : layoutEditor.getContents()) { 459 if (p instanceof SignalMastIcon) { 460 SignalMastIcon icon = (SignalMastIcon) p; 461 if (layoutTurntable.isApproachMast(icon.getSignalMast())) { 462 iconsToRemove.add(icon); 463 } 464 } 465 } 466 for (SignalMastIcon icon : iconsToRemove) { 467 icon.remove(); 468 editLayoutTurntableNeedsRedraw = true; 469 } 470 471 // Now, if requested, place the new icons. 472 if (!doNotPlaceIcons.isSelected()) { // placeIconsLeft or placeIconsRight is selected 473 for (int i = 0; i < approachMastComboBoxes.size(); i++) { 474 LayoutTurntable.RayTrack ray = layoutTurntable.getRayTrackList().get(i); 475 SignalMast mast = approachMastComboBoxes.get(i).getSelectedItem(); 476 if (mast != null) { 477 if (ray.getConnect() != null) { 478 SignalMastIcon icon = new SignalMastIcon(layoutEditor); 479 icon.setSignalMast(mast.getDisplayName()); 480 log.debug("Placing mast for turntable ray, connected to track segment: {}", ray.getConnect().getName()); // NOI18N 481 layoutEditor.getLETools().placingBlockForTurntable(icon, placeIconsRight.isSelected(), 0.0, 482 ray.getConnect(), layoutTurntableView.getRayCoordsIndexed(ray.getConnectionIndex())); 483 editLayoutTurntableNeedsRedraw = true; 484 } 485 } 486 } 487 } 488 489 // Save placement selection 490 int placementSelection; 491 if (placeIconsLeft.isSelected()) { 492 placementSelection = 1; 493 } else if (placeIconsRight.isSelected()) { 494 placementSelection = 2; 495 } else { 496 placementSelection = 0; 497 } 498 layoutTurntable.setSignalIconPlacement(placementSelection); 499 } 500 501 // check if new radius was entered 502 String str = editLayoutTurntableRadiusTextField.getText(); 503 if (!str.equals(editLayoutTurntableOldRadius)) { 504 double rad = 0.0; 505 try { 506 rad = Float.parseFloat(str); 507 } catch (Exception e) { 508 JmriJOptionPane.showMessageDialog(editLayoutTurntableFrame, Bundle.getMessage("EntryError") + ": " // NOI18N 509 + e + Bundle.getMessage("TryAgain"), Bundle.getMessage("ErrorTitle"), // NOI18N 510 JmriJOptionPane.ERROR_MESSAGE); 511 return; 512 } 513 layoutTurntable.setRadius(rad); 514 editLayoutTurntableNeedsRedraw = true; 515 } 516 // clean up 517 saveRayPanelDetail(); 518 editLayoutTurntableOpen = false; 519 editLayoutTurntableFrame.setVisible(false); 520 editLayoutTurntableFrame.dispose(); 521 editLayoutTurntableFrame = null; 522 if (editLayoutTurntableNeedsRedraw) { 523 layoutEditor.redrawPanel(); 524 layoutEditor.setDirty(); 525 editLayoutTurntableNeedsRedraw = false; 526 } 527 } 528 529 private void turntableEditCancelPressed(ActionEvent a) { 530 editLayoutTurntableOpen = false; 531 editLayoutTurntableFrame.setVisible(false); 532 editLayoutTurntableFrame.dispose(); 533 editLayoutTurntableFrame = null; 534 if (editLayoutTurntableNeedsRedraw) { 535 layoutEditor.redrawPanel(); 536 layoutEditor.setDirty(); 537 editLayoutTurntableNeedsRedraw = false; 538 } 539 } 540 541 /*===================*\ 542 | Turntable Ray Panel | 543 \*===================*/ 544 public class TurntableRayPanel extends JPanel { 545 546 // variables for Edit Turntable ray pane 547 private LayoutTurntable.RayTrack rayTrack = null; 548 private final JPanel rayTurnoutPanel; 549 private final NamedBeanComboBox<Turnout> turnoutNameComboBox; 550 private final TitledBorder rayTitledBorder; 551 private final JComboBox<String> rayTurnoutStateComboBox; 552 private final JLabel rayTurnoutStateLabel; 553 private final JTextField rayAngleTextField; 554 private final int[] rayTurnoutStateValues = new int[]{Turnout.CLOSED, Turnout.THROWN}; 555 private final DecimalFormat twoDForm = new DecimalFormat("#.00"); 556 557 /** 558 * constructor method. 559 * @param rayTrack the single ray track to edit. 560 */ 561 public TurntableRayPanel(@Nonnull LayoutTurntable.RayTrack rayTrack) { 562 this.rayTrack = rayTrack; 563 564 JPanel top = new JPanel(); 565 566 JLabel rayAngleLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("RayAngle"))); 567 top.add(rayAngleLabel); 568 top.add(rayAngleTextField = new JTextField(5)); 569 rayAngleLabel.setLabelFor(rayAngleTextField); 570 571 rayAngleTextField.addFocusListener(new FocusListener() { 572 @Override 573 public void focusGained(FocusEvent e) { 574 } 575 576 @Override 577 public void focusLost(FocusEvent e) { 578 try { 579 Float.parseFloat(rayAngleTextField.getText()); 580 } catch (Exception ex) { 581 JmriJOptionPane.showMessageDialog(editLayoutTurntableFrame, Bundle.getMessage("EntryError") + ": " // NOI18N 582 + ex + Bundle.getMessage("TryAgain"), Bundle.getMessage("ErrorTitle"), // NOI18N 583 JmriJOptionPane.ERROR_MESSAGE); 584 } 585 } 586 } 587 ); 588 this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 589 this.add(top); 590 591 turnoutNameComboBox = new NamedBeanComboBox<>(InstanceManager.getDefault(TurnoutManager.class)); 592 turnoutNameComboBox.setToolTipText(Bundle.getMessage("EditTurnoutToolTip")); 593 LayoutEditor.setupComboBox(turnoutNameComboBox, false, true, false); 594 turnoutNameComboBox.setSelectedItem(rayTrack.getTurnout()); 595 turnoutNameComboBox.addPopupMenuListener( 596 layoutEditor.newTurnoutComboBoxPopupMenuListener(turnoutNameComboBox, turntableTurnouts)); 597 String turnoutStateThrown = InstanceManager.turnoutManagerInstance().getThrownText(); 598 String turnoutStateClosed = InstanceManager.turnoutManagerInstance().getClosedText(); 599 String[] turnoutStates = new String[]{turnoutStateClosed, turnoutStateThrown}; 600 601 rayTurnoutStateComboBox = new JComboBox<>(turnoutStates); 602 rayTurnoutStateLabel = new JLabel(Bundle.getMessage("TurnoutState")); // NOI18N 603 rayTurnoutPanel = new JPanel(); 604 605 rayTurnoutPanel.setBorder(new EtchedBorder()); 606 JLabel turnoutLabel = new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("BeanNameTurnout"))); // NOI18N 607 rayTurnoutPanel.add(turnoutLabel); 608 turnoutLabel.setLabelFor(turnoutNameComboBox); 609 rayTurnoutPanel.add(turnoutNameComboBox); 610 rayTurnoutPanel.add(rayTurnoutStateLabel); 611 rayTurnoutStateLabel.setLabelFor(rayTurnoutStateComboBox); 612 rayTurnoutPanel.add(rayTurnoutStateComboBox); 613 if (rayTrack.getTurnoutState() == Turnout.CLOSED) { 614 rayTurnoutStateComboBox.setSelectedItem(turnoutStateClosed); 615 } else { 616 rayTurnoutStateComboBox.setSelectedItem(turnoutStateThrown); 617 } 618 this.add(rayTurnoutPanel); 619 620 JButton deleteRayButton; 621 top.add(deleteRayButton = new JButton(Bundle.getMessage("ButtonDelete"))); // NOI18N 622 deleteRayButton.setToolTipText(Bundle.getMessage("DeleteRayTrack")); // NOI18N 623 deleteRayButton.addActionListener((ActionEvent e) -> { 624 delete(); 625 updateRayPanel(); 626 }); 627 rayTitledBorder = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black)); 628 629 this.setBorder(rayTitledBorder); 630 631 showTurnoutDetails(); 632 633 rayAngleTextField.setText(twoDForm.format(rayTrack.getAngle())); 634 int rayNumber = rayTrack.getConnectionIndex() + 1; 635 rayTitledBorder.setTitle(Bundle.getMessage("Ray") + " : " + rayNumber); // NOI18N 636 if (rayTrack.getConnect() == null) { 637 rayTitledBorder.setTitle(Bundle.getMessage("MakeLabel", 638 Bundle.getMessage("Unconnected")) + " " 639 + rayNumber); // NOI18N 640 } else if (rayTrack.getConnect().getLayoutBlock() != null) { 641 rayTitledBorder.setTitle(Bundle.getMessage("MakeLabel", 642 Bundle.getMessage("Connected")) + " " 643 + rayTrack.getConnect().getLayoutBlock().getDisplayName() 644 + " (" + Bundle.getMessage("Ray") + " " + rayNumber + ")"); // NOI18N 645 } 646 } 647 648 private void delete() { 649 int n = JmriJOptionPane.showConfirmDialog(null, 650 Bundle.getMessage("Question7"), // NOI18N 651 Bundle.getMessage("WarningTitle"), // NOI18N 652 JmriJOptionPane.YES_NO_OPTION); 653 if (n == JmriJOptionPane.YES_OPTION) { 654 layoutTurntable.deleteRay(rayTrack); 655 } 656 } 657 658 private void updateDetails() { 659 if (turnoutNameComboBox == null || rayTurnoutStateComboBox == null) { 660 return; 661 } 662 String turnoutName = turnoutNameComboBox.getSelectedItemDisplayName(); 663 if (turnoutName == null) { 664 turnoutName = ""; 665 } 666 rayTrack.setTurnout(turnoutName, rayTurnoutStateValues[rayTurnoutStateComboBox.getSelectedIndex()]); 667 if (!rayAngleTextField.getText().equals(twoDForm.format(rayTrack.getAngle()))) { 668 try { 669 double ang = Float.parseFloat(rayAngleTextField.getText()); 670 rayTrack.setAngle(ang); 671 } catch (Exception e) { 672 log.error("Angle is not in correct format so will skip {}", rayAngleTextField.getText()); // NOI18N 673 } 674 } 675 } 676 677 private void showTurnoutDetails() { 678 boolean vis = layoutTurntable.isTurnoutControlled(); 679 rayTurnoutPanel.setVisible(vis); 680 turnoutNameComboBox.setVisible(vis); 681 rayTurnoutStateComboBox.setVisible(vis); 682 rayTurnoutStateLabel.setVisible(vis); 683 } 684 } 685 686 687 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutTurntableEditor.class); 688}