001package jmri.jmrit.operations.trains.tools; 002 003import java.awt.GridBagLayout; 004import java.io.File; 005import java.util.List; 006 007import javax.swing.*; 008 009import jmri.InstanceManager; 010import jmri.jmrit.operations.OperationsFrame; 011import jmri.jmrit.operations.OperationsXml; 012import jmri.jmrit.operations.setup.Setup; 013import jmri.jmrit.operations.trains.Train; 014import jmri.jmrit.operations.trains.TrainEditFrame; 015import jmri.jmrit.operations.trains.TrainManager; 016import jmri.jmrit.operations.trains.TrainManagerXml; 017import jmri.script.JmriScriptEngineManager; 018import jmri.script.swing.ScriptFileChooser; 019import jmri.util.FileUtil; 020import jmri.util.swing.JmriJOptionPane; 021 022/** 023 * Frame for user edit of a train's script options. Allows the user to execute 024 * scripts when a train is built, moved or terminated. 025 * 026 * @author Bob Jacobsen Copyright (C) 2004 027 * @author Dan Boudreau Copyright (C) 2010, 2011, 2013 028 */ 029public class TrainScriptFrame extends OperationsFrame { 030 031 TrainManager manager; 032 TrainManagerXml managerXml; 033 034 Train _train = null; 035 036 // script panels 037 JPanel pBuildScript = new JPanel(); 038 JPanel pAfterBuildScript = new JPanel(); 039 JPanel pMoveScript = new JPanel(); 040 JPanel pTerminationScript = new JPanel(); 041 JScrollPane buildScriptPane; 042 JScrollPane afterBuildScriptPane; 043 JScrollPane moveScriptPane; 044 JScrollPane terminationScriptPane; 045 046 // labels 047 JLabel trainName = new JLabel(); 048 JLabel trainDescription = new JLabel(); 049 050 // major buttons 051 JButton addBuildScriptButton = new JButton(Bundle.getMessage("AddScript")); 052 JButton addAfterBuildScriptButton = new JButton(Bundle.getMessage("AddScript")); 053 JButton addMoveScriptButton = new JButton(Bundle.getMessage("AddScript")); 054 JButton addTerminationScriptButton = new JButton(Bundle.getMessage("AddScript")); 055 056 JButton runBuildScriptButton = new JButton(Bundle.getMessage("RunScripts")); 057 JButton runAfterBuildScriptButton = new JButton(Bundle.getMessage("RunScripts")); 058 JButton runMoveScriptButton = new JButton(Bundle.getMessage("RunScripts")); 059 JButton runTerminationScriptButton = new JButton(Bundle.getMessage("RunScripts")); 060 061 JButton saveTrainButton = new JButton(Bundle.getMessage("SaveTrain")); 062 063 public TrainScriptFrame() { 064 super(Bundle.getMessage("MenuItemScripts")); 065 } 066 067 public void initComponents(TrainEditFrame parent) { 068 // Set up script options in a Scroll Pane.. 069 buildScriptPane = new JScrollPane(pBuildScript); 070 buildScriptPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 071 buildScriptPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("ScriptsBeforeBuild"))); 072 073 afterBuildScriptPane = new JScrollPane(pAfterBuildScript); 074 afterBuildScriptPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 075 afterBuildScriptPane.setBorder(BorderFactory.createTitledBorder(Bundle 076 .getMessage("ScriptsAfterBuild"))); 077 078 moveScriptPane = new JScrollPane(pMoveScript); 079 moveScriptPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 080 moveScriptPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("ScriptsWhenMoved"))); 081 082 terminationScriptPane = new JScrollPane(pTerminationScript); 083 terminationScriptPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 084 terminationScriptPane.setBorder(BorderFactory.createTitledBorder(Bundle 085 .getMessage("ScriptsWhenTerminated"))); 086 087 // remember who called us 088 parent.setChildFrame(this); 089 _train = parent._train; 090 091 // load managers 092 manager = InstanceManager.getDefault(TrainManager.class); 093 managerXml = InstanceManager.getDefault(TrainManagerXml.class); 094 095 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 096 097 // Layout the panel by rows 098 JPanel p1 = new JPanel(); 099 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 100 101 // row 1a 102 JPanel pName = new JPanel(); 103 pName.setLayout(new GridBagLayout()); 104 pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name"))); 105 addItem(pName, trainName, 0, 0); 106 107 // row 1b 108 JPanel pDesc = new JPanel(); 109 pDesc.setLayout(new GridBagLayout()); 110 pDesc.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Description"))); 111 addItem(pDesc, trainDescription, 0, 0); 112 113 p1.add(pName); 114 p1.add(pDesc); 115 116 // row 2 117 updateBuildScriptPanel(); 118 119 // row 3 120 updateAfterBuildScriptPanel(); 121 122 // row 4 123 updateMoveScriptPanel(); 124 125 // row 6 126 updateTerminationScriptPanel(); 127 128 // row 8 buttons 129 JPanel pB = new JPanel(); 130 pB.setLayout(new GridBagLayout()); 131 addItem(pB, saveTrainButton, 3, 0); 132 133 getContentPane().add(p1); 134 getContentPane().add(buildScriptPane); 135 getContentPane().add(afterBuildScriptPane); 136 getContentPane().add(moveScriptPane); 137 getContentPane().add(terminationScriptPane); 138 getContentPane().add(pB); 139 140 // setup buttons 141 addButtonAction(addBuildScriptButton); 142 addButtonAction(addAfterBuildScriptButton); 143 addButtonAction(addMoveScriptButton); 144 addButtonAction(addTerminationScriptButton); 145 addButtonAction(runBuildScriptButton); 146 addButtonAction(runAfterBuildScriptButton); 147 addButtonAction(runMoveScriptButton); 148 addButtonAction(runTerminationScriptButton); 149 addButtonAction(saveTrainButton); 150 151 if (_train != null) { 152 trainName.setText(_train.getName()); 153 trainDescription.setText(_train.getDescription()); 154 enableButtons(true); 155 } else { 156 enableButtons(false); 157 } 158 addHelpMenu("package.jmri.jmrit.operations.Operations_TrainScripts", true); // NOI18N 159 initMinimumSize(); 160 } 161 162 private void updateBuildScriptPanel() { 163 pBuildScript.removeAll(); 164 pBuildScript.setLayout(new GridBagLayout()); 165 addItem(pBuildScript, addBuildScriptButton, 0, 0); 166 167 // load any existing train build scripts 168 if (_train != null) { 169 List<String> scripts = _train.getBuildScripts(); 170 if (scripts.size() > 0) { 171 addItem(pBuildScript, runBuildScriptButton, 1, 0); 172 } 173 for (int i = 0; i < scripts.size(); i++) { 174 JButton removeBuildScripts = new JButton(Bundle.getMessage("RemoveScript")); 175 removeBuildScripts.setName(scripts.get(i)); 176 removeBuildScripts.addActionListener(new java.awt.event.ActionListener() { 177 @Override 178 public void actionPerformed(java.awt.event.ActionEvent e) { 179 buttonActionRemoveBuildScript(e); 180 } 181 }); 182 addButtonAction(removeBuildScripts); 183 JLabel pathname = new JLabel(scripts.get(i)); 184 addItem(pBuildScript, removeBuildScripts, 0, i + 1); 185 addItem(pBuildScript, pathname, 1, i + 1); 186 } 187 } 188 } 189 190 private void updateAfterBuildScriptPanel() { 191 pAfterBuildScript.removeAll(); 192 pAfterBuildScript.setLayout(new GridBagLayout()); 193 addItem(pAfterBuildScript, addAfterBuildScriptButton, 0, 0); 194 195 // load any existing train build scripts 196 if (_train != null) { 197 List<String> scripts = _train.getAfterBuildScripts(); 198 if (scripts.size() > 0) { 199 addItem(pAfterBuildScript, runAfterBuildScriptButton, 1, 0); 200 } 201 for (int i = 0; i < scripts.size(); i++) { 202 JButton removeAfterBuildScripts = new JButton(Bundle.getMessage("RemoveScript")); 203 removeAfterBuildScripts.setName(scripts.get(i)); 204 removeAfterBuildScripts.addActionListener(new java.awt.event.ActionListener() { 205 @Override 206 public void actionPerformed(java.awt.event.ActionEvent e) { 207 buttonActionRemoveAfterBuildScript(e); 208 } 209 }); 210 addButtonAction(removeAfterBuildScripts); 211 JLabel pathname = new JLabel(scripts.get(i)); 212 addItem(pAfterBuildScript, removeAfterBuildScripts, 0, i + 1); 213 addItem(pAfterBuildScript, pathname, 1, i + 1); 214 } 215 } 216 } 217 218 private void updateMoveScriptPanel() { 219 pMoveScript.removeAll(); 220 pMoveScript.setLayout(new GridBagLayout()); 221 addItem(pMoveScript, addMoveScriptButton, 0, 0); 222 223 // load any existing train move scripts 224 if (_train != null) { 225 List<String> scripts = _train.getMoveScripts(); 226 if (scripts.size() > 0) { 227 addItem(pMoveScript, runMoveScriptButton, 1, 0); 228 } 229 for (int i = 0; i < scripts.size(); i++) { 230 JButton removeMoveScripts = new JButton(Bundle.getMessage("RemoveScript")); 231 removeMoveScripts.setName(scripts.get(i)); 232 removeMoveScripts.addActionListener(new java.awt.event.ActionListener() { 233 @Override 234 public void actionPerformed(java.awt.event.ActionEvent e) { 235 buttonActionRemoveMoveScript(e); 236 } 237 }); 238 addButtonAction(removeMoveScripts); 239 JLabel pathname = new JLabel(scripts.get(i)); 240 addItem(pMoveScript, removeMoveScripts, 0, i + 1); 241 addItem(pMoveScript, pathname, 1, i + 1); 242 } 243 } 244 } 245 246 private void updateTerminationScriptPanel() { 247 pTerminationScript.removeAll(); 248 pTerminationScript.setLayout(new GridBagLayout()); 249 addItem(pTerminationScript, addTerminationScriptButton, 0, 0); 250 251 // load any existing train termination scripts 252 if (_train != null) { 253 List<String> scripts = _train.getTerminationScripts(); 254 if (scripts.size() > 0) { 255 addItem(pTerminationScript, runTerminationScriptButton, 1, 0); 256 } 257 for (int i = 0; i < scripts.size(); i++) { 258 JButton removeTerminationScripts = new JButton(Bundle.getMessage("RemoveScript")); 259 removeTerminationScripts.setName(scripts.get(i)); 260 removeTerminationScripts.addActionListener(new java.awt.event.ActionListener() { 261 @Override 262 public void actionPerformed(java.awt.event.ActionEvent e) { 263 buttonActionRemoveTerminationScript(e); 264 } 265 }); 266 JLabel pathname = new JLabel(scripts.get(i)); 267 addItem(pTerminationScript, removeTerminationScripts, 0, i + 1); 268 addItem(pTerminationScript, pathname, 1, i + 1); 269 } 270 } 271 } 272 273 // Save train, add scripts buttons 274 @Override 275 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 276 if (_train != null) { 277 if (ae.getSource() == addBuildScriptButton) { 278 log.debug("train add build script button activated"); 279 File f = selectFile(); 280 if (f != null) { 281 _train.addBuildScript(FileUtil.getPortableFilename(f)); 282 updateBuildScriptPanel(); 283 pack(); 284 } 285 } 286 if (ae.getSource() == addAfterBuildScriptButton) { 287 log.debug("train add after build script button activated"); 288 File f = selectFile(); 289 if (f != null) { 290 _train.addAfterBuildScript(FileUtil.getPortableFilename(f)); 291 updateAfterBuildScriptPanel(); 292 pack(); 293 } 294 } 295 if (ae.getSource() == addMoveScriptButton) { 296 log.debug("train add move script button activated"); 297 File f = selectFile(); 298 if (f != null) { 299 _train.addMoveScript(FileUtil.getPortableFilename(f)); 300 updateMoveScriptPanel(); 301 pack(); 302 } 303 } 304 if (ae.getSource() == addTerminationScriptButton) { 305 log.debug("train add termination script button activated"); 306 File f = selectFile(); 307 if (f != null) { 308 _train.addTerminationScript(FileUtil.getPortableFilename(f)); 309 updateTerminationScriptPanel(); 310 pack(); 311 } 312 } 313 if (ae.getSource() == runBuildScriptButton) { 314 runScripts(_train.getBuildScripts()); 315 } 316 if (ae.getSource() == runAfterBuildScriptButton) { 317 runScripts(_train.getAfterBuildScripts()); 318 } 319 if (ae.getSource() == runMoveScriptButton) { 320 runScripts(_train.getMoveScripts()); 321 } 322 if (ae.getSource() == runTerminationScriptButton) { 323 runScripts(_train.getTerminationScripts()); 324 } 325 if (ae.getSource() == saveTrainButton) { 326 log.debug("train save button activated"); 327 OperationsXml.save(); 328 if (Setup.isCloseWindowOnSaveEnabled()) { 329 dispose(); 330 } 331 } 332 } 333 } 334 335 public void buttonActionRemoveBuildScript(java.awt.event.ActionEvent ae) { 336 if (_train != null) { 337 JButton rbutton = (JButton) ae.getSource(); 338 log.debug("remove build script button activated {}", rbutton.getName()); 339 _train.deleteBuildScript(rbutton.getName()); 340 updateBuildScriptPanel(); 341 pack(); 342 } 343 } 344 345 public void buttonActionRemoveAfterBuildScript(java.awt.event.ActionEvent ae) { 346 if (_train != null) { 347 JButton rbutton = (JButton) ae.getSource(); 348 log.debug("remove after build script button activated {}", rbutton.getName()); 349 _train.deleteAfterBuildScript(rbutton.getName()); 350 updateAfterBuildScriptPanel(); 351 pack(); 352 } 353 } 354 355 public void buttonActionRemoveMoveScript(java.awt.event.ActionEvent ae) { 356 if (_train != null) { 357 JButton rbutton = (JButton) ae.getSource(); 358 log.debug("remove move script button activated {}", rbutton.getName()); 359 _train.deleteMoveScript(rbutton.getName()); 360 updateMoveScriptPanel(); 361 pack(); 362 } 363 } 364 365 public void buttonActionRemoveTerminationScript(java.awt.event.ActionEvent ae) { 366 if (_train != null) { 367 JButton rbutton = (JButton) ae.getSource(); 368 log.debug("remove termination script button activated {}", rbutton.getName()); 369 _train.deleteTerminationScript(rbutton.getName()); 370 updateTerminationScriptPanel(); 371 pack(); 372 } 373 } 374 375 private void runScripts(List<String> scripts) { 376 for (String script : scripts) { 377 String scriptPathname = jmri.util.FileUtil.getExternalFilename(script); 378 File file = new File(scriptPathname); 379 if (file.exists()) { 380 JmriScriptEngineManager.getDefault().runScript(file); 381 } else { 382 JmriJOptionPane.showMessageDialog(this, script, Bundle.getMessage("ScriptFileNotFound"), 383 JmriJOptionPane.ERROR_MESSAGE); 384 } 385 } 386 } 387 388 /** 389 * We always use the same file chooser in this class, so that the user's 390 * last-accessed directory remains available. 391 */ 392 ScriptFileChooser fc = new ScriptFileChooser(FileUtil.getUserFilesPath()); 393 394 private File selectFile() { 395 if (fc == null) { 396 log.error("Could not find user directory"); 397 } else { 398 fc.setDialogTitle(Bundle.getMessage("FindDesiredScriptFile")); 399 // when reusing the chooser, make sure new files are included 400 fc.rescanCurrentDirectory(); 401 int retVal = fc.showOpenDialog(null); 402 // handle selection or cancel 403 if (retVal == JFileChooser.APPROVE_OPTION) { 404 return fc.getSelectedFile(); 405 } 406 } 407 return null; 408 } 409 410 private void enableButtons(boolean enabled) { 411 addBuildScriptButton.setEnabled(enabled); 412 addAfterBuildScriptButton.setEnabled(enabled); 413 addMoveScriptButton.setEnabled(enabled); 414 addTerminationScriptButton.setEnabled(enabled); 415 saveTrainButton.setEnabled(enabled); 416 } 417 418 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainScriptFrame.class); 419}