001package jmri.jmrit.logixng.expressions.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.expressions.ExpressionSignalMast; 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 ExpressionSignalMast object with a Swing JPanel. 026 * 027 * @author Daniel Bergqvist Copyright 2021 028 */ 029public class ExpressionSignalMastSwing extends AbstractDigitalExpressionSwing { 030 031 public static final int NUM_COLUMNS_TEXT_FIELDS = 20; 032 033 private LogixNG_SelectNamedBeanSwing<SignalMast> _selectNamedBeanSwing; 034 035 private JTabbedPane _tabbedPaneQueryType; 036 private JPanel _panelQueryTypeDirect; 037 private JPanel _panelQueryTypeReference; 038 private JPanel _panelQueryTypeLocalVariable; 039 private JPanel _panelQueryTypeFormula; 040 041 private JComboBox<ExpressionSignalMast.QueryType> _operationComboBox; 042 private JTextField _signalMastQueryReferenceTextField; 043 private JTextField _signalMastQueryLocalVariableTextField; 044 private JTextField _signalMastQueryFormulaTextField; 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 ExpressionSignalMastSwing() { 061 } 062 063 public ExpressionSignalMastSwing(JDialog dialog) { 064 super.setJDialog(dialog); 065 } 066 067 @Override 068 protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) { 069 ExpressionSignalMast expression = (ExpressionSignalMast)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 (expression != null) { 080 _tabbedPaneNamedBean = _selectNamedBeanSwing.createPanel(expression.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 expressionPanel = 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 // Set up the tabbed pane for selecting the operation 109 _tabbedPaneQueryType = new JTabbedPane(); 110 _panelQueryTypeDirect = new javax.swing.JPanel(); 111 _panelQueryTypeDirect.setLayout(new BoxLayout(_panelQueryTypeDirect, BoxLayout.Y_AXIS)); 112 _panelQueryTypeReference = new javax.swing.JPanel(); 113 _panelQueryTypeReference.setLayout(new BoxLayout(_panelQueryTypeReference, BoxLayout.Y_AXIS)); 114 _panelQueryTypeLocalVariable = new javax.swing.JPanel(); 115 _panelQueryTypeLocalVariable.setLayout(new BoxLayout(_panelQueryTypeLocalVariable, BoxLayout.Y_AXIS)); 116 _panelQueryTypeFormula = new javax.swing.JPanel(); 117 _panelQueryTypeFormula.setLayout(new BoxLayout(_panelQueryTypeFormula, BoxLayout.Y_AXIS)); 118 119 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Direct.toString(), _panelQueryTypeDirect); 120 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Reference.toString(), _panelQueryTypeReference); 121 _tabbedPaneQueryType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelQueryTypeLocalVariable); 122 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Formula.toString(), _panelQueryTypeFormula); 123 124 _tabbedPaneQueryType.addChangeListener((ChangeEvent e) -> { 125 setGuiEnabledStates(); 126 }); 127 128 _operationComboBox = new JComboBox<>(); 129 for (ExpressionSignalMast.QueryType e : ExpressionSignalMast.QueryType.values()) { 130 _operationComboBox.addItem(e); 131 } 132 JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox); 133 134 _operationComboBox.addActionListener(e -> { 135 setGuiEnabledStates(); 136 }); 137 138 _panelQueryTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query"))); 139 _panelQueryTypeDirect.add(_operationComboBox); 140 141 _signalMastQueryReferenceTextField = new JTextField(); 142 _signalMastQueryReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 143 _panelQueryTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query"))); 144 _panelQueryTypeReference.add(_signalMastQueryReferenceTextField); 145 146 _signalMastQueryLocalVariableTextField = new JTextField(); 147 _signalMastQueryLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 148 _panelQueryTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query"))); 149 _panelQueryTypeLocalVariable.add(_signalMastQueryLocalVariableTextField); 150 151 _signalMastQueryFormulaTextField = new JTextField(); 152 _signalMastQueryFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 153 _panelQueryTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Query"))); 154 _panelQueryTypeFormula.add(_signalMastQueryFormulaTextField); 155 156 157 // Set up the tabbed pane for selecting the aspect 158 _tabbedPaneAspectType = new JTabbedPane(); 159 _panelAspectTypeDirect = new javax.swing.JPanel(); 160 _panelAspectTypeDirect.setLayout(new BoxLayout(_panelAspectTypeDirect, BoxLayout.Y_AXIS)); 161 _panelAspectTypeReference = new javax.swing.JPanel(); 162 _panelAspectTypeReference.setLayout(new BoxLayout(_panelAspectTypeReference, BoxLayout.Y_AXIS)); 163 _panelAspectTypeLocalVariable = new javax.swing.JPanel(); 164 _panelAspectTypeLocalVariable.setLayout(new BoxLayout(_panelAspectTypeLocalVariable, BoxLayout.Y_AXIS)); 165 _panelAspectTypeFormula = new javax.swing.JPanel(); 166 _panelAspectTypeFormula.setLayout(new BoxLayout(_panelAspectTypeFormula, BoxLayout.Y_AXIS)); 167 168 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Direct.toString(), _panelAspectTypeDirect); 169 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Reference.toString(), _panelAspectTypeReference); 170 _tabbedPaneAspectType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelAspectTypeLocalVariable); 171 _tabbedPaneAspectType.addTab(NamedBeanAddressing.Formula.toString(), _panelAspectTypeFormula); 172 173 _tabbedPaneAspectType.addChangeListener((ChangeEvent e) -> { 174 setGuiEnabledStates(); 175 }); 176 177 _signalMastAspectComboBox = new JComboBox<>(); 178 _panelAspectTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect"))); 179 _panelAspectTypeDirect.add(_signalMastAspectComboBox); 180 181 _signalMastAspectReferenceTextField = new JTextField(); 182 _signalMastAspectReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 183 _panelAspectTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect"))); 184 _panelAspectTypeReference.add(_signalMastAspectReferenceTextField); 185 186 _signalMastAspectLocalVariableTextField = new JTextField(); 187 _signalMastAspectLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 188 _panelAspectTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect"))); 189 _panelAspectTypeLocalVariable.add(_signalMastAspectLocalVariableTextField); 190 191 _signalMastAspectFormulaTextField = new JTextField(); 192 _signalMastAspectFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 193 _panelAspectTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_Aspect"))); 194 _panelAspectTypeFormula.add(_signalMastAspectFormulaTextField); 195 196 197 JPanel notePanel = new JPanel(); 198 notePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.white)); 199 examplePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.white)); 200 201 JLabel noteLabel = new JLabel(Bundle.getMessage("SignalExampleText", 202 Bundle.getMessage("SignalExampleMast"), 203 Bundle.getMessage("SignalExampleAspects"))); 204 notePanel.add(noteLabel); 205 206 207 examplePanel.add(new JLabel(Bundle.getMessage("ExpressionSignalMast_ExampleBean"))); 208 examplePanel.add(innerExamplePanel); 209 210 211 if (expression != null) { 212 if (expression.getSelectExampleNamedBean().getNamedBean() != null) { 213 _exampleSignalMastBeanPanel.setDefaultNamedBean(expression.getSelectExampleNamedBean().getNamedBean().getBean()); 214 } 215 216 switch (expression.getQueryAddressing()) { 217 case Direct: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeDirect); break; 218 case Reference: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeReference); break; 219 case LocalVariable: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeLocalVariable); break; 220 case Formula: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeFormula); break; 221 default: throw new IllegalArgumentException("invalid _addressing state: " + expression.getQueryAddressing().name()); 222 } 223 _operationComboBox.setSelectedItem(expression.getQueryType()); 224 _signalMastQueryReferenceTextField.setText(expression.getQueryReference()); 225 _signalMastQueryLocalVariableTextField.setText(expression.getQueryLocalVariable()); 226 _signalMastQueryFormulaTextField.setText(expression.getQueryFormula()); 227 228 229 230 switch (expression.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: " + expression.getAspectAddressing().name()); 236 } 237 _signalMastAspectReferenceTextField.setText(expression.getAspectReference()); 238 _signalMastAspectLocalVariableTextField.setText(expression.getAspectLocalVariable()); 239 _signalMastAspectFormulaTextField.setText(expression.getAspectFormula()); 240 241 jmri.util.ThreadingUtil.runOnGUIEventually(() -> { setAspectComboBox(expression); }); 242 } 243 244 JComponent[] components = new JComponent[]{ 245 _tabbedPaneNamedBean, 246 _tabbedPaneQueryType, 247 _tabbedPaneAspectType 248 }; 249 250 List<JComponent> componentList = SwingConfiguratorInterface.parseMessage( 251 Bundle.getMessage("ExpressionSignalMast_Components"), components); 252 253 for (JComponent c : componentList) expressionPanel.add(c); 254 255 panel.add(expressionPanel); 256 panel.add(notePanel); 257 panel.add(examplePanel); 258 259 setGuiEnabledStates(); 260 } 261 262 263 private void setGuiEnabledStates() { 264 _tabbedPaneAspectType.setEnabled(false); 265 _signalMastAspectComboBox.setEnabled(false); 266 _signalMastAspectReferenceTextField.setEnabled(false); 267 _signalMastAspectLocalVariableTextField.setEnabled(false); 268 _signalMastAspectFormulaTextField.setEnabled(false); 269 _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(false); 270 271 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect && 272 _operationComboBox.getSelectedItem() != ExpressionSignalMast.QueryType.Aspect && 273 _operationComboBox.getSelectedItem() != ExpressionSignalMast.QueryType.NotAspect) { 274 return; 275 } 276 277 _tabbedPaneAspectType.setEnabled(true); 278 279 if (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct && 280 _tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 281 _exampleSignalMastBeanPanel.getBeanCombo().setEnabled(true); 282 } 283 284 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 285 _signalMastAspectComboBox.setEnabled(true); 286 } 287 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) { 288 _signalMastAspectReferenceTextField.setEnabled(true); 289 } 290 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) { 291 _signalMastAspectLocalVariableTextField.setEnabled(true); 292 } 293 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) { 294 _signalMastAspectFormulaTextField.setEnabled(true); 295 } 296 } 297 298 private void setAspectComboBox(ExpressionSignalMast expression) { 299 SignalMast sm; 300 if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) { 301 sm = _selectNamedBeanSwing.getBean(); 302 } else { 303 sm = _exampleSignalMastBeanPanel.getBeanCombo().getSelectedItem(); 304 } 305 306 if (sm != null) { 307 _signalMastAspectComboBox.removeAllItems(); 308 for (String aspect : sm.getValidAspects()) { 309 _signalMastAspectComboBox.addItem(aspect); 310 if (expression != null) { 311 if (aspect.equals(expression.getAspect())) _signalMastAspectComboBox.setSelectedItem(aspect); 312 } 313 } 314 JComboBoxUtil.setupComboBoxMaxRows(_signalMastAspectComboBox); 315 } 316 } 317 318 319 /** {@inheritDoc} */ 320 @Override 321 public boolean validate(@Nonnull List<String> errorMessages) { 322 // Create a temporary expression to test formula 323 ExpressionSignalMast expression = new ExpressionSignalMast("IQDE1", null); 324 325 _selectNamedBeanSwing.validate(expression.getSelectNamedBean(), errorMessages); 326 327 try { 328 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) { 329 expression.setQueryReference(_signalMastQueryReferenceTextField.getText()); 330 } 331 } catch (IllegalArgumentException e) { 332 errorMessages.add(e.getMessage()); 333 return false; 334 } 335 336 return errorMessages.isEmpty(); 337 } 338 339 /** {@inheritDoc} */ 340 @Override 341 public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) { 342 ExpressionSignalMast expression = new ExpressionSignalMast(systemName, userName); 343 updateObject(expression); 344 return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(expression); 345 } 346 347 /** {@inheritDoc} */ 348 @Override 349 public void updateObject(@Nonnull Base object) { 350 if (! (object instanceof ExpressionSignalMast)) { 351 throw new IllegalArgumentException("object must be an ExpressionSignalMast but is a: "+object.getClass().getName()); 352 } 353 ExpressionSignalMast expression = (ExpressionSignalMast)object; 354 355 _selectNamedBeanSwing.updateObject(expression.getSelectNamedBean()); 356 357 if (!_exampleSignalMastBeanPanel.isEmpty() 358 && (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct) 359 && (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect)) { 360 361 SignalMast signalMast = _exampleSignalMastBeanPanel.getNamedBean(); 362 if (signalMast != null) { 363 NamedBeanHandle<SignalMast> handle 364 = InstanceManager.getDefault(NamedBeanHandleManager.class) 365 .getNamedBeanHandle(signalMast.getDisplayName(), signalMast); 366 expression.getSelectExampleNamedBean().setNamedBean(handle); 367 } 368 } else { 369 expression.getSelectExampleNamedBean().removeNamedBean(); 370 } 371 372 try { 373 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect) { 374 expression.setQueryAddressing(NamedBeanAddressing.Direct); 375 expression.setQueryType((ExpressionSignalMast.QueryType)_operationComboBox.getSelectedItem()); 376 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) { 377 expression.setQueryAddressing(NamedBeanAddressing.Reference); 378 expression.setQueryReference(_signalMastQueryReferenceTextField.getText()); 379 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeLocalVariable) { 380 expression.setQueryAddressing(NamedBeanAddressing.LocalVariable); 381 expression.setQueryLocalVariable(_signalMastQueryLocalVariableTextField.getText()); 382 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeFormula) { 383 expression.setQueryAddressing(NamedBeanAddressing.Formula); 384 expression.setQueryFormula(_signalMastQueryFormulaTextField.getText()); 385 } else { 386 throw new IllegalArgumentException("_tabbedPaneQueryType has unknown selection"); 387 } 388 389 if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeDirect) { 390 expression.setAspectAddressing(NamedBeanAddressing.Direct); 391 392 if (_signalMastAspectComboBox.getItemCount() > 0) { 393 expression.setAspect(_signalMastAspectComboBox 394 .getItemAt(_signalMastAspectComboBox.getSelectedIndex())); 395 } 396 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeReference) { 397 expression.setAspectAddressing(NamedBeanAddressing.Reference); 398 expression.setAspectReference(_signalMastAspectReferenceTextField.getText()); 399 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeLocalVariable) { 400 expression.setAspectAddressing(NamedBeanAddressing.LocalVariable); 401 expression.setAspectLocalVariable(_signalMastAspectLocalVariableTextField.getText()); 402 } else if (_tabbedPaneAspectType.getSelectedComponent() == _panelAspectTypeFormula) { 403 expression.setAspectAddressing(NamedBeanAddressing.Formula); 404 expression.setAspectFormula(_signalMastAspectFormulaTextField.getText()); 405 } else { 406 throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection"); 407 } 408 } catch (ParserException e) { 409 throw new RuntimeException("ParserException: "+e.getMessage(), e); 410 } 411 } 412 413 /** {@inheritDoc} */ 414 @Override 415 public String toString() { 416 return Bundle.getMessage("SignalMast_Short"); 417 } 418 419 @Override 420 public void dispose() { 421 } 422 423 424// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSignalMastSwing.class); 425 426}