package net.xoetrope.swing;
import java.awt.BasicStroke;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.SystemColor;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import net.xoetrope.swing.util.XGradientBorder;
import net.xoetrope.swing.util.XGradientHeaderPanel;
import net.xoetrope.xui.DialogSupport;
import net.xoetrope.xui.PageSupport;
import net.xoetrope.xui.XContentHolder;
import net.xoetrope.xui.XContentPane;
import net.xoetrope.xui.XPage;
import net.xoetrope.xui.XPageManager;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.build.BuildProperties;
import net.xoetrope.xui.helper.XuiUtilities;
/**
* <p>Provides support for Popups. This class extends XPage giving
* a blank panel on which you can create custom dialogs. The dialog can be shown
* as a modal dialog which will block execution of the client code till the
* dialog is dismissed.</p>
* <p>The XDialog is a form of page, however it contains a panel to which all the
* children are added. The panel is setup with a null layout as is normal and
* the pack method should be used to calculate the size of the dialog.</p>
* <p>The XDialog is then added to a border layout contained in either a window
* or a dialog. This parent also contains the window decorations</p>.
* <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003<br>
* License: see license.txt
* @version 1.0
*/
public class XDialog extends XPage implements XContentPane, XPage.IXDialog, DialogSupport
{
public static final int BUTTON_SIZE = 14;
/*
* Record style information for when the contentPanel is created.
*/
private Color backColour, foreColour;
private Font font;
/** A boolean value used for checking a 'true' value */
public static final boolean trueField = true;
/** The default dialog padding. the padding indents the content page within the dialog frame */
public static final int DEFAULT_PADDING = 0;
/** A state flag indicating that no button clicked so far */
public static final int NOTHING_CLICKED_YET = 0;
/** A state flag indicating that the OK button was clicked */
public static final int OK_CLICKED = 1;
/** A state flag indicating that the CANCEL button was clicked */
public static final int CANCEL_CLICKED = 2;
/** A state flag indicating that the CLOSE button was clicked */
public static final int CLOSE_CLICKED = 3;
/** A state flag indicating that the NO button was clicked */
public static final int NO_CLICKED = 4;
/** A flag indicating whether or not the dialog is modal */
protected boolean bIsModal = false;
/** A flag indicating whether or not the dialog uses the system headers or if it draws the header itself */
private boolean bUseNativeHeaders = false;
/** A flag indicating whether or not the dialog should be sizable */
private boolean bResizable = false;
/** A flag indicating whether or not the dialog automatically saves its data when it is closed */
protected boolean saveOnClose = true;
/** The return value, indicating which button was clicked */
protected int returnValue = 0;
/** The last return value */
protected static int lastReturnValue;
/** The return value, a user defined value */
public Object returnObject;
/** The 'content' panel that holds the dialog's XPage */
protected XPanel contentPanel;
/** The current dialog padding */
protected int padding = 2;
/** The component that had focus prior to display of the dialog. The dialog attempts to restore focus to this component when dismissed */
protected Component focusComponent = null;
/** Was the event dispatch thread found */
boolean QAvailable = true;
/** The name of the callback method */
private String callback;
/** The owner of the callback method */
private Component callbackParent;
/** The dialog title */
private String title = "";
/** The location at which to display the dialog specified by the user */
private Point onScreenLocation;
/** Was the close button clicked */
protected int closeButtonID = -1;
/* If true don't add the title panel */
private boolean hideFrame = false;
private boolean mouseDragged = false;
private boolean doResize = false;
private Window dialogWindow;
private static int minorVersion = 1;
private XGradientHeaderPanel titlePanel;
private static Image[] closeImages;
/**
* true to fire empty events on the EDT
*/
static final boolean bFireEmptyEvent = useEmptyEvent();
/**
* The client JFrame
*/
final Frame clientFrame;
/**
* The application window
*/
final Window appWindow;
/**
* Creates a new dialog and adds a content panel to the page. A handler is also
* set so that the dialog will be dismissed when the escape key is pressed.
*/
public XDialog()
{
super();
clientFrame = project.getAppFrame();
appWindow = project.getAppWindow();
padding = DEFAULT_PADDING;
bIsModal = true;
init();
}
/**
* Creates a new dialog and adds a content panel to the page. A handler is also
* set so that the dialog will be dismissed when the escape key is pressed.
* @param modal true for a modal dialog
* @param pad the amount of padding in pixels
*/
public XDialog( boolean modal, int pad )
{
super();
clientFrame = project.getAppFrame();
appWindow = project.getAppWindow();
padding = pad;
bIsModal = modal;
init();
}
/**
* Overload the XPage XCreated event and set the caption of the dialog from
* the title attribute. Call super if overloaded.
*/
public void pageCreated()
{
String lafAttrib = (String)getAttribute( "laf", null );
if (( lafAttrib != null ) && lafAttrib.equals( "true" )) {
contentPanel.setAttribute( "laf", "true" );
contentPanel.setAttribute( "opaque", "false" );
setBackground( contentPanel.getBackground() );
}
String canResizeStr = (String)getAttribute( "resize", null );
if ( canResizeStr != null )
bResizable = canResizeStr.equals( "true" );
String titleAttrib = (String)getAttribute( "title", null );
if ( titleAttrib != null )
setCaption( pageHelper.componentFactory.translate( titleAttrib ));
}
private void init()
{
if ( !BuildProperties.BUILD_JDK_118 ) {
Hashtable dialogList = (Hashtable)project.getObject( "DialogList" );
if ( dialogList == null ) {
dialogList = new Hashtable();
project.setObject( "DialogList", dialogList );
}
String pageName = getPageName();
if ( pageName != null )
dialogList.put( pageName, new java.lang.ref.SoftReference( this ));
}
onScreenLocation = null;
pageHelper.componentFactory.setParentComponent( this );
contentPanel = ( XPanel )pageHelper.componentFactory.addComponent( XPage.PANEL, 0, 0, 800, 600 );
if ( backColour != null )
contentPanel.setBackground( backColour );
if ( foreColour != null )
contentPanel.setForeground( foreColour );
if ( font != null )
contentPanel.setFont( font );
pageHelper.componentFactory.setParentComponent( contentPanel );
super.setVisible( false );
// The content should be sized or the pack method should be called prior to
// displaying the dialog with showDialog. The null layout allows it to setup
// according to the sizes in the XML
super.setLayout( null );
contentPanel.setLayout( null );
setBackground( Color.white );
lastReturnValue = NOTHING_CLICKED_YET;
}
/**
* Set the layout manager for the content pane
* @param lm the layout manager
*/
public void setLayout( LayoutManager lm )
{
// if ( lm != null ) {
super.setLayout( new BorderLayout());
add( contentPanel, BorderLayout.CENTER );
contentPanel.setLayout( lm );
// }
// else
// contentPanel.setLayout( lm );
}
/*
* Record the background color so the contentPanel can be set with it when created
* @param c the background color
*/
public void setBackground( Color c )
{
super.setBackground( c );
backColour = c;
}
/*
* Record the foreground color so the contentPanel can be set with it when created
* @param c the foreground color
*/
public void setForeground( Color c )
{
super.setForeground( c );
foreColour = c;
}
/**
* Set flag to indicate whether to paint the border and add the title panel
* @param hide if set to true don't add the title panel and don't paint the
* border
*/
public void setHideFrame( boolean hide )
{
hideFrame = hide;
}
/*
* Record the font so the contentPanel can be set with it when created
* @param f the font
*/
public void setFont( Font f )
{
super.setFont( f );
font = f;
}
/**
* Get the return value of the most recently dismissed dialog
* @return a value indicating the status or the button that was used to dismiss the dialog
*/
public static int getLastReturnValue()
{
return lastReturnValue;
}
/**
* The 'content' pane to which the pages are added
* @return the content pane
*/
public Object getContentPane()
{
return contentPanel;
}
/**
* Size the dialog to hold the largest components (i.e. children of the content panel)
*/
public void pack()
{
if ( padding == 0 ) {
String padStr = (String)pageHelper.attribs.get( "padding" );
if (( padStr != null ) && ( padStr.length() > 0 ))
padding = new Integer( padStr ).intValue();
}
Point size = XuiUtilities.getMaxCoordinates( contentPanel );
// Point pt = contentPanel.getLocation();
if ( padding > 0 )
setSize( size.x + 2*padding + 2, size.y + 2*padding + 4 );
else
setSize( size.x, size.y );
}
/**
* Set the dialog caption/title
* @param c the new caption
*/
public void setCaption( String c )
{
title = c;
}
/**
* Get the minimum layout size
* @return the min size
*/
public Dimension getMinimumSize()
{
return getSize();
}
/**
* Get the preferred layout size
* @return the preferred size
*/
public Dimension getPreferredSize()
{
return getSize();
}
/**
* Set the dialog to use the native platform decorations (title bar and borders).
* @param bh true to use native decorations.
*/
public void setUseNativeHeaders( boolean bh )
{
bUseNativeHeaders = bh;
}
/**
* Set the dialog to be modal or non-modal
* @param modal true for a modal dialog
*/
public void setModal( boolean modal )
{
bIsModal = modal;
}
/**
* Overrides the setVisible method to close or show the dialog
* @param b false to hide the dialog or true to show it
*/
/* public void setVisible( boolean b )
{
if ( !b )
closeDlg();
else
super.setVisible( true );
}*/
/**
* Set the save on close option
* @param save true to save the data when the dialog is closed or dismissed, false to
* discard the data.
*/
public void setSaveOnClose( boolean save )
{
saveOnClose = save;
}
/**
* Set the resizable property. The resizing of dialogs only works if native
* headers are used
* @param state true for a resizable dialog
* @since 2.0.7
* @see setUseNativeHeaders
*/
public void setResizable( boolean state )
{
bResizable = state;
}
/**
* Dismiss the dialog and discard the data.
*/
public void cancelDlg()
{
saveOnClose = false;
closeButtonID = CANCEL_CLICKED;
closeDlg();
}
/**
* Close the dialog and restore focus
*/
public void closeDlg()
{
if ( dialogWindow == null )
return;
dialogWindow.setVisible( false );
if ( callback != null ) {
try {
Class params[] = new Class[ 1 ];
params[ 0 ] = this.getClass(); //Class.forName( "net.xoetrope.xui.XDialog" );
Method m = callbackParent.getClass().getMethod( callback, params );
Object args[] = new Object[ 1 ];
args[ 0 ] = this;
m.invoke( callbackParent, args );
}
catch ( Exception ex ) {
ex.getCause().printStackTrace();
}
}
if ( focusComponent != null ) {
final Component myFocusComponent = focusComponent;
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
myFocusComponent.requestFocus();
}
} );
}
pageHelper.eventHandler.suppressFocusEvents( false );
clientFrame.setEnabled( true );
appWindow.setEnabled( true );
if (( closeButtonID != CANCEL_CLICKED ) && saveOnClose ) {
saveBoundComponentValues();
XPageManager pm = XProjectManager.getPageManager();
int numTargets = pm.getNumTargets();
// Skip any toolbars
int targetIdx = 0;
Object t = pm.getTarget( targetIdx );
if ( !( t instanceof XContentHolder ))
targetIdx++;
for ( ; targetIdx < numTargets; targetIdx++ ) {
XContentHolder targetArea = (XContentHolder)pm.getTarget( targetIdx );
PageSupport currentPage = pm.getCurrentPage( targetArea.getName());
if ( currentPage != null )
currentPage.updateBoundComponentValues();
}
}
setStatus( XPage.LOADED );
if ( closeButtonID == CLOSE_CLICKED )
lastReturnValue = CLOSE_CLICKED;
else if ( closeButtonID == CANCEL_CLICKED )
lastReturnValue = CANCEL_CLICKED;
else if ( closeButtonID == NO_CLICKED )
lastReturnValue = NO_CLICKED;
else
lastReturnValue = OK_CLICKED;
//cleanupListeners
pageHelper.eventHandler.removeHandlers( this );
((Cleanup)dialogWindow).cleanup();
dialogWindow.dispose();
pageHelper = null;
dialogWindow = null;
titlePanel = null;
contentPanel = null;
}
/**
* Shows the dialog. This method calls showDialog( this ) after setting the
* title, location and after setting the dialog to a size just large enough to
* display all its content
*
* @param owner The container to which the dialog is added.
* @param title The dialog title/caption
* @param location The location on screen to show the dialog
* @return the returnValue
*/
public int showDialog( Object owner, String title, Point location )
{
setModal( true );
setCaption( pageHelper.componentFactory.translate( title ));
setLocation( location );
pack();
return showDialog( owner );
}
/**
* Shows the dialog. For modal dialog the showDialog method blocks till the
* dialog is dismissed or hidden. This method provides an alternative that
* does not block execution of the calling thread but instead calls back a
* method specified as an argument once the dialog has been dismissed.
*
* In some VMs such as the Microsoft VM it is not possible to gain access to
* the EventQueue so as to implement blocking unless the code is loaded from a
* signed CAB file. If this situtaion occurs an exception is thrown and a
* non-blocking strategy is used.
*
* When the dialog is shown it will attempt to gain focus and upon dismissal
* focus will be returned to the component that had focus prior to display of
* the dialog. A special case occurs when the dialog is displayed in response
* to a focus event handler. The focus event will be processed as normal,
* allowing transfer of focus but focus handler invocations related to the
* showing and hiding of the dialog will be suppressed.
* @param cbParent The parent/owner for purposes of a callback.
* @param cb The name of a callback method in the parent (or null) to be invoked when the dialog is dismissed.
*/
public void showDialog( Object cbParent, String cb )
{
callbackParent = ((Container)cbParent);
callback = cb;
if ( callbackParent.getParent() == null )
showDialog( callbackParent );
else
showDialog( callbackParent.getParent() );
}
/**
* Shows the dialog. For modal dialog this method blocks till the dialog is
* dismissed or hidden. A subclass can set the returnValue member to indicate
* the status of the dialog upon dismissal.
*
* When the dialog is shown it will attempt to gain focus and upon dismissal
* focus will be returned to the component that had focus prior to display of
* the dialog. A special case occurs when the dialog is displayed in response
* to a focus event handler. The focus event will be processed as normal,
* allowing transfer of focus but focus handler invocations related to the
* showing and hiding of the dialog will be suppressed.
*
* @param owner The container to which the dialog is added.
* @return the returnValue
*/
public int showDialog( Object owner )
{
closeButtonID = -1;
if ( owner != null )
focusComponent = getFocusComponent( (Container)owner );
updateBoundComponentValues();
pageActivated();
showModalWindow( this );
// Gets around bug in the container control which doesn't diable it's child components
requestFocus();
repaint();
if ( minorVersion < 4 ) {
synchronized ( getTreeLock() ) {
Container parent = getParent();
if ( ( parent != null ) && ( parent.getPeer() == null ) )
parent.addNotify();
if ( getPeer() == null )
addNotify();
}
validate();
if ( dialogWindow.isVisible() ) {
if ( bIsModal ) {
try {
if ( QAvailable ) {
dt = new XDialogEventDispatchThread( "AWT-Dispatch-Proxy",
getToolkit().getSystemEventQueue() );
dt.start();
}
else
return -1;
}
catch ( Exception ex ) {
System.err.println( "error 1" );
ex.printStackTrace();
QAvailable = false;
return -1;
}
while ( dialogWindow.isVisible() ) {
try {
Thread.currentThread().yield();
Thread.currentThread().sleep( 100 );
}
catch ( Exception e ) {}
}
if ( dt != null )
try {
dt.stopDispatching( bFireEmptyEvent );
}
catch ( Exception ex1 ) {
}
}
else
super.show();
dt = null;
}
}
clientFrame.toFront();
return returnValue;
}
/**
* Set the size of the dialog and centres it within the parent.
* @param width The new width
* @param height The new height
*/
public void setSize( int width, int height )
{
contentPanel.setBounds( padding, padding, width - ( padding * 2 ), height - ( padding * 2 ) );
( ( XPanel )getContentPane() ).setBackground( contentPanel.getBackground());
super.setSize( width, height );
}
/**
* Set the location of the dialog window
* @param location the point on screen at which the dialog is to be shown.
*/
public void setLocation( Point location )
{
onScreenLocation = location;
if ( onScreenLocation != null ) {
Component objWindow = this;
while (( objWindow != null ) && !( objWindow instanceof Window ))
objWindow = objWindow.getParent();
if ( objWindow != null )
((Window)objWindow).setLocation( onScreenLocation );
}
}
/**
* Set the location of the dialog window
* @param x the x coordinate, or -1 for ignore/default location, -2 for centered on screen
* @param y the y coordinate
*/
public void setLocation( int x, int y )
{
if (( x >= 0 ) && ( y >= 0 ))
setLocation( new Point( x, y ));
else if ( x == -2 )
XuiUtilities.centerOnScreen( this );
}
/**
* Gets the component that owns the focus.
* @param cont the container to be checked for focus.
* @return the focus component or null if the container does not have a
* component that owns the input focus.
*/
protected Component getFocusComponent( Container cont )
{
int numChildren = cont.getComponentCount();
for ( int i = 0; i < numChildren; i++ ) {
Component c = cont.getComponent( i );
if ( c instanceof Container ) {
Component cc = getFocusComponent( ( Container )c );
if ( cc != null )
return cc;
}
else if ( ( project.getAppWindow() != null ) && ( c == project.getAppWindow().getFocusOwner() ) )
return c;
}
return null;
}
/**
* Provides access to an object representing the state of the dialog when it
* was closed. It is the responsibility of the subclass to set this value
* when it closes.
* @return the return object
*/
public Object getReturnObject()
{
return returnObject;
}
/**
* A utility method used to determine if the last event corrseponds to a mouse
* click. The notion of a click is extended by assuming the a mouse press and
* release within a single component constitutes a click even if not at the
* same coordinate. A MouseEvent.MOUSE_CLICKED is only triggered when the press
* and release are at the same location and this is often inadequate for end-user
* interaction.
* @return true if the mouse was clicked
*/
public boolean wasMouseClicked()
{
boolean res = ( closeButtonID == CLOSE_CLICKED ) || pageHelper.eventHandler.wasMouseClicked();
closeButtonID = -1;
return res;
}
/**
* Show the dialog ina modal way
* @param contents The dialog's content
*/
public void showModalWindow( Component contents )
{
class HidingWindow extends JWindow implements Cleanup, MouseListener, MouseMotionListener
{
Point startPoint;
XImageButton b = new XImageButton();
ActionListener al;
KeyListener kl;
public HidingWindow( Frame frame )
{
super( frame );
b.setImage( getCloseImage( 0 ));
b.setPressedImage( getCloseImage( 1 ));
b.setRolloverImage( getCloseImage( 2 ));
b.setBackground( SystemColor.activeCaption );
b.setOpaque( true );
addMouseListener( this );
addMouseMotionListener( this );
dialogWindow = this;
setBackground( SystemColor.control );
setLayout( new BorderLayout() );
b.addActionListener( al = new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
closeButtonID = CLOSE_CLICKED;
closeDlg();
}
} );
b.addKeyListener( kl = new KeyListener()
{
public void keyPressed( KeyEvent e )
{
if ( e.getKeyCode() == e.VK_ESCAPE ) {
closeButtonID = CANCEL_CLICKED;
closeDlg(); //setVisible( false );
}
}
public void keyReleased( KeyEvent e )
{}
public void keyTyped( KeyEvent e )
{}
} );
b.setPreferredSize( new Dimension( BUTTON_SIZE, BUTTON_SIZE ));
if ( ! hideFrame ) {
titlePanel = new XGradientHeaderPanel();
titlePanel.setLayout( new BorderLayout());
titlePanel.setText( title );
JPanel closePanel = new JPanel( new BorderLayout( 0, 0 ));
closePanel.setPreferredSize( new Dimension( BUTTON_SIZE + 4, BUTTON_SIZE + 4 ));
closePanel.setBackground( SystemColor.activeCaption );
closePanel.add( b, BorderLayout.CENTER );
titlePanel.setBackground( SystemColor.activeCaption );
titlePanel.setForeground( SystemColor.activeCaptionText );
titlePanel.add( closePanel, BorderLayout.EAST );
add( titlePanel, BorderLayout.NORTH ); // 'this' identifier is needed for Ant compilation
}
if ( !bUseNativeHeaders ) {
((JComponent)getContentPane()).setBorder( new XGradientBorder());
((JComponent)getContentPane()).setBackground( Color.cyan );
setBackground( new Color( 255, 255, 255, 0 ));
}
//pack(); // LOC 22-3-2007 Commented out dur to problems sizing the dialog bug 1677371
doLayout();
titlePanel.doLayout();
}
public void cleanup()
{
removeMouseListener( this );
removeMouseMotionListener( this );
b.removeActionListener( al );
b.removeKeyListener( kl );
al = null;
kl = null;
b = null;
}
public void setVisible( boolean show )
{
if ( show )
dialogWindow.doLayout();
super.setVisible( show );
if ( !show ) {
clientFrame.setEnabled( true );
appWindow.setEnabled( true );
clientFrame.toFront();
}
else {
toFront();
b.requestFocus();
}
}
// public void paint( Graphics g )
// {
// paintHeaders( this, g );
//
// super.paint( g );
// }
//
// Start of mouse methods-----------------------------------------------------
public void mouseClicked( MouseEvent e )
{}
public void mouseEntered( MouseEvent e )
{}
public void mouseExited( MouseEvent e )
{}
public void mouseMoved( MouseEvent e )
{
if ( bResizable ) {
Point p = e.getPoint();
if (( p.x > ( dialogWindow.getWidth() - 15 )) && ( p.y > ( dialogWindow.getHeight() - 15 )))
setCursor( Cursor.getPredefinedCursor( Cursor.SE_RESIZE_CURSOR ));
else
setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ));
}
}
public void mousePressed( MouseEvent e )
{
startPoint = e.getPoint();
if (( startPoint.x > ( dialogWindow.getWidth() - 15 )) && ( startPoint.y > ( dialogWindow.getHeight() - 15 ))) {
doResize = bResizable;
if ( !bResizable )
startPoint = null;
}
else if ( startPoint.y > titlePanel.getHeight())
startPoint = null;
}
public void mouseReleased( MouseEvent e )
{
Point endPoint = e.getPoint();
Point oldPos = getLocation();
if ( startPoint != null ) {
if ( doResize ) {
Dimension size = getSize();
resizeDialog( size.width + endPoint.x - startPoint.x, size.height + endPoint.y - startPoint.y );
startPoint = endPoint;
repaint();
}
else {
setLocation( oldPos.x + endPoint.x - startPoint.x, oldPos.y + endPoint.y - startPoint.y );
repaint();
}
}
doResize = false;
startPoint = null;
}
public void mouseDragged( MouseEvent e )
{
Point endPoint = e.getPoint();
Point oldPos = getLocation();
if ( startPoint != null ) {
if ( doResize ) {
Dimension size = getSize();
resizeDialog( size.width + endPoint.x - startPoint.x, size.height + endPoint.y - startPoint.y );
startPoint = endPoint;
repaint();
}
else {
setLocation( oldPos.x + endPoint.x - startPoint.x, oldPos.y + endPoint.y - startPoint.y );
mouseDragged = true;
repaint();
}
}
}
// End of mouse methods-------------------------------------------------------
private void resizeDialog( int width, int height )
{
setSize( width, height );
doLayout();
if ( !hideFrame ) {
titlePanel.getParent().layout();
titlePanel.layout();
}
getRootPane().layout();
contentPanel.getParent().doLayout();
contentPanel.doLayout();
}
};
class HidingDialog extends JDialog implements Cleanup, MouseListener, MouseMotionListener
{
Point startPoint;
XImageButton b = new XImageButton();
ActionListener al;
KeyListener kl;
WindowListener wl;
public HidingDialog( Frame frame )
{
super( frame, bIsModal );
setResizable( bResizable );
//getRootPane().getLayeredPane().setLayout( new BorderLayout());
b.setImage( getCloseImage( 0 ));
b.setPressedImage( getCloseImage( 1 ));
b.setRolloverImage( getCloseImage( 2 ));
b.setBackground( SystemColor.activeCaption );
b.setOpaque( true );
addMouseListener( this );
addMouseMotionListener( this );
dialogWindow = this;
if ( !bUseNativeHeaders ) {
setBackground( SystemColor.control );
this.getContentPane().setLayout( new BorderLayout() ); // 'this' identifier is needed for Ant compilation
callDecorationMethod( this, true );
b.addActionListener( al = new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
closeButtonID = CLOSE_CLICKED;
closeDlg();
}
} );
b.addKeyListener( kl = new KeyListener()
{
public void keyPressed( KeyEvent e )
{
if ( e.getKeyCode() == e.VK_ESCAPE ) {
closeButtonID = CANCEL_CLICKED;
closeDlg(); //setVisible( false );
}
}
public void keyReleased( KeyEvent e )
{}
public void keyTyped( KeyEvent e )
{}
} );
b.setPreferredSize( new Dimension( BUTTON_SIZE, BUTTON_SIZE ));
if ( !hideFrame ) {
titlePanel = new XGradientHeaderPanel();
titlePanel.setText( title );
JPanel closePanel = new JPanel( new BorderLayout( 0, 0 ));
closePanel.setBackground( SystemColor.activeCaption );
closePanel.setPreferredSize( new Dimension( BUTTON_SIZE + 4, BUTTON_SIZE + 4 ));
closePanel.add( b, BorderLayout.CENTER );
titlePanel.setBackground( SystemColor.activeCaption );
titlePanel.setForeground( SystemColor.activeCaptionText );
titlePanel.setLayout( new BorderLayout());
titlePanel.add( closePanel, BorderLayout.EAST );
this.getContentPane().add( titlePanel, BorderLayout.NORTH ); // 'this' identifier is needed for Ant compilation
}
}
else
super.setTitle( title );
addWindowListener( wl = new WindowListener()
{
public void windowClosing( WindowEvent e )
{
closeButtonID = CLOSE_CLICKED;
closeDlg();
}
public void windowActivated( WindowEvent e ){}
public void windowDeactivated( WindowEvent e ){}
public void windowClosed( WindowEvent e ){}
public void windowOpened( WindowEvent e ){}
public void windowDeiconified( WindowEvent e ){}
public void windowIconified( WindowEvent e ){}
} );
if ( !bUseNativeHeaders ) {
setBackground( new Color( 255, 255, 255, 0 ));
((JComponent)getContentPane()).setBorder( new XGradientBorder());
}
//pack(); // LOC 22-3-2007 Commented out dur to problems sizing the dialog bug 1677371
doLayout();
}
public void cleanup()
{
if ( b != null ) {
removeMouseListener( this );
removeMouseMotionListener( this );
removeWindowListener( wl );
b.removeActionListener( al );
b.removeKeyListener( kl );
wl = null;
al = null;
kl = null;
b = null;
}
}
// Start of mouse methods-----------------------------------------------------
public void mouseClicked( MouseEvent e )
{}
public void mouseEntered( MouseEvent e )
{}
public void mouseExited( MouseEvent e )
{}
public void mouseMoved( MouseEvent e )
{
if ( bResizable ) {
Point p = e.getPoint();
if (( p.x > ( dialogWindow.getWidth() - 15 )) && ( p.y > ( dialogWindow.getHeight() - 15 )))
setCursor( Cursor.getPredefinedCursor( Cursor.SE_RESIZE_CURSOR ));
else
setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ));
}
}
public void mousePressed( MouseEvent e )
{
startPoint = e.getPoint();
if (( startPoint.x > ( dialogWindow.getWidth() - 15 )) && ( startPoint.y > ( dialogWindow.getHeight() - 15 ))) {
doResize = bResizable;
if ( !bResizable )
startPoint = null;
}
else if ( ( ! hideFrame ) && startPoint.y > titlePanel.getHeight())
startPoint = null;
}
public void mouseReleased( MouseEvent e )
{
Point endPoint = e.getPoint();
Point oldPos = getLocation();
if ( startPoint != null ) {
if ( doResize ) {
Dimension size = getSize();
resizeDialog( size.width + endPoint.x - startPoint.x, size.height + endPoint.y - startPoint.y );
startPoint = endPoint;
repaint();
}
else {
setLocation( oldPos.x + endPoint.x - startPoint.x, oldPos.y + endPoint.y - startPoint.y );
repaint();
}
}
doResize = false;
startPoint = null;
}
public void mouseDragged( MouseEvent e )
{
Point endPoint = e.getPoint();
Point oldPos = getLocation();
if ( startPoint != null ) {
if ( doResize ) {
Dimension size = getSize();
resizeDialog( size.width + endPoint.x - startPoint.x, size.height + endPoint.y - startPoint.y );
startPoint = endPoint;
repaint();
}
else {
setLocation( oldPos.x + endPoint.x - startPoint.x, oldPos.y + endPoint.y - startPoint.y );
mouseDragged = true;
repaint();
}
}
}
// End of mouse methods-------------------------------------------------------
private void resizeDialog( int width, int height )
{
setSize( width, height );
doLayout();
titlePanel.getParent().layout();
titlePanel.layout();
getRootPane().layout();
contentPanel.getParent().doLayout();
contentPanel.doLayout();
}
};
dialogWindow = ( ( !bUseNativeHeaders && ( minorVersion < 4 ) ) ?
( Window )new HidingWindow( clientFrame ) :
new HidingDialog( clientFrame ) );
if ( dialogWindow instanceof JDialog )
( ( JDialog )dialogWindow ).getContentPane().add( contents, BorderLayout.CENTER );
else
dialogWindow.add( contents, BorderLayout.CENTER );
contents.setVisible( true );
setStatus ( XPage.ACTIVATED );
dialogWindow.pack();
Dimension wSize = dialogWindow.getSize();
if ( onScreenLocation != null )
dialogWindow.setLocation( onScreenLocation );
else
dialogWindow.setLocation( appWindow.getLocation().x + ( appWindow.getSize().width / 2 - wSize.width / 2 ),
appWindow.getLocation().y + ( appWindow.getSize().height / 2 - wSize.height / 2 ) );
/**
* @todo This needs to be retested with different JDKs. Suspect that the
* check should be if ( ! bUseNativeHeaders && bIsModal )
*/
if ( bUseNativeHeaders && bIsModal ) {
clientFrame.setEnabled( false );
appWindow.setEnabled( false );
}
dialogWindow.doLayout();
dialogWindow.setVisible( true );
if (( dialogWindow != null ) && dialogWindow.isValid())
dialogWindow.repaint();
}
/**
* The event dispatch mechanism inserts an empty event when stopping dispatching.
* This mechanism fails on some VMs. This method determines whether or not to
* use the mechanism. It does not work for the MS VM (1.1.4) for instance.
* @return true to use the empty event mechanism.
*/
private static boolean useEmptyEvent()
{
minorVersion = XuiUtilities.getMinorVersion();
if ( minorVersion < 2 )
return true;
return true;
}
/**
* Call setUndecorated via reflection as it is only in JDK1.4+
* @param obj a reference to the dialog instance
* @param value the boolean argument
* @return true if the call succeeds
*/
private boolean callDecorationMethod( Object obj, boolean value )
{
try {
Class c = obj.getClass();
Field f = this.getClass().getField( "trueField" );
Class[] params = new Class[ 1 ];
params[ 0 ] = f.getType();
Method theMethod = c.getMethod( "setUndecorated", params );
// String methodString = theMethod.getName();
Object args[] = new Object[ 1 ];
args[ 0 ] = f.get( this );
theMethod.invoke( obj, args );
return true;
}
catch ( Exception ex ) {
ex.getCause().printStackTrace();
}
return false;
}
private Image getCloseImage( int state )
{
if ( closeImages == null )
closeImages = new Image[ 3 ];
if ( closeImages[ state ] == null ) {
if ( !hideFrame ) {
closeImages[ state ] = new BufferedImage( 14, 14, BufferedImage.TYPE_INT_ARGB );
Graphics2D g2d = (Graphics2D)closeImages[ state ].getGraphics();
Object hint = g2d.getRenderingHint( RenderingHints.KEY_RENDERING );
g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
g2d.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY );
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
g2d.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g2d.setColor( Color.white );
Area borderArea = new Area( new RoundRectangle2D.Double( 0.0, 0.0, BUTTON_SIZE, BUTTON_SIZE, 4.0, 4.0 ));
g2d.fill( borderArea );
// Rotate the color by 180 degrees
Color frgdColor = SystemColor.activeCaption;
float f[] = frgdColor.RGBtoHSB( frgdColor.getRed(), frgdColor.getGreen(), frgdColor.getBlue(), null );
frgdColor = Color.RED;//Color.getHSBColor(( f[ 0 ] + 0.5F ) % 1.0F, 1.0F, 1.0F );
frgdColor = ( state == 0 ? frgdColor.darker() : state == 1 ? frgdColor.darker().darker() : frgdColor );
GradientPaint gradient = new GradientPaint( 0.0F, 0.0F, frgdColor,
(float)BUTTON_SIZE/2.0F, (float)BUTTON_SIZE/2.0F,
frgdColor.darker(), true );
Area innerArea = new Area( new RoundRectangle2D.Double( 1.0, 1.0, BUTTON_SIZE-2.0, BUTTON_SIZE-2.0, 4.0, 4.0 ));
g2d.setPaint( gradient );
g2d.fill( innerArea );
g2d.setColor( state == 1 ? Color.white.darker() : Color.white );
g2d.setStroke( new BasicStroke( 2.0F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ));
Line2D.Double l1 = new Line2D.Double( 3.4, 3.4, 4.7, 4.7 );
g2d.draw( l1 );
g2d.drawLine( 7, 7, BUTTON_SIZE-4, BUTTON_SIZE-4 );
g2d.drawLine( BUTTON_SIZE-4, 3, 4, BUTTON_SIZE-4 );
g2d.setRenderingHint( RenderingHints.KEY_RENDERING, hint );
g2d.dispose();
}
}
return closeImages[ state ];
}
private XDialogEventDispatchThread dt = null;
}
interface Cleanup
{
public void cleanup();
}