001package jmri.jmrit.logixng.actions.swing; 002 003import java.awt.GridBagConstraints; 004import java.awt.GridBagLayout; 005import java.util.List; 006 007import javax.annotation.CheckForNull; 008import javax.annotation.Nonnull; 009import javax.swing.*; 010 011import jmri.*; 012import jmri.jmrit.logixng.*; 013import jmri.jmrit.logixng.actions.ActionDispatcher; 014import jmri.jmrit.logixng.actions.ActionDispatcher.DirectOperation; 015import jmri.jmrit.logixng.swing.SwingConfiguratorInterface; 016import jmri.jmrit.logixng.util.DispatcherActiveTrainManager; 017import jmri.jmrit.logixng.util.parser.ParserException; 018import jmri.jmrit.logixng.util.swing.LogixNG_SelectEnumSwing; 019import jmri.util.swing.JComboBoxUtil; 020 021/** 022 * Configures an ActionDispatcher object with a Swing JPanel. 023 * 024 * @author Daniel Bergqvist Copyright 2021 025 * @author Dave Sand Copyright 2021 026 */ 027public class ActionDispatcherSwing extends AbstractDigitalActionSwing { 028 029 private JTabbedPane _tabbedPaneDispatcher; 030 private JPanel _panelDispatcherDirect; 031 private JPanel _panelDispatcherReference; 032 private JPanel _panelDispatcherLocalVariable; 033 private JPanel _panelDispatcherFormula; 034 035 private JComboBox<String> _fileNamesComboBox; 036 private JTextField _dispatcherReferenceTextField; 037 private JTextField _dispatcherLocalVariableTextField; 038 private JTextField _dispatcherFormulaTextField; 039 040 private LogixNG_SelectEnumSwing<DirectOperation> _selectOperationSwing; 041 042 private JTabbedPane _tabbedPaneData; 043 private JPanel _panelDataDirect; 044 private JPanel _panelDataReference; 045 private JPanel _panelDataLocalVariable; 046 private JPanel _panelDataFormula; 047 048 JLabel _priorityLabel; 049 JLabel _resetLabel; 050 JLabel _terminateLabel; 051 private JSpinner _priority; 052 private JCheckBox _resetOption; 053 private JCheckBox _terminateOption; 054 private JTextField _dispatcherDataReferenceTextField; 055 private JTextField _dispatcherDataLocalVariableTextField; 056 private JTextField _dispatcherDataFormulaTextField; 057 058 059 public ActionDispatcherSwing() { 060 } 061 062 public ActionDispatcherSwing(JDialog dialog) { 063 super.setJDialog(dialog); 064 } 065 066 @Override 067 protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) { 068 ActionDispatcher action = (ActionDispatcher)object; 069 070 _selectOperationSwing = new LogixNG_SelectEnumSwing<>(getJDialog(), this); 071 072 panel = new JPanel(); 073 074 // Left section 075 _tabbedPaneDispatcher = new JTabbedPane(); 076 _panelDispatcherDirect = new javax.swing.JPanel(); 077 _panelDispatcherReference = new javax.swing.JPanel(); 078 _panelDispatcherLocalVariable = new javax.swing.JPanel(); 079 _panelDispatcherFormula = new javax.swing.JPanel(); 080 081 _tabbedPaneDispatcher.addTab(NamedBeanAddressing.Direct.toString(), _panelDispatcherDirect); 082 _tabbedPaneDispatcher.addTab(NamedBeanAddressing.Reference.toString(), _panelDispatcherReference); 083 _tabbedPaneDispatcher.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelDispatcherLocalVariable); 084 _tabbedPaneDispatcher.addTab(NamedBeanAddressing.Formula.toString(), _panelDispatcherFormula); 085 086 _fileNamesComboBox = new JComboBox<>(); 087 InstanceManager.getDefault(DispatcherActiveTrainManager.class).getTrainInfoFileNames().forEach(name -> { 088 _fileNamesComboBox.addItem(name); 089 }); 090 JComboBoxUtil.setupComboBoxMaxRows(_fileNamesComboBox); 091 _panelDispatcherDirect.add(_fileNamesComboBox); 092 093 _dispatcherReferenceTextField = new JTextField(); 094 _dispatcherReferenceTextField.setColumns(30); 095 _panelDispatcherReference.add(_dispatcherReferenceTextField); 096 097 _dispatcherLocalVariableTextField = new JTextField(); 098 _dispatcherLocalVariableTextField.setColumns(30); 099 _panelDispatcherLocalVariable.add(_dispatcherLocalVariableTextField); 100 101 _dispatcherFormulaTextField = new JTextField(); 102 _dispatcherFormulaTextField.setColumns(30); 103 _panelDispatcherFormula.add(_dispatcherFormulaTextField); 104 105 106 // Center section 107 JPanel _tabbedPaneOperation; 108 109 if (action != null) { 110 _tabbedPaneOperation = _selectOperationSwing.createPanel(action.getSelectEnum(), DirectOperation.values()); 111 } else { 112 _tabbedPaneOperation = _selectOperationSwing.createPanel(null, DirectOperation.values()); 113 } 114 115 116 // Right section 117 _tabbedPaneData = new JTabbedPane(); 118 _panelDataDirect = new javax.swing.JPanel(); 119 _panelDataDirect.setLayout(new BoxLayout(_panelDataDirect, BoxLayout.Y_AXIS)); 120 _panelDataReference = new javax.swing.JPanel(); 121 _panelDataLocalVariable = new javax.swing.JPanel(); 122 _panelDataFormula = new javax.swing.JPanel(); 123 124 _tabbedPaneData.addTab(NamedBeanAddressing.Direct.toString(), _panelDataDirect); 125 _tabbedPaneData.addTab(NamedBeanAddressing.Reference.toString(), _panelDataReference); 126 _tabbedPaneData.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelDataLocalVariable); 127 _tabbedPaneData.addTab(NamedBeanAddressing.Formula.toString(), _panelDataFormula); 128 129 130 _priorityLabel = new JLabel(Bundle.getMessage("ActionDispatcher_Priority")); 131 _priority = new JSpinner(new SpinnerNumberModel(5, 0, 100, 1)); 132 _resetLabel = new JLabel(Bundle.getMessage("ActionDispatcher_Reset")); 133 _resetOption = new JCheckBox(); 134 _terminateLabel = new JLabel(Bundle.getMessage("ActionDispatcher_Terminate")); 135 _terminateOption = new JCheckBox(); 136 137 JPanel dataGroup = new JPanel(); 138 dataGroup.setLayout(new GridBagLayout()); 139 GridBagConstraints constraint = new GridBagConstraints(); 140 constraint.gridwidth = 1; 141 constraint.gridheight = 1; 142 constraint.gridx = 0; 143 constraint.gridy = 0; 144 constraint.anchor = GridBagConstraints.EAST; 145 dataGroup.add(_priorityLabel, constraint); 146 _priorityLabel.setLabelFor(_priority); 147 constraint.gridy = 1; 148 dataGroup.add(_resetLabel, constraint); 149 _resetLabel.setLabelFor(_resetOption); 150 constraint.gridy = 2; 151 dataGroup.add(_terminateLabel, constraint); 152 _terminateLabel.setLabelFor(_terminateOption); 153 constraint.gridx = 1; 154 constraint.gridy = 0; 155 constraint.anchor = GridBagConstraints.WEST; 156 dataGroup.add(_priority, constraint); 157 constraint.gridy = 1; 158 dataGroup.add(_resetOption, constraint); 159 constraint.gridy = 2; 160 dataGroup.add(_terminateOption, constraint); 161 162 _panelDataDirect.add(dataGroup); 163 164 _dispatcherDataReferenceTextField = new JTextField(); 165 _dispatcherDataReferenceTextField.setColumns(30); 166 _panelDataReference.add(_dispatcherDataReferenceTextField); 167 168 _dispatcherDataLocalVariableTextField = new JTextField(); 169 _dispatcherDataLocalVariableTextField.setColumns(30); 170 _panelDataLocalVariable.add(_dispatcherDataLocalVariableTextField); 171 172 _dispatcherDataFormulaTextField = new JTextField(); 173 _dispatcherDataFormulaTextField.setColumns(30); 174 _panelDataFormula.add(_dispatcherDataFormulaTextField); 175 176 177 if (action != null) { 178 switch (action.getAddressing()) { 179 case Direct: _tabbedPaneDispatcher.setSelectedComponent(_panelDispatcherDirect); break; 180 case Reference: _tabbedPaneDispatcher.setSelectedComponent(_panelDispatcherReference); break; 181 case LocalVariable: _tabbedPaneDispatcher.setSelectedComponent(_panelDispatcherLocalVariable); break; 182 case Formula: _tabbedPaneDispatcher.setSelectedComponent(_panelDispatcherFormula); break; 183 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAddressing().name()); 184 } 185 _fileNamesComboBox.setSelectedItem(action.getTrainInfoFileName()); 186 _dispatcherReferenceTextField.setText(action.getReference()); 187 _dispatcherLocalVariableTextField.setText(action.getLocalVariable()); 188 _dispatcherFormulaTextField.setText(action.getFormula()); 189 190 switch (action.getDataAddressing()) { 191 case Direct: _tabbedPaneData.setSelectedComponent(_panelDataDirect); break; 192 case Reference: _tabbedPaneData.setSelectedComponent(_panelDataReference); break; 193 case LocalVariable: _tabbedPaneData.setSelectedComponent(_panelDataLocalVariable); break; 194 case Formula: _tabbedPaneData.setSelectedComponent(_panelDataFormula); break; 195 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getDataAddressing().name()); 196 } 197 _priority.setValue(action.getTrainPriority()); 198 _resetOption.setSelected(action.getResetOption()); 199 _terminateOption.setSelected(action.getTerminateOption()); 200 _dispatcherDataReferenceTextField.setText(action.getDataReference()); 201 _dispatcherDataLocalVariableTextField.setText(action.getDataLocalVariable()); 202 _dispatcherDataFormulaTextField.setText(action.getDataFormula()); 203 } 204 205 setDataPanelState(); 206 207 _selectOperationSwing.addAddressingListener((evt) -> { setDataPanelState(); }); 208 _selectOperationSwing.addEnumListener((evt) -> { setDataPanelState(); }); 209 210 JComponent[] components = new JComponent[]{ 211 _tabbedPaneDispatcher, 212 _tabbedPaneOperation, 213 _tabbedPaneData}; 214 215 List<JComponent> componentList = SwingConfiguratorInterface.parseMessage( 216 Bundle.getMessage("ActionDispatcher_Components"), components); 217 218 for (JComponent c : componentList) panel.add(c); 219 } 220 221 private void setDataPanelState() { 222 223 _priorityLabel.setVisible(false); 224 _priority.setVisible(false); 225 _resetLabel.setVisible(false); 226 _resetOption.setVisible(false); 227 _terminateLabel.setVisible(false); 228 _terminateOption.setVisible(false); 229 230 boolean newState = false; 231 232 if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing( 233 DirectOperation.TrainPriority)) { 234 _priorityLabel.setVisible(true); 235 _priority.setVisible(true); 236 newState = true; 237 } 238 239 if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing( 240 DirectOperation.ResetWhenDoneOption)) { 241 _resetLabel.setVisible(true); 242 _resetOption.setVisible(true); 243 newState = true; 244 } 245 246 if (_selectOperationSwing.isEnumSelectedOrIndirectAddressing( 247 DirectOperation.TerminateWhenDoneOption)) { 248 _terminateLabel.setVisible(true); 249 _terminateOption.setVisible(true); 250 newState = true; 251 } 252 253 _tabbedPaneData.setEnabled(newState); 254 _dispatcherDataReferenceTextField.setEnabled(newState); 255 _dispatcherDataLocalVariableTextField.setEnabled(newState); 256 _dispatcherDataFormulaTextField.setEnabled(newState); 257 } 258 259 /** {@inheritDoc} */ 260 @Override 261 public boolean validate(@Nonnull List<String> errorMessages) { 262 // Create a temporary action to test formula 263 ActionDispatcher action = new ActionDispatcher("IQDA2", null); 264 265 validateInfoFileSection(errorMessages); 266 _selectOperationSwing.validate(action.getSelectEnum(), errorMessages); 267 268 if ((_selectOperationSwing.getAddressing() == NamedBeanAddressing.Direct) 269 && (_selectOperationSwing.getEnum() == DirectOperation.None)) { 270 errorMessages.add(Bundle.getMessage("ActionDispatcher_ErrorDispatcherActionNotSelected")); 271 } 272 validateDataSection(errorMessages); 273 return errorMessages.isEmpty(); 274 } 275 276 private void validateInfoFileSection(List<String> errorMessages) { 277 // Create a temporary action to test formula 278 ActionDispatcher action = new ActionDispatcher("IQDA1", null); 279 280 try { 281 if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherReference) { 282 action.setReference(_dispatcherReferenceTextField.getText()); 283 } 284 } catch (IllegalArgumentException e) { 285 errorMessages.add(e.getMessage()); 286 return; 287 } 288 289 try { 290 action.setFormula(_dispatcherFormulaTextField.getText()); 291 if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherDirect) { 292 action.setAddressing(NamedBeanAddressing.Direct); 293 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherReference) { 294 action.setAddressing(NamedBeanAddressing.Reference); 295 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherLocalVariable) { 296 action.setAddressing(NamedBeanAddressing.LocalVariable); 297 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherFormula) { 298 action.setAddressing(NamedBeanAddressing.Formula); 299 } else { 300 throw new IllegalArgumentException("_tabbedPane has unknown selection"); 301 } 302 } catch (ParserException e) { 303 errorMessages.add("Cannot parse formula: " + e.getMessage()); 304 } 305 306// if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherDirect) { 307// if (_stateComboBox.getSelectedItem() == null) { 308// errorMessages.add(Bundle.getMessage("ActionDispatcher_ErrorFile")); 309// } 310// } 311 } 312 313 private void validateDataSection(List<String> errorMessages) { 314 // Create a temporary action to test formula 315 ActionDispatcher action = new ActionDispatcher("IQDA3", null); 316 317 try { 318 if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) { 319 action.setDataReference(_dispatcherDataReferenceTextField.getText()); 320 } 321 } catch (IllegalArgumentException e) { 322 errorMessages.add(e.getMessage()); 323 return; 324 } 325 326 try { 327 action.setDataFormula(_dispatcherDataFormulaTextField.getText()); 328 if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) { 329 action.setDataAddressing(NamedBeanAddressing.Direct); 330 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) { 331 action.setDataAddressing(NamedBeanAddressing.Reference); 332 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) { 333 action.setDataAddressing(NamedBeanAddressing.LocalVariable); 334 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) { 335 action.setDataAddressing(NamedBeanAddressing.Formula); 336 } else { 337 throw new IllegalArgumentException("_tabbedPane has unknown selection"); 338 } 339 } catch (ParserException e) { 340 errorMessages.add("Cannot parse formula: " + e.getMessage()); 341 } 342 343 } 344 345 /** {@inheritDoc} */ 346 @Override 347 public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) { 348 ActionDispatcher action = new ActionDispatcher(systemName, userName); 349 updateObject(action); 350 return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action); 351 } 352 353 /** {@inheritDoc} */ 354 @Override 355 public void updateObject(@Nonnull Base object) { 356 if (! (object instanceof ActionDispatcher)) { 357 throw new IllegalArgumentException("object must be an ActionDispatcher but is a: "+object.getClass().getName()); 358 } 359 ActionDispatcher action = (ActionDispatcher) object; 360 361 try { 362 // Left section 363 if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherDirect) { 364 action.setAddressing(NamedBeanAddressing.Direct); 365 action.setTrainInfoFileName((String) _fileNamesComboBox.getSelectedItem()); 366 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherReference) { 367 action.setAddressing(NamedBeanAddressing.Reference); 368 action.setReference(_dispatcherReferenceTextField.getText()); 369 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherLocalVariable) { 370 action.setAddressing(NamedBeanAddressing.LocalVariable); 371 action.setLocalVariable(_dispatcherLocalVariableTextField.getText()); 372 } else if (_tabbedPaneDispatcher.getSelectedComponent() == _panelDispatcherFormula) { 373 action.setAddressing(NamedBeanAddressing.Formula); 374 action.setFormula(_dispatcherFormulaTextField.getText()); 375 } else { 376 throw new IllegalArgumentException("_tabbedPaneDispatcher has unknown selection"); 377 } 378 379 // Center section 380 _selectOperationSwing.updateObject(action.getSelectEnum()); 381 382 // Right section 383 if (_tabbedPaneData.getSelectedComponent() == _panelDataDirect) { 384 action.setDataAddressing(NamedBeanAddressing.Direct); 385 action.setTrainPriority((int) _priority.getValue()); 386 action.setResetOption(_resetOption.isSelected()); 387 action.setTerminateOption(_terminateOption.isSelected()); 388 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataReference) { 389 action.setDataAddressing(NamedBeanAddressing.Reference); 390 action.setDataReference(_dispatcherDataReferenceTextField.getText()); 391 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataLocalVariable) { 392 action.setDataAddressing(NamedBeanAddressing.LocalVariable); 393 action.setDataLocalVariable(_dispatcherDataLocalVariableTextField.getText()); 394 } else if (_tabbedPaneData.getSelectedComponent() == _panelDataFormula) { 395 action.setDataAddressing(NamedBeanAddressing.Formula); 396 action.setDataFormula(_dispatcherDataFormulaTextField.getText()); 397 } else { 398 throw new IllegalArgumentException("_tabbedPaneData has unknown selection"); 399 } 400 } catch (ParserException e) { 401 throw new RuntimeException("ParserException: "+e.getMessage(), e); 402 } 403 } 404 405 /** {@inheritDoc} */ 406 @Override 407 public String toString() { 408 return Bundle.getMessage("ActionDispatcher_Short"); 409 } 410 411 @Override 412 public void setDefaultValues() { 413 _selectOperationSwing.setEnum(DirectOperation.LoadTrainFromFile); 414 } 415 416 @Override 417 public void dispose() { 418 _selectOperationSwing.dispose(); 419 } 420 421 422// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionDispatcherSwing.class); 423 424}