001package jmri.jmrix.dccpp.swing.virtuallcd; 002 003import java.awt.*; 004import java.util.*; 005 006import static jmri.jmrit.display.Editor.ICONS; 007 008import java.util.List; 009 010import javax.annotation.CheckForNull; 011import javax.swing.*; 012 013import jmri.jmrit.display.*; 014import jmri.jmrit.display.PositionableFactory.DoAfter; 015import jmri.jmrix.dccpp.*; 016import jmri.jmrix.dccpp.swing.virtuallcd.VirtualLCDConfiguration.DisplayConfig; 017import jmri.util.JmriJFrame; 018import jmri.util.swing.JmriJOptionPane; 019 020/** 021 * Configure a VirtualLCD display. 022 * 023 * @author Daniel Bergqvist (C) 2026 024 */ 025public class ConfigureVirtualLCD extends JmriJFrame { 026 027 private static ConfigureVirtualLCD editPositionableFrame; 028 029 private final Editor editor; 030 private final VirtualLCDConfiguration virtualLCDConfiguration; 031 private final DoAfter doAfter; 032 private final Map<DCCppSystemConnectionMemo, Integer> highestDisplayNoMap = new HashMap<>(); 033 034 private final JComboBox<DCCppConnection> _memoComboBox = new JComboBox<>(); 035 private final JTextField _numColumnsTextField = new JTextField(); 036 private final JTextField _numRowsTextField = new JTextField(); 037 private final JComboBox<DisplayConfig> displayConfigComboBox = new JComboBox<>(); 038 private final JPanel selectedDisplays = new JPanel(); 039 private final JComboBox<Integer> displayNoComboBox = new JComboBox<>(); 040 private final JComboBox<Integer> minDisplayNoComboBox = new JComboBox<>(); 041 private final JComboBox<Integer> maxDisplayNoComboBox = new JComboBox<>(); 042 private final Map<Integer, JCheckBox> selectDisplayNoCheckBox = new HashMap<>(); 043 044 public static void createConfigureVirtualLCD(Editor editor, DoAfter doAfter) { 045 editPositionableFrame = new ConfigureVirtualLCD(editor, null, doAfter); 046 editPositionableFrame.initComponents(); 047 } 048 049 public static void editConfigureVirtualLCD( 050 Editor editor, VirtualLCDConfiguration virtualLCDConfiguration) { 051 052 closeDialog(null); 053 054 editPositionableFrame = new ConfigureVirtualLCD( 055 editor, virtualLCDConfiguration, null); 056 editPositionableFrame.initComponents(); 057 } 058 059 private static void closeDialog(@CheckForNull Editor editor) { 060 if (editPositionableFrame != null) { 061 editPositionableFrame.setVisible(false); 062 editPositionableFrame.dispose(); 063 064 if (editor != null) { 065 editor.setVisible(true); 066 } 067 } 068 } 069 070 private ConfigureVirtualLCD( 071 Editor editor, 072 VirtualLCDConfiguration virtualLCDConfiguration, 073 DoAfter doAfter) { 074 075 super(Bundle.getMessage("AddVirtualLcdPositionable"), false, false); 076 this.editor = editor; 077 this.virtualLCDConfiguration = virtualLCDConfiguration; 078 this.doAfter = doAfter; 079 } 080 081 @Override 082 public void initComponents() { 083 addHelpMenu("package.jmri.jmrix.dccpp.swing.virtuallcd.VirtualLcdPositionableFactory", true); 084 setLocation(50, 30); 085 Container contentPane = getContentPane(); 086 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 087 088 List<DCCppSystemConnectionMemo> systemConnections = 089 jmri.InstanceManager.getList(DCCppSystemConnectionMemo.class); 090 for (DCCppSystemConnectionMemo connection : systemConnections) { 091 DCCppConnection c = new DCCppConnection(connection); 092 _memoComboBox.addItem(c); 093 if (virtualLCDConfiguration != null && connection == virtualLCDConfiguration.getMemo()) { 094 _memoComboBox.setSelectedItem(c); 095 } 096 } 097 if (_memoComboBox.getSelectedIndex() == -1) { 098 _memoComboBox.setSelectedIndex(0); 099 } 100 _memoComboBox.setToolTipText(Bundle.getMessage("ConnectionHint")); 101 102 JLabel memoLabel = new JLabel(Bundle.getMessage("Connection")); 103 JLabel displayNoLabel = new JLabel(Bundle.getMessage("DisplayNo")); 104 105 JPanel p = new JPanel(); 106 p.setLayout(new java.awt.GridBagLayout()); 107 java.awt.GridBagConstraints c = new java.awt.GridBagConstraints(); 108 c.gridwidth = 1; 109 c.gridheight = 1; 110 c.gridx = 0; 111 c.gridy = 0; 112 c.anchor = java.awt.GridBagConstraints.EAST; 113 if (virtualLCDConfiguration == null 114 || virtualLCDConfiguration.isMemoEditable()) { 115 p.add(memoLabel, c); 116 memoLabel.setLabelFor(_memoComboBox); 117 } 118 c.gridy = 1; 119 p.add(new JLabel(Bundle.getMessage("ConfigureVirtualLCD_NumColumns")), c); 120 displayNoLabel.setLabelFor(_numColumnsTextField); 121 c.gridy = 2; 122 p.add(new JLabel(Bundle.getMessage("ConfigureVirtualLCD_NumRows")), c); 123 displayNoLabel.setLabelFor(_numRowsTextField); 124 c.gridy = 3; 125 c.gridwidth = 2; 126 c.anchor = java.awt.GridBagConstraints.WEST; 127 p.add(new JLabel(Bundle.getMessage("ConfigureVirtualLCD_ColumsRowsHelp")), c); 128 displayNoLabel.setLabelFor(displayNoComboBox); 129 c.gridwidth = 1; 130 c.gridy = 4; 131 p.add(Box.createVerticalStrut(8), c); 132 c.gridy = 5; 133 c.anchor = java.awt.GridBagConstraints.EAST; 134 p.add(displayNoLabel, c); 135 displayNoLabel.setLabelFor(displayNoComboBox); 136 c.gridx = 1; 137 c.gridy = 0; 138 c.anchor = java.awt.GridBagConstraints.WEST; 139 c.weightx = 1.0; 140 c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand 141 if (virtualLCDConfiguration == null 142 || virtualLCDConfiguration.isMemoEditable()) { 143 p.add(_memoComboBox, c); 144 } 145 c.gridy = 1; 146 c.fill = java.awt.GridBagConstraints.NONE; // text field will expand 147 _numColumnsTextField.setColumns(5); 148 p.add(_numColumnsTextField, c); 149 c.gridy = 2; 150 _numRowsTextField.setColumns(5); 151 p.add(_numRowsTextField, c); 152 c.gridy = 5; 153 c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand 154 for (DisplayConfig dc : DisplayConfig.values()) { 155 displayConfigComboBox.addItem(dc); 156 if (virtualLCDConfiguration != null 157 && dc == virtualLCDConfiguration.getDisplayConfig()) { 158 displayConfigComboBox.setSelectedItem(dc); 159 } 160 } 161 p.add(displayConfigComboBox, c); 162 c.gridx = 2; 163 c.gridy = 1; 164 c.anchor = java.awt.GridBagConstraints.WEST; 165 c.weightx = 1.0; 166 c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand 167 c.gridy = 0; 168// displayNoTextField.setToolTipText(Bundle.getMessage("DisplayNoHint")); 169 170 171 JPanel allDisplays = new JPanel(); 172 allDisplays.add(new JLabel(Bundle.getMessage("ConfigureVirtualLCD_AllDisplays"))); 173 174 JPanel oneDisplay = new JPanel(); 175 oneDisplay.add(new JLabel(Bundle.getMessage("DisplayNo"))); 176 oneDisplay.add(displayNoComboBox); 177 178 JPanel intervalDisplays = new JPanel(); 179 intervalDisplays.add(new JLabel(Bundle.getMessage("DisplayNo"))); 180 intervalDisplays.add(minDisplayNoComboBox); 181 intervalDisplays.add(new JLabel(" - ")); 182 intervalDisplays.add(maxDisplayNoComboBox); 183 184 selectedDisplays.setLayout(new BoxLayout(selectedDisplays, BoxLayout.Y_AXIS)); 185 186 JPanel cards; // A panel that uses CardLayout 187 CardLayout cardLayout = new CardLayout(); 188 cards = new JPanel(cardLayout); // Create the panel that contains the "cards". 189 cards.setBorder(BorderFactory.createLineBorder(Color.black)); 190 cards.add(allDisplays, DisplayConfig.ConfigureVirtualLCD_AllDisplays.name()); 191 cards.add(oneDisplay, DisplayConfig.ConfigureVirtualLCD_OneDisplay.name()); 192 cards.add(intervalDisplays, DisplayConfig.ConfigureVirtualLCD_IntervalDisplay.name()); 193 cards.add(selectedDisplays, DisplayConfig.ConfigureVirtualLCD_SelectedDisplays.name()); 194 195 displayConfigComboBox.addItemListener(evt -> { 196 cardLayout.show(cards, ((DisplayConfig) evt.getItem()).name()); 197 }); 198 199 c.gridwidth = 2; 200 c.gridheight = 1; 201 c.gridx = 0; 202 c.gridy = 6; 203 c.anchor = java.awt.GridBagConstraints.EAST; 204 p.add(cards, c); 205 206 c.gridy = 7; 207 p.add(new JLabel(Bundle.getMessage("VirtualLcdPositionable_DialogTakesTime")), c); 208 209 contentPane.add(p); 210 211 // set up create and cancel buttons 212 JPanel panel5 = new JPanel(); 213 panel5.setLayout(new FlowLayout()); 214 // Cancel 215 JButton cancel = new JButton(Bundle.getMessage("ButtonCancel")); 216 panel5.add(cancel); 217 cancel.addActionListener((e) -> closeDialog(editor)); 218 cancel.setToolTipText(Bundle.getMessage("CancelButtonHint")); 219 220 if (virtualLCDConfiguration != null) { // Edit configuration 221 222 Dimension lcdSize = virtualLCDConfiguration.getLCDSize(); 223 if (lcdSize != null) { 224 _numColumnsTextField.setText(Integer.toString(lcdSize.width)); 225 _numRowsTextField.setText(Integer.toString(lcdSize.height)); 226 } 227 228 cardLayout.show(cards, virtualLCDConfiguration.getDisplayConfig().name()); 229 230 JButton ok = new JButton(Bundle.getMessage("ButtonOK")); 231 panel5.add(ok); 232 ok.addActionListener((e) -> { 233 var memo = _memoComboBox.getItemAt(_memoComboBox.getSelectedIndex())._memo; 234 try { 235 updateVirtualLCD(memo); 236 closeDialog(editor); 237 } catch (NumberFormatException ex) { 238 JmriJOptionPane.showMessageDialog( 239 editor, 240 Bundle.getMessage("ErrorDisplayNoMustBeInteger"), 241 Bundle.getMessage("ErrorTitle"), 242 JmriJOptionPane.ERROR_MESSAGE); 243 } 244 }); 245 ok.setToolTipText(Bundle.getMessage("CreateButtonHint")); 246 247 } else { // Create new VirtualLCD icon on a panel 248 249 JButton create = new JButton(Bundle.getMessage("ButtonCreate")); 250 panel5.add(create); 251 create.addActionListener((e) -> { 252 var memo = _memoComboBox.getItemAt(_memoComboBox.getSelectedIndex())._memo; 253 try { 254 addVirtualLCD(memo); 255 closeDialog(editor); 256 } catch (NumberFormatException ex) { 257 JmriJOptionPane.showMessageDialog( 258 editor, 259 Bundle.getMessage("ErrorDisplayNoMustBeInteger"), 260 Bundle.getMessage("ErrorTitle"), 261 JmriJOptionPane.ERROR_MESSAGE); 262 } 263 }); 264 create.setToolTipText(Bundle.getMessage("CreateButtonHint")); 265 } 266 267 addWindowListener(new java.awt.event.WindowAdapter() { 268 @Override 269 public void windowClosing(java.awt.event.WindowEvent e) { 270 closeDialog(editor); 271 } 272 }); 273 274 contentPane.add(panel5); 275 276 // Add listeners for each memo 277 for (DCCppSystemConnectionMemo memo : systemConnections) { 278 memo.getDCCppTrafficController().addDCCppListener(DCCppInterface.CS_INFO, new DCCppListener(){ 279 @Override 280 public void message(DCCppReply msg) { 281 if (msg.isLCDTextReply()) { // <@ display# line# "message text"> 282 int displayNumber = msg.getLCDDisplayNumInt(); 283 int highestDisplayNo = highestDisplayNoMap.getOrDefault(memo,0); 284 if (displayNumber > highestDisplayNo) { 285 highestDisplayNoMap.put(memo, displayNumber); 286 if (memo == _memoComboBox.getItemAt(_memoComboBox.getSelectedIndex())._memo) { 287 configureDisplaySelection(memo); 288 } 289// System.out.format("Higest display: %s:%d%n", memo.getUserName(), displayNumber); 290 } 291 } 292 } 293 294 @Override 295 public void message(DCCppMessage msg) { 296 } 297 298 @Override 299 public void notifyTimeout(DCCppMessage msg) { 300 } 301 }); 302 } 303 304 pack(); 305 setVisible(true); 306 } 307 308 private void configureDisplaySelection(DCCppSystemConnectionMemo memo) { 309 selectedDisplays.removeAll(); 310 displayNoComboBox.removeAllItems(); 311 minDisplayNoComboBox.removeAllItems(); 312 maxDisplayNoComboBox.removeAllItems(); 313 for (int i=0; i <= highestDisplayNoMap.getOrDefault(memo,0); i++) { 314 displayNoComboBox.addItem(i); 315 if (virtualLCDConfiguration != null 316 && i == virtualLCDConfiguration.getDisplayNo()) { 317 displayNoComboBox.setSelectedItem(i); 318 } 319 320 minDisplayNoComboBox.addItem(i); 321 if (virtualLCDConfiguration != null 322 && i == virtualLCDConfiguration.getMinDisplayNo()) { 323 minDisplayNoComboBox.setSelectedItem(i); 324 } 325 326 maxDisplayNoComboBox.addItem(i); 327 if (virtualLCDConfiguration != null 328 && i == virtualLCDConfiguration.getMaxDisplayNo()) { 329 maxDisplayNoComboBox.setSelectedItem(i); 330 } 331 332 JCheckBox cb = new JCheckBox(Bundle.getMessage("ConfigureVirtualLCD_SelectedDisplays_CheckBox", i)); 333 if (virtualLCDConfiguration != null 334 && virtualLCDConfiguration.getSelectedDisplays().contains(i)) { 335 cb.setSelected(true); 336 } 337 selectDisplayNoCheckBox.put(i, cb); 338 selectedDisplays.add(cb); 339 } 340 this.pack(); 341 } 342 343 private void addVirtualLCD(DCCppSystemConnectionMemo memo) { 344 345 VirtualLcdPositionable virtLcdPositionable = new VirtualLcdPositionable(editor); 346 updateVirtualLCD(memo, virtLcdPositionable.getVirtualLCDPanel()); 347 virtLcdPositionable.initComponents(); 348 virtLcdPositionable.setDisplayLevel(ICONS); 349 editor.setNextLocation(virtLcdPositionable); 350 try { 351 editor.putItem(virtLcdPositionable, true); 352 } catch (Positionable.DuplicateIdException e) { 353 // This should never happen 354 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 355 } 356 if (doAfter != null) { 357 doAfter.doAfter(virtLcdPositionable); 358 } 359 } 360 361 private void updateVirtualLCD(DCCppSystemConnectionMemo memo) { 362 updateVirtualLCD(memo, virtualLCDConfiguration); 363 } 364 365 private void updateVirtualLCD(DCCppSystemConnectionMemo memo, VirtualLCDConfiguration virtLCDConfig) { 366 virtLCDConfig.setMemo(memo); 367 if (!_numColumnsTextField.getText().isBlank() && !_numRowsTextField.getText().isBlank()) { 368 virtLCDConfig.setLCDSize(new Dimension( 369 Integer.parseInt(_numColumnsTextField.getText()), 370 Integer.parseInt(_numRowsTextField.getText()))); 371 } else { 372 virtLCDConfig.setLCDSize(null); 373 } 374 virtLCDConfig.setDisplayConfig(displayConfigComboBox.getItemAt(displayConfigComboBox.getSelectedIndex())); 375 if (displayNoComboBox.getSelectedIndex() >= 0) { 376 virtLCDConfig.setDisplayNo(displayNoComboBox.getItemAt(displayNoComboBox.getSelectedIndex())); 377 } 378 if (minDisplayNoComboBox.getSelectedIndex() >= 0) { 379 virtLCDConfig.setMinDisplayNo(minDisplayNoComboBox.getItemAt(minDisplayNoComboBox.getSelectedIndex())); 380 } 381 if (maxDisplayNoComboBox.getSelectedIndex() >= 0) { 382 virtLCDConfig.setMaxDisplayNo(maxDisplayNoComboBox.getItemAt(maxDisplayNoComboBox.getSelectedIndex())); 383 } 384 Set<Integer> selectedDisplaysSet = new HashSet<>(); 385 for (var entry : selectDisplayNoCheckBox.entrySet()) { 386 if (entry.getValue().isSelected()) { 387 selectedDisplaysSet.add(entry.getKey()); 388 } 389 } 390 virtLCDConfig.setSelectedDisplays(selectedDisplaysSet); 391 } 392 393 394 private static class DCCppConnection { 395 396 private DCCppSystemConnectionMemo _memo; 397 398 public DCCppConnection(DCCppSystemConnectionMemo memo) { 399 _memo = memo; 400 } 401 402 @Override 403 public String toString() { 404 return _memo.getUserName(); 405 } 406 } 407 408 409 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConfigureVirtualLCD.class); 410}