package nodebox.ui;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeMapped;
import com.sun.jna.PointerType;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import nodebox.client.Application;
public class Platform {
public static final int WIN = 1;
public static final int MAC = 2;
public static final int OTHER = 3;
public static final int current_platform;
public static final int platformSpecificModifier;
public static final String SEP = System.getProperty("file.separator");
private static File userDataDirectory = null;
private static Map<String, Object> JNA_OPTIONS = new HashMap<String, Object>();
static {
if (!GraphicsEnvironment.isHeadless()) {
platformSpecificModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
} else {
platformSpecificModifier = Event.CTRL_MASK;
}
if (com.sun.jna.Platform.isWindows()) {
current_platform = WIN;
JNA_OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
JNA_OPTIONS.put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
} else if (com.sun.jna.Platform.isMac()) {
current_platform = MAC;
} else {
current_platform = OTHER;
}
}
public static boolean onMac() {
return current_platform == MAC;
}
public static boolean onWindows() {
return current_platform == WIN;
}
public static boolean onOther() {
return current_platform == OTHER;
}
//// Application directories ////
public static File getHomeDirectory() {
return new File(System.getProperty("user.home"));
}
/**
* Get the directory that contains the user's NodeBox library directory.
* <p/>
* <p/>
* <ul>
* <li>Mac: <code>/Users/username/Library/NodeBox</code></li>
* <li>Windows: <code>/Documents And Settings/username/Local Settings/Application Data/NodeBox</code></li>
* <li>Linux/BSD/Other: <code>~/.local/share/nodebox</code></li>
* </ul>
*
* @return the user's library directory.
*/
public static File getUserDataDirectory() throws RuntimeException {
if (userDataDirectory != null)
return userDataDirectory;
if (onMac()) {
userDataDirectory = new File(getHomeDirectory(), "Library/" + Application.NAME);
} else if (onWindows()) {
String localAppData;
HWND hwndOwner = null;
int nFolder = Shell32.CSIDL_LOCAL_APPDATA;
HANDLE hToken = null;
int dwFlags = Shell32.SHGFP_TYPE_CURRENT;
char[] pszPath = new char[Shell32.MAX_PATH];
int hResult = Shell32.INSTANCE.SHGetFolderPath(hwndOwner, nFolder, hToken, dwFlags, pszPath);
if (Shell32.S_OK == hResult) {
String path = new String(pszPath);
int len = path.indexOf('\0');
localAppData = path.substring(0, len);
} else {
// If the native call fails, use the home directory.
localAppData = getHomeDirectory().getPath();
}
userDataDirectory = new File(localAppData, Application.NAME);
} else {
userDataDirectory = new File(getHomeDirectory(), ".local/share/" + Application.NAME.toLowerCase(Locale.US));
}
return userDataDirectory;
}
/**
* Get the directory that contains NodeBox scripts the user has installed.
* <p/>
* <ul>
* <li>Mac: <code>/Users/username/Library/NodeBox/Scripts</code></li>
* <li>Windows: <code>/Users/username/Application Data/NodeBox/Scripts</code></li>
* <li>Linux/BSD/Other: <code>~/.local/share/nodebox/scripts</code></li>
* </ul>
*
* @return the user's NodeBox scripts directory.
*/
public static File getUserScriptsDirectory() {
if (onMac() || onWindows())
return new File(getUserDataDirectory(), "Scripts");
else
return new File(getUserDataDirectory(), "scripts");
}
/**
* Get the directory that contains Python libraries the user has installed.
* <p/>
* This directory is added to the PYTHONPATH; anything below it can be used in scripts.
* <p/>
* <ul>
* <li>Mac: <code>/Users/username/Library/NodeBox/Python</code></li>
* <li>Windows: <code>/Users/username/Application Data/NodeBox/Python</code></li>
* <li>Linux/BSD/Other: <code>~/.local/share/nodebox/python</code></li>
* </ul>
*
* @return the user's Python directory.
*/
public static File getUserPythonDirectory() {
if (onMac() || onWindows())
return new File(getUserDataDirectory(), "Python");
else
return new File(getUserDataDirectory(), "python");
}
/**
* Get the directory that contains the application's builtin NodeBox scripts.
*
* @return the application's NodeBox scripts directory.
*/
public static File getApplicationScriptsDirectory() {
return new File("libraries");
}
//// Keystrokes ////
public static KeyStroke getKeyStroke(int key) {
return KeyStroke.getKeyStroke(key, platformSpecificModifier);
}
public static KeyStroke getKeyStroke(int key, int modifier) {
return KeyStroke.getKeyStroke(key, platformSpecificModifier | modifier);
}
public static void openURL(String url) {
try {
Desktop.getDesktop().browse(URI.create(url));
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "Could not open browser window. Go to " + url + " directly. \n" + e.getLocalizedMessage());
}
}
private static class HANDLE extends PointerType implements NativeMapped {
}
private static class HWND extends HANDLE {
}
private static interface Shell32 extends Library {
public static final int MAX_PATH = 260;
public static final int CSIDL_LOCAL_APPDATA = 0x001c;
public static final int SHGFP_TYPE_CURRENT = 0;
public static final int S_OK = 0;
static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, JNA_OPTIONS);
/**
* See http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
* <p/>
*
* @param hwndOwner [in] Reserved.
* @param nFolder [in] A CSIDL value that identifies the folder whose path is to be retrieved.
* @param hToken [in] An access token that can be used to represent a particular user. Always set this to null.
* @param dwFlags [in] Flags that specify the path to be returned.
* @param pszPath [out] A pointer to a null-terminated string of length MAX_PATH which will receive the path.
* @return S_OK if successful, or an error value otherwise.
*/
public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken,
int dwFlags, char[] pszPath);
}
}