org.syncany.gui.util.DesktopUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.syncany.gui.util.DesktopUtil.java

Source

/*
 * Syncany, www.syncany.org
 * Copyright (C) 2011-2015 Philipp C. Heckel <philipp.heckel@gmail.com>
 *
 * 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */
package org.syncany.gui.util;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.FileUtils;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
import org.syncany.gui.preferences.GeneralPanel;
import org.syncany.util.EnvironmentUtil;
import org.syncany.util.FileUtil;
import com.google.common.base.StandardSystemProperty;

/**
 * Helper class to open web sites and local folders, and to center
 * a window on the screen.
 *
 * @author Vincent Wiencek <vwiencek@gmail.com>
 * @author Philipp C. Heckel <philipp.heckel@gmail.com>
 */
public class DesktopUtil {
    private static final Logger logger = Logger.getLogger(DesktopUtil.class.getSimpleName());

    private static final String STARTUP_LINUX_SCRIPT_RESOURCE = "/"
            + GeneralPanel.class.getPackage().getName().replace('.', '/') + "/syncany.desktop";
    private static final String STARTUP_LINUX_SCRIPT_TARGET_FILENAME = "syncany.desktop";

    private static final String STARTUP_WINDOWS_APP_HOME_ENV_VARIABLE = "APP_HOME";
    private static final String STARTUP_WINDOWS_APP_LAUNCHER_PATH_FORMAT = "%s\\bin\\launcher.vbs";
    private static final String STARTUP_WINDOWS_REG_ROOT = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
    private static final String STARTUP_WINDOWS_REG_KEY = "Syncany";

    private static final String STARTUP_OSX_APPLICATION_NAME = "Syncany";
    private static final Path STARTUP_OSX_OSASCRIPT = Paths.get("/usr/bin/osascript");
    private static final String STARTUP_OSX_OSASCRIPT_ADD = "tell application \"System Events\" to make login item at end with properties {name: \"%s\", path:\"%s\", hidden:false}";
    private static final String STARTUP_OSX_OSASCRIPT_REMOVE = "tell application \"System Events\" to delete login item \"%s\"";

    /**
     * Launches a program or a URL using SWT's {@link Program}
     * class. This method returns immediately and hands over the
     * opening task to the UI thread.
     */
    public static void launch(final String uri) {
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                try {
                    if (!Program.launch(uri)) {
                        throw new Exception("Unable to open URI: " + uri);
                    }
                } catch (Exception e) {
                    logger.log(Level.WARNING, "Cannot open folder " + uri, e);
                }
            }
        });
    }

    /**
     * This method centers the dialog on the screen using
     * <code>Display.getCurrent().getPrimaryManitor()</code>
     */
    public static void centerOnScreen(Shell shell) {
        Monitor primary = Display.getCurrent().getPrimaryMonitor();
        Rectangle bounds = primary.getBounds();
        Rectangle rect = shell.getBounds();

        int x = bounds.x + (bounds.width - rect.width) / 2;
        int y = bounds.y + (bounds.height - rect.height) / 2;

        shell.setLocation(x, y);
    }

    /**
     * Brings the window to the front (might not work on all
     * operating systems).
     */
    public static void bringToFront(final Shell shell) {
        shell.getDisplay().asyncExec(new Runnable() {
            public void run() {
                shell.forceActive();
            }
        });
    }

    /**
     * Copies the given text to the user clipboard.
     */
    public static void copyToClipboard(String copyText) {
        StringSelection applicationLinkStringSelection = new StringSelection(copyText);

        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(applicationLinkStringSelection, applicationLinkStringSelection);
    }

    /**
     * Set or unset the automatic system startup for Syncany.
     */
    // TODO [low] This method should be more generic. It is very Syncany-specific.
    public static void writeAutostart(boolean launchAtStartupEnabled) {
        switch (EnvironmentUtil.getOperatingSystem()) {
        case WINDOWS:
            writeAutostartWindows(launchAtStartupEnabled);
            break;
        case OSX:
            writeAutostartOSX(launchAtStartupEnabled);
            break;
        case UNIX_LIKE:
            writeAutostartLinux(launchAtStartupEnabled);
            break;
        default:
            logger.log(Level.INFO,
                    "Autostart: Launch at startup feature is NOT SUPPORTED (yet) on this operating system. Ignoring option.");
            break;
        }
    }

    private static void writeAutostartLinux(boolean launchAtStartupEnabled) {
        File autostartDir = new File(StandardSystemProperty.USER_HOME.value(), ".config/autostart");
        File startupScriptFile = new File(autostartDir, STARTUP_LINUX_SCRIPT_TARGET_FILENAME);

        if (launchAtStartupEnabled) {
            writeLinuxStartupFile(autostartDir, startupScriptFile);
        } else {
            deleteLinuxStartupScriptFile(startupScriptFile);
        }
    }

    private static void writeLinuxStartupFile(File autostartDir, File startupScriptFile) {
        // This method always re-writes the startup/autostart script. This
        // makes sure that any altered settings (X-GNOME-Autostart, etc.) are
        // wiped out.

        logger.log(Level.INFO,
                "Autostart (enabled): Writing Linux startup script to " + startupScriptFile + " ...");

        if (!autostartDir.isDirectory()) {
            autostartDir.mkdirs();
        }

        try {
            InputStream startupScriptInputStream = GeneralPanel.class
                    .getResourceAsStream(STARTUP_LINUX_SCRIPT_RESOURCE);
            FileUtils.copyInputStreamToFile(startupScriptInputStream, startupScriptFile);
        } catch (IOException e) {
            logger.log(Level.WARNING,
                    "Autostart: Cannot write Linux startup script to " + startupScriptFile + ". Ignoring.", e);
        }
    }

    private static void deleteLinuxStartupScriptFile(File startupScriptFile) {
        if (startupScriptFile.exists()) {
            logger.log(Level.INFO,
                    "Autostart (disabled): Deleting startup script file from " + startupScriptFile + " ...");
            startupScriptFile.delete();
        } else {
            logger.log(Level.INFO, "Autostart (disabled): Linux startup script does not exist at "
                    + startupScriptFile + ". Nothing to do.");
        }
    }

    private static void writeAutostartWindows(boolean launchAtStartupEnabled) {
        try {
            if (launchAtStartupEnabled) {
                addAutostartRegistryKeyWindows();
            } else {
                deleteAutostartRegistryKeyWindows();
            }
        } catch (IOException e) {
            logger.log(Level.WARNING, "Autostart: Cannot write Windows registry key for startup.", e);
        }
    }

    private static void addAutostartRegistryKeyWindows() throws IOException {
        String appHome = System.getenv(STARTUP_WINDOWS_APP_HOME_ENV_VARIABLE);

        if (appHome != null) {
            String appLauncherFilePath = String.format(STARTUP_WINDOWS_APP_LAUNCHER_PATH_FORMAT, appHome);
            String canonicalAppLauncherFilePath = FileUtil.getCanonicalFile(new File(appLauncherFilePath))
                    .getAbsolutePath();

            logger.log(Level.INFO, "Autostart (enabled): Windows writing registry key " + STARTUP_WINDOWS_REG_ROOT
                    + " -> " + STARTUP_WINDOWS_REG_KEY + " to value '" + canonicalAppLauncherFilePath + "' ...");

            WindowsRegistryUtil.writeString(STARTUP_WINDOWS_REG_ROOT, STARTUP_WINDOWS_REG_KEY,
                    canonicalAppLauncherFilePath);
        } else {
            logger.log(Level.WARNING, "Autostart (enabled): CANNOT write Windows registry key. No "
                    + STARTUP_WINDOWS_APP_HOME_ENV_VARIABLE + " env variable present. Ignoring.");
        }
    }

    private static void deleteAutostartRegistryKeyWindows() throws IOException {
        logger.log(Level.INFO, "Autostart (disabled): Windows deleting registry key " + STARTUP_WINDOWS_REG_ROOT
                + " -> " + STARTUP_WINDOWS_REG_KEY + " ...");
        WindowsRegistryUtil.deleteKey(STARTUP_WINDOWS_REG_ROOT, STARTUP_WINDOWS_REG_KEY);
    }

    private static void writeAutostartOSX(boolean launchAtStartupEnabled) {
        try {
            if (launchAtStartupEnabled) {
                addLoginItemsEntryOSX();
            } else {
                removeLoginItemsEntryOSX();
            }
        } catch (IOException e) {
            logger.log(Level.WARNING, "Autostart: Cannot alter OSX login items.", e);
        }
    }

    private static void addLoginItemsEntryOSX() throws IOException {
        logger.log(Level.INFO, "Autostart (enabled): Adding item to OSX login items");
        final String javaLibraryPath = System.getProperty("java.library.path");

        if (javaLibraryPath == null || javaLibraryPath.equals("")) {
            throw new IOException("Unable to add autostart for unbundled app (1)");
        }

        // -Djava.library.path=/Users/chr/Desktop/Syncany.app/Contents/MacOS
        final Path bundlePath = Paths.get(javaLibraryPath).getParent().getParent();

        // make sure that path ends with *.app
        if (!bundlePath.getFileName().toString().endsWith(".app")) {
            throw new IOException("Unable to add autostart for unbundled app (2): " + bundlePath);
        }

        Runtime.getRuntime().exec(new String[] { STARTUP_OSX_OSASCRIPT.toString(), "-e",
                String.format(STARTUP_OSX_OSASCRIPT_ADD, STARTUP_OSX_APPLICATION_NAME, bundlePath) });
    }

    private static void removeLoginItemsEntryOSX() throws IOException {
        logger.log(Level.INFO, "Autostart (disabled): Removing item from OSX login items");

        Runtime.getRuntime().exec(new String[] { STARTUP_OSX_OSASCRIPT.toString(), "-e",
                String.format(STARTUP_OSX_OSASCRIPT_REMOVE, STARTUP_OSX_APPLICATION_NAME) });
    }
}