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 @Override 120 public void handleGroupPaneEnd(JPanel pane) { 121 if (gpane != null && evt1 != null && evt2 != null && desc != null) { 122 JPanel p = new JPanel(); 123 p.setLayout(new WrapLayout()); 124 p.setAlignmentX(-1.0f); 125 pane.add(p); 126 JButton button = new JButton(Bundle.getMessage("CdiPanelMakeSensor")); 127 p.add(button); 128 sensorButtonList.add(button); 129 button.addActionListener(new java.awt.event.ActionListener() { 130 @Override 131 public void actionPerformed(java.awt.event.ActionEvent e) { 132 jmri.Sensor sensor = jmri.InstanceManager.sensorManagerInstance() 133 .provideSensor(memo.getSystemPrefix() + "S" + mevt1.getText() + ";" + mevt2.getText()); 134 if (mdesc.getText().length() > 0) { 135 sensor.setUserName(mdesc.getText()); 136 } 137 log.info("make sensor MS{};{} [{}]", mevt1.getText(), mevt2.getText(), mdesc.getText()); 138 } 139 140 final JTextField mdesc = desc; 141 final JTextComponent mevt1 = evt1; 142 final JTextComponent mevt2 = evt2; 143 }); 144 button = new JButton(Bundle.getMessage("CdiPanelMakeTurnout")); 145 p.add(button); 146 turnoutButtonList.add(button); 147 button.addActionListener(new java.awt.event.ActionListener() { 148 @Override 149 public void actionPerformed(java.awt.event.ActionEvent e) { 150 jmri.Turnout turnout = jmri.InstanceManager.turnoutManagerInstance() 151 .provideTurnout(memo.getSystemPrefix() + "T" + mevt1.getText() + ";" + mevt2.getText()); 152 if (mdesc.getText().length() > 0) { 153 turnout.setUserName(mdesc.getText()); 154 } 155 log.info("make turnout MT{};{} [{}]", mevt1.getText(), mevt2.getText(), mdesc.getText()); 156 } 157 158 final JTextField mdesc = desc; 159 final JTextComponent mevt1 = evt1; 160 final JTextComponent mevt2 = evt2; 161 }); 162 if (!haveButtons) { 163 haveButtons = true; 164 cdiPanel.addButtonToFooter(buttonForList(sensorButtonList, Bundle.getMessage("CdiPanelMakeAllSensors"))); 165 cdiPanel.addButtonToFooter(buttonForList(turnoutButtonList, Bundle.getMessage("CdiPanelMakeAllTurnouts"))); 166 } 167 gpane = null; 168 evt1 = null; 169 evt2 = null; 170 desc = null; 171 } 172 } 173 174 @Override 175 public JTextComponent handleEventIdTextField(EventIdTextField input) { 176 var field = new NamedEventIdTextField(memo); // return our own constructed field 177 178 // What does this field do entry for? 179 if (evt1 == null) { 180 evt1 = field; 181 } else if (evt2 == null) { 182 evt2 = field; 183 } else { 184 gpane = null; // flag too many 185 } 186 return field; 187 } 188 189 @Override 190 public JTextField handleStringValue(JTextField value) { 191 desc = value; 192 return value; 193 } 194 195 @Override 196 /** 197 * Make a sensor from a single Event ID. 198 * Set the user name from the CDI description (if available) 199 * {@inheritDoc} 200 */ 201 public void makeSensor(String ev, String mdesc) { 202 jmri.Sensor sensor = 203 jmri.InstanceManager.sensorManagerInstance() 204 .provideSensor(memo.getSystemPrefix() + "S" + ev); 205 if (mdesc.length() > 0) { 206 sensor.setUserName(mdesc); 207 } 208 log.debug("make sensor MS{} [{}]", ev, mdesc); 209 } 210 211 JPanel gpane = null; 212 JTextField desc = null; 213 JTextComponent evt1 = null; 214 JTextComponent evt2 = null; 215 }; 216 ConfigRepresentation rep = iface.getConfigForNode(destNode); 217 rep.eventNameStore = memo.get(OlcbEventNameStore.class); 218 219 cdiPanel.initComponents(rep, factory); 220 221 f.pack(); 222 f.setVisible(true); 223 } 224 225 JButton buttonForList(final java.util.ArrayList<JButton> list, String label) { 226 JButton b = new JButton(label); 227 b.addActionListener(e -> { 228 int delay = 0; //milliseconds 229 for (final JButton b1 : list) { 230 231 ActionListener taskPerformer = new ActionListener() { 232 @Override 233 public void actionPerformed(ActionEvent evt) { 234 target.doClick(); 235 } 236 final JButton target = b1; 237 }; 238 Timer t = new Timer(delay, taskPerformer); 239 t.setRepeats(false); 240 t.start(); 241 delay = delay + 150; 242 } 243 }); 244 return b; 245 } 246 247 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ClientActions.class); 248}