All Downloads are FREE. Search and download functionalities are using the official Maven repository.

editor.search.StudioUtilities Maven / Gradle / Ivy

package editor.search;

import editor.BasicGosuEditor;
import editor.RunMe;

import javax.swing.*;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import static editor.util.EditorUtilities.handleUncaughtException;

/**
 * Sundry ui utility methods.
 */
public class StudioUtilities implements SwingConstants
{
  static final HashMap ICON_TABLE = new HashMap();

  static protected Rectangle g_rcClipCursor;
  static protected ClipCursorHandler g_clipCursorListener;
  static protected Robot g_robot;

  static final Rectangle RCTEXT = new Rectangle();
  static final Rectangle SHOULDPAINT_RECT = new Rectangle();
  static final Rectangle SHOULDPAINT_RECT_IN = new Rectangle();
  static Map CONTAINS_FOCUS;
  static Map FOCUS_CONTAINS;

  private StudioUtilities()
  {
  }

  public static void enableComponent( Component c, boolean bEnabled )
  {
    if( c.isEnabled() != bEnabled )
    {
      c.setEnabled( bEnabled );
    }

    if( c instanceof Container )
    {
      Component[] children = ((Container)c).getComponents();
      if( children != null )
      {
        for( Component child : children )
        {
          enableComponent( child, bEnabled );
        }
      }
    }
  }

  public static Component getFocus()
  {
    return KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
  }

  public static Window getFocusedWindow()
  {
    return KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
  }

  public static Window getActiveWindow()
  {
    Window activeWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
    if( activeWindow == null )
    {
      Frame[] frames = Frame.getFrames();
      if( frames != null && frames.length > 0 )
      {
        return frames[0];
      }
    }
    return activeWindow;
  }

  public static boolean containsFocus( Component c )
  {
    addFocusListener();
    Boolean containsFocus = CONTAINS_FOCUS.get( c );
    if( containsFocus != null )
    {
      return containsFocus;
    }
    Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
    // Verify focusOwner is a descendant of c
    for( Component temp = focusOwner; temp != null; temp = (temp instanceof Window) ? null : temp.getParent() )
    {
      if( temp == c )
      {
        CONTAINS_FOCUS.put( c, true );
        return true;
      }
    }
    CONTAINS_FOCUS.put( c, false );
    return false;
  }

  public static boolean focusContains( Component c )
  {
    addFocusListener();

    Boolean focusContains = FOCUS_CONTAINS.get( c );
    if( focusContains != null )
    {
      return focusContains;
    }
    Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
    // Verify c is a descendant of focusOwner
    for( Component temp = c; temp != null; temp = (temp instanceof Window) ? null : temp.getParent() )
    {
      if( temp == focusOwner )
      {
        FOCUS_CONTAINS.put( c, true );
        return true;
      }
    }
    FOCUS_CONTAINS.put( c, false );
    return false;
  }

  private static void addFocusListener()
  {
    if( CONTAINS_FOCUS != null )
    {
      return;
    }
    CONTAINS_FOCUS = new HashMap();
    FOCUS_CONTAINS = new HashMap();
    KeyboardFocusManager focusMgr = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    focusMgr.addPropertyChangeListener( "permanentFocusOwner",
                                        new PropertyChangeListener()
                                        {
                                          public void propertyChange( PropertyChangeEvent evt )
                                          {
                                            CONTAINS_FOCUS.clear();
                                            FOCUS_CONTAINS.clear();
                                          }
                                        } );
  }

  public static boolean isInFocusLineage( Component c )
  {
    return containsFocus( c ) || focusContains( c );
  }

  public static void centerWindowInFrame( Component window, Window frame )
  {
    // Note FileDialog instances in jdk 1.4.1 have no size until FileDialog.show()
    // which blocks i.e., we can't center FileDialogs.

    Dimension dimCenter;
    Point ptOffset;
    if( frame != null )
    {
      if( (!(frame instanceof Frame) || ((Frame)frame).getState() != Frame.ICONIFIED) && frame.isShowing() )
      {
        // Center in frame
        dimCenter = frame.getSize();
        ptOffset = frame.getLocation();
      }
      else
      {
        // Retry either containing window or screen
        centerWindowInFrame( window, null );
        return;
      }
    }
    else
    {
      Window owner = SwingUtilities.getWindowAncestor( window );
      if( owner != null && owner.isShowing() && (owner.getMinimumSize().height < owner.getHeight()) )
      {
        // Retry with owner window as frame
        if( (!(owner instanceof Frame) || ((Frame)owner).getState() != Frame.ICONIFIED) && owner.isShowing() )
        {
          // Center in frame
          dimCenter = owner.getSize();
          ptOffset = owner.getLocation();
          window.setLocation( ptOffset.x + (dimCenter.width - window.getWidth()) / 2, ptOffset.y + (dimCenter.height - window.getHeight()) / 2 );
        }

        return;
      }

      // Center in screen
      Rectangle screenRect = getPrimaryMonitorScreenRect();
      dimCenter = new Dimension( (int)screenRect.getWidth(), (int)screenRect.getHeight() );
      ptOffset = new Point( (int)screenRect.getX(), (int)screenRect.getY() );
    }

    window.setLocation( ptOffset.x + (dimCenter.width - window.getWidth()) / 2, ptOffset.y + (dimCenter.height - window.getHeight()) / 2 );
  }

//  public Point getCenterOfActiveWindow()
//  {
//    Window activeWin = getActiveWindow();
//    Rectangle rc = null;
//    if( activeWin == null )
//    {
//      Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
//      rc = new Rectangle( 0, 0, dim.width, dim.height );
//    }
//    else
//    {
//      rc = activeWin.getBounds();
//    }
//  }

  public static void removePopupBorder( final Container c )
  {
    EventQueue.invokeLater(
      new Runnable()
      {
        public void run()
        {
          Container p = c;
          while( p != null )
          {
            if( p instanceof JComponent )
            {
              ((JComponent)p).setBorder( null );
            }
            p = p.getParent();
          }
        }
      } );
  }

  /**
   * @param comp the component to analyze
   *
   * @return the root pane for the component
   */
  public static JRootPane rootPaneForComponent( Component comp )
  {
    for( Component p = comp; p != null; p = p.getParent() )
    {
      if( p instanceof JRootPane )
      {
        return (JRootPane)p;
      }

      if( comp instanceof JFrame )
      {
        return ((JFrame)comp).getRootPane();
      }

      if( comp instanceof JDialog )
      {
        return ((JDialog)comp).getRootPane();
      }

      if( comp instanceof JWindow )
      {
        return ((JWindow)comp).getRootPane();
      }
    }

    return null;
  }

  public static Component showWaitCursor( final boolean bWait )
  {
    return WaitCursorRunner.showWaitCursor( bWait );
  }

  public static void showWaitCursor( boolean bWait, Component c )
  {
    WaitCursorRunner.showWaitCursor( bWait, c );
  }

  public static void doWaitOperation( Runnable op )
  {
    Component key = StudioUtilities.showWaitCursor( true );
    try
    {
      op.run();
    }
    finally
    {
      showWaitCursor( false, key );
    }
  }

  public static String wrapText( String strText )
  {
    return wrapText( strText, 60 );
  }

  public static String wrapText( String strText, int iLineLen )
  {
    Vector vStrings = drawTextWrapped( null, new Rectangle(), strText, new Font( "Tahoma", Font.PLAIN, 11 ), iLineLen, false, true );
    String strRet = "";
    for( int i = 0; i < vStrings.size(); i++ )
    {
      strRet += vStrings.elementAt( i );
    }

    return strRet;
  }

  public static void invokeInDispatchThread( Runnable task )
  {
    if( task == null )
    {
      return;
    }

    if( EventQueue.isDispatchThread() )
    {
      task.run();
    }
    else
    {
      try
      {
        EventQueue.invokeAndWait( task );
      }
      catch( Throwable t )
      {
        handleUncaughtException( t );
      }
    }
  }

  public static void invokeNowOrLater( Runnable task )
  {
    if( task == null )
    {
      return;
    }

    if( EventQueue.isDispatchThread() )
    {
      task.run();
    }
    else
    {
      try
      {
        EventQueue.invokeLater( task );
      }
      catch( Throwable t )
      {
        handleUncaughtException( t );
      }
    }
  }

  public static Rectangle drawStringInRectClipped( Graphics g, String strText, Rectangle rcClip, int iHorzAlign, int iVertAlign )
  {
    return drawStringInRectClipped( g, null, strText, rcClip, iHorzAlign, iVertAlign, true );
  }

  public static Rectangle drawStringInRectClipped( Graphics g, FontMetrics fm, String strText, Rectangle rcClip, int iHorzAlign, int iVertAlign, boolean bReturnBounds )
  {
    RCTEXT.setBounds( 0, 0, 0, 0 );
    MessageDisplay.SCRATCH_RECT.setBounds( 0, 0, 0, 0 );
    fm = fm == null ? g.getFontMetrics() : fm;

    String str = SwingUtilities.layoutCompoundLabel( fm,
                                                     strText,
                                                     null, // no icon
                                                     iVertAlign, // vertical alignment
                                                     iHorzAlign, // horizontal alignment
                                                     BOTTOM, // vertical text pos relative to icon
                                                     RIGHT, // horizontal text pos relative to icon
                                                     rcClip,
                                                     MessageDisplay.SCRATCH_RECT,
                                                     RCTEXT,
                                                     0 );    // text/icon gap

    if( str != null && !str.equals( "" ) )
    {
      g.drawString( str, RCTEXT.x, RCTEXT.y + fm.getAscent() );
    }

    return bReturnBounds ? new Rectangle( RCTEXT ) : null;
  }

  public static void drawStringInRect( Graphics g, String strText, Rectangle rc, int justification, boolean bClip )
  {
    drawStringInRect( g, strText, rc.x, rc.y, rc.width, rc.height, justification, bClip );
  }

  public static void drawStringInRect( Graphics g, String strText, int x, int y,
                                       int width, int height, int justification, boolean bClip )
  {
    FontMetrics fontMetrics;
    int drawWidth, startX, startY, delta;

    if( g.getFont() == null )
    {
      return;
    }
    fontMetrics = g.getFontMetrics();
    if( fontMetrics == null )
    {
      return;
    }

    if( bClip )
    {
      MessageDisplay.SCRATCH_RECT.setBounds( g.getClipBounds() );

      MessageDisplay.SCRATCH_RECT2.setBounds( x, y, width, height );
      if( MessageDisplay.SCRATCH_RECT.intersects( MessageDisplay.SCRATCH_RECT2 ) )
      {
        MessageDisplay.SCRATCH_RECT2.setBounds( MessageDisplay.SCRATCH_RECT.intersection( MessageDisplay.SCRATCH_RECT2 ) );
        g.setClip( MessageDisplay.SCRATCH_RECT2 );
      }
      else
      {
        return;
      }
    }

    if( justification == CENTER )
    {
      drawWidth = fontMetrics.stringWidth( strText );
      if( drawWidth > width )
      {
        drawWidth = width;
      }
      startX = x + (width - drawWidth) / 2;
    }
    else if( justification == RIGHT )
    {
      drawWidth = fontMetrics.stringWidth( strText );
      if( drawWidth > width )
      {
        drawWidth = width;
      }
      startX = x + width - drawWidth;
    }
    else
    {
      startX = x;
    }

    delta = (height - fontMetrics.getAscent() - fontMetrics.getDescent()) / 2;
    if( delta < 0 )
    {
      delta = 0;
    }

    startY = y + height - delta - fontMetrics.getDescent();

    g.drawString( strText, startX, startY );

    if( bClip )
    {
      g.setClip( MessageDisplay.SCRATCH_RECT );
    }
  }

  public static boolean shouldPaint( Graphics g, Component comp )
  {
    Rectangle rcBounds = comp.getBounds();
    return shouldPaint( g, rcBounds.x, rcBounds.y, rcBounds.width, rcBounds.height );
  }

  public static boolean shouldPaint( Graphics g, int x, int y, int iWidth, int iHeight )
  {
    Rectangle rcClipBounds = g.getClipBounds();
    if( rcClipBounds == null )
    {
      return true;
    }

    SHOULDPAINT_RECT.setBounds( rcClipBounds );
    SHOULDPAINT_RECT_IN.setBounds( x, y, iWidth, iHeight );

    return SHOULDPAINT_RECT.intersects( SHOULDPAINT_RECT_IN );
  }

  public static Vector drawTextWrapped( Graphics g, Rectangle rect, String strText )
  {
    return drawTextWrapped( g, rect, strText, null, 0, true, true );
  }

  public static Vector drawTextWrapped( Graphics g, Rectangle rect, String strText, Font font, int iLineLengthChars, boolean bClip, boolean bAppendLineFeed )
  {
    try
    {
      Vector vStrings = (g == null) ? new Vector() : null;

      if( bClip && (g != null) && (rect != null) && !rect.isEmpty() )
      {
        MessageDisplay.SCRATCH_RECT.setBounds( g.getClipBounds() );

        MessageDisplay.SCRATCH_RECT2.setBounds( rect.x, rect.y, rect.width, rect.height );
        if( MessageDisplay.SCRATCH_RECT.intersects( MessageDisplay.SCRATCH_RECT2 ) )
        {
          MessageDisplay.SCRATCH_RECT2.setBounds( MessageDisplay.SCRATCH_RECT.intersection( MessageDisplay.SCRATCH_RECT2 ) );
          g.setClip( MessageDisplay.SCRATCH_RECT2 );
        }
        else
        {
          return vStrings;
        }
      }
      else
      {
        bClip = false;
      }

      if( strText == null || strText.length() == 0 ||
          ((iLineLengthChars <= 0) && (rect == null || rect.width == 0)) )
      {
        return vStrings;
      }

      // Replace tabs with single spaces
      strText = (strText.indexOf( '\t' ) >= 0) ? strText.replace( '\t', ' ' ) : strText;

      FontMetrics fm = (g == null) ? Toolkit.getDefaultToolkit().getFontMetrics( font ) : g.getFontMetrics();

      if( iLineLengthChars > 0 )
      {
        rect.width = fm.charWidth( 'p' ) * iLineLengthChars;
      }

      int x = rect.x;
      int y = rect.y + fm.getAscent();
      int iWidth = rect.width;
      if( iWidth < 0 )
      {
        return vStrings;
      }

      boolean bSkip;
      String strLine = "";

      boolean bNeedToDrawLastToken = false;

      StringTokenizer tokenizer = new StringTokenizer( strText, MessageDisplay.STRING_DELIMITERS, true );
      String token = null;
      while( tokenizer.hasMoreTokens() || bNeedToDrawLastToken )
      {
        token = bNeedToDrawLastToken ? token : tokenizer.nextToken();

        bSkip = false;

        for( int i = 0; i < MessageDisplay.STRING_DELIMITERS.length(); i++ )
        {
          if( token.charAt( 0 ) == MessageDisplay.STRING_DELIMITERS.charAt( i ) )
          {
            // Skip all delimiters but spaces and new lines, they have effect on output.
            if( MessageDisplay.STRING_DELIMITERS.charAt( i ) != ' ' &&
                MessageDisplay.STRING_DELIMITERS.charAt( i ) != '\n' )
            {
              bSkip = true;
            }
            break;
          }
        }

        if( bSkip )
        {
          continue;
        }

        bNeedToDrawLastToken = !tokenizer.hasMoreTokens();

        int iLinePlusToken = fm.stringWidth( strLine ) + fm.stringWidth( token );

        // if( bNeedToDrawLastToken && (iLinePlusToken <= iWidth) )
        // {
        //   strLine = strLine.concat( token );
        //   bNeedToDrawLastToken = false;
        // }

        boolean bLastLineOfRect = false;
        if( bNeedToDrawLastToken )
        {
          if( (iLinePlusToken <= iWidth) ||
              (bLastLineOfRect = (rect.height > 0) && ((rect.y + rect.height) < (y - fm.getAscent() + fm.getHeight() + fm.getAscent() / 2))) )// last line of the rectangle
          {
            // Force the last token to paint if:
            //
            // 1.) We have room for it on the line
            // 2.) We are on the last *visible* line in our bounds.
            //     Note determining the last visible line is a fuzzy scheme as the math above shows.

            strLine = strLine.concat( token );
            bNeedToDrawLastToken = false;
          }
        }


        if( (iLinePlusToken > iWidth) ||
            (token.charAt( 0 ) == '\n') ||
            !tokenizer.hasMoreTokens() ) // Force draw of last line
        {
          if( (strLine.length() > 0) &&
              ((token.charAt( 0 ) == '\n') || tokenizer.hasMoreTokens() || (iLinePlusToken <= iWidth) || bNeedToDrawLastToken || bLastLineOfRect) )
          {
            if( g != null )
            {
              g.drawString( strLine, x, y );
            }
            if( vStrings != null )
            {
              vStrings.addElement( bAppendLineFeed ? (strLine + "\n") : strLine );
            }

            y += fm.getHeight();

            strLine = "";

            if( token.charAt( 0 ) == ' ' ||
                token.charAt( 0 ) == '\n' )
            {
              continue;
            }
          }
          else if( token.charAt( 0 ) == '\n' )
          {
            y += fm.getHeight();
            continue;
          }
          else
          {
            do
            {
              if( token.length() == 1 )
              {
                // Rectangle isn't wide enough to display a single character.
                return vStrings;
              }

              int iSeg = token.length() / 2 + token.length() % 2;

              int iLen = iSeg;

              String strTokenPart = null;

              while( iSeg >= 1 )
              {
                try
                {
                  strTokenPart = token.substring( 0, iLen - 1 );
                }
                catch( Exception e )
                {
                  // ignore
                }

                int iTestWidth = fm.stringWidth( strTokenPart );

                iSeg = iSeg / 2 + (iSeg == 1 ? 0 : iSeg % 2);

                if( iTestWidth > iWidth )
                {
                  iLen -= iSeg;
                }
                else if( iTestWidth == iWidth )
                {
                  break;
                }
                else
                {
                  iLen += iSeg;
                }
              }

              if( strTokenPart != null )
              {
                if( strText.startsWith( "" ) && strTokenPart.lastIndexOf( "<" ) > strTokenPart.lastIndexOf( ">" ) )
                {
                  strTokenPart = strTokenPart.substring( 0, strTokenPart.lastIndexOf( "<" ) );
                  iLen = strTokenPart.length();
                }
                if( g != null )
                {
                  g.drawString( strTokenPart, x, y );
                }
                if( vStrings != null )
                {
                  vStrings.addElement( bAppendLineFeed ? (strTokenPart + "\n") : strTokenPart );
                }
              }
              else
              {
                break;
              }

              y += fm.getHeight();

              if( iLen >= token.length() )
              {
                // We're drawing the token anyway, so we might as well just leave
                bNeedToDrawLastToken = false;
                break;
              }

              token = token.substring( strTokenPart.length() );

            }
            while( fm.stringWidth( token ) > iWidth );
          }
        }

        strLine = bNeedToDrawLastToken ? "" : strLine.concat( token );
      }

      if( bAppendLineFeed && !vStrings.isEmpty() )
      {
        // Remove the last line feed

        String strLast = vStrings.lastElement();
        if( strLast.endsWith( "\n" ) )
        {
          vStrings.setElementAt( strLast.substring( 0, strLast.length() - 1 ), vStrings.size() - 1 );
        }
      }

      return vStrings;
    }
    finally
    {
      if( bClip )
      {
        g.setClip( MessageDisplay.SCRATCH_RECT );
      }
    }
  }

  public static Frame frameForComponent( Component comp )
  {
    for( Component p = comp; p != null; p = p.getParent() )
    {
      if( p instanceof Frame )
      {
        return (Frame)p;
      }
    }

    return null;
  }

  public static Window windowForComponent( Component comp )
  {
    for( Component p = comp; p != null; p = p.getParent() )
    {
      if( p instanceof Window )
      {
        return (Window)p;
      }
    }

    return null;
  }

  public static Robot getRobot()
  {
    if( g_robot == null )
    {
      try
      {
        g_robot = new Robot();
      }
      catch( AWTException e )
      {
        throw new RuntimeException( e );
      }
    }
    return g_robot;
  }

  public static void clipCursor( Rectangle rcScreen )
  {
    if( rcScreen == null || rcScreen.isEmpty() )
    {
      if( g_clipCursorListener != null )
      {
        Toolkit.getDefaultToolkit().removeAWTEventListener( g_clipCursorListener );
        g_clipCursorListener = null;
      }

      g_rcClipCursor = null;

      return;
    }

    g_clipCursorListener = new ClipCursorHandler();
    g_rcClipCursor = rcScreen;

    Toolkit.getDefaultToolkit().addAWTEventListener( g_clipCursorListener, AWTEvent.MOUSE_MOTION_EVENT_MASK );
  }

  public static boolean clipPoint( Point pt )
  {
    if( g_rcClipCursor == null || g_rcClipCursor.contains( pt ) )
    {
      return false;
    }

    if( pt.x < g_rcClipCursor.x )
    {
      pt.x = g_rcClipCursor.x;
    }

    if( pt.x >= g_rcClipCursor.x + g_rcClipCursor.width )
    {
      pt.x = g_rcClipCursor.x + g_rcClipCursor.width - 1;
    }

    if( pt.y < g_rcClipCursor.y )
    {
      pt.y = g_rcClipCursor.y;
    }

    if( pt.y >= g_rcClipCursor.y + g_rcClipCursor.height )
    {
      pt.y = g_rcClipCursor.y + g_rcClipCursor.height - 1;
    }

    getRobot().mouseMove( pt.x, pt.y );

    return true;
  }

  public static Dimension boundDimensionWithin( Dimension preferredSize, Dimension minimumSize, Dimension maxSize )
  {
    return boundWithMax( maxSize, boundWithMin( minimumSize, preferredSize ) );
  }

  private static Dimension boundWithMin( Dimension minimumSize, Dimension preferredSize )
  {
    if( minimumSize == null )
    {
      return preferredSize;
    }

    if( preferredSize == null )
    {
      return minimumSize;
    }


    return new Dimension( Math.max( preferredSize.width, minimumSize.width ),
                          Math.max( preferredSize.height, minimumSize.height ) );
  }

  private static Dimension boundWithMax( Dimension maxSize, Dimension preferredSize )
  {
    if( maxSize == null )
    {
      return preferredSize;
    }

    if( preferredSize == null )
    {
      return maxSize;
    }


    return new Dimension( Math.min( preferredSize.width, maxSize.width ),
                          Math.min( preferredSize.height, maxSize.height ) );
  }

  public static void invalidateTree( Component component )
  {
    component.invalidate();
    if( component instanceof Container )
    {
      for( Component child : ((Container)component).getComponents() )
      {
        invalidateTree( child );
      }
    }
  }

  /**
   * Finds the first widget above the passed in widget of the given class
   *
   * @param start  the start component
   * @param aClass the class to find
   *
   * @return the found component
   */
  public static  T findAncestor( Component start, Class aClass )
  {
    if( start == null )
    {
      return null;
    }
    return findAtOrAbove( start.getParent(), aClass );
  }

  /**
   * Finds the first widget at or above the passed in widget of the given class
   *
   * @param start  the start component
   * @param aClass the class to find
   *
   * @return the found component
   */
  public static  T findAtOrAbove( Component start, Class aClass )
  {
    Component comp = start;
    while( comp != null )
    {
      if( aClass.isInstance( comp ) )
      {
        //noinspection unchecked
        return (T)comp;
      }
      else
      {
        comp = comp.getParent();
      }
    }
    return null;
  }

  public static void ensureWindowIsVisible( Window w )
  {
    int width = w.getWidth();
    int height = w.getHeight();
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    GraphicsConfiguration gc = w.getGraphicsConfiguration();
    Insets screenInsets = toolkit.getScreenInsets( gc );
    Rectangle screenSize = gc.getBounds();
    w.setLocation( Math.max( screenInsets.left, Math.min( w.getX(), screenSize.width - screenInsets.right - width ) ),
                   Math.max( screenInsets.top, Math.min( w.getY(), screenSize.height - screenInsets.bottom - height ) ) );
  }

  public static void hideToolTip( JComponent c )
  {
    try
    {
      Method hideMethod = ToolTipManager.class.getDeclaredMethod( "hide", JComponent.class );
      hideMethod.setAccessible( true );
      hideMethod.invoke( ToolTipManager.sharedInstance(), c );
    }
    catch( Exception e )
    {
      throw new RuntimeException( e );
    }
  }

  public static void convertRectangleToScreen( Rectangle rectangle, Component component )
  {
    Point loc = rectangle.getLocation();
    SwingUtilities.convertPointToScreen( loc, component );
    rectangle.setLocation( loc );
  }

  /**
   */
  static final class ClipCursorHandler implements AWTEventListener
  {
    public void eventDispatched( AWTEvent e )
    {
      if( e instanceof MouseEvent )
      {
        MouseEvent me = (MouseEvent)e;

        switch( me.getID() )
        {
          //
          // Process MouseMotion events only
          //
          case MouseEvent.MOUSE_MOVED:
          case MouseEvent.MOUSE_DRAGGED:
          {
            Component comp = me.getComponent();
            if( comp == null )
            {
              break;
            }

            Point pt = me.getPoint();
            SwingUtilities.convertPointToScreen( pt, comp );

            if( clipPoint( pt ) )
            {
              me.consume();
            }

            break;
          }

          default:
            break;
        }
      }
    }
  }


  /**
   */
  static final class WaitCursorRunner
  {
    private static final WaitCursorRunner WAIT_CURSOR_RUNNER = new WaitCursorRunner();

    private WeakHashMap _waitCursorMap;
    private WeakHashMap _rootPaneMap;
    private boolean _bWait;
    private WeakReference _c;

    private WaitCursorRunner()
    {
      _waitCursorMap = new WeakHashMap();
      _rootPaneMap = new WeakHashMap();
    }

    static Component showWaitCursor( boolean bWait )
    {
      if( !EventQueue.isDispatchThread() )
      {
        // Can only do this safely from within the AWT Dispatch thread.
        // Also note we can't make any assumptions about interaction between
        // the AWT Dispatch thread and other threads e.g., we can't call invokeAndWait() here.
        return null;
      }

      WAIT_CURSOR_RUNNER._bWait = bWait;
      WAIT_CURSOR_RUNNER._c = null;
      return WAIT_CURSOR_RUNNER.run();
    }

    static void showWaitCursor( boolean bWait, Component c )
    {
      if( !EventQueue.isDispatchThread() )
      {
        // Can only do this safely from within the AWT Dispatch thread.
        // Also note we can't make any assumptions about interaction between
        // the AWT Dispatch thread and other threads e.g., we can't call invokeAndWait() here.
        return;
      }

      WAIT_CURSOR_RUNNER._bWait = bWait;
      WAIT_CURSOR_RUNNER._c = new WeakReference( c );
      WAIT_CURSOR_RUNNER.run();
    }

    public Component run()
    {
      if( _c != null )
      {
        JRootPane rootPane = _rootPaneMap.get( _c.get() );
        if( rootPane != null )
        {
          showWaitCursorNow( _bWait, rootPane );
          return rootPane;
        }
      }

      Component focus = _c == null ? getActiveWindow() : _c.get();
      focus = focus == null ? getFocusedWindow() : focus;

      JRootPane rootPane = rootPaneForComponent( focus );
      if( rootPane == null )
      {
        // Just use the active window's rootpane.
        // (e.g., the component is no longer attatched to a rootpane
        focus = getActiveWindow();
        focus = focus == null ? getFocusedWindow() : focus;

        rootPane = rootPaneForComponent( focus );
        if( rootPane == null )
        {
          return null;
        }
      }

      if( !_bWait && !rootPane.isShowing() )
      {
        Window win = StudioUtilities.windowForComponent( rootPane );
        if( win != null )
        {
          win = win.getOwner();
          if( win != null )
          {
            rootPane = rootPaneForComponent( win );
          }
        }
      }

      _rootPaneMap.put( focus, rootPane );

      showWaitCursorNow( _bWait, rootPane );

      return rootPane;
    }

    void showWaitCursorNow( boolean bWait, JRootPane rootPane )
    {
      if( rootPane == null )
      {
        return;
      }

      RefCounter refCounter = _waitCursorMap.get( rootPane );
      try
      {
        Component glassPane = rootPane.getGlassPane();
        if( bWait && refCounter == null )
        {
          Cursor cursorWait = Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR );
          rootPane.setCursor( cursorWait );
          glassPane.setCursor( cursorWait );
          glassPane.setVisible( true );
          glassPane.invalidate();

          refCounter = new RefCounter();
          _waitCursorMap.put( rootPane, refCounter );
        }
        else if( !bWait && (refCounter == null || refCounter._iRefCount == 1) )
        {
          Cursor cursorDefault = Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR );
          glassPane.setVisible( false );
          glassPane.setCursor( cursorDefault );
          rootPane.setCursor( cursorDefault );
          glassPane.invalidate();

          _waitCursorMap.remove( rootPane );
        }

        //## NOTE: Do NOT validate here. Side effects could include perpetual validation.
        // rootPane.validate();
      }
      catch( Exception e )
      {
        handleUncaughtException( e );
      }
      finally
      {
        if( refCounter != null )
        {
          refCounter._iRefCount += (bWait ? 1 : -1);
          if( refCounter._iRefCount < 0 )
          {
            _waitCursorMap.remove( rootPane );
          }
        }
      }
    }

    static final class RefCounter
    {
      public int _iRefCount;
    }
  }

  public static Rectangle getPrimaryMonitorScreenRect()
  {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gds = ge.getScreenDevices();
    BasicGosuEditor frame = RunMe.getEditorFrame();
    Rectangle foundBounds = null;
    if( frame != null )
    {
      Rectangle windowBounds = frame.getBounds();
      for( GraphicsDevice gd : gds )
      {
        Rectangle bounds = gd.getDefaultConfiguration().getBounds();
        if( bounds.contains( windowBounds.getX(), windowBounds.getY() ) )
        {
          foundBounds = bounds;
          break;
        }
      }
    }
    if( foundBounds == null )
    {
      foundBounds = gds[0].getDefaultConfiguration().getBounds();
    }

    return foundBounds;
  }

  public static Point getXYForDialogRelativeToStudioFrame( int width, int height )
  {
    Rectangle screenRect = getPrimaryMonitorScreenRect();
    return new Point( (int)(screenRect.getX() + (screenRect.getWidth() - width) / 2),
                      (int)(screenRect.getY() + (screenRect.getHeight() - height) / 2) );
  }

  public static void mapCancelKeystroke( final JDialog dialog, Action cancelAction )
  {
    Object key = dialog.getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).get( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ) );
    if( key == null )
    {
      key = "Cancel";
      dialog.getRootPane().getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ), key );
    }
    dialog.getRootPane().getActionMap().put( key, cancelAction );
  }

  public static List filterStrings( Collection collection, String filter )
  {
    return filterStrings( collection, filter, false );
  }

  public static List filterStrings( Collection collection, String filter, boolean showChoicesIfEmpty )
  {
    if( filter == null )
    {
      filter = "";
    }
    int iDotIndex = filter.lastIndexOf( '.' );
    if( iDotIndex >= 0 )
    {
      filter = filter.substring( iDotIndex + 1 );
    }

    List filteredTypes = new ArrayList();
    if( showChoicesIfEmpty || filter.length() > 0 )
    {
      int iFlags = 0;
      if( filter.length() > 0 && filter.indexOf( '*' ) < 0 &&
          Character.isUpperCase( filter.charAt( 0 ) ) )
      {
        filter = camelCasePrefix( filter );
      }
      else
      {
        iFlags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
      }

      // Replace all wildcard '*' chars with the regex ".*" expression
      filter = filter.replaceAll( "\\*", "\\.\\*" );

      // A '#' char indicates that the proper regex syntax has already been embedded in the string;
      // we only need to replace the '#' with '*'
      filter = filter.replaceAll( "\\#", "\\*" );

      boolean bHasDot = filter.indexOf( '~' ) >= 0;
      filter = filter.replaceAll( "~", "(\\\\.|" + '\u2024' + ")" );

      boolean exactMatch = filter.endsWith( " " );
      filter = filter.trim();

      // Match the expression string followed by any number of chars
      try
      {
        Pattern pattern = Pattern.compile( '^' + filter + (exactMatch ? "" : (filter.startsWith( ".*" ) ? "" : ".*")), iFlags );
        for( CharSequence cs : collection )
        {
          String strType = cs.toString();
          String strName = bHasDot ? strType : getRelativeTypeName( strType );
          boolean shouldAdd = exactMatch ? pattern.matcher( strName ).matches() : pattern.matcher( strName ).find();
          if( shouldAdd )
          {
            filteredTypes.add( strType );
          }
        }
      }
      catch( PatternSyntaxException e )
      {
        // Skip
      }
    }
    return filteredTypes;
  }

  private static String camelCasePrefix( String strPrefix )
  {
    StringBuilder sb = new StringBuilder();
    for( int i = strPrefix.length() - 1; i >= 0; i-- )
    {
      char c = strPrefix.charAt( i );
      sb.insert( 0, c );
      if( i != 0 && Character.isUpperCase( c ) )
      {
        // Each uppercase char in the prefix match all but uppercase chars preceding it e.g.,
        // "AcT" matches any string starting with "Ac" followed by any number of non-uppercase chars followed by "T".
        // It's the same as the regex "Ac[^A-Z]*T"
        sb.insert( 0, "[^A-Z]#" );
      }
    }
    return sb.toString();
  }

  private static String getRelativeTypeName( String strType )
  {
    int iIndex = strType.lastIndexOf( '.' );
    if( iIndex > 0 )
    {
      return strType.substring( iIndex + 1 );
    }
    return strType;
  }

  public static void htmlEncode( StringBuilder sb )
  {
    for( int i = 0; i < sb.length(); i++ )
    {
      char ch = sb.charAt( i );
      switch( ch )
      {
        case '<':
          sb.replace( i, i + 1, "<" );
          i += 3;
          break;
        case '>':
          sb.replace( i, i + 1, ">" );
          i += 3;
          break;
        case '&':
          sb.replace( i, i + 1, "&" );
          i += 4;
          break;
        case '"':
          sb.replace( i, i + 1, """ );
          i += 5;
          break;
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy