001package jmri.jmrit.logixng.actions.swing; 002 003import java.awt.Color; 004import java.util.List; 005 006import javax.annotation.CheckForNull; 007import javax.annotation.Nonnull; 008import javax.swing.*; 009import javax.swing.event.ChangeEvent; 010 011import jmri.InstanceManager; 012import jmri.NamedBeanHandle; 013import jmri.NamedBeanHandleManager; 014import jmri.SignalMast; 015import jmri.SignalMastManager; 016import jmri.jmrit.logixng.*; 017import jmri.jmrit.logixng.actions.ActionSignalMast; 018import jmri.jmrit.logixng.swing.SwingConfiguratorInterface; 019import jmri.jmrit.logixng.util.swing.LogixNG_SelectNamedBeanSwing; 020import jmri.jmrit.logixng.util.parser.ParserException; 021import jmri.util.swing.BeanSelectPanel; 022import jmri.util.swing.JComboBoxUtil; 023 024/** 025 * Configures an ActionSignalMast object with a Swing JPanel. 026 * 027 * @author Daniel Bergqvist Copyright 2021 028 */ 029public class ActionSignalMastSwing extends AbstractDigitalActionSwing { 030 031 public static final int NUM_COLUMNS_TEXT_FIELDS = 20; 032 033 private LogixNG_SelectNamedBeanSwing<SignalMast> _selectNamedBeanSwing; 034 035 private JTabbedPane _tabbedPaneOperationType; 036 private JPanel _panelOperationTypeDirect; 037 private JPanel _panelOperationTypeReference; 038 private JPanel _panelOperationTypeLocalVariable; 039 private JPanel _panelOperationTypeFormula; 040 041 private JComboBox<ActionSignalMast.OperationType> _operationComboBox; 042 private JTextField _signalMastOperationReferenceTextField; 043 private JTextField _signalMastOperationLocalVariableTextField; 044 private JTextField _signalMastOperationFormulaTextField; 045 046 private JTabbedPane _tabbedPaneAspectType; 047 private JPanel _panelAspectTypeDirect; 048 private JPanel _panelAspectTypeReference; 049 private JPanel _panelAspectTypeLocalVariable; 050 private JPanel _panelAspectTypeFormula; 051 052 private JComboBox<String> _signalMastAspectComboBox; 053 private JTextField _signalMastAspectReferenceTextField; 054 private JTextField _signalMastAspectLocalVariableTextField; 055 private JTextField _signalMastAspectFormulaTextField; 056 057 private BeanSelectPanel<SignalMast> _exampleSignalMastBeanPanel; 058 059 060 public ActionSignalMastSwing() { 061 } 062 063 public ActionSignalMastSwing(JDialog dialog) { 064 super.setJDialog(dialog); 065 } 066 067 @Override 068 protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) { 069 ActionSignalMast action = (ActionSignalMast)object; 070 071 _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>( 072 InstanceManager.getDefault(SignalMastManager.class), getJDialog(), this); 073 074 panel = new JPanel(); 075 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 076 077 JPanel _tabbedPaneNamedBean; 078 079 if (action != null) { 080 _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(action.getSelectNamedBean()); 081 } else { 082 _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(null); 083 } 084 085 JPanel examplePanel = new JPanel(); 086 JPanel innerExamplePanel = new JPanel(); 087 innerExamplePanel.setBorder(BorderFactory.createLineBorder(Color.black)); 088 _exampleSignalMastBeanPanel = new BeanSelectPanel<>(InstanceManager.getDefault(SignalMastManager.class), null); 089 innerExamplePanel.add(_exampleSignalMastBeanPanel); 090 091 _exampleSignalMastBeanPanel.getBeanCombo().addActionListener((java.awt.event.ActionEvent e) -> { 092 setAspectComboBox(null); 093 }); 094 095 096 JPanel actionPanel = new JPanel(); 097 098 099 _selectNamedBeanSwing.addAddressingListener((ChangeEvent e) -> { 100 setGuiEnabledStates(); 101 }); 102 103 _selectNamedBeanSwing.getBeanSelectPanel().getBeanCombo() 104 .addActionListener((java.awt.event.ActionEvent e) -> { 105 setAspectComboBox(null); 106 }); 107 108 109 // Set up the tabbed pane for selecting the operation 110 _tabbedPaneOperationType = new JTabbedPane(); 111 _panelOperationTypeDirect = new javax.swing.JPanel(); 112 _panelOperationTypeDirect.setLayout(new BoxLayout(_panelOperationTypeDirect, BoxLayout.Y_AXIS)); 113 _panelOperationTypeReference = new javax.swing.JPanel(); 114 _panelOperationTypeReference.setLayout(new BoxLayout(_panelOperationTypeReference, BoxLayout.Y_AXIS)); 115 _panelOperationTypeLocalVariable = new javax.swing.JPanel(); 116 _panelOperationTypeLocalVariable.setLayout(new BoxLayout(_panelOperationTypeLocalVariable, BoxLayout.Y_AXIS)); 117 _panelOperationTypeFormula = new javax.swing.JPanel(); 118 _panelOperationTypeFormula.setLayout(new BoxLayout(_panelOperationTypeFormula, BoxLayout.Y_AXIS)); 119 120 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Direct.toString(), _panelOperationTypeDirect); 121 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Reference.toString(), _panelOperationTypeReference); 122 _tabbedPaneOperationType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelOperationTypeLocalVariable); 123 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Formula.toString(), _panelOperationTypeFormula); 124 125 _tabbedPaneOperationType.addChangeListener((ChangeEvent e) -> { 126 setGuiEnabledStates(); 127 }); 128 129 _operationComboBox = new JComboBox<>(); 130 for (ActionSignalMast.OperationType e : ActionSignalMast.OperationType.values()) { 131 _operationComboBox.addItem(e); 132 } 133 JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox); 134 135 _operationComboBox.addActionListener(e -> { 136 setGuiEnabledStates(); 137 }); 138 139 _panelOperationTypeDirect.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation"))); 140 _panelOperationTypeDirect.add(_operationComboBox); 141 142 _signalMastOperationReferenceTextField = new JTextField(); 143 _signalMastOperationReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 144 _panelOperationTypeReference.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation"))); 145 _panelOperationTypeReference.add(_signalMastOperationReferenceTextField); 146 147 _signalMastOperationLocalVariableTextField = new JTextField(); 148 _signalMastOperationLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 149 _panelOperationTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation"))); 150 _panelOperationTypeLocalVariable.add(_signalMastOperationLocalVariableTextField); 151 152 _signalMastOperationFormulaTextField = new JTextField(); 153 _signalMastOperationFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 154 _panelOperationTypeFormula.add(new JLabel(Bundle.getMessage("ActionSignalMast_Operation"))); 155 _panelOperationTypeFormula.add(_signalMastOperationFormulaTextField); 156 157 158 // Set up the tabbed pane for selecting the appearance 159 _tabbedPaneAspectType = new JTabbedPane(); 160 _panelAspectTypeDirect = new javax.swing.JPanel(); 161 _panelAspectTypeDirect.setLayout(new BoxLayout(_panelAspectTypeDirect, BoxLayout.Y_AXIS)); 162 _panelAspectTypeReference = new javax.swing.JPanel(); 163 _panelAspectTypeReference.setLayout(new BoxLayout(_panelAspectTypeReference, BoxLayout.Y_AXIS)); 164 _panelAspectTypeLocalVariable = new javax.swing.JPanel(); 165 _panelAspectTypeLocalVariable.setLayout(new BoxLayout(_panelAspectTypeLocalVariable, BoxLayout.Y_AXIS)); 166 _panelAspectTypeFormula = new javax.swing.JPanel(); 167 _panelAspectTypeFormula.setLayout(new BoxLayout(_panelAspectTypeFormula, BoxLayout.Y_AXIS)); 168 169 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Direct.toString(), _panelAspectTypeDirect); 170 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Reference.toString(), _panelAspectTypeReference); 171 _tabbedPaneAspectType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelAspectTypeLocalVariable); 172 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Formula.toString(), _panelAspectTypeFormula); 173 174 _tabbedPaneAspectType.addChangeListener((ChangeEvent e) -> { 175 setGuiEnabledStates(); 176 }); 177 178 _signalMastAspectComboBox = new JComboBox<>(); 179 _panelAspectTypeDirect.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect"))); 180 _panelAspectTypeDirect.add(_signalMastAspectComboBox); 181 182 _signalMastAspectReferenceTextField = new JTextField(); 183 _signalMastAspectReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 184 _panelAspectTypeReference.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect"))); 185 _panelAspectTypeReference.add(_signalMastAspectReferenceTextField); 186 187 _signalMastAspectLocalVariableTextField = new JTextField(); 188 _signalMastAspectLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 189 _panelAspectTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect"))); 190 _panelAspectTypeLocalVariable.add(_signalMastAspectLocalVariableTextField); 191 192 _signalMastAspectFormulaTextField = new JTextField(); 193 _signalMastAspectFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 194 _panelAspectTypeFormula.add(new JLabel(Bundle.getMessage("ActionSignalMast_Aspect"))); 195 _panelAspectTypeFormula.add(_signalMastAspectFormulaTextField); 196 197 198 JPanel notePanel = new JPanel(); 199 notePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.white)); 200 examplePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.white)); 201 202 JLabel noteLabel = new JLabel(Bundle.getMessage("SignalExampleText", 203 Bundle.getMessage("SignalExampleMast"), 204 Bundle.getMessage("SignalExampleAspects"))); 205 notePanel.add(noteLabel); 206 207 208 examplePanel.add(new JLabel(Bundle.getMessage("ActionSignalMast_ExampleBean"))); 209 examplePanel.add(innerExamplePanel); 210 211 212 if (action != null) { 213 if (action.getSelectExampleNamedBean().getNamedBean() != null) { 214 _exampleSignalMastBeanPanel.setDefaultNamedBean(action.getSelectExampleNamedBean().getNamedBean().getBean()); 215 } 216 217 switch (action.getOperationAddressing()) { 218 case Direct: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeDirect); break; 219 case Reference: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeReference); break; 220 case LocalVariable: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeLocalVariable); break; 221 case Formula: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeFormula); break; 222 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getOperationAddressing().name()); 223 } 224 _operationComboBox.setSelectedItem(action.getOperationType()); 225 _signalMastOperationReferenceTextField.setText(action.getOperationReference()); 226 _signalMastOperationLocalVariableTextField.setText(action.getOperationLocalVariable()); 227 _signalMastOperationFormulaTextField.setText(action.getOperationFormula()); 228 229 230 switch (action.getAspectAddressing()) { 231 case Direct: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeDirect); break; 232 case Reference: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeReference); break; 233 case LocalVariable: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeLocalVariable); break; 234 case Formula: _tabbedPaneAspectType.setSelectedComponent(_panelAspectTypeFormula); break; 235 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getAspectAddressing().name()); 236 } 237 _signalMastAspectReferenceTextField.setText(action.getAspectReference()); 238 _signalMastAspectLocalVariableTextField.setText(action.getAspectLocalVariable()); 239 _signalMastAspectFormulaTextField.setText(action.getAspectFormula()); 240 241 jmri.util.ThreadingUtil.runOnGUIEventually(() -> { setAspectComboBox(action); }); 242 } 243 244 JComponent[] components = new JComponent[]{ 245 _tabbedPaneNamedBean, 246 _tabbedPaneOperationType, 247 _tabbedPaneAspectType 248 }; 249 250 List<JComponent> componentList = SwingConfiguratorInterface.parseMessage( 251 Bundle.getMessage("ActionSignalMast_Components"), components); 252 253 for (JComponent c : componentList) actionPanel.add(c); 254 255 panel.add(actionPanel); 256 panel.add(notePanel); 257 panel.add(examplePanel); 258 259 setGuiEnabledStates(); 260 } 261 262 private void setGuiEnabledStates() { 263 _tabbedPaneAspectType.setEnabled(false); 264 _signalMastAspectComboBox.setEnabled(false); 265 _signalMastAspectReferenceTextField.setEnabled(false); 266 _signalMastAspectLocalVariableTextField.setEnabled(false); 267 _signalMastAspectFormulaTextField.setEnabled(false); 268 _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(false); 269 270 if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeDirect && 271 _operationComboBox.getSelectedItem() != ActionSignalMast.OperationType.Aspect) { 272 return; 273 } 274 275 _tabbedPaneAspectType.setEnabled(true); 276 277 if (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct && 278 _tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 279 _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(true); 280 } 281 282 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 283 _signalMastAspectComboBox.setEnabled(true); 284 } 285 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) { 286 _signalMastAspectReferenceTextField.setEnabled(true); 287 } 288 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) { 289 _signalMastAspectLocalVariableTextField.setEnabled(true); 290 } 291 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) { 292 _signalMastAspectFormulaTextField.setEnabled(true); 293 } 294 } 295 296 private void setAspectComboBox(ActionSignalMast action) { 297 SignalMast sm; 298 if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) { 299 sm = _selectNamedBeanSwing.getBean(); 300 } else { 301 sm = _exampleSignalMastBeanPanel.getBeanCombo().getSelectedItem(); 302 } 303 304 if (sm != null) { 305 _signalMastAspectComboBox.removeAllItems(); 306 for (String aspect : sm.getValidAspects()) { 307 _signalMastAspectComboBox.addItem(aspect); 308 if (action != null) { 309 if (aspect.equals(action.getAspect())) _signalMastAspectComboBox.setSelectedItem(aspect); 310 } 311 } 312 JComboBoxUtil.setupComboBoxMaxRows(_signalMastAspectComboBox); 313 } 314 } 315 316 317 /** {@inheritDoc} */ 318 @Override 319 public boolean validate(@Nonnull List<String> errorMessages) { 320 // Create a temporary action to test formula 321 ActionSignalMast action = new ActionSignalMast("IQDA1", null); 322 323 _selectNamedBeanSwing.validate(action.getSelectNamedBean(), errorMessages); 324 325 try { 326 if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) { 327 action.setOperationReference(_signalMastOperationReferenceTextField.getText()); 328 } 329 } catch (IllegalArgumentException e) { 330 errorMessages.add(e.getMessage()); 331 return false; 332 } 333 334 return errorMessages.isEmpty(); 335 } 336 337 /** {@inheritDoc} */ 338 @Override 339 public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) { 340 ActionSignalMast action = new ActionSignalMast(systemName, userName); 341 updateObject(action); 342 return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action); 343 } 344 345 /** {@inheritDoc} */ 346 @Override 347 public void updateObject(@Nonnull Base object) { 348 if (! (object instanceof ActionSignalMast)) { 349 throw new IllegalArgumentException("object must be an ActionSignalMast but is a: "+object.getClass().getName()); 350 } 351 ActionSignalMast action = (ActionSignalMast)object; 352 353 _selectNamedBeanSwing.updateObject(action.getSelectNamedBean()); 354 355 if (!_exampleSignalMastBeanPanel.isEmpty() 356 && (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct) 357 && (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect)) { 358 359 SignalMast signalMast = _exampleSignalMastBeanPanel.getNamedBean(); 360 if (signalMast != null) { 361 NamedBeanHandle<SignalMast> handle 362 = InstanceManager.getDefault(NamedBeanHandleManager.class) 363 .getNamedBeanHandle(signalMast.getDisplayName(), signalMast); 364 action.getSelectExampleNamedBean().setNamedBean(handle); 365 } 366 } else { 367 action.getSelectExampleNamedBean().removeNamedBean(); 368 } 369 370 try { 371 if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeDirect) { 372 action.setOperationAddressing(NamedBeanAddressing.Direct); 373 action.setOperationType((ActionSignalMast.OperationType)_operationComboBox.getSelectedItem()); 374 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) { 375 action.setOperationAddressing(NamedBeanAddressing.Reference); 376 action.setOperationReference(_signalMastOperationReferenceTextField.getText()); 377 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeLocalVariable) { 378 action.setOperationAddressing(NamedBeanAddressing.LocalVariable); 379 action.setOperationLocalVariable(_signalMastOperationLocalVariableTextField.getText()); 380 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeFormula) { 381 action.setOperationAddressing(NamedBeanAddressing.Formula); 382 action.setOperationFormula(_signalMastOperationFormulaTextField.getText()); 383 } else { 384 throw new IllegalArgumentException("_tabbedPaneOperationType has unknown selection"); 385 } 386 387 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 388 action.setAspectAddressing(NamedBeanAddressing.Direct); 389 390 if (_signalMastAspectComboBox.getItemCount() > 0) { 391 action.setAspect(_signalMastAspectComboBox 392 .getItemAt(_signalMastAspectComboBox.getSelectedIndex())); 393 } 394 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) { 395 action.setAspectAddressing(NamedBeanAddressing.Reference); 396 action.setAspectReference(_signalMastAspectReferenceTextField.getText()); 397 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) { 398 action.setAspectAddressing(NamedBeanAddressing.LocalVariable); 399 action.setAspectLocalVariable(_signalMastAspectLocalVariableTextField.getText()); 400 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) { 401 action.setAspectAddressing(NamedBeanAddressing.Formula); 402 action.setAspectFormula(_signalMastAspectFormulaTextField.getText()); 403 } else { 404 throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection"); 405 } 406 } catch (ParserException e) { 407 throw new RuntimeException("ParserException: "+e.getMessage(), e); 408 } 409 } 410 411 /** {@inheritDoc} */ 412 @Override 413 public String toString() { 414 return Bundle.getMessage("SignalMast_Short"); 415 } 416 417 @Override 418 public void dispose() { 419 } 420 421 422// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionSignalMastSwing.class); 423 424}