/* * PS3 Media Server, for streaming any medias to your PS3. * Copyright (C) 2008 A.Brochard * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.newgui; import ch.qos.logback.classic.Level; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.swing.*; import javax.swing.border.EtchedBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.Document; import net.pms.Messages; import net.pms.PMS; import net.pms.configuration.PmsConfiguration; import net.pms.logging.LoggingConfig; import net.pms.newgui.components.*; import net.pms.util.FormLayoutUtil; import net.pms.util.ProcessUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TracesTab { private static final Logger LOGGER = LoggerFactory.getLogger(TracesTab.class); private PmsConfiguration configuration; private CustomJTextField jSearchBox, jSyslogHost; private CustomJComboBox<String> jTracesFilter, jSyslogFacility; private CustomJCheckBox jCSSearch, jRESearch, jMLSearch, jShowOptions, jBuffered, jUseSyslog; private JSpinner jLineBuffer, jSyslogPort; private Pattern searchPattern = null; private JLabel jSearchOutput = new JLabel(); private TextAreaFIFO jList; private JPanel jOptionsPanel; private JLabel jBufferLabel; private JSeparator jBufferSeparator; private Component jBufferSpace1, jBufferSpace2, jBufferSpace3, jCSSpace, jRESpace, jMLSpace; protected JScrollPane jListPane; private final String[] levelStrings = { Messages.getString("TracesTab.6"), Messages.getString("TracesTab.7"), Messages.getString("TracesTab.8"), Messages.getString("TracesTab.9"), Messages.getString("TracesTab.10"), Messages.getString("TracesTab.15"), Messages.getString("TracesTab.16") }; private final Level[] logLevels = { Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE, Level.ALL, Level.OFF }; private final String[] syslogFacilities = { "AUTH", "AUTHPRIV", "DAEMON", "CRON", "FTP", "LPR", "KERN", "MAIL", "NEWS", "SYSLOG", "USER", "UUCP", "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3", "LOCAL4", "LOCAL5", "LOCAL6", "LOCAL7" }; private int findSyslogFacilityIdx(String facility) { for (int i = 0; i < syslogFacilities.length; i++) { if (facility.equalsIgnoreCase(syslogFacilities[i])) { return i; } } return -1; } static class PopupTriggerMouseListener extends MouseAdapter { private JPopupMenu popup; private JComponent component; public PopupTriggerMouseListener(JPopupMenu popup, JComponent component) { this.popup = popup; this.component = component; } // Some systems trigger popup on mouse press, others on mouse release, we want to cater for both private void showMenuIfPopupTrigger(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(component, e.getX() + 3, e.getY() + 3); } } // According to the javadocs on isPopupTrigger, checking for popup trigger on mousePressed and mouseReleased // Should be all that is required @Override public void mousePressed(MouseEvent e) { showMenuIfPopupTrigger(e); } @Override public void mouseReleased(MouseEvent e) { showMenuIfPopupTrigger(e); } } private LooksFrame looksFrame; private ViewLevel viewLevel; TracesTab(PmsConfiguration configuration, LooksFrame looksFrame) { this.configuration = configuration; this.looksFrame = looksFrame; } /** * Set/update the visibility of all components affected by view level */ public void applyViewLevel() { viewLevel = looksFrame.getViewLevel(); jCSSpace.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jCSSearch.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jRESpace.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jRESearch.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jMLSpace.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jMLSearch.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jLineBuffer.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jShowOptions.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jOptionsPanel.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED) && jShowOptions.isSelected()); jBufferLabel.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jBufferSeparator.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jBufferSpace1.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jBufferSpace2.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); jBufferSpace3.setVisible(viewLevel.isGreaterOrEqual(ViewLevel.ADVANCED)); // Turn off some options for Normal/Novice if (viewLevel == ViewLevel.NORMAL) { jCSSearch.setSelected(false); configuration.setGUILogSearchCaseSensitive(false); jRESearch.setSelected(false); configuration.setGUILogSearchRegEx(false); jMLSearch.setSelected(false); configuration.setGUILogSearchMultiLine(false); jShowOptions.setSelected(false); jUseSyslog.setSelected(false); configuration.setLoggingUseSyslog(false); } } public JTextArea getList() { return jList; } public void append(String msg) { getList().append(msg); } private int findLevelsIdx(Level level) { for (int i=0; i < logLevels.length; i++) { if (logLevels[i] == level) { return i; } } return -1; } private void searchTraces() { boolean found = false; Matcher match = null; Document document = jList.getDocument(); int flags = Pattern.UNICODE_CASE; String find = jSearchBox.getText(); if (find.isEmpty()) { jSearchOutput.setText(""); } else if (document.getLength() > 0) { if (jMLSearch.isSelected()) { flags += Pattern.DOTALL + Pattern.MULTILINE; } if (!jRESearch.isSelected()) { flags += Pattern.LITERAL; } if (!jCSSearch.isSelected()) { flags += Pattern.CASE_INSENSITIVE; } try { if (searchPattern == null || !find.equals(searchPattern.pattern()) || flags != searchPattern.flags()) { searchPattern = Pattern.compile(find, flags); } match = searchPattern.matcher(document.getText(0,document.getLength())); found = match.find(jList.getCaretPosition()); if (!found && match.hitEnd()) { found = match.find(0); } if (found) { jList.requestFocusInWindow(); Rectangle viewRect = jList.modelToView(match.start()); Rectangle viewRectEnd = jList.modelToView(match.end()); if (viewRectEnd.x < viewRect.x) { viewRectEnd.x = jList.getWidth(); } viewRect.width = viewRectEnd.x - viewRect.x; viewRect.height += viewRectEnd.y - viewRect.y; jList.scrollRectToVisible(viewRect); jList.setCaretPosition(match.start()); jList.moveCaretPosition(match.end()); jSearchOutput.setText(""); } else { jSearchOutput.setText(String.format(Messages.getString("TracesTab.21"), jSearchBox.getText())); } } catch (PatternSyntaxException pe) { jSearchOutput.setText(String.format(Messages.getString("TracesTab.22"),pe.getLocalizedMessage())); } catch (Exception ex) { LOGGER.debug("Exception caught while searching traces list: "+ex); jSearchOutput.setText(Messages.getString("TracesTab.23")); } } } @SuppressWarnings("serial") public JComponent build() { // Apply the orientation for the locale ComponentOrientation orientation = ComponentOrientation.getOrientation(PMS.getLocale()); String colSpec = FormLayoutUtil.getColSpec("pref, pref:grow, pref, 3dlu, pref, pref, pref", orientation); int cols = colSpec.split(",").length; FormLayout layout = new FormLayout( colSpec, "p, fill:10:grow, p, p" ); PanelBuilder builder = new PanelBuilder(layout); builder.opaque(true); CellConstraints cc = new CellConstraints(); // Create the search box JPanel jSearchPanel = new JPanel(); jSearchPanel.setLayout(new BoxLayout(jSearchPanel,BoxLayout.LINE_AXIS)); jSearchPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); JLabel jFilterLabel = new JLabel(Messages.getString("TracesTab.24") + ":"); jFilterLabel.setDisplayedMnemonic(KeyEvent.VK_F); jFilterLabel.setToolTipText(Messages.getString("TracesTab.33")); jTracesFilter = new CustomJComboBox<>(levelStrings); jTracesFilter.setSelectedIndex(findLevelsIdx(configuration.getLoggingFilterLogsTab())); jFilterLabel.setLabelFor(jTracesFilter); jTracesFilter.setToolTipText(Messages.getString("TracesTab.33")); jTracesFilter.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { configuration.setLoggingFilterLogsTab(logLevels[jTracesFilter.getSelectedIndex()]); LoggingConfig.setTracesFilter(); } }); jSearchPanel.add(jFilterLabel); jSearchPanel.add(Box.createRigidArea(new Dimension(5,0))); jSearchPanel.add(jTracesFilter); jSearchPanel.add(Box.createRigidArea(new Dimension(5,0))); jSearchBox = new CustomJTextField(); jSearchBox.setBackground(new Color(248,248,248)); jSearchBox.setToolTipText(Messages.getString("TracesTab.34")); jSearchPanel.add(jSearchBox); jSearchPanel.add(Box.createRigidArea(new Dimension(5,0))); JButton jSearchButton = new JButton(Messages.getString("PMS.144")); jSearchButton.setMnemonic(KeyEvent.VK_S); jSearchButton.setToolTipText(Messages.getString("TracesTab.34")); jSearchPanel.add(jSearchButton); jSearchPanel.add(jCSSpace = Box.createRigidArea(new Dimension(5,0))); jCSSearch = new CustomJCheckBox(Messages.getString("TracesTab.19"), configuration.getGUILogSearchCaseSensitive()); jCSSearch.setMnemonic(KeyEvent.VK_C); jCSSearch.setToolTipText(Messages.getString("TracesTab.35")); jSearchPanel.add(jCSSearch); jSearchPanel.add(jRESpace = Box.createRigidArea(new Dimension(5,0))); jRESearch = new CustomJCheckBox("RegEx",configuration.getGUILogSearchRegEx()); jRESearch.setMnemonic(KeyEvent.VK_R); jRESearch.setToolTipText(Messages.getString("TracesTab.36")); jSearchPanel.add(jRESearch); jSearchPanel.add(jMLSpace = Box.createRigidArea(new Dimension(5,0))); jMLSearch = new CustomJCheckBox(Messages.getString("TracesTab.20"),configuration.getGUILogSearchMultiLine()); jMLSearch.setMnemonic(KeyEvent.VK_M); jMLSearch.setToolTipText(Messages.getString("TracesTab.37")); jSearchPanel.add(jMLSearch); jSearchPanel.add(jBufferSpace1 = Box.createRigidArea(new Dimension(4,0))); jSearchPanel.add(jBufferSeparator = new JSeparator(SwingConstants.VERTICAL)); jSearchPanel.add(jBufferSpace2 = Box.createRigidArea(new Dimension(4,0))); jBufferLabel = new JLabel(Messages.getString("TracesTab.17")); jBufferLabel.setDisplayedMnemonic(KeyEvent.VK_B); jBufferLabel.setToolTipText(Messages.getString("TracesTab.38")); jLineBuffer = new CustomJSpinner(new SpinnerIntModel( configuration.getLoggingLogsTabLinebuffer(), PmsConfiguration.LOGGING_LOGS_TAB_LINEBUFFER_MIN, PmsConfiguration.LOGGING_LOGS_TAB_LINEBUFFER_MAX, PmsConfiguration.LOGGING_LOGS_TAB_LINEBUFFER_STEP ), true); jLineBuffer.setToolTipText(Messages.getString("TracesTab.38")); jBufferLabel.setLabelFor(jLineBuffer); jSearchPanel.add(jBufferLabel); jSearchPanel.add(jBufferSpace3 = Box.createRigidArea(new Dimension(5,0))); jSearchPanel.add(jLineBuffer); jLineBuffer.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { jList.setMaxLines((Integer) jLineBuffer.getValue()); configuration.setLoggingLogsTabLinebuffer(jList.getMaxLines()); } }); jSearchBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { searchTraces(); } }); jSearchButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { searchTraces(); } }); jCSSearch.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { configuration.setGUILogSearchCaseSensitive(jCSSearch.isSelected()); } }); jRESearch.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { configuration.setGUILogSearchRegEx(jRESearch.isSelected()); } }); jMLSearch.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { configuration.setGUILogSearchMultiLine(jMLSearch.isSelected()); } }); builder.add(jSearchPanel, cc.xyw(1, 1, cols)); // Create traces text box jList = new TextAreaFIFO(configuration.getLoggingLogsTabLinebuffer()); jList.setEditable(false); jList.setBackground(Color.WHITE); jList.setFont(new Font(Font.MONOSPACED, Font.PLAIN, jList.getFont().getSize())); final JPopupMenu popup = new JPopupMenu(); Action copy = jList.getActionMap().get("copy-to-clipboard"); JMenuItem copyItem = new JMenuItem(copy); copyItem.setText(Messages.getString("General.1")); popup.add(copyItem); popup.addSeparator(); JMenuItem clearItem = new JMenuItem(Messages.getString("TracesTab.3")); clearItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jList.setText(""); } }); popup.add(clearItem); jList.addMouseListener(new PopupTriggerMouseListener(popup, jList)); jList.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { searchTraces(); } } @Override public void keyReleased(KeyEvent e) {} @Override public void keyTyped(KeyEvent e) {} }); jListPane = new JScrollPane(jList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); jListPane.setBorder(BorderFactory.createEmptyBorder()); new SmartScroller(jListPane); builder.add(jListPane, cc.xyw(1, 2, cols)); // Create the logging options panel jOptionsPanel = new JPanel(); jOptionsPanel.setLayout(new BoxLayout(jOptionsPanel,BoxLayout.LINE_AXIS)); jOptionsPanel.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createEmptyBorder(5, 5, 5, 5), BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), Messages.getString("TracesTab.26") ), BorderFactory.createEmptyBorder(10, 5, 10, 5) ) )); jBuffered = new CustomJCheckBox(Messages.getString("TracesTab.25"), configuration.getLoggingBuffered()); jBuffered.setMnemonic(KeyEvent.VK_U); jBuffered.setToolTipText(Messages.getString("TracesTab.43")); jBuffered.setHorizontalTextPosition(SwingConstants.LEADING); jBuffered.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (PMS.getTraceMode() == 2 && jBuffered.isSelected()) { jBuffered.setSelected(false); return; } configuration.setLoggingBuffered(jBuffered.isSelected()); LoggingConfig.setBuffered(jBuffered.isSelected()); } }); jOptionsPanel.add(jBuffered); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); boolean useSyslog = configuration.getLoggingUseSyslog(); jUseSyslog = new CustomJCheckBox(Messages.getString("TracesTab.27"), useSyslog); jUseSyslog.setMnemonic(KeyEvent.VK_Y); jUseSyslog.setToolTipText(Messages.getString("TracesTab.44")); jUseSyslog.setHorizontalTextPosition(SwingConstants.LEADING); jUseSyslog.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (PMS.getTraceMode() == 2 && jUseSyslog.isSelected()) { jUseSyslog.setSelected(false); return; } else if (jSyslogHost.getText().trim().isEmpty()) { jSearchOutput.setText(Messages.getString("TracesTab.31")); jUseSyslog.setSelected(false); return; } jSearchOutput.setText(""); boolean useSyslog = jUseSyslog.isSelected(); configuration.setLoggingUseSyslog(useSyslog); LoggingConfig.setSyslog(); jSyslogHost.setEnabled(!useSyslog); jSyslogPort.setEnabled(!useSyslog); jSyslogFacility.setEnabled(!useSyslog); } }); jOptionsPanel.add(jUseSyslog); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); JLabel jSyslogHostLabel = new JLabel(Messages.getString("TracesTab.28")); jSyslogHostLabel.setDisplayedMnemonic(KeyEvent.VK_N); jSyslogHostLabel.setToolTipText(Messages.getString("TracesTab.45")); jOptionsPanel.add(jSyslogHostLabel); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); jSyslogHost = new CustomJTextField(configuration.getLoggingSyslogHost(),10); jSyslogHostLabel.setLabelFor(jSyslogHost); jSyslogHost.setToolTipText(Messages.getString("TracesTab.45")); jSyslogHost.setEnabled(!useSyslog); jSyslogHost.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { jSyslogHost.setText(configuration.getLoggingSyslogHost()); } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { FocusManager.getCurrentManager().focusNextComponent(); } } }); jSyslogHost.setInputVerifier(new InputVerifier() { @Override public boolean verify(JComponent input) { String s = ((CustomJTextField) input).getText().trim(); if (!s.isEmpty() && !( // Hostname or IPv4 s.matches("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$") || // Simplified IPv6 s.matches("(^([0-9a-fA-F]{0,4}:)+[0-9a-fA-F]{1,4}([0-9a-fA-F]{0,4}:)*$)|(^([0-9a-fA-F]{0,4}:)*[0-9a-fA-F]{1,4}([0-9a-fA-F]{0,4}:)+$)|(^::$)") )) { jSearchOutput.setText(String.format(Messages.getString("TracesTab.32"), s)); return false; } jSearchOutput.setText(""); configuration.setLoggingSyslogHost(jSyslogHost.getText().trim()); return true; } }); jOptionsPanel.add(jSyslogHost); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); JLabel jSyslogPortLabel = new JLabel(Messages.getString("TracesTab.29")); jSyslogPortLabel.setToolTipText(Messages.getString("TracesTab.46")); jOptionsPanel.add(jSyslogPortLabel); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); jSyslogPort = new CustomJSpinner(new SpinnerIntModel(configuration.getLoggingSyslogPort(),1,65535), true); jSyslogPort.setToolTipText(Messages.getString("TracesTab.46")); jSyslogPort.setEnabled(!useSyslog); jSyslogPortLabel.setLabelFor(jSyslogPort); jSyslogPort.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { configuration.setLoggingSyslogPort((Integer) jSyslogPort.getValue()); } }); jOptionsPanel.add(jSyslogPort); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); JLabel jSyslogFacilityLabel = new JLabel(Messages.getString("TracesTab.30")); jSyslogFacilityLabel.setDisplayedMnemonic(KeyEvent.VK_A); jSyslogFacilityLabel.setToolTipText(Messages.getString("TracesTab.47")); jOptionsPanel.add(jSyslogFacilityLabel); jOptionsPanel.add(Box.createRigidArea(new Dimension(4,0))); jSyslogFacility = new CustomJComboBox<>(syslogFacilities); jSyslogFacility.setToolTipText(Messages.getString("TracesTab.47")); jSyslogFacility.setEnabled(!useSyslog); jSyslogFacility.setSelectedIndex(findSyslogFacilityIdx(configuration.getLoggingSyslogFacility())); jSyslogFacilityLabel.setLabelFor(jSyslogFacility); jSyslogFacility.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { configuration.setLoggingSyslogFacility(syslogFacilities[jSyslogFacility.getSelectedIndex()]); } }); jOptionsPanel.add(jSyslogFacility); jOptionsPanel.setFocusTraversalPolicyProvider(true); builder.add(jOptionsPanel, cc.xyw(1, 3, cols)); jShowOptions = new CustomJCheckBox(Messages.getString("TracesTab.18"), PMS.getTraceMode() != 2 && configuration.getLoggingUseSyslog()); jShowOptions.setHorizontalTextPosition(SwingConstants.LEADING); jShowOptions.setToolTipText(Messages.getString("TracesTab.41")); jShowOptions.setMnemonic(KeyEvent.VK_G); jShowOptions.setEnabled(PMS.getTraceMode() != 2); jShowOptions.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jOptionsPanel.setVisible(jShowOptions.isSelected()); if (jShowOptions.isSelected()) { jBuffered.requestFocusInWindow(); } } }); builder.add(jShowOptions, cc.xy(3, 4)); // Add buttons to open logfiles (there may be more than one) JPanel pLogFileButtons = new JPanel(new FlowLayout(FlowLayout.RIGHT)); HashMap<String, String> logFiles = LoggingConfig.getLogFilePaths(); for (Map.Entry<String,String> logger : logFiles.entrySet()) { String loggerNameDisplay = logger.getKey(); if (logger.getKey().toLowerCase().startsWith("default.log")) { loggerNameDisplay = Messages.getString("TracesTab.5"); } CustomJButton b = new CustomJButton(loggerNameDisplay); if (!logger.getKey().equals(loggerNameDisplay)) { b.setMnemonic(KeyEvent.VK_O); } b.setToolTipText(logger.getValue()); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { File logFile = new File(((CustomJButton) e.getSource()).getToolTipText()); try { java.awt.Desktop.getDesktop().open(logFile); } catch (IOException | UnsupportedOperationException ioe) { LOGGER.error("Failed to open file \"{}\" in default editor: {}", logFile, ioe); } } }); pLogFileButtons.add(b); } builder.add(pLogFileButtons, cc.xy(cols, 4)); final ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); JLabel rootLevelLabel = new JLabel(Messages.getString("TracesTab.11") + ": "); rootLevelLabel.setDisplayedMnemonic(KeyEvent.VK_L); rootLevelLabel.setToolTipText(Messages.getString("TracesTab.42")); CustomJComboBox<String> rootLevel = new CustomJComboBox<>(levelStrings); rootLevelLabel.setLabelFor(rootLevel); rootLevel.setSelectedIndex(findLevelsIdx(rootLogger.getLevel())); rootLevel.setToolTipText(Messages.getString("TracesTab.42")); rootLevel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { CustomJComboBox<?> cb = (CustomJComboBox<?>)e.getSource(); rootLogger.setLevel(logLevels[cb.getSelectedIndex()]); Level newLevel = rootLogger.getLevel(); if (newLevel.toInt() > Level.INFO_INT) { rootLogger.setLevel(Level.INFO); } LOGGER.info("Changed debug level to " + newLevel); if (newLevel != rootLogger.getLevel()) { rootLogger.setLevel(newLevel); } configuration.setRootLogLevel(newLevel); } }); builder.add(rootLevelLabel, cc.xy(5, 4)); builder.add(rootLevel, cc.xy(6, 4)); if (PMS.getTraceMode() == 2) { // Forced trace mode rootLevel.setEnabled(false); } // Add buttons to pack logs (there may be more than one) JPanel pLogPackButtons = new JPanel(new FlowLayout(FlowLayout.LEFT)); if (PMS.getTraceMode() == 0) { // PMS was not started in trace mode CustomJButton rebootTrace = new CustomJButton(Messages.getString("TracesTab.12")); rebootTrace.setToolTipText(Messages.getString("TracesTab.39")); rebootTrace.setMnemonic(KeyEvent.VK_T); rebootTrace.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int opt = JOptionPane.showConfirmDialog(null, Messages.getString("TracesTab.13"), Messages.getString("TracesTab.14"), JOptionPane.YES_NO_OPTION); if (opt == JOptionPane.YES_OPTION) { ProcessUtil.reboot("trace"); } } }); pLogPackButtons.add(rebootTrace); } CustomJButton packDbg = new CustomJButton(Messages.getString("TracesTab.4")); packDbg.setMnemonic(KeyEvent.VK_P); packDbg.setToolTipText(Messages.getString("TracesTab.40")); packDbg.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JComponent comp = PMS.get().dbgPack().config(); String[] cancelStr = {Messages.getString("Dialog.Close")}; JOptionPane.showOptionDialog(looksFrame, comp, Messages.getString("Dialog.Options"), JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE, null, cancelStr, null); } }); pLogPackButtons.add(packDbg); builder.add(pLogPackButtons, cc.xy(1, 4)); builder.add(jSearchOutput, cc.xy(2, 4)); JPanel builtPanel = builder.getPanel(); // Add a Ctrl + F shortcut to search field builtPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), "Ctrl_F"); builtPanel.getActionMap().put("Ctrl_F", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { jSearchBox.requestFocusInWindow(); } }); builtPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), "F3"); builtPanel.getActionMap().put("F3", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { searchTraces(); } }); applyViewLevel(); return builtPanel; } }