001package jmri.jmrix.dccpp.swing.mon; 002 003import jmri.jmrix.dccpp.DCCppListener; 004import jmri.jmrix.dccpp.DCCppMessage; 005import jmri.jmrix.dccpp.DCCppReply; 006import jmri.jmrix.dccpp.DCCppSystemConnectionMemo; 007import jmri.jmrix.dccpp.DCCppTrafficController; 008import jmri.jmrix.dccpp.serial.SerialDCCppPacketizer; 009 010import java.awt.BorderLayout; 011import java.awt.Dimension; 012import java.awt.event.ActionEvent; 013 014import javax.swing.*; 015 016/** 017 * Frame displaying (and logging) DCCpp command messages. 018 * 019 * @author Bob Jacobsen Copyright (C) 2001 020 * @author Chuck Catania Copyright (C) 2014, 2016, 2017 021 * @author mstevetodd Copyright (C) 2021 022 */ 023public class DCCppMonFrame extends jmri.jmrix.AbstractMonFrame implements DCCppListener { 024 025 // member declarations 026 final java.util.ResourceBundle rb = java.util.ResourceBundle.getBundle("jmri.jmrix.dccpp.swing.DCCppSwingBundle"); // NOI18N 027 028 private DCCppTrafficController tc = null; 029 private DCCppSystemConnectionMemo _memo = null; 030 031 private SerialDCCppPacketizer serialDCCppTC = null; 032 033 private final JPanel serialPane = new JPanel(); 034 private final JLabel queuedEntriesLabel = new JLabel("", SwingConstants.LEFT); // NOI18N 035 private final JToggleButton pauseRefreshButton = new JToggleButton(); 036 private final JButton clearRefreshQueueButton = new JButton(); 037 private final JCheckBox displayTranslatedCheckBox = new JCheckBox(Bundle.getMessage("ButtonShowTranslation")); 038 039 private final String doNotDisplayTranslatedCheck = this.getClass().getName() + ".DoNotDisplayTranslated"; // NOI18N 040 041 public DCCppMonFrame(DCCppSystemConnectionMemo memo) { 042 super(); 043 _memo = memo; 044 } 045 046 @Override 047 protected String title() { 048 return rb.getString("DCCppMonFrameTitle")+" (" + _memo.getSystemPrefix() + ")"; // NOI18N 049 } 050 051 @Override 052 protected void init() { 053 054 // connect to TrafficController 055 tc = _memo.getDCCppTrafficController(); 056 tc.addDCCppListener(~0, this); 057 058 if ((tc instanceof SerialDCCppPacketizer) && tc.getCommandStation().isFunctionRefreshRequired()) { 059 serialDCCppTC = (SerialDCCppPacketizer) tc; 060 061 pauseRefreshButton.setSelected(!serialDCCppTC.isActiveRefresh()); 062 063 refreshQueuedMessages(); 064 065 add(serialPane, BorderLayout.PAGE_END); 066 } 067 068 // Create the background function refreshing-related buttons and add 069 // them to a panel. Will be hidden if not required by command station. 070 final JLabel functionLabel = new JLabel(Bundle.getMessage("LabelFunctionRefresh"), SwingConstants.LEFT); // NOI18N 071 072 pauseRefreshButton.setText(Bundle.getMessage("ButtonPauseRefresh")); // NOI18N 073 pauseRefreshButton.setVisible(true); 074 pauseRefreshButton.setToolTipText(Bundle.getMessage("TooltipPauseRefresh")); // NOI18N 075 // the selected state of pauseRefreshButton will be set when the context 076 // is created 077 078 clearRefreshQueueButton.setText(Bundle.getMessage("ButtonClearRefreshQueue")); // NOI18N 079 clearRefreshQueueButton.setVisible(true); 080 clearRefreshQueueButton.setToolTipText(Bundle.getMessage("TooltipClearRefreshQueue")); // NOI18N 081 082 serialPane.setLayout(new BoxLayout(serialPane, BoxLayout.LINE_AXIS)); 083 serialPane.add(functionLabel); 084 serialPane.add(Box.createRigidArea(new Dimension(5, 0))); 085 serialPane.add(pauseRefreshButton); 086 serialPane.add(Box.createRigidArea(new Dimension(5, 0))); 087 serialPane.add(clearRefreshQueueButton); 088 serialPane.add(Box.createRigidArea(new Dimension(5, 0))); 089 serialPane.add(queuedEntriesLabel); 090 091 pauseRefreshButton.addActionListener((final java.awt.event.ActionEvent e) -> { 092 pauseButtonEvent(e); 093 }); 094 095 clearRefreshQueueButton.addActionListener((final java.awt.event.ActionEvent e) -> { 096 clearButtonEvent(e); 097 }); 098 099 pack(); 100 } 101 102 /** 103 * Define system-specific help item. 104 */ 105// @Override 106// protected void setHelp() { 107// addHelpMenu("package.jmri.jmrix.DCCpp.DCCpp.DCCppmon.DCCppMonFrame", true); // NOI18N 108// } 109 110 //------------------- 111 // Transmit Packets 112 //------------------- 113 @Override 114 public synchronized void message(DCCppMessage l) { 115 116 // display the decoded data 117 StringBuilder text = new StringBuilder(); 118 if ( displayTranslatedCheckBox.isSelected() ) { 119 text.append("TX: "); 120 text.append(l.toMonitorString()); 121 } 122 text.append("\n"); 123 124 nextLine(text.toString(), (rawCheckBox.isSelected() ? l.toString() : "")); 125 refreshQueuedMessages(); 126 127 } 128 129 @Override 130 public void message(DCCppReply l) { 131 // receive a DCC++ message and log it 132 // display the raw data if requested 133 if (log.isDebugEnabled()) { 134 log.debug("Message in Monitor: '{}' opcode {}", l, Character.toString(l.getOpCodeChar())); 135 } 136 137 StringBuilder text = new StringBuilder(); 138 if ( displayTranslatedCheckBox.isSelected() ) { 139 text.append(" RX: "); 140 text.append(l.toMonitorString()); 141 } 142 text.append("\n"); 143 144 nextLine( text.toString(), (rawCheckBox.isSelected() ? l.toString() : "")); 145 146 //enable or disable the refresh pane based on support by command station 147 if (l.isStatusReply()) { 148 if (tc.getCommandStation().isFunctionRefreshRequired()) { 149 serialPane.setVisible(true); 150 } else { 151 serialPane.setVisible(false); 152 } 153 } 154 155 } 156 157 @Override 158 public void notifyTimeout(DCCppMessage msg) { 159 // TODO Auto-generated method stub 160 161 } 162 163 private void clearButtonEvent(final ActionEvent e) { 164 if (serialDCCppTC != null) 165 serialDCCppTC.clearRefreshQueue(); 166 167 refreshQueuedMessages(); 168 } 169 170 private void pauseButtonEvent(final ActionEvent e) { 171 final JToggleButton source = (JToggleButton) e.getSource(); 172 173 if (serialDCCppTC != null) 174 serialDCCppTC.setActiveRefresh(!source.isSelected()); 175 } 176 177 private int previouslyQueuedMessages = -1; 178 179 public synchronized void refreshQueuedMessages() { 180 if (serialDCCppTC != null) { 181 final int currentlyQueuedMessages = serialDCCppTC.getQueueLength(); 182 183 if (currentlyQueuedMessages != previouslyQueuedMessages) { 184 queuedEntriesLabel.setText(Bundle.getMessage("LabelQueuedEntries", String.valueOf(currentlyQueuedMessages))); // NOI18N 185 186 clearRefreshQueueButton.setEnabled(currentlyQueuedMessages > 0); 187 188 previouslyQueuedMessages = currentlyQueuedMessages; 189 } 190 } 191 } 192 193 private void displayTranslatedEvent(final ActionEvent e) { 194 if ( neitherCheckBoxSelected() ) { 195 rawCheckBox.setSelected(true); 196 } 197 } 198 199 private void rawCheckBoxEvent(final ActionEvent e) { 200 if ( neitherCheckBoxSelected() ) { 201 displayTranslatedCheckBox.setSelected(true); 202 } 203 } 204 205 private boolean neitherCheckBoxSelected() { 206 return (!( displayTranslatedCheckBox.isSelected()) ) && (!(rawCheckBox.isSelected())); 207 } 208 209 @Override 210 public JPanel getCheckBoxPanel(){ 211 JPanel a = super.getCheckBoxPanel(); 212 a.add(displayTranslatedCheckBox,0); 213 displayTranslatedCheckBox.addActionListener(this::displayTranslatedEvent); 214 rawCheckBox.addActionListener(this::rawCheckBoxEvent); 215 216 displayTranslatedCheckBox.setSelected(!userPrefs.getSimplePreferenceState(doNotDisplayTranslatedCheck)); 217 rawCheckBoxEvent(null); // if neither raw on tranalated selected, display translated. 218 return a; 219 } 220 221 @Override 222 public void dispose() { 223 if ( tc != null ) { 224 tc.removeDCCppListener(~0, this); 225 } 226 if (userPrefs!=null) { 227 userPrefs.setSimplePreferenceState(doNotDisplayTranslatedCheck, !displayTranslatedCheckBox.isSelected()); 228 } 229 super.dispose(); 230 } 231 232 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DCCppMonFrame.class); 233 234}