/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.util;
import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.concurrent.RejectedExecutionException;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.UIManager;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.ui.runtime.IRuntimeComponent;
import com.servoy.j2db.util.gui.AppletController;
public class UIUtils
{
/**
* Gets the UI property from the given component (if available) or from UIManager.getDefaults(). If it cannot be found in either, the
* default value will be returned. For smart client use.
* @param component the component.
* @param name the name of the property.
* @param defaultValue the default value for this property.
* @return the value of the UI property from the given component (if available) or from UIManager.getDefaults(). If it cannot be found in either, the default value will be returned.
*/
public static Object getUIProperty(JComponent component, String name, Object defaultValue)
{
Object val = component.getClientProperty(name);
if (val == null)
{
val = UIManager.getDefaults().get(name);
if (val == null) val = defaultValue;
}
return val;
}
/**
* Find out the UI property with given name relevant to the given component. (can be used in both web client and smart client).
* @param component the component.
* @param application the Servoy application.
* @param name the property name.
* @param defaultValue default value for this property.
* @return the UI property with given name relevant to the given component.
*/
public static Object getUIProperty(IRuntimeComponent component, IApplication application, String name, Object defaultValue)
{
Object val = component.getClientProperty(name);
if (val == null)
{
val = application.getClientProperty(name);
}
if (val == null) val = defaultValue;
return val;
}
public static boolean isOnScreen(Rectangle r)
{
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
if (ge != null)
{
GraphicsDevice[] gs = ge.getScreenDevices();
for (GraphicsDevice element : gs)
{
GraphicsConfiguration gc = element.getDefaultConfiguration();
if (gc != null)
{
Rectangle gcBounds = gc.getBounds();
if (gcBounds.contains(r.x, r.y))
{
return true;
}
}
}
}
return false;
}
public static boolean isCommandKeyDown(InputEvent e)
{
return Utils.isAppleMacOS() ? e.isMetaDown() : e.isControlDown();
}
public static int getClickInterval()
{
int clickInterval = 200;
try
{
if (Toolkit.getDefaultToolkit() != null && Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval") instanceof Integer) //$NON-NLS-1$
{
clickInterval = ((Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval")).intValue(); //$NON-NLS-1$
}
}
catch (Exception ex)
{
Debug.error(ex);
}
return clickInterval;
}
public static Rectangle getCenteredBoundsOn(Rectangle srcBounds, int width, int height)
{
return new Rectangle(srcBounds.x + (srcBounds.width - width) / 2, srcBounds.y + (srcBounds.height - height) / 2, width, height);
}
// TODO how can we refactor this to handle exceptions of unknown subtypes nicer, allowing a variable number of exception types?
public static abstract class ThrowingRunnable<E1T extends Exception, E2T extends Exception> implements Runnable
{
protected E1T e1;
protected E2T e2;
public void throwExceptionIfNeeded() throws E1T, E2T
{
if (e1 != null) throw e1;
if (e2 != null) throw e2;
}
}
public static <E1T extends Exception, E2T extends Exception> void runWhileDispatchingEvents(final ThrowingRunnable<E1T, E2T> r,
IServiceProvider serviceProvider) throws E1T, E2T
{
final boolean done[] = new boolean[1];
Runnable tmp = new Runnable()
{
@Override
public void run()
{
try
{
r.run();
}
finally
{
done[0] = true;
}
}
};
if (serviceProvider.isEventDispatchThread())
{
// dispatch events for UI responsiveness while the actual work runs in a background thread
try
{
serviceProvider.getScheduledExecutor().execute(tmp);
}
catch (RejectedExecutionException e)
{
tmp.run();
}
while (!done[0])
{
SwingHelper.dispatchEvents(20);
try
{
Thread.sleep(20);
}
catch (InterruptedException e)
{
Debug.warn(e);
}
}
}
else
{
tmp.run();
}
r.throwExceptionIfNeeded();
}
public static boolean setWindowTransparency(Window w, Container contentPane, boolean undecoratedW, boolean transparent, boolean complainInLogs)
{
boolean applied = false;
if ((JDialog.isDefaultLookAndFeelDecorated() || undecoratedW))
{
if (contentPane instanceof JComponent || transparent != contentPane.isOpaque())
{
// set on window if possible
if (JavaVersion.CURRENT_JAVA_VERSION.major >= 7)
{
// set it the Java 7 way with bg color that has alpha 0
if (transparent)
{
try
{
Color oldC = w.getBackground();
Color newC = (oldC != null) ? new Color(oldC.getRed(), oldC.getGreen(), oldC.getBlue(), 0) : new Color(255, 255, 255, 0);
w.setBackground(newC);
applied = true;
}
catch (Exception ex)
{
if (complainInLogs) Debug.trace("Error while trying to set transparency on window using v7 API; the capability might be missing.",
ex);
}
}
else
{
w.setBackground(null);
applied = true;
}
}
else if (JavaVersion.CURRENT_JAVA_VERSION.major == 6 && JavaVersion.CURRENT_JAVA_VERSION.update >= 10) // see http://docs.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html
{
try
{
// for java 1.6 u10 or later try this, as the above will only work in java 7
// AWTUtilities.setWindowOpaque(boolean)
Class< ? > awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities");
Method mSetWindowOpaque = awtUtilitiesClass.getMethod("setWindowOpaque", Window.class, boolean.class);
mSetWindowOpaque.invoke(null, w, Boolean.valueOf(!transparent));
applied = true;
}
catch (Exception ex)
{
if (complainInLogs) Debug.trace("Error while trying to set transparency on window using v6 API; the capability might be missing.", ex);
}
}
else
{
if (complainInLogs) Debug.warn("Cannot set transparency on window; it is supported only with Java 6 update 10 or higher.");
}
// also set it on intermediate panes
if (applied && contentPane instanceof JComponent) ((JComponent)contentPane).setOpaque(!transparent); // normally it will be a JComponent
}
else
{
if (complainInLogs) Debug.warn("Transparency will no be applied. Can't change opaque value (not JComponent).");
}
}
else
{
if (complainInLogs) Debug.warn("Transparency will no be applied to some decorated dialogs. It can lead to strange visual effects.");
}
return applied;
}
/**
* @param appletContext
* @param applet
* @param initialSize
*/
public static void initializeApplet(AppletController appletContext, Applet applet, Dimension initialSize) throws Exception
{
String resourceName = applet.getClass().getName().replace('.', '/').concat(".class"); //$NON-NLS-1$
URL objectUrl = applet.getClass().getClassLoader().getResource(resourceName);
URL codeBase = null;
URL docBase = null;
String s = objectUrl.toExternalForm();
if (s.endsWith(resourceName))
{
int ix = s.length() - resourceName.length();
codeBase = new URL(s.substring(0, ix));
docBase = codeBase;
ix = s.lastIndexOf('/');
if (ix >= 0)
{
docBase = new URL(s.substring(0, ix + 1));
}
}
// Setup a default context and stub.
appletContext.add(applet);
AppletStub stub = new Stub(applet, appletContext, codeBase, docBase);
applet.setStub(stub);
if (initialSize != null) applet.setSize(initialSize.width, initialSize.height);
else applet.setSize(100, 100);
applet.init();
((Stub)stub).active = true;
}
static class Stub implements AppletStub
{
transient boolean active;
transient Applet target;
transient AppletContext context;
transient URL codeBase;
transient URL docBase;
Stub(Applet target, AppletContext context, URL codeBase, URL docBase)
{
this.target = target;
this.context = context;
this.codeBase = codeBase;
this.docBase = docBase;
}
public boolean isActive()
{
return active;
}
public URL getDocumentBase()
{
// use the root directory of the applet's class-loader
return docBase;
}
public URL getCodeBase()
{
// use the directory where we found the class or serialized object.
return codeBase;
}
public String getParameter(String name)
{
return null;
}
public AppletContext getAppletContext()
{
return context;
}
public void appletResize(int width, int height)
{
// we do nothing.
}
}
}