/*
* @(#)OSXSheetSupport.java
*
* Copyright (c) 2009-2010 Werner Randelshofer, Immensee, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package ch.randelshofer.quaqua.osx;
import java.awt.Window;
import java.security.AccessControlException;
import javax.swing.JDialog;
import ch.randelshofer.quaqua.JSheet;
import ch.randelshofer.quaqua.QuaquaManager;
/**
* {@link OSXSheetSupport} provides support for native {@link JDialog JDialogs} for Java 5 and
* lower.
* <p>
* See {@link #showAsSheet(JDialog)} and {@link #hideSheet(JDialog)} for
* further information.
* <p>
* Please note: Sheets shown by this classed have no resize indicator and block
* their owner window from user interaction.
*
* @version $Id: OSXSheetSupport.java 106 2009-07-19 20:34:09Z fedr $
* @author Felix Draxler
*/
public class OSXSheetSupport {
/**
* This variable is set to true, if native code is available.
*/
private static volatile Boolean isNativeCodeAvailable;
/**
* Version of the native code library.
*/
private final static int EXPECTED_NATIVE_CODE_VERSION = 0;
private OSXSheetSupport() {
}
/**
* Checks if the native code was loaded and loads it if it has not been yet.
*
* @return <code>true</code>, if it has been loaded or could be loaded;
* <code>false</code> otherwise.
**/
private final static boolean isNativeCodeAvailable() {
if (isNativeCodeAvailable == null) {
synchronized (OSXSheetSupport.class) {
if (isNativeCodeAvailable == null) {
boolean success = false;
try {
String value = QuaquaManager.getProperty("Quaqua.jniIsPreloaded");
if (value == null) {
value = QuaquaManager.getProperty("Quaqua.JNI.isPreloaded");
}
if (value != null && value.equals("true")) {
success = true;
} else {
// Try to load 64-bit libraries if possible
String[] libraryNames;
String osArch = System.getProperty("os.arch");
if (osArch.equals("x86_64")) {
libraryNames = new String[]{"quaqua64"};
} else {
libraryNames = new String[]{"quaqua64", "quaqua"};
}
for (String libraryName:libraryNames) {
try {
System.loadLibrary(libraryName);
success = true;
break;
} catch (UnsatisfiedLinkError e) {
System.err.println("Warning: " + OSXSheetSupport.class + " couldn't load library \"" + System.mapLibraryName(libraryName) + "\". " + e);
success = false;
} catch (AccessControlException e) {
System.err.println("Warning: " + OSXSheetSupport.class + " access controller denied loading library \"" + System.mapLibraryName(libraryName) + "\". " + e);
success = false;
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Warning: " + OSXSheetSupport.class + " couldn't load library \"" + System.mapLibraryName(libraryName) + "\". " + e);
success = false;
}
}
}
if (success) {
int nativeCodeVersion = nativeGetNativeCodeVersion();
if (nativeCodeVersion != EXPECTED_NATIVE_CODE_VERSION) {
System.err.println("Warning: " + OSXSheetSupport.class
+ " can't use library libquaqua.jnilib. It has version "
+ nativeCodeVersion + " instead of "
+ EXPECTED_NATIVE_CODE_VERSION);
success = false;
}
}
} finally {
isNativeCodeAvailable = Boolean.valueOf(success);
}
}
}
}
return isNativeCodeAvailable == Boolean.TRUE;
}
/**
* Returns the version of the native code library. If the version does not
* match with the version that we expect, we can not use it.
*
* @return The version number of the native code.
*/
private static native int nativeGetNativeCodeVersion();
/**
* Shows a sheet on the given owner and immediately returns.
* <p>
* The native part of this method gets the NSWindow peers from the sheet and
* its owner. Then it tells the shared NSApplication to show the sheet as a
* standard native sheet.<br>
* See <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/NSApplication/beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:">NSApplication reference</a>
* <p>
* You have to call {@link JDialog#setVisible(boolean) setVisible(true)}
* after showing the sheet to enable lightweight components. That method
* must not have been called before this method.
* <p>
* In addition, {@link #hideSheet(JDialog)} must be called to hide the sheet
* before you call {@link JDialog#setVisible(boolean) setVisible(false)} on
* it.
* <p>
* The dialog must be undecorated.
* <p>
* {@link JSheet} handles all those details, but the method is enabled for
* any {@link JDialog}.
*
* @see JDialog#setVisible(boolean)
* @see #hideSheet(JDialog)
* @see JDialog#setUndecorated(boolean)
* @param sheet
* @return <code>true</code>, if showing the sheet succeeds.
* <code>false</code> otherwise.
*/
public static boolean showAsSheet(JDialog sheet) {
Window owner = sheet.getOwner();
if (isNativeCodeAvailable() && owner != null) {
if (!sheet.isDisplayable())
sheet.addNotify();
try {
// Start showing the sheet
nativeShowSheet(sheet, owner);
} catch (UnsatisfiedLinkError e) {
System.err.println("Warning: " + OSXSheetSupport.class
+ " could not show a sheet with the native method.");
return false;
}
return true;
} else {
return false;
}
}
/**
* Native method to show a sheet.
*
* @param sheet
* The sheet.
* @param owner
* The owner.
*/
private static native void nativeShowSheet(JDialog sheet, Window owner);
/**
* Hides a sheet.
* <p>
* See <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/NSApplication/endSheet:">NSApplication reference</a>
*
* @see #showAsSheet(JDialog)
* @param sheet
* The sheet to hide.
*/
public static void hideSheet(JDialog sheet) {
if (isNativeCodeAvailable() && sheet.isVisible()) {
nativeHideSheet(sheet);
}
}
/**
* Native method to hide a sheet.
*
* @param sheet
* The sheet.
*/
private static native void nativeHideSheet(JDialog sheet);
// Callback support removed - not needed
// @SuppressWarnings("unused")
// private static void fireSheetFinished(JSheet sheet) {
// // Just post a String on the Console.
// System.out.println(sheet + " was closed.");
// }
}