001package jmri.jmrit.display.layoutEditor.LayoutEditorDialogs; 002 003import java.awt.event.ActionListener; 004import java.awt.event.KeyEvent; 005import java.util.ArrayList; 006import java.util.List; 007 008import javax.annotation.Nonnull; 009import javax.swing.*; 010 011import jmri.InstanceManager; 012import jmri.InvokeOnGuiThread; 013import jmri.jmrit.display.layoutEditor.*; 014 015/** 016 * MVC root Editor component for LayoutTrack hierarchy objects. 017 * 018 * @author Bob Jacobsen Copyright (c) 2020 019 * 020 */ 021abstract public class LayoutTrackEditor { 022 023 /** 024 * constructor method. 025 * @param layoutEditor main layout editor. 026 */ 027 public LayoutTrackEditor(@Nonnull LayoutEditor layoutEditor) { 028 this.layoutEditor = layoutEditor; 029 } 030 031 // temporary method to get a correct-type *Editor or subclass. 032 // Eventually, this will go away once *Editor's are created 033 // in type-specific *View classes 034 // TODO: should be made not necessary 035 @Nonnull 036 static public LayoutTrackEditor makeTrackEditor(@Nonnull LayoutTrack layoutTrack, @Nonnull LayoutEditor layoutEditor) { 037 038 if (layoutTrack instanceof LayoutTurnout) { 039 040 if (layoutTrack instanceof LayoutRHTurnout) { return new LayoutRHTurnoutEditor(layoutEditor); } 041 if (layoutTrack instanceof LayoutLHTurnout) { return new LayoutLHTurnoutEditor(layoutEditor); } 042 if (layoutTrack instanceof LayoutWye) { return new LayoutWyeEditor(layoutEditor); } 043 044 if (layoutTrack instanceof LayoutXOver) { 045 if (layoutTrack instanceof LayoutRHXOver) { return new LayoutRHXOverEditor(layoutEditor); } 046 if (layoutTrack instanceof LayoutLHXOver) { return new LayoutLHXOverEditor(layoutEditor); } 047 if (layoutTrack instanceof LayoutDoubleXOver) { return new LayoutDoubleXOverEditor(layoutEditor); } 048 049 return new LayoutXOverEditor(layoutEditor); 050 } 051 052 if (layoutTrack instanceof LayoutSlip) { 053 if (layoutTrack instanceof LayoutSingleSlip) { return new LayoutSingleSlipEditor(layoutEditor); } 054 if (layoutTrack instanceof LayoutDoubleSlip) { return new LayoutDoubleSlipEditor(layoutEditor); } 055 056 return new LayoutSlipEditor(layoutEditor); 057 } 058 059 return new LayoutTurnoutEditor(layoutEditor); 060 } 061 if (layoutTrack instanceof TrackSegment) { return new TrackSegmentEditor(layoutEditor); } 062 if (layoutTrack instanceof PositionablePoint) { return new PositionablePointEditor(layoutEditor); } 063 if (layoutTrack instanceof LevelXing) { return new LevelXingEditor(layoutEditor); } 064 if (layoutTrack instanceof LayoutTurntable) { return new LayoutTurntableEditor(layoutEditor); } 065 066 log.error("makeTrackEditor did not match type of {}", layoutTrack, new Exception("traceback")); 067 return new LayoutTrackEditor(layoutEditor){ 068 @Override 069 public void editLayoutTrack(@Nonnull LayoutTrackView layoutTrackView) { 070 log.error("Not a valid LayoutTrackEditor implementation", new Exception("traceback")); 071 } 072 }; 073 } 074 075 /** 076 * Launch the editor for a particular LayoutTrack-tree object. 077 * @param layoutTrackView the layout track view to edit. 078 */ 079 abstract public void editLayoutTrack(@Nonnull LayoutTrackView layoutTrackView); 080 081 final protected LayoutEditor layoutEditor; 082 083 List<String> sensorList = new ArrayList<>(); 084 085 protected void addDoneCancelButtons(JPanel target, JRootPane rp, ActionListener doneCallback, ActionListener cancelCallback) { 086 // Done 087 JButton doneButton = new JButton(Bundle.getMessage("ButtonDone")); 088 target.add(doneButton); // NOI18N 089 doneButton.addActionListener(doneCallback); 090 doneButton.setToolTipText(Bundle.getMessage("DoneHint", Bundle.getMessage("ButtonDone"))); // NOI18N 091 092 // Cancel 093 JButton cancelButton = new JButton(Bundle.getMessage("ButtonCancel")); // NOI18N 094 target.add(cancelButton); 095 cancelButton.addActionListener(cancelCallback); 096 cancelButton.setToolTipText(Bundle.getMessage("CancelHint", Bundle.getMessage("ButtonCancel"))); // NOI18N 097 098 rp.setDefaultButton(doneButton); 099 // bind ESC to close window 100 rp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( 101 KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close"); // NOI18N 102 } 103 104 105 /** 106 * Display a message describing the reason for the block selection combo box 107 * being disabled. An option is provided to hide the message. Note: The 108 * EditorManager class is being used to satisfy the showInfoMessage requirement 109 * for a default manager type class. 110 * 111 * @since 4.11.2 112 */ 113 @InvokeOnGuiThread 114 void showSensorMessage() { 115 if (sensorList.isEmpty()) { 116 return; 117 } 118 StringBuilder msg = new StringBuilder(Bundle.getMessage("BlockSensorLine1")); // NOI18N 119 msg.append(Bundle.getMessage("BlockSensorLine2")); // NOI18N 120 String chkDup = ""; 121 sensorList.sort(null); 122 for (String sName : sensorList) { 123 if (!sName.equals(chkDup)) { 124 msg.append("<br> " + sName); // NOI18N 125 } 126 chkDup = sName; 127 } 128 msg.append("<br> </html>"); // NOI18N 129 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class). 130 showInfoMessage( 131 Bundle.getMessage("BlockSensorTitle"), // NOI18N 132 msg.toString(), 133 "jmri.jmrit.display.EditorManager", // NOI18N 134 "skipEntryExitDialog"); // NOI18N 135 } 136 137 138 /** 139 * Create a list of NX sensors that refer to the current layout block. This 140 * is used to disable block selection in the edit dialog. The list is built 141 * by {@link jmri.jmrit.entryexit.EntryExitPairs#layoutBlockSensors}. 142 * 143 * @since 4.11.2 144 * @param loBlk The current layout block. 145 * @return true if sensors are affected. 146 */ 147 boolean hasNxSensorPairs(LayoutBlock loBlk) { 148 if (loBlk == null) { 149 return false; 150 } 151 List<String> blockSensors = InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class) 152 .layoutBlockSensors(loBlk); 153 if (blockSensors.isEmpty()) { 154 return false; 155 } 156 sensorList.addAll(blockSensors); 157 return true; 158 } 159 160 161 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutTrackEditor.class); 162}