Package net.xoetrope.swing

Source Code of net.xoetrope.swing.HidingWindow

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();
}
TOP

Related Classes of net.xoetrope.swing.HidingWindow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.