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}