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.SignalHead; 015import jmri.SignalHeadManager; 016import jmri.jmrit.logixng.*; 017import jmri.jmrit.logixng.expressions.ExpressionSignalHead; 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 ExpressionSignalHead object with a Swing JPanel. 026 * 027 * @author Daniel Bergqvist Copyright 2021 028 */ 029public class ExpressionSignalHeadSwing extends AbstractDigitalExpressionSwing { 030 031 public static final int NUM_COLUMNS_TEXT_FIELDS = 20; 032 033 private LogixNG_SelectNamedBeanSwing<SignalHead> _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<ExpressionSignalHead.QueryType> _operationComboBox; 042 private JTextField _signalHeadQueryReferenceTextField; 043 private JTextField _signalHeadQueryLocalVariableTextField; 044 private JTextField _signalHeadQueryFormulaTextField; 045 046 private JTabbedPane _tabbedPaneAppearanceType; 047 private JPanel _panelAppearanceTypeDirect; 048 private JPanel _panelAppearanceTypeReference; 049 private JPanel _panelAppearanceTypeLocalVariable; 050 private JPanel _panelAppearanceTypeFormula; 051 052 private JComboBox<SignalHeadAppearance> _signalHeadAppearanceComboBox; 053 private JTextField _signalHeadAppearanceReferenceTextField; 054 private JTextField _signalHeadAppearanceLocalVariableTextField; 055 private JTextField _signalHeadAppearanceFormulaTextField; 056 057 private BeanSelectPanel<SignalHead> _exampleSignalHeadBeanPanel; 058 059 060 public ExpressionSignalHeadSwing() { 061 } 062 063 public ExpressionSignalHeadSwing(JDialog dialog) { 064 super.setJDialog(dialog); 065 } 066 067 @Override 068 protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) { 069 ExpressionSignalHead expression = (ExpressionSignalHead)object; 070 071 _selectNamedBeanSwing = new LogixNG_SelectNamedBeanSwing<>( 072 InstanceManager.getDefault(SignalHeadManager.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 _exampleSignalHeadBeanPanel = new BeanSelectPanel<>(InstanceManager.getDefault(SignalHeadManager.class), null); 089 innerExamplePanel.add(_exampleSignalHeadBeanPanel); 090 091 _exampleSignalHeadBeanPanel.getBeanCombo().addActionListener((java.awt.event.ActionEvent e) -> { 092 setAppearanceComboBox(null); 093 }); 094 095 096 JPanel expressionPanel = new JPanel(); 097 098 _selectNamedBeanSwing.addAddressingListener((ChangeEvent e) -> { 099 setGuiEnabledStates(); 100 }); 101 102 _selectNamedBeanSwing.getBeanSelectPanel().getBeanCombo() 103 .addActionListener((java.awt.event.ActionEvent e) -> { 104 setAppearanceComboBox(null); 105 }); 106 107 // Set up the tabbed pane for selecting the operation 108 _tabbedPaneQueryType = new JTabbedPane(); 109 _panelQueryTypeDirect = new javax.swing.JPanel(); 110 _panelQueryTypeDirect.setLayout(new BoxLayout(_panelQueryTypeDirect, BoxLayout.Y_AXIS)); 111 _panelQueryTypeReference = new javax.swing.JPanel(); 112 _panelQueryTypeReference.setLayout(new BoxLayout(_panelQueryTypeReference, BoxLayout.Y_AXIS)); 113 _panelQueryTypeLocalVariable = new javax.swing.JPanel(); 114 _panelQueryTypeLocalVariable.setLayout(new BoxLayout(_panelQueryTypeLocalVariable, BoxLayout.Y_AXIS)); 115 _panelQueryTypeFormula = new javax.swing.JPanel(); 116 _panelQueryTypeFormula.setLayout(new BoxLayout(_panelQueryTypeFormula, BoxLayout.Y_AXIS)); 117 118 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Direct.toString(), _panelQueryTypeDirect); 119 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Reference.toString(), _panelQueryTypeReference); 120 _tabbedPaneQueryType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelQueryTypeLocalVariable); 121 _tabbedPaneQueryType.addTab(NamedBeanAddressing.Formula.toString(), _panelQueryTypeFormula); 122 123 _tabbedPaneQueryType.addChangeListener((ChangeEvent e) -> { 124 setGuiEnabledStates(); 125 }); 126 127 _operationComboBox = new JComboBox<>(); 128 for (ExpressionSignalHead.QueryType e : ExpressionSignalHead.QueryType.values()) { 129 _operationComboBox.addItem(e); 130 } 131 JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox); 132 133 _operationComboBox.addActionListener(e -> { 134 setGuiEnabledStates(); 135 }); 136 137 _panelQueryTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Query"))); 138 _panelQueryTypeDirect.add(_operationComboBox); 139 140 _signalHeadQueryReferenceTextField = new JTextField(); 141 _signalHeadQueryReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 142 _panelQueryTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Query"))); 143 _panelQueryTypeReference.add(_signalHeadQueryReferenceTextField); 144 145 _signalHeadQueryLocalVariableTextField = new JTextField(); 146 _signalHeadQueryLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 147 _panelQueryTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Query"))); 148 _panelQueryTypeLocalVariable.add(_signalHeadQueryLocalVariableTextField); 149 150 _signalHeadQueryFormulaTextField = new JTextField(); 151 _signalHeadQueryFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 152 _panelQueryTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Query"))); 153 _panelQueryTypeFormula.add(_signalHeadQueryFormulaTextField); 154 155 156 // Set up the tabbed pane for selecting the appearance 157 _tabbedPaneAppearanceType = new JTabbedPane(); 158 _panelAppearanceTypeDirect = new javax.swing.JPanel(); 159 _panelAppearanceTypeDirect.setLayout(new BoxLayout(_panelAppearanceTypeDirect, BoxLayout.Y_AXIS)); 160 _panelAppearanceTypeReference = new javax.swing.JPanel(); 161 _panelAppearanceTypeReference.setLayout(new BoxLayout(_panelAppearanceTypeReference, BoxLayout.Y_AXIS)); 162 _panelAppearanceTypeLocalVariable = new javax.swing.JPanel(); 163 _panelAppearanceTypeLocalVariable.setLayout(new BoxLayout(_panelAppearanceTypeLocalVariable, BoxLayout.Y_AXIS)); 164 _panelAppearanceTypeFormula = new javax.swing.JPanel(); 165 _panelAppearanceTypeFormula.setLayout(new BoxLayout(_panelAppearanceTypeFormula, BoxLayout.Y_AXIS)); 166 167 _tabbedPaneAppearanceType.addTab(NamedBeanAddressing.Direct.toString(), _panelAppearanceTypeDirect); 168 _tabbedPaneAppearanceType.addTab(NamedBeanAddressing.Reference.toString(), _panelAppearanceTypeReference); 169 _tabbedPaneAppearanceType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelAppearanceTypeLocalVariable); 170 _tabbedPaneAppearanceType.addTab(NamedBeanAddressing.Formula.toString(), _panelAppearanceTypeFormula); 171 172 _tabbedPaneAppearanceType.addChangeListener((ChangeEvent e) -> { 173 setGuiEnabledStates(); 174 }); 175 176 _signalHeadAppearanceComboBox = new JComboBox<>(); 177 _panelAppearanceTypeDirect.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Appearance"))); 178 _panelAppearanceTypeDirect.add(_signalHeadAppearanceComboBox); 179 180 _signalHeadAppearanceReferenceTextField = new JTextField(); 181 _signalHeadAppearanceReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 182 _panelAppearanceTypeReference.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Appearance"))); 183 _panelAppearanceTypeReference.add(_signalHeadAppearanceReferenceTextField); 184 185 _signalHeadAppearanceLocalVariableTextField = new JTextField(); 186 _signalHeadAppearanceLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 187 _panelAppearanceTypeLocalVariable.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Appearance"))); 188 _panelAppearanceTypeLocalVariable.add(_signalHeadAppearanceLocalVariableTextField); 189 190 _signalHeadAppearanceFormulaTextField = new JTextField(); 191 _signalHeadAppearanceFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 192 _panelAppearanceTypeFormula.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_Appearance"))); 193 _panelAppearanceTypeFormula.add(_signalHeadAppearanceFormulaTextField); 194 195 196 JPanel notePanel = new JPanel(); 197 notePanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.white)); 198 examplePanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.white)); 199 200 JLabel noteLabel = new JLabel(Bundle.getMessage("SignalExampleText", 201 Bundle.getMessage("SignalExampleHead"), 202 Bundle.getMessage("SignalExampleAppearances"))); 203 notePanel.add(noteLabel); 204 205 206 examplePanel.add(new JLabel(Bundle.getMessage("ExpressionSignalHead_ExampleBean"))); 207 examplePanel.add(innerExamplePanel); 208 209 210 if (expression != null) { 211 if (expression.getSelectExampleNamedBean().getNamedBean() != null) { 212 _exampleSignalHeadBeanPanel.setDefaultNamedBean(expression.getSelectExampleNamedBean().getNamedBean().getBean()); 213 } 214 215 switch (expression.getQueryAddressing()) { 216 case Direct: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeDirect); break; 217 case Reference: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeReference); break; 218 case LocalVariable: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeLocalVariable); break; 219 case Formula: _tabbedPaneQueryType.setSelectedComponent(_panelQueryTypeFormula); break; 220 default: throw new IllegalArgumentException("invalid _addressing state: " + expression.getQueryAddressing().name()); 221 } 222 _operationComboBox.setSelectedItem(expression.getQueryType()); 223 _signalHeadQueryReferenceTextField.setText(expression.getQueryReference()); 224 _signalHeadQueryLocalVariableTextField.setText(expression.getQueryLocalVariable()); 225 _signalHeadQueryFormulaTextField.setText(expression.getQueryFormula()); 226 227 228 switch (expression.getAppearanceAddressing()) { 229 case Direct: _tabbedPaneAppearanceType.setSelectedComponent(_panelAppearanceTypeDirect); break; 230 case Reference: _tabbedPaneAppearanceType.setSelectedComponent(_panelAppearanceTypeReference); break; 231 case LocalVariable: _tabbedPaneAppearanceType.setSelectedComponent(_panelAppearanceTypeLocalVariable); break; 232 case Formula: _tabbedPaneAppearanceType.setSelectedComponent(_panelAppearanceTypeFormula); break; 233 default: throw new IllegalArgumentException("invalid _addressing state: " + expression.getAppearanceAddressing().name()); 234 } 235 _signalHeadAppearanceReferenceTextField.setText(expression.getAppearanceReference()); 236 _signalHeadAppearanceLocalVariableTextField.setText(expression.getAppearanceLocalVariable()); 237 _signalHeadAppearanceFormulaTextField.setText(expression.getAppearanceFormula()); 238 239 jmri.util.ThreadingUtil.runOnGUIEventually(() -> { setAppearanceComboBox(expression); }); 240 } 241 242 JComponent[] components = new JComponent[]{ 243 _tabbedPaneNamedBean, 244 _tabbedPaneQueryType, 245 _tabbedPaneAppearanceType 246 }; 247 248 List<JComponent> componentList = SwingConfiguratorInterface.parseMessage( 249 Bundle.getMessage("ExpressionSignalHead_Components"), components); 250 251 for (JComponent c : componentList) expressionPanel.add(c); 252 253 panel.add(expressionPanel); 254 panel.add(notePanel); 255 panel.add(examplePanel); 256 257 setGuiEnabledStates(); 258 } 259 260 261 private void setGuiEnabledStates() { 262 _tabbedPaneAppearanceType.setEnabled(false); 263 _signalHeadAppearanceComboBox.setEnabled(false); 264 _signalHeadAppearanceReferenceTextField.setEnabled(false); 265 _signalHeadAppearanceLocalVariableTextField.setEnabled(false); 266 _signalHeadAppearanceFormulaTextField.setEnabled(false); 267 _exampleSignalHeadBeanPanel.getBeanCombo().setEnabled(false); 268 269 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect && 270 _operationComboBox.getSelectedItem() != ExpressionSignalHead.QueryType.Appearance && 271 _operationComboBox.getSelectedItem() != ExpressionSignalHead.QueryType.NotAppearance) { 272 return; 273 } 274 275 _tabbedPaneAppearanceType.setEnabled(true); 276 277 if (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct && 278 _tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeDirect) { 279 _exampleSignalHeadBeanPanel.getBeanCombo().setEnabled(true); 280 } 281 282 if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeDirect) { 283 _signalHeadAppearanceComboBox.setEnabled(true); 284 } 285 if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeReference) { 286 _signalHeadAppearanceReferenceTextField.setEnabled(true); 287 } 288 if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeLocalVariable) { 289 _signalHeadAppearanceLocalVariableTextField.setEnabled(true); 290 } 291 if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeFormula) { 292 _signalHeadAppearanceFormulaTextField.setEnabled(true); 293 } 294 } 295 296 private void setAppearanceComboBox(ExpressionSignalHead expression) { 297 SignalHead sh; 298 if (_selectNamedBeanSwing.getAddressing() == NamedBeanAddressing.Direct) { 299 sh = _selectNamedBeanSwing.getBean(); 300 } else { 301 sh = _exampleSignalHeadBeanPanel.getBeanCombo().getSelectedItem(); 302 } 303 304 if (sh != null) { 305 _signalHeadAppearanceComboBox.removeAllItems(); 306 int[] states = sh.getValidStates(); 307 for (int s : states) { 308 SignalHeadAppearance sha = new SignalHeadAppearance(); 309 sha._state = s; 310 sha._name = sh.getAppearanceName(s); 311 _signalHeadAppearanceComboBox.addItem(sha); 312 if (expression != null) { 313 if (expression.getAppearance() == s) _signalHeadAppearanceComboBox.setSelectedItem(sha); 314 } 315 } 316 JComboBoxUtil.setupComboBoxMaxRows(_signalHeadAppearanceComboBox); 317 } 318 } 319 320 321 /** {@inheritDoc} */ 322 @Override 323 public boolean validate(@Nonnull List<String> errorMessages) { 324 // Create a temporary expression to test formula 325 ExpressionSignalHead expression = new ExpressionSignalHead("IQDE1", null); 326 327 _selectNamedBeanSwing.validate(expression.getSelectNamedBean(), errorMessages); 328 329 try { 330 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) { 331 expression.setQueryReference(_signalHeadQueryReferenceTextField.getText()); 332 } 333 } catch (IllegalArgumentException e) { 334 errorMessages.add(e.getMessage()); 335 return false; 336 } 337 338 return errorMessages.isEmpty(); 339 } 340 341 /** {@inheritDoc} */ 342 @Override 343 public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) { 344 ExpressionSignalHead expression = new ExpressionSignalHead(systemName, userName); 345 updateObject(expression); 346 return InstanceManager.getDefault(DigitalExpressionManager.class).registerExpression(expression); 347 } 348 349 /** {@inheritDoc} */ 350 @Override 351 public void updateObject(@Nonnull Base object) { 352 if (! (object instanceof ExpressionSignalHead)) { 353 throw new IllegalArgumentException("object must be an ExpressionSignalHead but is a: "+object.getClass().getName()); 354 } 355 ExpressionSignalHead expression = (ExpressionSignalHead)object; 356 357 _selectNamedBeanSwing.updateObject(expression.getSelectNamedBean()); 358 359 if (!_exampleSignalHeadBeanPanel.isEmpty() 360 && (_selectNamedBeanSwing.getAddressing() != NamedBeanAddressing.Direct) 361 && (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeDirect)) { 362 363 SignalHead signalHead = _exampleSignalHeadBeanPanel.getNamedBean(); 364 if (signalHead != null) { 365 NamedBeanHandle<SignalHead> handle 366 = InstanceManager.getDefault(NamedBeanHandleManager.class) 367 .getNamedBeanHandle(signalHead.getDisplayName(), signalHead); 368 expression.getSelectExampleNamedBean().setNamedBean(handle); 369 } 370 } else { 371 expression.getSelectExampleNamedBean().removeNamedBean(); 372 } 373 374 try { 375 if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeDirect) { 376 expression.setQueryAddressing(NamedBeanAddressing.Direct); 377 expression.setQueryType((ExpressionSignalHead.QueryType)_operationComboBox.getSelectedItem()); 378 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeReference) { 379 expression.setQueryAddressing(NamedBeanAddressing.Reference); 380 expression.setQueryReference(_signalHeadQueryReferenceTextField.getText()); 381 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeLocalVariable) { 382 expression.setQueryAddressing(NamedBeanAddressing.LocalVariable); 383 expression.setQueryLocalVariable(_signalHeadQueryLocalVariableTextField.getText()); 384 } else if (_tabbedPaneQueryType.getSelectedComponent() == _panelQueryTypeFormula) { 385 expression.setQueryAddressing(NamedBeanAddressing.Formula); 386 expression.setQueryFormula(_signalHeadQueryFormulaTextField.getText()); 387 } else { 388 throw new IllegalArgumentException("_tabbedPaneQueryType has unknown selection"); 389 } 390 391 if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeDirect) { 392 expression.setAppearanceAddressing(NamedBeanAddressing.Direct); 393 394 if (_signalHeadAppearanceComboBox.getItemCount() > 0) { 395 expression.setAppearance(_signalHeadAppearanceComboBox 396 .getItemAt(_signalHeadAppearanceComboBox.getSelectedIndex())._state); 397 } 398 } else if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeReference) { 399 expression.setAppearanceAddressing(NamedBeanAddressing.Reference); 400 expression.setAppearanceReference(_signalHeadAppearanceReferenceTextField.getText()); 401 } else if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeLocalVariable) { 402 expression.setAppearanceAddressing(NamedBeanAddressing.LocalVariable); 403 expression.setAppearanceLocalVariable(_signalHeadAppearanceLocalVariableTextField.getText()); 404 } else if (_tabbedPaneAppearanceType.getSelectedComponent() == _panelAppearanceTypeFormula) { 405 expression.setAppearanceAddressing(NamedBeanAddressing.Formula); 406 expression.setAppearanceFormula(_signalHeadAppearanceFormulaTextField.getText()); 407 } else { 408 throw new IllegalArgumentException("_tabbedPaneAppearanceType has unknown selection"); 409 } 410 } catch (ParserException e) { 411 throw new RuntimeException("ParserException: "+e.getMessage(), e); 412 } 413 } 414 415 /** {@inheritDoc} */ 416 @Override 417 public String toString() { 418 return Bundle.getMessage("SignalHead_Short"); 419 } 420 421 @Override 422 public void dispose() { 423 } 424 425 426 private static class SignalHeadAppearance { 427 428 private int _state; 429 private String _name; 430 431 @Override 432 public String toString() { 433 return _name; 434 } 435 436 } 437 438// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSignalHeadSwing.class); 439 440}