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