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