001package jmri.jmrix.can.cbus.swing.console; 002 003import java.awt.Color; 004import java.awt.Desktop; 005import java.io.File; 006import java.io.FileNotFoundException; 007import java.io.FileOutputStream; 008import java.io.IOException; 009import java.io.PrintStream; 010import javax.swing.*; 011import jmri.util.FileUtil; 012import jmri.util.swing.JmriJOptionPane; 013 014/** 015 * Pane for CBUS Console Logging to File Options 016 * 017 * @author Andrew Crosland Copyright (C) 2008 018 * @author Steve Young Copyright (C) 2018 019 */ 020public class CbusConsoleLoggingPane extends javax.swing.JPanel { 021 022 private final CbusConsolePane _mainPane; 023 private final JFileChooser logFileChooser; 024 private final JToggleButton startStopLogButton; 025 private final JButton openLogFileButton; 026 private final JButton openFileChooserButton; 027 private final JTextField entryField; 028 private final JButton logenterButton; 029 private static final String IS_LOGGING_TO_FILE = ".isLoggingToFile."; 030 031 // @SuppressFBWarnings(value = "IS2_INCONSISTENT_SYNC", justification = "separately interlocked") 032 private transient PrintStream logStream; 033 034 public CbusConsoleLoggingPane(CbusConsolePane mainPane){ 035 super(); 036 _mainPane = mainPane; 037 // set file chooser to a default 038 logFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath()); 039 logFileChooser.setSelectedFile(new File(FileUtil.getUserFilesPath() 040 + _mainPane.getMemo().getUserName() + "_monitorLog.txt")); 041 042 startStopLogButton = new JToggleButton(); 043 openLogFileButton = new JButton(); 044 openFileChooserButton = new JButton(); 045 entryField = new JTextField(); 046 logenterButton = new JButton(); 047 setupPane(); 048 049 } 050 051 private void setupPane() { 052 053 setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 054 setBorder(BorderFactory.createTitledBorder( 055 BorderFactory.createEtchedBorder(), Bundle.getMessage("Logging"))); 056 057 setButtonToolTips(); 058 059 add(startStopLogButton); 060 add(openFileChooserButton); 061 add(openLogFileButton); 062 add(logenterButton); 063 add(entryField); 064 065 addListeners(); 066 067 var p = jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class); 068 if (p.getSimplePreferenceState(logToFilePreferenceString())) { 069 startStopLogButton.setSelected(true); 070 updateStartStopButtonText(); 071 startLogButtonActionPerformed(null); 072 } 073 074 } 075 076 private void setSelectFileToolTip() { 077 078 openFileChooserButton.setToolTipText(logFileChooser.getSelectedFile().getPath()); 079 080 081 } 082 083 private void addListeners() { 084 085 startStopLogButton.addActionListener((java.awt.event.ActionEvent e) -> { 086 087 openFileChooserButton.setEnabled(!startStopLogButton.isSelected()); 088 089 if (startStopLogButton.isSelected()){ 090 startLogButtonActionPerformed(e); 091 } 092 else { 093 stopLogButtonActionPerformed(e); 094 } 095 096 updateStartStopButtonText(); 097 098 }); 099 100 openFileChooserButton.addActionListener(this::openFileChooserButtonActionPerformed); 101 102 openLogFileButton.addActionListener((java.awt.event.ActionEvent e) -> { 103 try { 104 openLogFileActionPerformed(e); 105 } catch (IOException ex) { 106 log.error("log file open exception", ex); 107 } 108 }); 109 110 logenterButton.addActionListener(this::textToLogButtonActionPerformed); 111 entryField.addActionListener(this::textToLogButtonActionPerformed); 112 113 updateStartStopButtonText(); 114 115 } 116 117 private void setButtonToolTips() { 118 119 logenterButton.setText(Bundle.getMessage("ButtonAddMessage")); 120 logenterButton.setToolTipText(Bundle.getMessage("TooltipAddMessage")); 121 122 openFileChooserButton.setText(Bundle.getMessage("ButtonChooseLogFile")); 123 setSelectFileToolTip(); 124 125 openLogFileButton.setText(Bundle.getMessage("OpenLogFile")); 126 openLogFileButton.setToolTipText(Bundle.getMessage("OpenLogFileTip")); 127 128 entryField.setToolTipText(Bundle.getMessage("EntryAddtoLogTip")); 129 130 } 131 132 private void updateStartStopButtonText(){ 133 134 if (startStopLogButton.isSelected()){ 135 136 startStopLogButton.setText(Bundle.getMessage("ButtonStopLogging")); 137 startStopLogButton.setToolTipText(Bundle.getMessage("TooltipStopLogging")); 138 startStopLogButton.setForeground(Color.red); 139 140 } 141 else { 142 143 startStopLogButton.setText(Bundle.getMessage("ButtonStartLogging")); 144 startStopLogButton.setToolTipText(Bundle.getMessage("TooltipStartLogging") + " " + 145 Bundle.getMessage("ButtonStartLogTipExtra")); 146 startStopLogButton.setForeground(new JToggleButton().getForeground()); 147 148 } 149 150 } 151 152 private void startLogButtonActionPerformed(java.awt.event.ActionEvent e) { 153 // start logging by creating the stream 154 if (logStream == null) { // successive clicks don't restart the file 155 // start logging 156 try { 157 logStream = new PrintStream(new FileOutputStream(logFileChooser.getSelectedFile())); 158 } catch (FileNotFoundException ex) { 159 log.error("exception", ex); 160 } 161 } 162 } 163 164 private void stopLogButtonActionPerformed(java.awt.event.ActionEvent e) { 165 // stop logging by removing the stream 166 if (logStream != null) { 167 logStream.flush(); 168 logStream.close(); 169 } 170 logStream = null; 171 } 172 173 private void openFileChooserButtonActionPerformed(java.awt.event.ActionEvent e) { 174 // start at current file, show dialog 175 int retVal = logFileChooser.showSaveDialog(this); 176 177 // handle selection or cancel 178 if (retVal == JFileChooser.APPROVE_OPTION) { 179 boolean loggingNow = (logStream != null); 180 stopLogButtonActionPerformed(e); // stop before changing file 181 //File file = logFileChooser.getSelectedFile(); 182 // if we were currently logging, start the new file 183 if (loggingNow) { 184 startLogButtonActionPerformed(e); 185 } 186 } 187 setSelectFileToolTip(); 188 } 189 190 private void openLogFileActionPerformed(java.awt.event.ActionEvent e) throws IOException { 191 // start at current file, show dialog 192 Desktop desktop = Desktop.getDesktop(); 193 File dirToOpen; 194 195 try { 196 dirToOpen = logFileChooser.getSelectedFile(); 197 desktop.open(dirToOpen); 198 } catch (IllegalArgumentException iae) { 199 JmriJOptionPane.showMessageDialog(_mainPane, 200 (Bundle.getMessage("NoOpenLogFile")), Bundle.getMessage("WarningTitle"), 201 JmriJOptionPane.ERROR_MESSAGE); 202 } 203 204 } 205 206 private void textToLogButtonActionPerformed(java.awt.event.ActionEvent e) { 207 _mainPane.nextLine(entryField.getText() + "\n", entryField.getText() + "\n", -1); 208 } 209 210 private final String newline = System.getProperty("line.separator"); 211 212 protected void sendLogToFile( String sbCbus ){ 213 if (logStream != null) { 214 String logLine = sbCbus; 215 if (!newline.equals("\n")) { 216 // have to massage the line-ends 217 StringBuilder out = new StringBuilder(sbCbus.length() + 10); // arbitrary guess at space 218 for (int j = 0; j < sbCbus.length(); j++) { 219 if (sbCbus.charAt(j) == '\n') { 220 out.append(newline); 221 } else { 222 out.append(sbCbus.charAt(j)); 223 } 224 } 225 logLine = new String(out); 226 } 227 logStream.print(logLine); 228 } 229 } 230 231 private String logToFilePreferenceString(){ 232 return getClass().getName() + IS_LOGGING_TO_FILE + _mainPane.getMemo().getSystemPrefix(); 233 } 234 235 public void dispose(){ 236 var p = jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class); 237 p.setSimplePreferenceState(logToFilePreferenceString(), startStopLogButton.isSelected()); 238 } 239 240 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusConsoleLoggingPane.class); 241 242}