001package jmri.jmrit.etcs.dmi.swing; 002 003import java.awt.Color; 004import java.awt.Font; 005import java.awt.event.ActionEvent; 006import java.util.*; 007 008import javax.annotation.Nonnull; 009import javax.swing.*; 010 011import jmri.InstanceManager; 012import jmri.Timebase; 013import jmri.jmrit.etcs.ResourceUtil; 014 015/** 016 * Class to demonstrate features of ERTMS DMI Panel G, 017 * Automatic Train Operation and clock. 018 * @author Steve Young Copyright (C) 2024 019 */ 020public class DmiPanelG extends JPanel { 021 022 private final DmiPanel main; 023 private final JLabel timeLabel; 024 private final JLabel g2g3g4LabelTop; 025 private final JLabel g2g3g4LabelBottom; 026 027 private final Timebase clock; 028 029 private final transient java.beans.PropertyChangeListener clockListener; 030 031 private final JButton g1Button; 032 private final JButton g2Button; 033 private final JButton g3Button; 034 private final JLabel g4Label; 035 private final JLabel g3LabelMins; 036 private final JLabel g3LabelSecs; 037 private final JButton g5Button; 038 039 public DmiPanelG(@Nonnull DmiPanel mainPanel){ 040 super(); 041 setLayout(null); 042 043 setBackground(DmiPanel.BACKGROUND_COLOUR); 044 setBounds(334, 315, 246, 150); 045 046 main = mainPanel; 047 JToggleButton g12PositionButton = new JToggleButton(); 048 049 g12PositionButton.setBounds(63,100,120,50); 050 g12PositionButton.setBorder(javax.swing.BorderFactory.createLineBorder(Color.black, 1)); 051 g12PositionButton.setBackground(DmiPanel.BACKGROUND_COLOUR); 052 053 g12PositionButton.setIcon(ResourceUtil.getImageIcon("DR_03.bmp")); 054 add(g12PositionButton); 055 056 g12PositionButton.setFocusable(false); 057 058 // position G13 059 timeLabel = new JLabel(); 060 timeLabel.setBounds(183, 100, 63, 50); 061 timeLabel.setForeground(DmiPanel.GREY); 062 timeLabel.setBackground(DmiPanel.BACKGROUND_COLOUR); 063 timeLabel.setBorder(javax.swing.BorderFactory.createLineBorder(Color.black, 1)); 064 timeLabel.setFont(new Font(DmiPanel.FONT_NAME, Font.PLAIN, 13)); 065 timeLabel.setHorizontalAlignment(SwingConstants.CENTER); 066 add(timeLabel); 067 068 clock = InstanceManager.getDefault(jmri.Timebase.class); 069 clockListener = (java.beans.PropertyChangeEvent e) -> update(); 070 clock.addMinuteChangeListener(clockListener); 071 DmiPanelG.this.update(); 072 073 g2g3g4LabelTop = new JLabel(); 074 g2g3g4LabelTop.setBounds(49,4,147,25); 075 g2g3g4LabelTop.setForeground(DmiPanel.GREY); 076 g2g3g4LabelTop.setBackground(DmiPanel.BACKGROUND_COLOUR); 077 g2g3g4LabelTop.setFont(new Font(DmiPanel.FONT_NAME, Font.PLAIN, 13)); 078 g2g3g4LabelTop.setHorizontalAlignment(SwingConstants.CENTER); 079 add(g2g3g4LabelTop); 080 081 g2g3g4LabelBottom = new JLabel(); 082 g2g3g4LabelBottom.setBounds(49,21,147,24); 083 g2g3g4LabelBottom.setForeground(DmiPanel.GREY); 084 g2g3g4LabelBottom.setBackground(DmiPanel.BACKGROUND_COLOUR); 085 g2g3g4LabelBottom.setFont(new Font(DmiPanel.FONT_NAME, Font.PLAIN, 13)); 086 g2g3g4LabelBottom.setHorizontalAlignment(SwingConstants.CENTER); 087 add(g2g3g4LabelBottom); 088 089 g1Button = new JButton(); 090 g1Button.setBorder(DmiPanel.BORDER_NORMAL); 091 g1Button.setFocusable(false); 092 g1Button.setVisible(false); 093 g1Button.setBackground(DmiPanel.BACKGROUND_COLOUR); 094 g1Button.setContentAreaFilled(false); // Make the button transparent 095 g1Button.addActionListener(this::gButtonPressed); 096 g1Button.setName("g1Button"); 097 098 g2Button = new JButton(); // stopping accuracy 099 g2Button.setBorder(DmiPanel.BORDER_NORMAL); 100 g2Button.setFocusable(false); 101 g2Button.setVisible(false); 102 g2Button.setBackground(DmiPanel.BACKGROUND_COLOUR); 103 g2Button.setContentAreaFilled(false); // Make the button transparent 104 g2Button.addActionListener(this::gButtonPressed); 105 g2Button.setName("g2Button"); 106 107 g3Button = new JButton(); 108 g3Button.setBorder(DmiPanel.BORDER_NORMAL); 109 g3Button.setFocusable(false); 110 g3Button.setVisible(false); 111 g3Button.setBackground(DmiPanel.BACKGROUND_COLOUR); 112 g3Button.setContentAreaFilled(false); // Make the button transparent 113 g3Button.addActionListener(this::gButtonPressed); 114 g3Button.setName("g3Button"); 115 116 g3LabelMins = new JLabel(); 117 g3LabelMins.setBounds(49+49,12,24,24); 118 g3LabelMins.setForeground(DmiPanel.GREY); 119 g3LabelMins.setBackground(DmiPanel.BACKGROUND_COLOUR); 120 g3LabelMins.setFont(new Font(DmiPanel.FONT_NAME, Font.PLAIN, 17)); 121 g3LabelMins.setHorizontalAlignment(SwingConstants.RIGHT); 122 add(g3LabelMins); 123 124 g3LabelSecs = new JLabel(); 125 g3LabelSecs.setBounds(49+49+24,14,24,24); 126 g3LabelSecs.setForeground(DmiPanel.GREY); 127 g3LabelSecs.setBackground(DmiPanel.BACKGROUND_COLOUR); 128 g3LabelSecs.setFont(new Font(DmiPanel.FONT_NAME, Font.PLAIN, 13)); 129 g3LabelSecs.setHorizontalAlignment(SwingConstants.LEFT); 130 add(g3LabelSecs); 131 132 g4Label = new JLabel(); 133 g4Label.setVisible(false); 134 g4Label.setBackground(DmiPanel.BACKGROUND_COLOUR); 135 136 g5Button = new JButton(); 137 g5Button.setBorder(DmiPanel.BORDER_NORMAL); 138 g5Button.setFocusable(false); 139 g5Button.setVisible(false); 140 g5Button.setBackground(DmiPanel.BACKGROUND_COLOUR); 141 g5Button.setContentAreaFilled(false); // Make the button transparent 142 g5Button.addActionListener(this::gButtonPressed); 143 g5Button.setName("g5Button"); 144 145 g1Button.setBounds(0,0,49,50); 146 g2Button.setBounds(49,0,49,50); 147 g3Button.setBounds(49+49,0,49,50); 148 g4Label.setBounds(49+49+49,0,49,50); 149 g5Button.setBounds(49+49+49+49,0,49,50); 150 151 add(g1Button); 152 add(g2Button); 153 add(g3Button); 154 add(g4Label); 155 add(g5Button); 156 } 157 158 /** 159 * Set Automatic Train Operation Mode. 160 * @param mode the new ATO Mode. 161 * 0: No ATO 162 * 1: ATO selected 163 * 2: ATO Ready for Engagement 164 * 3: ATO Engaged 165 * 4: ATO Disengaging 166 * 5: ATO failure 167 */ 168 protected void setAtoMode(int mode){ 169 switch(mode){ 170 case 1: 171 g1Button.setIcon(ResourceUtil.getImageIcon("ATO_01.bmp")); 172 g1Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_01.bmp")); 173 break; 174 case 2: 175 g1Button.setIcon(ResourceUtil.getImageIcon("ATO_02.bmp")); 176 g1Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_02.bmp")); 177 g1Button.setActionCommand(DmiPanel.PROP_CHANGE_ATO_DRIVER_REQUEST_START); 178 break; 179 case 3: 180 g1Button.setIcon(ResourceUtil.getImageIcon("ATO_03.bmp")); 181 g1Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_03.bmp")); 182 g1Button.setActionCommand(DmiPanel.PROP_CHANGE_ATO_DRIVER_REQUEST_STOP); 183 break; 184 case 4: 185 g1Button.setIcon(ResourceUtil.getImageIcon("ATO_04.bmp")); 186 g1Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_04.bmp")); 187 g1Button.setActionCommand(DmiPanel.PROP_CHANGE_ATO_DRIVER_REQUEST_STOP); 188 break; 189 case 5: 190 g1Button.setIcon(ResourceUtil.getImageIcon("ATO_05.bmp")); 191 g1Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_05.bmp")); 192 break; 193 case 0: 194 default: 195 g1Button.setIcon(null); 196 g1Button.setDisabledIcon(null); 197 } 198 g1Button.setEnabled( mode > 1 && mode < 5); 199 g1Button.setVisible(mode != 0); 200 } 201 202 /** 203 * Set Stopping accuracy symbol visible. 204 * Only valid in ATO Mode. 205 * @param acc -2: Hidden, -1: Undershot 0: Accurate 1: Overshot 206 */ 207 protected void setStoppingAccuracy(int acc){ 208 switch (acc){ 209 case -1: 210 g2Button.setIcon(ResourceUtil.getImageIcon("ATO_07.bmp")); 211 break; 212 case 0: 213 g2Button.setIcon(ResourceUtil.getImageIcon("ATO_08.bmp")); 214 break; 215 case 1: 216 g2Button.setIcon(ResourceUtil.getImageIcon("ATO_06.bmp")); 217 break; 218 case -2: 219 default: 220 221 } 222 g2Button.setVisible(acc != -2); 223 } 224 225 protected void setStoppingPointLabel(String station, String eta){ 226 g2g3g4LabelTop.setText(station); 227 g2g3g4LabelBottom.setText(eta); 228 g2g3g4LabelTop.setVisible(!station.isBlank()); 229 g2g3g4LabelBottom.setVisible(!eta.isBlank()); 230 } 231 232 protected void setDwellTime(int mins, int secs){ 233 g3LabelMins.setVisible(mins > 0); 234 g3LabelSecs.setVisible(secs > -1); 235 g3LabelMins.setText(String.valueOf(mins)); 236 g3LabelSecs.setText(( mins > 0 ? ":" : "") + ( secs < 10 ? "0": "")+ secs); 237 } 238 239 protected void setDoorIcon(int mode){ 240 switch (mode){ 241 case 10: 242 case 11: 243 case 12: 244 case 13: 245 case 14: 246 case 15: 247 case 16: 248 g4Label.setIcon(ResourceUtil.getImageIcon("ATO_"+mode+".bmp")); 249 break; 250 case 0: 251 default: 252 g4Label.setIcon(null); 253 } 254 g4Label.setVisible(mode != 0); 255 } 256 257 protected void setSkipStoppingPoint(int mode){ 258 g5Button.setEnabled(false); 259 switch (mode){ 260 case 17: 261 g5Button.setActionCommand(DmiPanel.PROP_CHANGE_SKIP_STOPPING_POINT_INACTIVE_DRIVER); 262 g5Button.setIcon(ResourceUtil.getImageIcon("ATO_17.bmp")); 263 g5Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_"+mode+".bmp")); 264 g5Button.setEnabled(true); 265 break; 266 case 18: 267 g5Button.setIcon(ResourceUtil.getImageIcon("ATO_18.bmp")); 268 g5Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_"+mode+".bmp")); 269 break; 270 case 19: 271 g5Button.setActionCommand(DmiPanel.PROP_CHANGE_SKIP_STOPPING_POINT_REQUEST_DRIVER); 272 g5Button.setIcon(ResourceUtil.getImageIcon("ATO_19.bmp")); 273 g5Button.setDisabledIcon(ResourceUtil.getImageIcon("ATO_"+mode+".bmp")); 274 g5Button.setEnabled(true); 275 break; 276 case 0: 277 default: 278 g5Button.setIcon(null); 279 g5Button.setDisabledIcon(null); 280 } 281 g5Button.setVisible(mode != 0); 282 } 283 284 private void gButtonPressed(ActionEvent e){ 285 main.firePropertyChange(e.getActionCommand(), false, true); 286 } 287 288 // todo - display seconds, add routine to TimeBase ?? 289 @SuppressWarnings("deprecation") // Date.getHours, getMinutes, getSeconds 290 public void update() { 291 Date now = clock.getTime(); 292 int hours = now.getHours(); 293 int minutes = now.getMinutes(); 294 295 String time = ( hours > 9 ? "" : "0" ) + hours + ":" + ( minutes > 9 ? "" : "0" ) + minutes; 296 timeLabel.setText(time); 297 } 298 299 public void dispose(){ 300 clock.removeMinuteChangeListener(clockListener); 301 } 302 303}