package net.xoetrope.xui.helper;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ResourceBundle;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.xui.WidgetAdapter;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.style.XStyle;
import net.xoetrope.xui.style.XStyleComponent;
import net.xoetrope.xui.style.XStyleManager;
/**
* A collection of utilities for use with XUI
* <p> Copyright (c) Xoetrope Ltd., 2002-2004</p>
* <p> $Revision: 2.15 $</p>
* <p> License: see License.txt</p>
*/
public class XuiUtilities
{
/**
* Count the instances of a character in a string
* @param source the source string
* @param match the character to match
* @return the numer of instances of the match character
*/
public static int count( String source, char match )
{
int count = 0;
int len = source.length();
for ( int i = 0; i < len; i++ ) {
if ( source.charAt( i ) == match )
count++;
}
return count;
}
/**
* Count the instances of a character in a string, skipping nested expressions
* delimited by the specified tokens
* @param source the source string
* @param match the character to match
* @param endingToken the ending token
* @param openingToken the opening token
* @return the numer of instances of the match character
*/
public static int count( String source, char match, char openingToken, char endingToken )
{
int count = 0;
int len = source.length();
for ( int i = 0; i < len; i++ ) {
char c = source.charAt( i );
if ( c == match )
count++;
else if ( c == openingToken )
i = indexOfMatchingEnding( source, openingToken, endingToken, i+1 );
}
return count;
}
/**
* Center a dialog on the screen.
* @param dialog the dialog window you want to center
*/
public static void centerOnScreen( Container dialog )
{
Component objWindow = dialog;
while (( objWindow != null ) && !( objWindow instanceof Window ))
objWindow = objWindow.getParent();
if ( objWindow != null ) {
Window w = (Window)objWindow;
Dimension screenSize = w.getToolkit().getScreenSize();
Dimension size = w.getSize();
screenSize.height = screenSize.height / 2;
screenSize.width = screenSize.width / 2;
size.height = size.height /2;
size.width = size.width / 2;
int y = screenSize.height - size.height;
int x = screenSize.width - size.width;
w.setLocation( x ,y );
}
}
/**
* Invoke the SwingUtilities invokeLater method via reflection.
* @param r the runnable to be passed to the SwingUtilities method
*/
public static void invokeLater( Runnable r )
{
if ( !BuildProperties.BUILD_JDK_118 ) {
try {
Class params[] = new Class[ 1 ];
params[ 0 ] = Runnable.class;
Class clazz = Class.forName( "javax.swing.SwingUtilities" );
Method method = clazz.getMethod( "invokeLater", params );
Object args[] = new Object[ 1 ];
args[ 0 ] = r;
if ( method != null )
method.invoke( null, args );
}
catch ( NoSuchMethodException ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logWarning( "Cannot invoke the SwingUtilities method invokeLater" );
}
catch ( Exception ex ) {
ex.getCause().printStackTrace();
}
}
}
/**
* Invoke the SwingUtilities invokeAndWait method via reflection.
* @param r the runnable to be passed to the SwingUtilities method
*/
public static void invokeAndWait( Runnable r )
{
if ( !BuildProperties.BUILD_JDK_118 ) {
try {
Class params[] = new Class[ 1 ];
params[ 0 ] = Runnable.class;
Class clazz = Class.forName( "javax.swing.SwingUtilities" );
Method method = clazz.getMethod( "invokeAndWait", params );
Object args[] = new Object[ 1 ];
args[ 0 ] = r;
if ( method != null )
method.invoke( null, args );
}
catch ( NoSuchMethodException ex ) {
if ( BuildProperties.DEBUG )
DebugLogger.logWarning( "Cannot invoke the SwingUtilities method invokeAndWait" );
}
catch ( Exception ex ) {
ex.getCause().printStackTrace();
}
}
}
/**
* Translate a key to the current language
* @param key the language key
* @return the translated text
*/
public static String translate( XProject currentProject, String key )
{
ResourceBundle languageResourceBundle = currentProject.getResourceBundle( currentProject.getStartupParam( "Language" ));
String ret = key;
try {
ret = languageResourceBundle.getString( key );
}
catch ( Exception ex ) {
}
return ret;
}
/**
* Get an unsaturated version of a color
* @param color the original color
* @param percentage the percentage of the original color saturation to return
*/
public static Color unsaturateColor( Color color, int percentage )
{
if ( percentage == 100 )
return color;
float[] hsb = new float[ 3 ];
color.RGBtoHSB( color.getRed(), color.getGreen(), color.getBlue(), hsb );
return new Color( color.HSBtoRGB( hsb[ 0 ], ( percentage * hsb[ 1 ] ) / 100.0F, hsb[ 2 ] ));
}
/**
* Get a darker/brighter version of a color
* @param color the original color
* @param percentage the percentage of the original color brightness to return
*/
public static Color brightenColor( Color color, int percentage )
{
if ( percentage == 100 )
return color;
float[] hsb = new float[ 3 ];
color.RGBtoHSB( color.getRed(), color.getGreen(), color.getBlue(), hsb );
return new Color( color.HSBtoRGB( hsb[ 0 ], hsb[ 1 ], ( percentage * hsb[ 2 ] ) / 100.0F ));
}
/**
* Get the argument types and values from an argument string
* @param argString the raw argument string e.g. foo,bar,12
* @param argTypes the argument class names - for the above example java.lang.String,java.lang.String,java.lang.int
* @param argValues the argument values - for the above example "foo", "bar", 12
* @param separator the argument seperator
*/
public static void getArguments( String argString, Class[] argTypes, Object[] argValues, char separator )
{
// Extract the arguments to the appropriate array
int start = 0;
int numArgs = argTypes.length;
for ( int i = 0; i < numArgs; i++ ) {
int pos = argString.indexOf( separator, start );
String argument;
if ( pos > -1 ) {
argument = argString.substring( start, pos );
start = pos + 1;
}
else {
argument = argString.substring( start );
// Make this to be the last iteration
numArgs = 0;
}
argument = argument.trim();
char firstChar = argument.charAt( 0 );
// If the first char is a digit or a minus then assume it's a number
if ( Character.isDigit( firstChar ) || ( firstChar == '-' ) ) {
argValues[ i ] = new Integer( argument );
argTypes[ i ] = int.class;
}
else if ( argument.equals( "true" ) || argument.equals( "false" )) {
argValues[ i ] = argument.equals( "true" ) ? Boolean.TRUE : Boolean.FALSE;
argTypes[ i ] = boolean.class;
}
else {
argValues[ i ] = argument;
argTypes[ i ] = String.class;
}
}
}
/**
* Get the argument types and values from an argument string, skipping nested
* expressions delimited by the specified tokens
* @param argString the raw argument string e.g. foo,bar,12
* @param argTypes the argument class names - for the above example java.lang.String,java.lang.String,java.lang.int
* @param argValues the argument values - for the above example "foo", "bar", 12
* @param separator the argument seperator
* @param endingToken the ending token
* @param openingToken the opening token
*/
public static void getArguments( String argString, Class[] argTypes, Object[] argValues, char separator, char openingToken, char endingToken )
{
// Extract the arguments to the appropriate array
int length = argString.length();
int start = 0;
int numArgs = argTypes.length;
for ( int i = 0; i < numArgs; i++ ) {
int pos = start;
while ( pos < length ) {
char c = argString.charAt( pos );
if ( c == separator )
break;
else if ( c == openingToken )
pos = indexOfMatchingEnding( argString, openingToken, endingToken, pos+1 );
pos++;
}
String argument;
if ( pos > -1 ) {
argument = argString.substring( start, pos );
start = pos + 1;
}
else {
argument = argString.substring( start );
// Make this to be the last iteration
numArgs = 0;
}
argument = argument.trim();
char firstChar = argument.charAt( 0 );
// If the first char is a digit or a minus then assume it's a number
if ( Character.isDigit( firstChar ) || ( firstChar == '-' ) ) {
argValues[ i ] = new Integer( argument );
argTypes[ i ] = int.class;
}
else if ( argument.equals( "true" ) || argument.equals( "false" )) {
argValues[ i ] = argument.equals( "true" ) ? Boolean.TRUE : Boolean.FALSE;
argTypes[ i ] = boolean.class;
}
else {
argValues[ i ] = argument;
argTypes[ i ] = String.class;
}
}
}
/**
* Apply a style to a component
* @param comp the component
* @param styleName the style to lookup
*/
public static void applyStyle( XProject currentProject, Object comp, String styleName )
{
XStyleManager styleManager = currentProject.getStyleManager();
XStyle xstyle = styleManager.getStyle( styleName );
WidgetAdapter adapter = WidgetAdapter.getInstance();
if ( xstyle != null ) {
adapter.setFont( comp, styleManager.getFont( xstyle ) );
adapter.setBackground( comp, xstyle.getStyleAsColor( XStyle.COLOR_BACK ) );
adapter.setForeground( comp, xstyle.getStyleAsColor( XStyle.COLOR_FORE ) );
if ( comp instanceof XStyleComponent )
(( XStyleComponent)comp).setStyle( styleName );
}
}
/**
* Get the minor version of the runtime Java platform
* @return the minor version e.g. 3 for JDK 1.3.x
*/
public static int getMinorVersion()
{
String prop = System.getProperty( "java.version" );
int pos = prop.indexOf( '.' );
pos++;
int pos2 = prop.indexOf( '.', pos );
return new Integer( prop.substring( pos, pos2 ) ).intValue();
}
/**
* Find the index of the matching token, taking into account any nested pairs
* @param s the string to search
* @param endingToken the ending token
* @param openingToken the opening token
* @startPos the index at which to start the search
* @return the index of the closing token
*/
public static int indexOfMatchingEnding( String s, char openingToken, char endingToken, int startPos )
{
int nextStartPos = s.indexOf( openingToken, startPos );
int nextEndPos = s.indexOf( endingToken, startPos );
while (( nextStartPos >= 0 ) && ( nextStartPos < nextEndPos )) {
startPos = nextEndPos + 1;
nextStartPos = s.indexOf( openingToken, startPos );
if ( nextStartPos < 0 )
break;
nextEndPos = s.indexOf( endingToken, startPos );
}
if ( BuildProperties.DEBUG ) {
if ( nextEndPos < 0 )
DebugLogger.logWarning( "Failed to find closing token (\'" + endingToken + "\') in the string: " + s );
}
return nextEndPos;
}
/**
* Replace all the occurances of one string with another
* @param srcValue the source string
* @param pattern the pattern to locate
* @param replacement the replacement text
* @return the new string
*/
public static String replace( String srcValue, String pattern, String replacement )
{
int pos = 0;
while (( pos = srcValue.indexOf( pattern )) >= 0 )
srcValue = srcValue.substring( 0, pos ) + replacement + srcValue.substring( pos + pattern.length() );
return srcValue;
}
/**
* Exec a process and output the error and output streams to the console
* @param commandArray the command and arguments
* @return 0 on success, non zero otherwise
*/
public static String exec( String[] commandArray )
{
String s = null;
String result = null;
try {
// run the Unix "ps -ef" command
Process p = Runtime.getRuntime().exec( commandArray );
BufferedReader stdInput = new BufferedReader( new InputStreamReader( p.getInputStream()));
BufferedReader stdError = new BufferedReader( new InputStreamReader( p.getErrorStream()));
// read the output from the command
System.out.println( "Here is the standard output of the command:\n" );
while (( s = stdInput.readLine()) != null ) {
result += s;
System.out.println( s );
}
System.out.println( "Here is the standard error of the command (if any):\n" + s );
while (( s = stdError.readLine()) != null )
System.out.println(s);
}
catch ( IOException e ) {
System.out.println( "Unable to run the command [" + commandArray[ 0 ] +"] - here's the error: ");
e.printStackTrace();
return null;
}
return result;
}
public static String getRegistryEntry( String key )
{
try {
Process proc = Runtime.getRuntime().exec( "REG QUERY " + key );
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String result = "";
String line;
while ((line = br.readLine()) != null) {
result += line;
}
return result;
}
catch ( Exception ex ) {
System.err.println( "Encountered error : \n\n" + ex.getMessage() );
ex.printStackTrace();
}
return null;
}
/**
* Get the maximum x and y coordinates of the children
* @param cont the container whose children will be examined
* @return the coordinate of the maximum x and y
*/
public static Point getMaxCoordinates( Container cont )
{
Point pt = cont.getLocation();
int maxX = pt.x;
int maxY = pt.y;
int numChildren = cont.getComponentCount();
for ( int i = 0; i < numChildren; i++ ) {
Component comp = cont.getComponent( i );
Dimension size = comp.getSize();
Point p = comp.getLocation();
maxX = Math.max( pt.x + p.x + size.width, maxX );
maxY = Math.max( pt.y + p.y + size.height, maxY );
if ( comp instanceof Container ) {
Point childDim = getMaxCoordinates( ( Container )comp );
maxX = Math.max( childDim.x, maxX );
maxY = Math.max( childDim.y, maxY );
}
}
return new Point( maxX, maxY );
}
/**
* Convert a color to a hexadecimal string e.g. Color( 255,0,0 ) becomes ff0000.
* The alpha channel is included if used
* @param c the color to convert
* @return the string representation
*/
public static String colorToHexString( Color c )
{
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int a = c.getAlpha();
String colorValue = "" +
(( r < 16 ) ? "0" : "" ) + Integer.toString( r, 16 ) +
(( g < 16 ) ? "0" : "" ) + Integer.toString( g, 16 ) +
(( b < 16 ) ? "0" : "" ) + Integer.toString( b, 16 ) +
(( a < 16 ) ? "0" : "" ) + ( a != 255 ? Integer.toString( a, 16 ) : "" );
return colorValue;
}
/**
* Check if a URL can be opened
* @param url the url to check
* @return the url or null if it cannot be opened
*/
public static URL checkUrl( URL url )
{
try {
InputStream is = url.openStream();
is.close();
}
catch ( IOException ex )
{
return null;
}
return url;
}
/**
* Count the number of files in a folder or the child folders
* @param targetFolder the folder to search
* @return the file count
*/
public static int getFileCount( File targetFolder )
{
int fileCount = 0;
File[] contents = targetFolder.listFiles();
for ( int i = 0; i < contents.length; i++ ) {
if ( contents[ i ].isFile() )
fileCount++;
else
fileCount += getFileCount( contents[ i ] );
}
return fileCount;
}
/**
* Does the folder or its children contain files
* @param targetFolder the folder to search
* @return true if the folders contain a file
*/
public static boolean hasFiles( File targetFolder )
{
File[] contents = targetFolder.listFiles();
for ( int i = 0; i < contents.length; i++ ) {
if ( contents[ i ].isFile() || hasFiles( contents[ i ] ))
return true;
}
return false;
}
/**
* Create a compatible image for the specified image if it doe not match the
* display's color model.
* @param g2d the display graphics object
* @param img the source image
* @return the compatible image
* @since 3.2
*/
public static BufferedImage createCompatibleImage( Graphics2D g2d, BufferedImage img )
{
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
if ( img.getColorModel().equals( gc.getColorModel()))
return img;
BufferedImage bi;
if ( BuildProperties.BUILD_JDK_150 ) {
// JDK 1.5 or later
int transparency = ((Integer)ReflectionHelper.getViaReflection( "getTransparency", img )).intValue();
bi = gc.createCompatibleImage( img.getWidth(), img.getHeight(), transparency );
}
else
bi = gc.createCompatibleImage( img.getWidth(), img.getHeight());
Graphics g = bi.getGraphics();
g.drawImage( img, 0, 0, null );
g.dispose();
return bi;
}
/**
* Create a compatible image for the specified image if it doe not match the
* display's color model.
* @param g2d the graphics object/context
* @param w the width
* @param h the width
* @return the compatible image
* @since 3.2
*/
public static BufferedImage createCompatibleImage( Graphics2D g2d, int w, int h )
{
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
BufferedImage bi = gc.createCompatibleImage( w, h );
return bi;
}
}