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