package net.pms.newgui; import com.sun.jna.Platform; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.swing.*; import javax.swing.filechooser.FileFilter; import javax.swing.plaf.metal.MetalIconFactory; import net.pms.Messages; import net.pms.PMS; import net.pms.configuration.DeviceConfiguration; import net.pms.configuration.PmsConfiguration; import net.pms.configuration.RendererConfiguration; import net.pms.external.DebugPacker; import net.pms.external.ExternalFactory; import net.pms.external.ExternalListener; import net.pms.logging.LoggingConfig; import net.pms.newgui.components.CustomJButton; import net.pms.util.FileUtil; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DbgPacker implements ActionListener { private static final Logger LOGGER = LoggerFactory.getLogger(DbgPacker.class); private LinkedHashMap<File, JCheckBox> items; private String defaultLogFile, zippedLogFile; private CustomJButton openZip; public DbgPacker() { items = new LinkedHashMap<>(); HashMap<String, String> logFilePaths = LoggingConfig.getLogFilePaths(); if (!logFilePaths.isEmpty()) { defaultLogFile = LoggingConfig.getLogFilePaths().get("default.log"); if (defaultLogFile == null) { // Just get the path of one of the files as we can't find the default Map.Entry<String, String> entry = logFilePaths.entrySet().iterator().next(); defaultLogFile = entry.getValue(); } zippedLogFile = new File(defaultLogFile).getParent().toString(); } else { // Fall back to getting the default folder zippedLogFile = PMS.getConfiguration().getDefaultLogFilePath(); } if (!zippedLogFile.isEmpty()) { zippedLogFile = FileUtil.appendPathSeparator(zippedLogFile) + "ums_dbg.zip"; } else { LOGGER.error("Could not find destination folder for packed debug files"); } } public JComponent config() { poll(); JPanel top = new JPanel(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.insets = new Insets(0, 5, 0, 5); c.ipadx = 5; c.gridx = 0; c.gridy = 0; for (Map.Entry<File, JCheckBox> item : items.entrySet()) { File file = item.getKey(); boolean exists = file.exists(); JCheckBox box = item.getValue(); if (box == null) { box = new JCheckBox(file.getName(), exists); item.setValue(box); } if (!exists) { box.setSelected(false); box.setEnabled(false); } c.weightx = 1.0; top.add(box, c); CustomJButton open = exists ? new CustomJButton(MetalIconFactory.getTreeLeafIcon()) : new CustomJButton("+"); open.setActionCommand(file.getAbsolutePath()); open.setToolTipText((exists ? "" : Messages.getString("DbgPacker.1") + " ") + file.getAbsolutePath()); open.addActionListener(this); c.gridx++; c.weightx = 0.0; top.add(open, c); c.gridx--; c.gridy++; } c.weightx = 2.0; CustomJButton debugPack = new CustomJButton(Messages.getString("DbgPacker.2")); debugPack.setActionCommand("pack"); debugPack.addActionListener(this); top.add(debugPack, c); openZip = new CustomJButton(MetalIconFactory.getTreeFolderIcon()); openZip.setActionCommand("showzip"); openZip.setToolTipText(Messages.getString("DbgPacker.3")); openZip.setEnabled(false); openZip.addActionListener(this); c.gridx++; c.weightx = 0.0; top.add(openZip, c); return top; } private void poll() { // call the client callbacks for (ExternalListener listener : ExternalFactory.getExternalListeners()) { if (listener instanceof DebugPacker) { LOGGER.debug("Found client {}",listener.name()); Object obj = ((DebugPacker) listener).dbgpack_cb(); if (obj instanceof String) { add(((String) obj).split(",")); } else if (obj instanceof String[]) { add((String[]) obj); } } } PmsConfiguration configuration = PMS.getConfiguration(); // check dbgpack property in UMS.conf LOGGER.debug("Checking dbgpack property in UMS.conf"); String f = (String) configuration.getCustomProperty("dbgpack"); if (f != null) { add(f.split(",")); } // add confs of connected renderers for (RendererConfiguration r : RendererConfiguration.getConnectedRenderersConfigurations()) { add(r.getFile()); if (((DeviceConfiguration)r).isCustomized()) { add(((DeviceConfiguration)r).getParentFile()); } } // add core items with the default logfile last (LinkedHashMap preserves insertion order) String profileDirectory = configuration.getProfileDirectory(); // add virtual folders file if it exists String vfolders = configuration.getVirtualFoldersFile(null); if (StringUtils.isNotEmpty(vfolders)) { add(new File(profileDirectory, vfolders)); } add(new File(profileDirectory, "WEB.conf")); add(new File(configuration.getProfilePath())); if (defaultLogFile != null && !defaultLogFile.isEmpty()){ add(new File(defaultLogFile + ".prev")); add(new File(defaultLogFile)); } } private void add(String[] files) { for (String file : files) { add(new File(file)); } } private void add(File file) { if (file != null) { LOGGER.debug("adding {}",file.getAbsolutePath()); try { items.put(file.getCanonicalFile(), null); } catch (IOException e) { } } } private void writeToZip(ZipOutputStream out, File f) throws Exception { byte[] buf = new byte[1024]; int len; if (!f.exists()) { LOGGER.debug("DbgPack file {} does not exist - ignoring",f.getAbsolutePath()); return; } try (FileInputStream in = new FileInputStream(f)) { out.putNextEntry(new ZipEntry(f.getName())); while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } out.closeEntry(); } } public Set<File> getItems() { poll(); return items.keySet(); } private boolean saveDialog() { JFileChooser fc = new JFileChooser() { private static final long serialVersionUID = -7279491708128801610L; @Override public void approveSelection() { File f = getSelectedFile(); if (!f.isDirectory()) { if (f.exists() && JOptionPane.showConfirmDialog(null, Messages.getString("DbgPacker.4"), "Confirm", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) { return; } super.approveSelection(); } } }; fc.setFileFilter( new FileFilter() { @Override public boolean accept(File f) { String s = f.getName(); return f.isDirectory() || (s.endsWith(".zip") || s.endsWith(".ZIP")); } @Override public String getDescription() { return "*.zip"; } }); fc.setSelectedFile(new File(zippedLogFile)); if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { zippedLogFile = fc.getSelectedFile().getPath(); return true; } return false; } private void packDbg() { if (!saveDialog()) { return; } try { try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zippedLogFile))) { for (Map.Entry<File, JCheckBox> item : items.entrySet()) { if (item.getValue().isSelected()) { File file = item.getKey(); LOGGER.debug("Packing {}", file.getAbsolutePath()); writeToZip(zos, file); } } } openZip.setEnabled(true); } catch (Exception e) { LOGGER.debug("Error packing zip file: {}", e.getLocalizedMessage()); } } @Override public void actionPerformed(ActionEvent e) { String str = e.getActionCommand(); if (str.equals("pack")) { packDbg(); } else { // Open: "showzip" - zipped file folder // not "showzip" - one of the listed files File file = str.equals("showzip") ? new File(zippedLogFile).getParentFile() : new File(str); if (file.exists()) { try { java.awt.Desktop.getDesktop().open(file); } catch (IOException e2) { LOGGER.warn("Failed to open default desktop application: {}", e2); if (Platform.isWindows()) { JOptionPane.showMessageDialog(null, Messages.getString("DbgPacker.5") + e2, Messages.getString("TracesTab.6"),JOptionPane.ERROR_MESSAGE); } else { JOptionPane.showMessageDialog(null, Messages.getString("DbgPacker.6") + e2, Messages.getString("TracesTab.6"), JOptionPane.ERROR_MESSAGE); } } } else { JOptionPane.showMessageDialog( null, String.format(Messages.getString("DbgPacker.7"), file.getAbsolutePath()), null, JOptionPane.INFORMATION_MESSAGE); reload((JComponent) e.getSource()); } } } private void reload(JComponent c) { // Rebuild and restart LOGGER.debug("Reloading..."); ((Window) c.getTopLevelAncestor()).dispose(); JOptionPane.showOptionDialog( SwingUtilities.getWindowAncestor((Component) PMS.get().getFrame()), config(), Messages.getString("Dialog.Options"), JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null ); } }