001package jmri.jmrix.openlcb.swing; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.awt.event.WindowEvent; 006 007import javax.swing.JButton; 008import javax.swing.JPanel; 009import javax.swing.JTextField; 010import javax.swing.Timer; 011import javax.swing.text.JTextComponent; 012 013import jmri.ShutDownTask; 014import jmri.jmrix.can.CanSystemConnectionMemo; 015import jmri.jmrix.openlcb.OlcbEventNameStore; 016import jmri.util.JmriJFrame; 017import jmri.util.swing.WrapLayout; 018 019import org.openlcb.NodeID; 020import org.openlcb.OlcbInterface; 021import org.openlcb.cdi.impl.ConfigRepresentation; 022import org.openlcb.cdi.swing.CdiPanel; 023import org.openlcb.swing.EventIdTextField; 024 025/** 026 * Shared code for creating UI elements from different places in the application. 027 * <p> 028 * Created by bracz on 11/21/16. 029 */ 030 031public class ClientActions { 032 private final OlcbInterface iface; 033 private final CanSystemConnectionMemo memo; 034 035 public ClientActions(OlcbInterface iface, CanSystemConnectionMemo memo) { 036 this.iface = iface; 037 this.memo = memo; 038 } 039 040 CdiPanel cdiPanel; 041 ShutDownTask shutDownTask; 042 043 public void openCdiWindow(NodeID destNode, String description) { 044 final java.util.ArrayList<JButton> sensorButtonList = new java.util.ArrayList<>(); 045 final java.util.ArrayList<JButton> turnoutButtonList = new java.util.ArrayList<>(); 046 047 JmriJFrame f = new NodeSpecificFrame(destNode); 048 f.setTitle(Bundle.getMessage("CdiPanelConfigure", description)); 049 f.setLayout(new javax.swing.BoxLayout(f.getContentPane(), javax.swing.BoxLayout.Y_AXIS)); 050 f.addHelpMenu("package.jmri.jmrix.openlcb.swing.networktree.NetworkTreePane_CDItool", true); 051 052 cdiPanel = new CdiPanel(){ 053 // override and extend window closing behavior 054 @Override 055 protected void targetWindowClosingEvent(WindowEvent evt) { // evt is ignored here 056 log.trace("overridden targetWindowClosingEvent runs"); 057 super.targetWindowClosingEvent(evt); 058 } 059 // when actually closing the window, also deregister the safety shutdown class 060 @Override 061 public void release() { 062 super.release(); 063 jmri.InstanceManager.getDefault(jmri.ShutDownManager.class).deregister(shutDownTask); 064 } 065 }; 066 f.add(cdiPanel); 067 cdiPanel.setEventTable(iface.getNodeStore().getSimpleNodeIdent(destNode).getUserName(), 068 iface.getEventTable()); 069 070 // Add a shutdown task to handle "Cancel" selections should there be unsaved 071 // changed at Shutdown 072 jmri.InstanceManager.getDefault(jmri.ShutDownManager.class).register( 073 shutDownTask = new ShutDownTask() { 074 @Override 075 public String getName() { return "CDI Window Check"; } 076 @Override 077 public Boolean call() { 078 log.trace("call( checks contents)"); 079 boolean result = cdiPanel.checkOnWindowClosing(); // true to continue shutdown, false to not 080 if (result) { 081 // you don't want a second check on automatic window closing during shutdown 082 cdiPanel.setWindowCloseCheckAlreadyHandled(); 083 } 084 return result; 085 } 086 087 @Override 088 public void propertyChange(java.beans.PropertyChangeEvent e) { 089 // don't care if somebody else cancels 090 } 091 092 @Override 093 public void run() { 094 // we're shutting down, nothing to do 095 } 096 }); 097 098 // create an object to add "New Sensor" buttons 099 CdiPanel.GuiItemFactory factory = new CdiPanel.GuiItemFactory() { 100 private boolean haveButtons = false; 101 @Override 102 public JButton handleReadButton(JButton button) { 103 return button; 104 } 105 106 @Override 107 public JButton handleWriteButton(JButton button) { 108 return button; 109 } 110 111 @Override 112 public void handleGroupPaneStart(JPanel pane) { 113 this.gpane = pane; 114 evt1 = null; 115 evt2 = null; 116 desc = null; 117 } 118 119 public void installButtonsOnEndOfGroup(JPanel pane, boolean buttonsCountTowardAllButtons) { 120 JPanel p = new JPanel(); 121 p.setLayout(new WrapLayout()); 122 p.setAlignmentX(-1.0f); 123 pane.add(p); 124 JButton button = new JButton(Bundle.getMessage("CdiPanelMakeSensor")); 125 p.add(button); 126 if (buttonsCountTowardAllButtons) { 127 sensorButtonList.add(button); 128 } 129 button.addActionListener(new java.awt.event.ActionListener() { 130 @Override 131 public void actionPerformed(java.awt.event.ActionEvent e) { 132 log.info("make sensor MS{};{} [{}]", mevt1.getEventIDAsDottedString(), mevt2.getEventIDAsDottedString(), mdesc.getText()); 133 jmri.Sensor sensor = jmri.InstanceManager.sensorManagerInstance() 134 .provideSensor(memo.getSystemPrefix() + "S" + mevt1.getEventIDAsDottedString() + ";" + mevt2.getEventIDAsDottedString()); 135 if (mdesc.getText().length() > 0) { 136 sensor.setUserName(mdesc.getText()); 137 } 138 } 139 140 final JTextField mdesc = desc; 141 final NamedEventIdTextField mevt1 = evt1; 142 final NamedEventIdTextField mevt2 = evt2; 143 }); 144 button = new JButton(Bundle.getMessage("CdiPanelMakeTurnout")); 145 p.add(button); 146 if (buttonsCountTowardAllButtons) { 147 turnoutButtonList.add(button); 148 } 149 button.addActionListener(new java.awt.event.ActionListener() { 150 @Override 151 public void actionPerformed(java.awt.event.ActionEvent e) { 152 log.info("make turnout MT{};{} [{}]", mevt1.getEventIDAsDottedString(), mevt2.getEventIDAsDottedString(), mdesc.getText()); 153 jmri.Turnout turnout = jmri.InstanceManager.turnoutManagerInstance() 154 .provideTurnout(memo.getSystemPrefix() + "T" + mevt1.getEventIDAsDottedString() + ";" + mevt2.getEventIDAsDottedString()); 155 if (mdesc.getText().length() > 0) { 156 turnout.setUserName(mdesc.getText()); 157 } 158 } 159 160 final JTextField mdesc = desc; 161 final NamedEventIdTextField mevt1 = evt1; 162 final NamedEventIdTextField mevt2 = evt2; 163 }); 164 if (!haveButtons && buttonsCountTowardAllButtons) { 165 log.debug("create Make Turnout/Sensor buttons, starting with {}", desc.getText()); 166 log.debug("events {} {}", evt1.getText(), evt2.getText()); 167 168 haveButtons = true; 169 cdiPanel.addButtonToFooter(buttonForList(sensorButtonList, Bundle.getMessage("CdiPanelMakeAllSensors"))); 170 cdiPanel.addButtonToFooter(buttonForList(turnoutButtonList, Bundle.getMessage("CdiPanelMakeAllTurnouts"))); 171 } 172 gpane = null; 173 evt1 = null; 174 evt2 = null; 175 desc = null; 176 } 177 178 @Override 179 public void handleManualEnd(JPanel pane) { 180 installButtonsOnEndOfGroup(pane, false); 181 } 182 183 @Override 184 public void handleGroupPaneEnd(JPanel pane) { 185 if (gpane != null 186 && evt1 != null && !evt1.getText().isEmpty() 187 && evt2 != null && !evt2.getText().isEmpty() 188 && desc != null && !desc.getText().isEmpty()) { 189 log.debug("handleGroupPaneEnd for {}", desc.getText()); 190 installButtonsOnEndOfGroup(pane, true); 191 } 192 } 193 194 @Override 195 public JTextComponent handleEventIdTextField(EventIdTextField input) { 196 var field = new NamedEventIdTextField(memo); // return our own constructed field 197 198 // What does this field do entry for? 199 if (evt1 == null) { 200 evt1 = field; 201 } else if (evt2 == null) { 202 evt2 = field; 203 } else { 204 gpane = null; // flag too many 205 } 206 return field; 207 } 208 209 @Override 210 public JTextField handleStringValue(JTextField value) { 211 desc = value; 212 return value; 213 } 214 215 @Override 216 /** 217 * Make a sensor from a single Event ID. 218 * Set the user name from the CDI description (if available) 219 * {@inheritDoc} 220 */ 221 public void makeSensor(String ev, String mdesc) { 222 log.debug("MakeSensor() invoked for {}",mdesc, new Exception("for traceback")); 223 jmri.Sensor sensor = 224 jmri.InstanceManager.sensorManagerInstance() 225 .provideSensor(memo.getSystemPrefix() + "S" + ev); 226 if (mdesc.length() > 0) { 227 sensor.setUserName(mdesc); 228 } 229 log.debug("make sensor MS{} [{}]", ev, mdesc); 230 } 231 232 JPanel gpane = null; 233 JTextField desc = null; 234 jmri.jmrix.openlcb.swing.NamedEventIdTextField evt1 = null; 235 jmri.jmrix.openlcb.swing.NamedEventIdTextField evt2 = null; 236 }; 237 ConfigRepresentation rep = iface.getConfigForNode(destNode); 238 rep.eventNameStore = memo.get(OlcbEventNameStore.class); 239 240 cdiPanel.initComponents(rep, factory); 241 242 f.pack(); 243 f.setVisible(true); 244 } 245 246 JButton buttonForList(final java.util.ArrayList<JButton> list, String label) { 247 JButton b = new JButton(label); 248 b.addActionListener(e -> { 249 int delay = 0; //milliseconds 250 for (final JButton b1 : list) { 251 252 ActionListener taskPerformer = new ActionListener() { 253 @Override 254 public void actionPerformed(ActionEvent evt) { 255 target.doClick(); 256 } 257 final JButton target = b1; 258 }; 259 Timer t = new Timer(delay, taskPerformer); 260 t.setRepeats(false); 261 t.start(); 262 delay = delay + 150; 263 } 264 }); 265 return b; 266 } 267 268 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ClientActions.class); 269}