package esmska.utils;
import esmska.gui.ThemeManager;
import esmska.integration.IntegrationAdapter;
import java.awt.Dialog.ModalityType;
import java.io.IOException;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JDialog;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
/** Methods for detecting current runtime environment (operating system,
* java version).
*
* @author ripper
*/
public class RuntimeUtils {
/** Enum of operating system types */
public static enum OSType {
/** GNU/Linux */
LINUX,
/** Mac OS X */
MAC_OS_X,
/** Microsoft Windows */
WINDOWS,
/** Other OS */
OTHER;
}
private static String vendor = StringUtils.defaultString(System.getProperty("java.vendor"));
private static String vm = StringUtils.defaultString(System.getProperty("java.vm.name"));
private static final Logger logger = Logger.getLogger(RuntimeUtils.class.getName());
/** Detect type of current OS
* @return OS type
*/
public static OSType detectOS() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("linux")) {
return OSType.LINUX;
} else if (os.contains("mac os x")) {
return OSType.MAC_OS_X;
} else if (os.contains("windows")) {
return OSType.WINDOWS;
} else {
return OSType.OTHER;
}
}
/** Check whether current OS is Linux */
public static boolean isLinux() {
return detectOS() == OSType.LINUX;
}
/** Check whether current OS is Mac */
public static boolean isMac() {
return detectOS() == OSType.MAC_OS_X;
}
/** Check whether current OS is Windows */
public static boolean isWindows() {
return detectOS() == OSType.WINDOWS;
}
/** Check whether current desktop environment is Gnome */
public static boolean isGnomeDesktop() {
return System.getenv("GNOME_DESKTOP_SESSION_ID") != null;
}
/** Check whether current desktop environment is KDE */
public static boolean isKDEDesktop() {
return System.getenv("KDE_FULL_SESSION") != null;
}
/** Check whether current desktop environment is Gnome 3.x */
public static boolean isGnome3Desktop() {
if (!isGnomeDesktop()) {
return false;
}
// gnome-default-applications-properties is only available in GNOME 2.x,
// but not in GNOME 3.x
// code taken from: https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=654746
try {
Process p = Runtime.getRuntime().exec("which gnome-default-applications-properties");
p.waitFor();
if (p.exitValue() != 0 && p.exitValue() != 1) {
logger.log(Level.WARNING, "''which'' returned an unexpected exit code: {0}", p.exitValue());
}
return p.exitValue() != 0;
} catch (IOException e) {
logger.log(Level.WARNING, "Can't test whether this is Gnome 3", e);
} catch (InterruptedException e) {
logger.log(Level.WARNING, "Can't test whether this is Gnome 3", e);
}
return false;
}
/** Checks whether the current Java implementation is Oracle Java */
public static boolean isOracleJava() {
return (vendor.toLowerCase().contains("sun microsystems") ||
vendor.toLowerCase().contains("oracle corporation")) &&
!isOpenJDK();
}
/** Checks whether the current Java implementation is OpenJDK */
public static boolean isOpenJDK() {
return vm.toLowerCase().contains("openjdk");
}
/** Checks whether the current Java implementation is Apple Java */
public static boolean isAppleJava() {
return vendor.toLowerCase().contains("apple");
}
/** Checks whether the current Java implementation is supported.
* Currently supported and tested are: Oracle Java, OpenJDK, Apple Java
*/
public static boolean isSupportedJava() {
return isOracleJava() || isOpenJDK() || isAppleJava();
}
/** Get basic information about current system. Useful for debugging
* print-outs.
*/
public static String getSystemInfo() {
String[] props = new String[]{
"os.name", "os.version", "os.arch", "user.name", "user.home",
"user.dir", "java.version", "java.vendor", "java.vm.name",
"java.vm.version"
};
StringBuilder builder = new StringBuilder();
for (String prop : props) {
builder.append(prop);
builder.append("=");
builder.append(System.getProperty(prop));
builder.append("; ");
}
if (isGnomeDesktop()) {
builder.append("desktop=GNOME; ");
} else if (isKDEDesktop()) {
builder.append("desktop=KDE; ");
}
builder.append("language=").append(Locale.getDefault().getLanguage()).append("; ");
// delete the trailing semicolon
builder.delete(builder.length()-2, builder.length());
return builder.toString();
}
@SuppressWarnings("unchecked")
/** Sorts options provided to dialog as a buttons according to current look
* and feel. Some L&Fs are reversing order of the buttons, which is an
* unwanted behaviour. This method reverts it again for such L&Fs, so options
* are in original order. In every case be sure never rely on exact
* option position.<br>
* <br>
* This method is intended to be used only for dialogs created with
* JOptionPane methods (works around its own option swapping). For custom
* dialogs use {@link #sortOptions(java.lang.Object[])}.<br>
* <br>
* More detailed explanation:<br>
* There are two ways to display options:<br>
* 1. Standard (default option rightmost): Cancel | Action<br>
* 2. Windows-like (default option leftmost): Action | Cancel<br>
* <br>
* In Esmska all dialogs are written using the standard notation.<br>
* <br>
* Desktop environments are divided by the way of displaying options:<br>
* 1. Standard: Gnome, Mac OS<br>
* 2. Windows like: Windows, KDE<br>
* <br>
* In following LAFs and OSs Java displays the options in wrong order:<br>
* 1. Metal: Windows, KDE<br>
* 2. GTK: Gnome, Mac OS<br>
* 3. Windows: Windows (available nowhere else)<br>
* 4. Aqua: Mac OS (available nowhere else)<br>
* 5. JGoodies: Windows, KDE<br>
* 6. Substance: Windows, KDE<br>
* 7. Nimbus: Windows, Gnome, Mac<br>
* <br>
* In these cases this method will revert the button order to display
* it like native application.
*
* @param options options written in the standard notation (default option rightmost)
* @return options adjusted to current environment and LaF;
* null if <code>options</code> was null
*/
public static <T> T[] sortDialogOptions(T... options) {
T[] reversed = (T[]) ArrayUtils.clone(options);
ArrayUtils.reverse(reversed);
if (isWindows()) {
return reversed;
}
if (isKDEDesktop() && !ThemeManager.isGTKCurrentLaF() &&
!ThemeManager.isNimbusCurrentLaF()) {
return reversed;
}
if (ThemeManager.isGTKCurrentLaF() && !isKDEDesktop()) {
return reversed;
}
if (ThemeManager.isAquaCurrentLaF()) {
return reversed;
}
if (ThemeManager.isNimbusCurrentLaF() && !isKDEDesktop()) {
return reversed;
}
//no change needed
return options;
}
@SuppressWarnings("unchecked")
/** Sorts options provided to custom dialog as a buttons according to current
* desktop environment.<br>
* <br>
* For dialogs created by JOptionPane use
* {@link #sortDialogOptions(java.lang.Object[])}.<br>
* <br>
* More detailed explanation:<br>
* There are two ways to display options:<br>
* 1. Standard (default option rightmost): Cancel | Action<br>
* 2. Windows-like (default option leftmost): Action | Cancel<br>
* <br>
* In Esmska all dialogs are written using the standard notation.<br>
* <br>
* Desktop environments are divided by the way of displaying options:<br>
* 1. Standard: Gnome, Mac OS<br>
* 2. Windows like: Windows, KDE<br>
* <br>
* In the second case this method will revert the button order to display
* it like native application.
*/
public static <T> T[] sortOptions(T... options) {
if (isWindows() || isKDEDesktop()) {
//revert options
T[] reversed = (T[]) ArrayUtils.clone(options);
ArrayUtils.reverse(reversed);
return reversed;
}
//no change needed
return options;
}
/** Set dialog to be document modal and set property so it will look as
* native modal dialog on Mac (has no effect on other platforms).
* Also notifies Integration adapter about this event.
*
* @param dialog dialog which should be document modal and Mac native
* looking (only on Mac)
*/
public static void setDocumentModalDialog(JDialog dialog) {
dialog.setModalityType(ModalityType.DOCUMENT_MODAL);
dialog.getRootPane().putClientProperty("apple.awt.documentModalSheet",
Boolean.TRUE);
IntegrationAdapter.getInstance().registerModalSheet(dialog);
}
}