package de.micromata.borgbutler.server.rest; import de.micromata.borgbutler.json.JsonUtils; import de.micromata.borgbutler.server.RunningMode; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.swing.*; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import java.awt.*; import java.io.File; @Path("/files") public class FilesystemBrowserRest { private Logger log = LoggerFactory.getLogger(FilesystemBrowserRest.class); /** * Opens a directory browser or file browser on the desktop app and returns the chosen dir/file. Works only if Browser and Desktop app are running * on the same host. * * @param current The current path of file. If not given the directory/file browser starts with the last used directory or user.home. * @return The chosen directory path (absolute path). */ @GET @Path("/browse-local-filesystem") @Produces(MediaType.APPLICATION_JSON) public String browseLocalFilesystem(@Context HttpServletRequest requestContext, @QueryParam("current") String current) { String msg = RestUtils.checkLocalDesktopAvailable(requestContext); if (msg != null) { log.info(msg); return msg; } if (fileDialog != null || fileChooser != null) { log.warn("Cannot call already opened file choose twice. Close file chooser first."); return "{\"directory\": \"\"}"; } File file = null; synchronized (FilesystemBrowserRest.class) { if (frame == null) { frame = new JFrame("BorgButler"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 100); frame.setResizable(false); frame.setLocationRelativeTo(null); frame.setBackground(Color.WHITE); frame.getContentPane().setBackground(Color.WHITE); JLabel label = new JLabel("Click for choosing directory...", SwingConstants.CENTER); frame.add(label); } if (RunningMode.getOSType() == RunningMode.OSType.MAC_OS) { // The JFileChooser will hang after several calls, use AWT file dialog instead for Mac OS: System.setProperty("apple.awt.fileDialogForDirectories", "true"); frame.setAlwaysOnTop(true); frame.setVisible(true); try { fileDialog = new FileDialog(frame, "Choose a directory", FileDialog.LOAD); if (StringUtils.isNotBlank(current)) { fileDialog.setDirectory(current); } fileDialog.toFront(); fileDialog.setVisible(true); String filename = fileDialog.getFile(); String directory = fileDialog.getDirectory(); frame.setVisible(false); if (filename == null) { return ""; } file = new File(directory, filename); if (!file.isDirectory()) { file = new File(directory); } } finally { fileDialog = null; } } else { try { if (StringUtils.isNotBlank(current)) { fileChooser = new JFileChooser(current); } else { fileChooser = new JFileChooser(); } fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); frame.setVisible(true); frame.setAlwaysOnTop(true); int returnCode = fileChooser.showDialog(frame, "Choose"); frame.setVisible(false); frame.setAlwaysOnTop(false); if (returnCode == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile(); } } finally { fileChooser = null; } } } String filename = file != null ? JsonUtils.toJson(file.getAbsolutePath()) : ""; String result = "{\"directory\":\"" + filename + "\"}"; return result; } /** * @return OK, if the local desktop services such as open file browser etc. are available. */ @GET @Path("/local-fileservices-available") @Produces(MediaType.TEXT_PLAIN) public String browseLocalFilesystem(@Context HttpServletRequest requestContext) { String msg = RestUtils.checkLocalDesktopAvailable(requestContext); if (msg != null) { log.info(msg); return msg; } return "OK"; } private static JFrame frame; private static FileDialog fileDialog; private static JFileChooser fileChooser; }