001package jmri.jmrit.operations.automation; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005 006import javax.swing.*; 007 008import jmri.InstanceManager; 009import jmri.jmrit.operations.OperationsFrame; 010import jmri.jmrit.operations.OperationsXml; 011import jmri.jmrit.operations.automation.actions.Action; 012import jmri.jmrit.operations.setup.Control; 013import jmri.jmrit.operations.setup.Setup; 014import jmri.swing.JTablePersistenceManager; 015import jmri.util.swing.JmriJOptionPane; 016 017/** 018 * Frame for user edit of a automation 019 * 020 * @author Dan Boudreau Copyright (C) 2016 021 */ 022public class AutomationTableFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 023 024 AutomationTableModel _automationTableModel = new AutomationTableModel(); 025 JTable _automationTable = new JTable(_automationTableModel); 026 JScrollPane _automationPane; 027 028 AutomationManager automationManager; 029 030 Automation _automation = null; 031 AutomationItem _automationItem = null; 032 033 // labels 034 // major buttons 035 JButton stepActionButton = new JButton(Bundle.getMessage("StepAutomation")); 036 JButton runActionButton = new JButton(Bundle.getMessage("RunAutomation")); 037 JButton stopActionButton = new JButton(Bundle.getMessage("StopAutomation")); 038 JButton resumeActionButton = new JButton(Bundle.getMessage("ResumeAutomation")); 039 040 JButton addActionButton = new JButton(Bundle.getMessage("AddAction")); 041 JButton saveAutomationButton = new JButton(Bundle.getMessage("SaveAutomation")); 042 JButton deleteAutomationButton = new JButton(Bundle.getMessage("DeleteAutomation")); 043 JButton addAutomationButton = new JButton(Bundle.getMessage("AddAutomation")); 044 045 // radio buttons 046 JRadioButton addActionAtTopRadioButton = new JRadioButton(Bundle.getMessage("Top")); 047 JRadioButton addActionAtMiddleRadioButton = new JRadioButton(Bundle.getMessage("Middle")); 048 JRadioButton addActionAtBottomRadioButton = new JRadioButton(Bundle.getMessage("Bottom")); 049 050 // text field 051 JTextField automationNameTextField = new JTextField(20); 052 JTextField commentTextField = new JTextField(35); 053 054 // combo boxes 055 056 public static final int MAX_NAME_LENGTH = Control.max_len_string_automation_name; 057 public static final String NAME = Bundle.getMessage("Name"); 058 public static final String DISPOSE = "dispose"; // NOI18N 059 060 public AutomationTableFrame(Automation automation) { 061 super(); 062 063 _automation = automation; 064 065 // load managers 066 automationManager = InstanceManager.getDefault(AutomationManager.class); 067 068 // tool tips 069 stepActionButton.setToolTipText(Bundle.getMessage("TipStepAutomation")); 070 runActionButton.setToolTipText(Bundle.getMessage("TipRunAutomation")); 071 stopActionButton.setToolTipText(Bundle.getMessage("TipStopAutomation")); 072 resumeActionButton.setToolTipText(Bundle.getMessage("TipResumeAutomation")); 073 074 // Set up the jtable in a Scroll Pane.. 075 _automationPane = new JScrollPane(_automationTable); 076 _automationPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 077 078 _automationTableModel.initTable(this, _automationTable, automation); 079 if (_automation != null) { 080 automationNameTextField.setText(_automation.getName()); 081 commentTextField.setText(_automation.getComment()); 082 setTitle(Bundle.getMessage("TitleAutomationEdit")); 083 enableButtons(true); 084 } else { 085 setTitle(Bundle.getMessage("TitleAutomationAdd")); 086 enableButtons(false); 087 } 088 089 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 090 091 // Layout the panel by rows 092 JPanel p1 = new JPanel(); 093 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 094 095 JScrollPane p1Pane = new JScrollPane(p1); 096 p1Pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 097 p1Pane.setMinimumSize(new Dimension(300, 098 3 * automationNameTextField.getPreferredSize().height)); 099 p1Pane.setMaximumSize(new Dimension(2000, 200)); 100 101 // row 1a name 102 JPanel pName = new JPanel(); 103 pName.setLayout(new GridBagLayout()); 104 pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name"))); 105 addItem(pName, automationNameTextField, 0, 0); 106 107 // row 1b comment 108 JPanel pComment = new JPanel(); 109 pComment.setLayout(new GridBagLayout()); 110 pComment.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Comment"))); 111 addItem(pComment, commentTextField, 0, 0); 112 113 p1.add(pName); 114 p1.add(pComment); 115 116 // row 10 117 JPanel p3 = new JPanel(); 118 p3.setLayout(new GridBagLayout()); 119 p3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("AddItem"))); 120 p3.setMaximumSize(new Dimension(2000, 200)); 121 122 addItem(p3, addActionButton, 1, 1); 123 addItem(p3, addActionAtTopRadioButton, 2, 1); 124 addItem(p3, addActionAtMiddleRadioButton, 3, 1); 125 addItem(p3, addActionAtBottomRadioButton, 4, 1); 126 127 ButtonGroup group = new ButtonGroup(); 128 group.add(addActionAtTopRadioButton); 129 group.add(addActionAtMiddleRadioButton); 130 group.add(addActionAtBottomRadioButton); 131 addActionAtBottomRadioButton.setSelected(true); 132 133 // row 9 buttons 134 JPanel pControl = new JPanel(); 135 pControl.setLayout(new GridBagLayout()); 136 pControl.setBorder(BorderFactory.createTitledBorder("")); 137 pControl.setMaximumSize(new Dimension(2000, 200)); 138 139 addItem(pControl, stepActionButton, 0, 0); 140 addItem(pControl, runActionButton, 1, 0); 141 addItem(pControl, resumeActionButton, 2, 0); 142 addItem(pControl, stopActionButton, 3, 0); 143 144 // row 11 buttons 145 JPanel pB = new JPanel(); 146 pB.setLayout(new GridBagLayout()); 147 pB.setBorder(BorderFactory.createTitledBorder("")); 148 pB.setMaximumSize(new Dimension(2000, 200)); 149 150 // row 13 151 addItem(pB, deleteAutomationButton, 0, 0); 152 addItem(pB, addAutomationButton, 1, 0); 153 addItem(pB, saveAutomationButton, 3, 0); 154 155 getContentPane().add(p1Pane); 156 getContentPane().add(_automationPane); 157 getContentPane().add(p3); 158 getContentPane().add(pControl); 159 getContentPane().add(pB); 160 161 // setup buttons 162 addButtonAction(stepActionButton); 163 addButtonAction(runActionButton); 164 addButtonAction(stopActionButton); 165 addButtonAction(resumeActionButton); 166 167 addButtonAction(addActionButton); 168 addButtonAction(deleteAutomationButton); 169 addButtonAction(addAutomationButton); 170 addButtonAction(saveAutomationButton); 171 172 if (_automation != null) { 173 _automation.addPropertyChangeListener(this); 174 } 175 176 // build menu 177 JMenuBar menuBar = new JMenuBar(); 178 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 179 menuBar.add(toolMenu); 180 toolMenu.add(new AutomationResetAction(this)); 181 toolMenu.add(new AutomationCopyAction(automation)); 182 setJMenuBar(menuBar); 183 addHelpMenu("package.jmri.jmrit.operations.Operations_Automation", true); // NOI18N 184 185 // set frame size and automation for display 186 initMinimumSize(new Dimension(Control.panelWidth700, Control.panelHeight400)); 187 } 188 189 // Save, Delete, Add 190 @Override 191 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 192 stopCellEditing(); 193 if (_automation != null) { 194 if (ae.getSource() == stepActionButton) { 195 _automation.step(); 196 } 197 if (ae.getSource() == runActionButton) { 198 _automation.run(); 199 } 200 if (ae.getSource() == stopActionButton) { 201 _automation.stop(); 202 } 203 if (ae.getSource() == resumeActionButton) { 204 _automation.resume(); 205 } 206 } 207 if (ae.getSource() == addActionButton) { 208 addNewAutomationItem(); 209 } 210 if (ae.getSource() == saveAutomationButton) { 211 log.debug("automation save button activated"); 212 Automation automation = automationManager.getAutomationByName(automationNameTextField.getText()); 213 if (_automation == null && automation == null) { 214 saveNewAutomation(); 215 } else { 216 if (automation != null && automation != _automation) { 217 reportAutomationExists(Bundle.getMessage("save")); 218 return; 219 } 220 saveAutomation(); 221 } 222 if (Setup.isCloseWindowOnSaveEnabled()) { 223 dispose(); 224 } 225 } 226 if (ae.getSource() == deleteAutomationButton) { 227 log.debug("automation delete button activated"); 228 if (JmriJOptionPane.showConfirmDialog(this, 229 Bundle.getMessage("DoYouWantToDeleteAutomation", automationNameTextField.getText()), 230 Bundle.getMessage("DeleteAutomation?"), 231 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 232 return; 233 } 234 Automation automation = automationManager.getAutomationByName(automationNameTextField.getText()); 235 if (automation == null) { 236 return; 237 } 238 239 automationManager.deregister(automation); 240 _automation = null; 241 242 enableButtons(false); 243 // save automation file 244 OperationsXml.save(); 245 } 246 if (ae.getSource() == addAutomationButton) { 247 Automation automation = automationManager.getAutomationByName(automationNameTextField.getText()); 248 if (automation != null) { 249 reportAutomationExists(Bundle.getMessage("add")); 250 return; 251 } 252 saveNewAutomation(); 253 } 254 } 255 256 private void addNewAutomationItem() { 257 // add item to this automation 258 if (addActionAtTopRadioButton.isSelected()) { 259 _automation.addNewItem(0); 260 } else if (addActionAtBottomRadioButton.isSelected()) { 261 _automation.addItem(); 262 } else { 263 // middle radio button selected 264 if (_automationTable.getSelectedRow() >= 0) { 265 int row = _automationTable.getSelectedRow(); 266 _automation.addNewItem(row); 267 // we need to reselect the table since the content has changed 268 _automationTable.getSelectionModel().setSelectionInterval(row, row); 269 } else { 270 _automation.addNewItem(_automation.getSize() / 2); 271 } 272 } 273 } 274 275 private void saveNewAutomation() { 276 if (!checkName(Bundle.getMessage("add"))) { 277 return; 278 } 279 Automation automation = automationManager.newAutomation(automationNameTextField.getText()); 280 _automationTableModel.initTable(this, _automationTable, automation); 281 _automation = automation; 282 _automation.addPropertyChangeListener(this); 283 // enable checkboxes 284 enableButtons(true); 285 saveAutomation(); 286 } 287 288 private void saveAutomation() { 289 if (!checkName(Bundle.getMessage("save"))) { 290 return; 291 } 292 _automation.setName(automationNameTextField.getText()); 293 _automation.setComment(commentTextField.getText()); 294 295 // save automation file 296 OperationsXml.save(); 297 } 298 299 private void stopCellEditing() { 300 if (_automationTable.isEditing()) { 301 log.debug("automation table edit true"); 302 _automationTable.getCellEditor().stopCellEditing(); 303 } 304 } 305 306 /** 307 * 308 * @return true if name is less than 26 characters 309 */ 310 private boolean checkName(String s) { 311 if (automationNameTextField.getText().trim().isEmpty()) { 312 return false; 313 } 314 if (automationNameTextField.getText().length() > MAX_NAME_LENGTH) { 315 JmriJOptionPane.showMessageDialog(this, 316 Bundle.getMessage("AutomationNameLengthMax", Integer.toString(MAX_NAME_LENGTH)), 317 Bundle.getMessage("CanNotAutomation", s), JmriJOptionPane.ERROR_MESSAGE); 318 return false; 319 } 320 return true; 321 } 322 323 private void reportAutomationExists(String s) { 324 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("ReportExists"), 325 Bundle.getMessage("CanNotAutomation", s), JmriJOptionPane.ERROR_MESSAGE); 326 } 327 328 private void enableButtons(boolean enabled) { 329 enableControlButtons(enabled); 330 331 addActionButton.setEnabled(enabled); 332 addActionAtTopRadioButton.setEnabled(enabled); 333 addActionAtMiddleRadioButton.setEnabled(enabled); 334 addActionAtBottomRadioButton.setEnabled(enabled); 335 saveAutomationButton.setEnabled(enabled); 336 deleteAutomationButton.setEnabled(enabled); 337 _automationTable.setEnabled(enabled); 338 // the inverse! 339 addAutomationButton.setEnabled(!enabled); 340 } 341 342 private void enableControlButtons(boolean enabled) { 343 boolean b = enabled && _automation != null && _automation.getSize() > 0; 344 stepActionButton.setEnabled(b && !_automation.isActionRunning()); 345 runActionButton.setEnabled(b && !_automation.isRunning()); 346 stopActionButton.setEnabled(b); 347 resumeActionButton.setEnabled(b && !_automation.isRunning()); 348 } 349 350 @Override 351 public void dispose() { 352 if (_automation != null) { 353 _automation.removePropertyChangeListener(this); 354 } 355 InstanceManager.getOptionalDefault(JTablePersistenceManager.class).ifPresent(tpm -> { 356 tpm.stopPersisting(_automationTable); 357 }); 358 _automationTableModel.dispose(); 359 super.dispose(); 360 } 361 362 @Override 363 public void propertyChange(java.beans.PropertyChangeEvent e) { 364 // if (Control.showProperty) 365 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 366 .getNewValue()); 367 if (e.getPropertyName().equals(Automation.LISTCHANGE_CHANGED_PROPERTY) || 368 e.getPropertyName().equals(Automation.RUNNING_CHANGED_PROPERTY) || 369 e.getPropertyName().equals(Action.ACTION_RUNNING_CHANGED_PROPERTY)) { 370 enableControlButtons(true); 371 } 372 } 373 374 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AutomationTableFrame.class); 375}