Package org.pushingpixels.substance.internal.ui

Source Code of org.pushingpixels.substance.internal.ui.SubstanceRootPaneUI$TitleMouseInputHandler

/*
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  o Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*    
*  o Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*    
*  o Neither the name of Substance Kirill Grouchnikov nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*    
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.substance.internal.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRootPaneUI;

import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.SubstanceSkin;
import org.pushingpixels.substance.internal.animation.RootPaneDefaultButtonTracker;
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
import org.pushingpixels.substance.internal.utils.MemoryAnalyzer;
import org.pushingpixels.substance.internal.utils.SubstanceColorUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceTitlePane;

/**
* UI for root panes in <b>Substance </b> look and feel.
*
* @author Kirill Grouchnikov
* @author Larry Salibra (fix for defect 198)
*/
public class SubstanceRootPaneUI extends BasicRootPaneUI {
  private enum CursorState {
    EXITED, ENTERED, NIL
  }

  /**
   * The amount of space (in pixels) that the cursor is changed on.
   */
  private static final int CORNER_DRAG_WIDTH = 16;

  /**
   * Region from edges that dragging is active from.
   */
  private static final int BORDER_DRAG_THICKNESS = 5;

  /**
   * Window the <code>JRootPane</code> is in.
   */
  private Window window;

  /**
   * <code>JComponent</code> providing window decorations. This will be null
   * if not providing window decorations.
   */
  private JComponent titlePane;

  /**
   * <code>MouseInputListener</code> that is added to the parent
   * <code>Window</code> the <code>JRootPane</code> is contained in.
   */
  private MouseInputListener substanceMouseInputListener;

  /**
   * Mouse listener on the title pane (dragging).
   */
  private MouseInputListener substanceTitleMouseInputListener;

  /**
   * The <code>LayoutManager</code> that is set on the <code>JRootPane</code>.
   */
  private LayoutManager layoutManager;

  /**
   * <code>LayoutManager</code> of the <code>JRootPane</code> before we
   * replaced it.
   */
  private LayoutManager savedOldLayout;

  /**
   * <code>JRootPane</code> providing the look and feel for.
   */
  protected JRootPane root;

  /**
   * Window listener that stops all Substance thread when the last frame is
   * disposed.
   */
  protected WindowListener substanceWindowListener;

  /**
   * The current window.
   */
  protected Window substanceCurrentWindow;

  /**
   * Hierarchy listener to keep track of the associated top-level window.
   */
  protected HierarchyListener substanceHierarchyListener;

  /**
   * Component listener to keep track of the primary graphics configuration
   * (for recomputing the maximized bounds) - fix for defect 213.
   */
  protected ComponentListener substanceWindowComponentListener;

  /**
   * The graphics configuration that contains the top-left corner of the
   * window (fix for defect 213).
   */
  protected GraphicsConfiguration currentRootPaneGC;

  protected PropertyChangeListener substancePropertyChangeListener;

  /**
   * <code>Cursor</code> used to track the cursor set by the user. This is
   * initially <code>Cursor.DEFAULT_CURSOR</code>.
   */
  private Cursor lastCursor = Cursor
      .getPredefinedCursor(Cursor.DEFAULT_CURSOR);

  /**
   * Optimization to speed up the
   * {@link SubstanceCoreUtilities#getSkin(Component)} implementation.
   */
  private static int rootPanesWithCustomSkin = 0;

  /**
   * Creates a UI for a <code>JRootPane</code>.
   *
   * @param comp
   *            the JRootPane the RootPaneUI will be created for
   * @return the RootPaneUI implementation for the passed in JRootPane
   */
  public static ComponentUI createUI(JComponent comp) {
    SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
    return new SubstanceRootPaneUI();
  }

  /**
   * Invokes supers implementation of <code>installUI</code> to install the
   * necessary state onto the passed in <code>JRootPane</code> to render the
   * metal look and feel implementation of <code>RootPaneUI</code>. If the
   * <code>windowDecorationStyle</code> property of the <code>JRootPane</code>
   * is other than <code>JRootPane.NONE</code>, this will add a custom
   * <code>Component</code> to render the widgets to <code>JRootPane</code>,
   * as well as installing a custom <code>Border</code> and
   * <code>LayoutManager</code> on the <code>JRootPane</code>.
   *
   * @param c
   *            the JRootPane to install state onto
   */
  @Override
  public void installUI(JComponent c) {
    super.installUI(c);
    this.root = (JRootPane) c;
    int style = this.root.getWindowDecorationStyle();
    if (style != JRootPane.NONE) {
      this.installClientDecorations(this.root);
    }

    if (SubstanceCoreUtilities.isRootPaneModified(this.root)) {
      propagateModificationState();
    }

    if (this.root.getClientProperty(SubstanceLookAndFeel.SKIN_PROPERTY) instanceof SubstanceSkin) {
      rootPanesWithCustomSkin++;
    }
  }

  /**
   * Invokes supers implementation to uninstall any of its state. This will
   * also reset the <code>LayoutManager</code> of the <code>JRootPane</code>.
   * If a <code>Component</code> has been added to the <code>JRootPane</code>
   * to render the window decoration style, this method will remove it.
   * Similarly, this will revert the Border and LayoutManager of the
   * <code>JRootPane</code> to what it was before <code>installUI</code> was
   * invoked.
   *
   * @param c
   *            the JRootPane to uninstall state from
   */
  @Override
  public void uninstallUI(JComponent c) {
    super.uninstallUI(c);
    this.uninstallClientDecorations(this.root);

    this.layoutManager = null;
    this.substanceMouseInputListener = null;

    if (this.root.getClientProperty(SubstanceLookAndFeel.SKIN_PROPERTY) instanceof SubstanceSkin) {
      rootPanesWithCustomSkin--;
    }

    this.root = null;
  }

  /**
   * Installs the appropriate <code>Border</code> onto the
   * <code>JRootPane</code>.
   *
   * @param root
   *            Root pane.
   */
  public void installBorder(JRootPane root) {
    int style = root.getWindowDecorationStyle();

    if (style == JRootPane.NONE) {
      LookAndFeel.uninstallBorder(root);
    } else {
      LookAndFeel.installBorder(root, "RootPane.border");
    }
  }

  /**
   * Removes any border that may have been installed.
   *
   * @param root
   *            Root pane.
   */
  private void uninstallBorder(JRootPane root) {
    LookAndFeel.uninstallBorder(root);
  }

  @Override
  protected void installDefaults(JRootPane c) {
    super.installDefaults(c);
    // support for per-window skins
    Color backgr = c.getBackground();
    if ((backgr == null) || (backgr instanceof UIResource)) {
      Color backgroundFillColor = SubstanceColorUtilities
          .getBackgroundFillColor(c);
      // fix for issue 244 - set the root pane BG color
      if (backgroundFillColor != null) {
        c.setBackground(new ColorUIResource(backgroundFillColor));
      }
    }
  }

  @Override
  public void update(Graphics g, JComponent c) {
    if (!SubstanceLookAndFeel.isCurrentLookAndFeel())
      return;

    // fix for issue 244 - paint the entire root pane so that it
    // picks the correct watermark
    if (SubstanceCoreUtilities.isOpaque(c)) {
      BackgroundPaintingUtils.update(g, c, false);
    }
    super.paint(g, c);
  }

  /**
   * Installs the necessary Listeners on the parent <code>Window</code>, if
   * there is one.
   * <p>
   * This takes the parent so that cleanup can be done from
   * <code>removeNotify</code>, at which point the parent hasn't been reset
   * yet.
   *
   *
   * @param root
   *            Root pane.
   * @param parent
   *            The parent of the JRootPane
   */
  private void installWindowListeners(JRootPane root, Component parent) {
    if (parent instanceof Window) {
      this.window = (Window) parent;
    } else {
      this.window = SwingUtilities.getWindowAncestor(parent);
    }
    // System.out.println(titlePanes.size() + " entries in map after adding
    // "
    // + window.getClass().getName() + ":" + window.hashCode());
    // for (Iterator<Map.Entry<JComponent, WeakReference<Window>>> it =
    // titlePanes
    // .entrySet().iterator(); it.hasNext();) {
    // Map.Entry<JComponent, WeakReference<Window>> entry = it
    // .next();
    // Window w = entry.getValue().get();
    // System.out.println("\t" + w.getClass().getName()
    // + ":" + w.hashCode());
    // }

    if (this.window != null) {
      if (this.substanceMouseInputListener == null) {
        this.substanceMouseInputListener = this
            .createWindowMouseInputListener(root);
      }
      this.window.addMouseListener(this.substanceMouseInputListener);
      this.window
          .addMouseMotionListener(this.substanceMouseInputListener);

      if (this.titlePane != null) {
        if (this.substanceTitleMouseInputListener == null) {
          this.substanceTitleMouseInputListener = new TitleMouseInputHandler();
        }
        this.titlePane
            .addMouseMotionListener(this.substanceTitleMouseInputListener);
        this.titlePane
            .addMouseListener(this.substanceTitleMouseInputListener);
      }
      this.setMaximized();
    }
  }

  /**
   * Uninstalls the necessary Listeners on the <code>Window</code> the
   * Listeners were last installed on.
   *
   * @param root
   *            Root pane.
   */
  private void uninstallWindowListeners(JRootPane root) {
    if (this.window != null) {
      this.window.removeMouseListener(this.substanceMouseInputListener);
      this.window
          .removeMouseMotionListener(this.substanceMouseInputListener);
    }
    if (this.titlePane != null) {
      this.titlePane
          .removeMouseListener(this.substanceTitleMouseInputListener);
      this.titlePane
          .removeMouseMotionListener(this.substanceTitleMouseInputListener);
    }
  }

  /**
   * Installs the appropriate LayoutManager on the <code>JRootPane</code> to
   * render the window decorations.
   *
   * @param root
   *            Root pane.
   */
  private void installLayout(JRootPane root) {
    if (this.layoutManager == null) {
      this.layoutManager = this.createLayoutManager();
    }
    this.savedOldLayout = root.getLayout();
    root.setLayout(this.layoutManager);
  }

  @Override
  protected void installListeners(final JRootPane root) {
    super.installListeners(root);

    // System.out.println("Listeners on root " + root.hashCode());

    this.substanceHierarchyListener = new HierarchyListener() {
      public void hierarchyChanged(HierarchyEvent e) {
        Component parent = root.getParent();
        if (parent == null) {
          // fix for defect 271 - check for null parent
          // as early as possible
          return;
        }
        // System.out.println("Root pane " + root.hashCode()
        // + " parent : " + parent.getClass().getName());
        if (MemoryAnalyzer.isRunning()) {
          MemoryAnalyzer.enqueueUsage("Root pane @" + root.hashCode()
              + "\n"
              + SubstanceCoreUtilities.getHierarchy(parent));
        }
        if (parent.getClass().getName().startsWith(
            "org.jdesktop.jdic.tray")
            || (parent.getClass().getName().compareTo(
                "javax.swing.Popup$HeavyWeightWindow") == 0)) {
          // Workaround for bug 240 - using JDIC system tray
          // menu results in an HierarchyEvent being fired right
          // after a MouseEvent. Somehow, the
          // EventQueue.getCurrentEvent() returns the HierarchyEvent
          // even when the MouseEvent is being processed, resulting
          // in zeroed modifiers set on the ActionEvent passed
          // to the action listeners on that menu item.
          SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              root
                  .removeHierarchyListener(substanceHierarchyListener);
              // System.out.println(root.hashCode() + ":"
              // + root.getHierarchyListeners().length);
              substanceHierarchyListener = null;
            };
          });
        }

        Window currWindow = null;
        if (parent instanceof Window) {
          currWindow = (Window) parent;
        } else {
          currWindow = SwingUtilities.getWindowAncestor(parent);
        }
        if (substanceWindowListener != null) {
          substanceCurrentWindow
              .removeWindowListener(substanceWindowListener);
          substanceWindowListener = null;
        }
        if (substanceWindowComponentListener != null) {
          substanceCurrentWindow
              .removeComponentListener(substanceWindowComponentListener);
          substanceWindowComponentListener = null;
        }
        if (currWindow != null) {
          // fix for bug 116 - stopping threads when all frames
          // are not displayable
          substanceWindowListener = new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
              SubstanceCoreUtilities
                  .testWindowCloseThreadingViolation(e
                      .getWindow());
              SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                  Frame[] frames = Frame.getFrames();
                  for (Frame frame : frames) {
                    if (frame.isDisplayable())
                      return;
                  }
                  SubstanceCoreUtilities.stopThreads();
                }
              });
            }
          };

          if (!(parent instanceof JInternalFrame)) {
            currWindow.addWindowListener(substanceWindowListener);
          }

          // fix for defect 213 - maximizing frame under multiple
          // screens shouldn't always use insets of the primary
          // screen.
          substanceWindowComponentListener = new ComponentAdapter() {
            @Override
            public void componentMoved(ComponentEvent e) {
              this.processNewPosition();
            }

            @Override
            public void componentResized(ComponentEvent e) {
              this.processNewPosition();
            }

            protected void processNewPosition() {
              SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                  if (window == null)
                    return;

                  if (!window.isShowing()
                      || !window.isDisplayable()) {
                    currentRootPaneGC = null;
                    return;
                  }

                  GraphicsEnvironment ge = GraphicsEnvironment
                      .getLocalGraphicsEnvironment();
                  GraphicsDevice[] gds = ge
                      .getScreenDevices();
                  if (gds.length == 1)
                    return;
                  Point midLoc = new Point(window
                      .getLocationOnScreen().x
                      + window.getWidth() / 2, window
                      .getLocationOnScreen().y
                      + window.getHeight() / 2);
                  // System.out.println("Loc : "
                  // + window.getLocationOnScreen()
                  // + ", width : "
                  // + window.getWidth()
                  // + ", mid : " + midLoc);
                  int index = 0;
                  for (GraphicsDevice gd : gds) {
                    GraphicsConfiguration gc = gd
                        .getDefaultConfiguration();
                    Rectangle bounds = gc.getBounds();
                    // System.out.println("Bounds : "
                    // + bounds);
                    if (bounds.contains(midLoc)) {
                      if (gc != currentRootPaneGC) {
                        currentRootPaneGC = gc;
                        setMaximized();
                        // System.out.println("Set");
                      }
                      break;
                    }
                    index++;
                  }
                }
              });
            }
          };
          // fix for defect 225 - install the listener only on
          // JFrames.
          if (parent instanceof JFrame) {
            currWindow
                .addComponentListener(substanceWindowComponentListener);
          }

          SubstanceRootPaneUI.this.window = currWindow;
        }
        substanceCurrentWindow = currWindow;
      }
    };
    root.addHierarchyListener(this.substanceHierarchyListener);
    // System.out.println(root.hashCode() + ":"
    // + root.getHierarchyListeners().length);

    JButton defaultButton = root.getDefaultButton();
    if (defaultButton != null) {
      RootPaneDefaultButtonTracker.update(defaultButton);
    }
    this.substancePropertyChangeListener = new PropertyChangeListener() {
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
        if ("defaultButton".equals(evt.getPropertyName())) {
          JButton prev = (JButton) evt.getOldValue();
          JButton next = (JButton) evt.getNewValue();

          RootPaneDefaultButtonTracker.update(prev);
          RootPaneDefaultButtonTracker.update(next);
        }

        if (SubstanceLookAndFeel.WINDOW_MODIFIED.equals(evt
            .getPropertyName())) {
          propagateModificationState();
        }
      }
    };
    root.addPropertyChangeListener(this.substancePropertyChangeListener);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * javax.swing.plaf.basic.BasicRootPaneUI#uninstallListeners(javax.swing
   * .JRootPane)
   */
  @Override
  protected void uninstallListeners(JRootPane root) {
    // fix for bug 116 - stopping threads when all frames are
    // not displayable
    if (this.window != null) {
      this.window.removeWindowListener(this.substanceWindowListener);
      this.substanceWindowListener = null;
      this.window
          .removeComponentListener(this.substanceWindowComponentListener);
      this.substanceWindowComponentListener = null;
    }
    root.removeHierarchyListener(this.substanceHierarchyListener);
    this.substanceHierarchyListener = null;

    root.removePropertyChangeListener(this.substancePropertyChangeListener);
    this.substancePropertyChangeListener = null;

    super.uninstallListeners(root);
  }

  /**
   * Uninstalls the previously installed <code>LayoutManager</code>.
   *
   * @param root
   *            Root pane.
   */
  private void uninstallLayout(JRootPane root) {
    if (this.savedOldLayout != null) {
      root.setLayout(this.savedOldLayout);
      this.savedOldLayout = null;
    }
  }

  /**
   * Installs the necessary state onto the JRootPane to render client
   * decorations. This is ONLY invoked if the <code>JRootPane</code> has a
   * decoration style other than <code>JRootPane.NONE</code>.
   *
   * @param root
   *            Root pane.
   */
  private void installClientDecorations(JRootPane root) {
    this.installBorder(root);

    JComponent titlePane = this.createTitlePane(root);

    this.setTitlePane(root, titlePane);
    this.installWindowListeners(root, root.getParent());
    this.installLayout(root);
    if (this.window != null) {
      root.revalidate();
      root.repaint();
    }
  }

  /**
   * Uninstalls any state that <code>installClientDecorations</code> has
   * installed.
   * <p>
   * NOTE: This may be called if you haven't installed client decorations yet
   * (ie before <code>installClientDecorations</code> has been invoked).
   *
   * @param root
   *            Root pane.
   */
  private void uninstallClientDecorations(JRootPane root) {
    this.uninstallBorder(root);
    this.uninstallWindowListeners(root);
    this.setTitlePane(root, null);
    this.uninstallLayout(root);
    // We have to revalidate/repaint root if the style is JRootPane.NONE
    // only. When we needs to call revalidate/repaint with other styles
    // the installClientDecorations is always called after this method
    // imediatly and it will cause the revalidate/repaint at the proper
    // time.
    int style = root.getWindowDecorationStyle();
    if (style == JRootPane.NONE) {
      root.repaint();
      root.revalidate();
    }
    // Reset the cursor, as we may have changed it to a resize cursor
    if (this.window != null) {
      this.window.setCursor(Cursor
          .getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }
    this.window = null;
  }

  /**
   * Returns the <code>JComponent</code> to render the window decoration
   * style.
   *
   * @param root
   *            Root pane.
   * @return The title pane component.
   */
  protected JComponent createTitlePane(JRootPane root) {
    return new SubstanceTitlePane(root, this);
  }

  /**
   * Returns a <code>MouseListener</code> that will be added to the
   * <code>Window</code> containing the <code>JRootPane</code>.
   *
   * @param root
   *            Root pane.
   * @return Window mouse listener.
   */
  private MouseInputListener createWindowMouseInputListener(JRootPane root) {
    return new MouseInputHandler();
  }

  /**
   * Returns a <code>LayoutManager</code> that will be set on the
   * <code>JRootPane</code>.
   *
   * @return Layout manager.
   */
  protected LayoutManager createLayoutManager() {
    return new SubstanceRootLayout();
  }

  /**
   * Sets the window title pane -- the JComponent used to provide a plaf a way
   * to override the native operating system's window title pane with one
   * whose look and feel are controlled by the plaf. The plaf creates and sets
   * this value; the default is null, implying a native operating system
   * window title pane.
   *
   * @param root
   *            Root pane
   * @param titlePane
   *            The <code>JComponent</code> to use for the window title pane.
   */
  private void setTitlePane(JRootPane root, JComponent titlePane) {
    JLayeredPane layeredPane = root.getLayeredPane();
    JComponent oldTitlePane = this.getTitlePane();

    if (oldTitlePane != null) {
      // fix for defect 109 - memory leak on skin change
      if (oldTitlePane instanceof SubstanceTitlePane)
        ((SubstanceTitlePane) oldTitlePane).uninstall();
      // oldTitlePane.setVisible(false);
      layeredPane.remove(oldTitlePane);
    }
    if (titlePane != null) {
      layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER);
      titlePane.setVisible(true);
    }
    this.titlePane = titlePane;
  }

  /**
   * Sets maximized bounds according to the display screen insets.
   */
  public void setMaximized() {
    Component tla = this.root.getTopLevelAncestor();
    // fix for defect 213 - maximizing frame under multiple
    // screens shouldn't always use insets of the primary
    // screen.
    GraphicsConfiguration gc = (currentRootPaneGC != null) ? currentRootPaneGC
        : tla.getGraphicsConfiguration();
    Rectangle screenBounds = gc.getBounds();
    screenBounds.x = 0;
    screenBounds.y = 0;
    Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
    Rectangle maxBounds = new Rectangle(
        (screenBounds.x + screenInsets.left),
        (screenBounds.y + screenInsets.top), screenBounds.width
            - ((screenInsets.left + screenInsets.right)),
        screenBounds.height
            - ((screenInsets.top + screenInsets.bottom)));
    if (tla instanceof JFrame)
      ((JFrame) tla).setMaximizedBounds(maxBounds);
    if (MemoryAnalyzer.isRunning()) {
      MemoryAnalyzer.enqueueUsage("Frame set to bounds " + maxBounds);
    }
  }

  /**
   * Returns the <code>JComponent</code> rendering the title pane. If this
   * returns null, it implies there is no need to render window decorations.
   * This method is <b>for internal use only</b>.
   *
   * @see #setTitlePane
   * @return Title pane.
   */
  public JComponent getTitlePane() {
    return this.titlePane;
  }

  /**
   * Returns the <code>JRootPane</code> we're providing the look and feel for.
   *
   * @return The associated root pane.
   */
  protected JRootPane getRootPane() {
    return this.root;
  }

  /*
   * (non-Javadoc)
   *
   * @seejavax.swing.plaf.basic.BasicRootPaneUI#propertyChange(java.beans.
   * PropertyChangeEvent)
   */
  @Override
  public void propertyChange(PropertyChangeEvent e) {
    super.propertyChange(e);

    String propertyName = e.getPropertyName();
    if (propertyName == null) {
      return;
    }

    if (propertyName.equals("windowDecorationStyle")) {
      JRootPane root = (JRootPane) e.getSource();
      int style = root.getWindowDecorationStyle();

      this.uninstallClientDecorations(root);
      if (style != JRootPane.NONE) {
        this.installClientDecorations(root);
      }
    }
    if (propertyName.equals("ancestor")) {
      this.uninstallWindowListeners(this.root);
      if (((JRootPane) e.getSource()).getWindowDecorationStyle() != JRootPane.NONE) {
        this.installWindowListeners(this.root, this.root.getParent());
      }
    }
    if (propertyName.equals("background")) {
      SubstanceLookAndFeel.getTitlePaneComponent(window).setBackground(
          (Color) e.getNewValue());
    }

    if (propertyName.equals(SubstanceLookAndFeel.SKIN_PROPERTY)) {
      SubstanceSkin oldValue = (SubstanceSkin) e.getOldValue();
      SubstanceSkin newValue = (SubstanceSkin) e.getNewValue();
      if ((oldValue == null) && (newValue != null)) {
        rootPanesWithCustomSkin++;
      }
      if ((oldValue != null) && (newValue == null)) {
        rootPanesWithCustomSkin--;
      }
    }
    return;
  }

  /**
   * A custom layout manager that is responsible for the layout of
   * layeredPane, glassPane, menuBar and titlePane, if one has been installed.
   */
  protected class SubstanceRootLayout implements LayoutManager2 {
    /**
     * Returns the amount of space the layout would like to have.
     *
     *
     * aram the Container for which this layout manager is being used
     *
     * @return a Dimension object containing the layout's preferred size
     */
    public Dimension preferredLayoutSize(Container parent) {
      Dimension cpd, mbd, tpd;
      int cpWidth = 0;
      int cpHeight = 0;
      int mbWidth = 0;
      int mbHeight = 0;
      int tpWidth = 0;
      int tpHeight = 0;
      Insets i = parent.getInsets();
      JRootPane root = (JRootPane) parent;

      if (root.getContentPane() != null) {
        cpd = root.getContentPane().getPreferredSize();
      } else {
        cpd = root.getSize();
      }
      if (cpd != null) {
        cpWidth = cpd.width;
        cpHeight = cpd.height;
      }

      if (root.getJMenuBar() != null) {
        mbd = root.getJMenuBar().getPreferredSize();
        if (mbd != null) {
          mbWidth = mbd.width;
          mbHeight = mbd.height;
        }
      }

      if ((root.getWindowDecorationStyle() != JRootPane.NONE)
          && (root.getUI() instanceof SubstanceRootPaneUI)) {
        JComponent titlePane = ((SubstanceRootPaneUI) root.getUI())
            .getTitlePane();
        if (titlePane != null) {
          tpd = titlePane.getPreferredSize();
          if (tpd != null) {
            tpWidth = tpd.width;
            tpHeight = tpd.height;
          }
        }
      }

      return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth)
          + i.left + i.right, cpHeight + mbHeight + tpHeight + i.top
          + i.bottom);
    }

    /**
     * Returns the minimum amount of space the layout needs.
     *
     *
     * aram the Container for which this layout manager is being used
     *
     * @return a Dimension object containing the layout's minimum size
     */
    public Dimension minimumLayoutSize(Container parent) {
      Dimension cpd, mbd, tpd;
      int cpWidth = 0;
      int cpHeight = 0;
      int mbWidth = 0;
      int mbHeight = 0;
      int tpWidth = 0;
      int tpHeight = 0;
      Insets i = parent.getInsets();
      JRootPane root = (JRootPane) parent;

      if (root.getContentPane() != null) {
        cpd = root.getContentPane().getMinimumSize();
      } else {
        cpd = root.getSize();
      }
      if (cpd != null) {
        cpWidth = cpd.width;
        cpHeight = cpd.height;
      }

      if (root.getJMenuBar() != null) {
        mbd = root.getJMenuBar().getMinimumSize();
        if (mbd != null) {
          mbWidth = mbd.width;
          mbHeight = mbd.height;
        }
      }
      if ((root.getWindowDecorationStyle() != JRootPane.NONE)
          && (root.getUI() instanceof SubstanceRootPaneUI)) {
        JComponent titlePane = ((SubstanceRootPaneUI) root.getUI())
            .getTitlePane();
        if (titlePane != null) {
          tpd = titlePane.getMinimumSize();
          if (tpd != null) {
            tpWidth = tpd.width;
            tpHeight = tpd.height;
          }
        }
      }

      return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth)
          + i.left + i.right, cpHeight + mbHeight + tpHeight + i.top
          + i.bottom);
    }

    /**
     * Returns the maximum amount of space the layout can use.
     *
     *
     * aram the Container for which this layout manager is being used
     *
     * @return a Dimension object containing the layout's maximum size
     */
    public Dimension maximumLayoutSize(Container target) {
      Dimension cpd, mbd, tpd;
      int cpWidth = Integer.MAX_VALUE;
      int cpHeight = Integer.MAX_VALUE;
      int mbWidth = Integer.MAX_VALUE;
      int mbHeight = Integer.MAX_VALUE;
      int tpWidth = Integer.MAX_VALUE;
      int tpHeight = Integer.MAX_VALUE;
      Insets i = target.getInsets();
      JRootPane root = (JRootPane) target;

      if (root.getContentPane() != null) {
        cpd = root.getContentPane().getMaximumSize();
        if (cpd != null) {
          cpWidth = cpd.width;
          cpHeight = cpd.height;
        }
      }

      if (root.getJMenuBar() != null) {
        mbd = root.getJMenuBar().getMaximumSize();
        if (mbd != null) {
          mbWidth = mbd.width;
          mbHeight = mbd.height;
        }
      }

      if ((root.getWindowDecorationStyle() != JRootPane.NONE)
          && (root.getUI() instanceof SubstanceRootPaneUI)) {
        JComponent titlePane = ((SubstanceRootPaneUI) root.getUI())
            .getTitlePane();
        if (titlePane != null) {
          tpd = titlePane.getMaximumSize();
          if (tpd != null) {
            tpWidth = tpd.width;
            tpHeight = tpd.height;
          }
        }
      }

      int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight);
      // Only overflows if 3 real non-MAX_VALUE heights, sum to >
      // MAX_VALUE
      // Only will happen if sums to more than 2 billion units. Not
      // likely.
      if (maxHeight != Integer.MAX_VALUE) {
        maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom;
      }

      int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth);
      // Similar overflow comment as above
      if (maxWidth != Integer.MAX_VALUE) {
        maxWidth += i.left + i.right;
      }

      return new Dimension(maxWidth, maxHeight);
    }

    /**
     * Instructs the layout manager to perform the layout for the specified
     * container.
     *
     *
     * aram the Container for which this layout manager is being used
     */
    public void layoutContainer(Container parent) {
      JRootPane root = (JRootPane) parent;
      Rectangle b = root.getBounds();
      Insets i = root.getInsets();
      int nextY = 0;
      int w = b.width - i.right - i.left;
      int h = b.height - i.top - i.bottom;

      if (root.getLayeredPane() != null) {
        root.getLayeredPane().setBounds(i.left, i.top, w, h);
      }
      if (root.getGlassPane() != null) {
        root.getGlassPane().setBounds(i.left, i.top, w, h);
      }
      // Note: This is laying out the children in the layeredPane,
      // technically, these are not our children.
      if ((root.getWindowDecorationStyle() != JRootPane.NONE)
          && (root.getUI() instanceof SubstanceRootPaneUI)) {
        JComponent titlePane = ((SubstanceRootPaneUI) root.getUI())
            .getTitlePane();
        if (titlePane != null) {
          Dimension tpd = titlePane.getPreferredSize();
          if (tpd != null) {
            int tpHeight = tpd.height;
            titlePane.setBounds(0, 0, w, tpHeight);
            nextY += tpHeight;
          }
        }
      }
      if (root.getJMenuBar() != null) {
        Dimension mbd = root.getJMenuBar().getPreferredSize();
        root.getJMenuBar().setBounds(0, nextY, w, mbd.height);
        nextY += mbd.height;
      }
      if (root.getContentPane() != null) {
        // Dimension cpd = root.getContentPane().getPreferredSize();
        root.getContentPane().setBounds(0, nextY, w,
            h < nextY ? 0 : h - nextY);
      }
    }

    public void addLayoutComponent(String name, Component comp) {
    }

    public void removeLayoutComponent(Component comp) {
    }

    public void addLayoutComponent(Component comp, Object constraints) {
    }

    public float getLayoutAlignmentX(Container target) {
      return 0.0f;
    }

    public float getLayoutAlignmentY(Container target) {
      return 0.0f;
    }

    public void invalidateLayout(Container target) {
    }
  }

  /**
   * Maps from positions to cursor type. Refer to calculateCorner and
   * calculatePosition for details of this.
   */
  private static final int[] cursorMapping = new int[] {
      Cursor.NW_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR,
      Cursor.N_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR,
      Cursor.NE_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, 0, 0, 0,
      Cursor.NE_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR, 0, 0, 0,
      Cursor.E_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, 0, 0, 0,
      Cursor.SE_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR,
      Cursor.SW_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR,
      Cursor.SE_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR };

  /**
   * MouseInputHandler is responsible for handling resize/moving of the
   * Window. It sets the cursor directly on the Window when then mouse moves
   * over a hot spot.
   */
  private class MouseInputHandler implements MouseInputListener {
    /**
     * Set to true if the drag operation is moving the window.
     */
    private boolean isMovingWindow;

    /**
     * Used to determine the corner the resize is occuring from.
     */
    private int dragCursor;

    /**
     * X location the mouse went down on for a drag operation.
     */
    private int dragOffsetX;

    /**
     * Y location the mouse went down on for a drag operation.
     */
    private int dragOffsetY;

    /**
     * Width of the window when the drag started.
     */
    private int dragWidth;

    /**
     * Height of the window when the drag started.
     */
    private int dragHeight;

    /**
     * PrivilegedExceptionAction needed by mouseDragged method to obtain new
     * location of window on screen during the drag.
     */
    @SuppressWarnings("unchecked")
    private final PrivilegedExceptionAction getLocationAction = new PrivilegedExceptionAction() {
      public Object run() throws HeadlessException {
        return MouseInfo.getPointerInfo().getLocation();
      }
    };

    public void mousePressed(MouseEvent ev) {
      JRootPane rootPane = SubstanceRootPaneUI.this.getRootPane();

      if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) {
        return;
      }
      Point dragWindowOffset = ev.getPoint();
      Window w = (Window) ev.getSource();
      if (w != null) {
        w.toFront();
      }
      Point convertedDragWindowOffset = SwingUtilities.convertPoint(w,
          dragWindowOffset, SubstanceRootPaneUI.this.getTitlePane());

      Frame f = null;
      Dialog d = null;

      if (w instanceof Frame) {
        f = (Frame) w;
      } else if (w instanceof Dialog) {
        d = (Dialog) w;
      }

      int frameState = (f != null) ? f.getExtendedState() : 0;

      if ((SubstanceRootPaneUI.this.getTitlePane() != null)
          && SubstanceRootPaneUI.this.getTitlePane().contains(
              convertedDragWindowOffset)) {
        if ((((f != null) && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) || (d != null))
            && (dragWindowOffset.y >= SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)
            && (dragWindowOffset.x >= SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)
            && (dragWindowOffset.x < w.getWidth()
                - SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)) {
          this.isMovingWindow = true;
          this.dragOffsetX = dragWindowOffset.x;
          this.dragOffsetY = dragWindowOffset.y;
        }
      } else if (((f != null) && f.isResizable() && ((frameState & Frame.MAXIMIZED_BOTH) == 0))
          || ((d != null) && d.isResizable())) {
        this.dragOffsetX = dragWindowOffset.x;
        this.dragOffsetY = dragWindowOffset.y;
        this.dragWidth = w.getWidth();
        this.dragHeight = w.getHeight();
        this.dragCursor = this.getCursor(this.calculateCorner(w,
            dragWindowOffset.x, dragWindowOffset.y));
      }
    }

    public void mouseReleased(MouseEvent ev) {
      if ((this.dragCursor != 0)
          && (SubstanceRootPaneUI.this.window != null)
          && !SubstanceRootPaneUI.this.window.isValid()) {
        // Some Window systems validate as you resize, others won't,
        // thus the check for validity before repainting.
        SubstanceRootPaneUI.this.window.validate();
        SubstanceRootPaneUI.this.getRootPane().repaint();
      }
      this.isMovingWindow = false;
      this.dragCursor = 0;
    }

    public void mouseMoved(MouseEvent ev) {
      JRootPane root = SubstanceRootPaneUI.this.getRootPane();

      if (root.getWindowDecorationStyle() == JRootPane.NONE) {
        return;
      }

      Window w = (Window) ev.getSource();

      Frame f = null;
      Dialog d = null;

      if (w instanceof Frame) {
        f = (Frame) w;
      } else if (w instanceof Dialog) {
        d = (Dialog) w;
      }

      // Update the cursor
      int cursor = this.getCursor(this.calculateCorner(w, ev.getX(), ev
          .getY()));

      if ((cursor != 0)
          && (((f != null) && (f.isResizable() && ((f
              .getExtendedState() & Frame.MAXIMIZED_BOTH) == 0))) || ((d != null) && d
              .isResizable()))) {
        w.setCursor(Cursor.getPredefinedCursor(cursor));
      } else {
        w.setCursor(SubstanceRootPaneUI.this.lastCursor);
      }
    }

    /**
     * Adjusts the bounds.
     *
     * @param bounds
     *            Original bounds.
     * @param min
     *            Minimum dimension.
     * @param deltaX
     *            Delta X.
     * @param deltaY
     *            Delta Y.
     * @param deltaWidth
     *            Delta width.
     * @param deltaHeight
     *            Delta height.
     */
    private void adjust(Rectangle bounds, Dimension min, int deltaX,
        int deltaY, int deltaWidth, int deltaHeight) {
      bounds.x += deltaX;
      bounds.y += deltaY;
      bounds.width += deltaWidth;
      bounds.height += deltaHeight;
      if (min != null) {
        if (bounds.width < min.width) {
          int correction = min.width - bounds.width;
          if (deltaX != 0) {
            bounds.x -= correction;
          }
          bounds.width = min.width;
        }
        if (bounds.height < min.height) {
          int correction = min.height - bounds.height;
          if (deltaY != 0) {
            bounds.y -= correction;
          }
          bounds.height = min.height;
        }
      }
    }

    @SuppressWarnings("unchecked")
    public void mouseDragged(MouseEvent ev) {
      Window w = (Window) ev.getSource();
      Point pt = ev.getPoint();

      if (this.isMovingWindow) {
        Point windowPt;
        try {
          windowPt = (Point) AccessController
              .doPrivileged(this.getLocationAction);
          windowPt.x = windowPt.x - this.dragOffsetX;
          windowPt.y = windowPt.y - this.dragOffsetY;
          w.setLocation(windowPt);
        } catch (PrivilegedActionException e) {
        }
      } else if (this.dragCursor != 0) {
        Rectangle r = w.getBounds();
        Rectangle startBounds = new Rectangle(r);
        Dimension min = w.getMinimumSize();

        switch (this.dragCursor) {
        case Cursor.E_RESIZE_CURSOR:
          this.adjust(r, min, 0, 0, pt.x
              + (this.dragWidth - this.dragOffsetX) - r.width, 0);
          break;
        case Cursor.S_RESIZE_CURSOR:
          this.adjust(r, min, 0, 0, 0, pt.y
              + (this.dragHeight - this.dragOffsetY) - r.height);
          break;
        case Cursor.N_RESIZE_CURSOR:
          this.adjust(r, min, 0, pt.y - this.dragOffsetY, 0,
              -(pt.y - this.dragOffsetY));
          break;
        case Cursor.W_RESIZE_CURSOR:
          this.adjust(r, min, pt.x - this.dragOffsetX, 0,
              -(pt.x - this.dragOffsetX), 0);
          break;
        case Cursor.NE_RESIZE_CURSOR:
          this.adjust(r, min, 0, pt.y - this.dragOffsetY, pt.x
              + (this.dragWidth - this.dragOffsetX) - r.width,
              -(pt.y - this.dragOffsetY));
          break;
        case Cursor.SE_RESIZE_CURSOR:
          this.adjust(r, min, 0, 0, pt.x
              + (this.dragWidth - this.dragOffsetX) - r.width,
              pt.y + (this.dragHeight - this.dragOffsetY)
                  - r.height);
          break;
        case Cursor.NW_RESIZE_CURSOR:
          this.adjust(r, min, pt.x - this.dragOffsetX, pt.y
              - this.dragOffsetY, -(pt.x - this.dragOffsetX),
              -(pt.y - this.dragOffsetY));
          break;
        case Cursor.SW_RESIZE_CURSOR:
          this.adjust(r, min, pt.x - this.dragOffsetX, 0,
              -(pt.x - this.dragOffsetX), pt.y
                  + (this.dragHeight - this.dragOffsetY)
                  - r.height);
          break;
        default:
          break;
        }
        if (!r.equals(startBounds)) {
          w.setBounds(r);
          // Defer repaint/validate on mouseReleased unless dynamic
          // layout is active.
          if (Toolkit.getDefaultToolkit().isDynamicLayoutActive()) {
            w.validate();
            SubstanceRootPaneUI.this.getRootPane().repaint();
          }
        }
      }
    }

    private CursorState cursorState = CursorState.NIL;

    public void mouseEntered(MouseEvent ev) {
      Window w = (Window) ev.getSource();
      if (cursorState == CursorState.EXITED
          || cursorState == CursorState.NIL) {
        // fix for defect 107
        SubstanceRootPaneUI.this.lastCursor = w.getCursor();
      }
      cursorState = CursorState.ENTERED;
      this.mouseMoved(ev);
    }

    public void mouseExited(MouseEvent ev) {
      Window w = (Window) ev.getSource();
      w.setCursor(SubstanceRootPaneUI.this.lastCursor);
      cursorState = CursorState.EXITED;
    }

    public void mouseClicked(MouseEvent ev) {
      Window w = (Window) ev.getSource();
      Frame f = null;

      if (w instanceof Frame) {
        f = (Frame) w;
      } else {
        return;
      }

      JComponent windowTitlePane = SubstanceRootPaneUI.this
          .getTitlePane();
      // fix for issue 444 - ignore double clicks when the title pane
      // is not showing (for example under JRootPane.NONE decoration
      // style).
      if (windowTitlePane == null)
        return;

      Point convertedPoint = SwingUtilities.convertPoint(w,
          ev.getPoint(), windowTitlePane);

      int state = f.getExtendedState();
      if ((windowTitlePane != null)
          && windowTitlePane.contains(convertedPoint)) {
        if (((ev.getClickCount() % 2) == 0)
            && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) {
          if (f.isResizable()) {
            if ((state & Frame.MAXIMIZED_BOTH) != 0) {
              setMaximized();
              f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
            } else {
              setMaximized();
              f.setExtendedState(state | Frame.MAXIMIZED_BOTH);
            }
            return;
          }
        }
      }
    }

    /**
     * Returns the corner that contains the point <code>x</code>,
     * <code>y</code>, or -1 if the position doesn't match a corner.
     *
     * @param w
     *            Window.
     * @param x
     *            X coordinate.
     * @param y
     *            Y coordinate.
     * @return Corner that contains the specified point.
     */
    private int calculateCorner(Window w, int x, int y) {
      Insets insets = w.getInsets();
      int xPosition = this.calculatePosition(x - insets.left, w
          .getWidth()
          - insets.left - insets.right);
      int yPosition = this.calculatePosition(y - insets.top, w
          .getHeight()
          - insets.top - insets.bottom);

      if ((xPosition == -1) || (yPosition == -1)) {
        return -1;
      }
      return yPosition * 5 + xPosition;
    }

    /**
     * Returns the Cursor to render for the specified corner. This returns 0
     * if the corner doesn't map to a valid Cursor
     *
     * @param corner
     *            Corner
     * @return Cursor to render for the specified corner.
     */
    private int getCursor(int corner) {
      if (corner == -1) {
        return 0;
      }
      return SubstanceRootPaneUI.cursorMapping[corner];
    }

    /**
     * Returns an integer indicating the position of <code>spot</code> in
     * <code>width</code>. The return value will be: 0 if <
     * BORDER_DRAG_THICKNESS 1 if < CORNER_DRAG_WIDTH 2 if >=
     * CORNER_DRAG_WIDTH && < width - BORDER_DRAG_THICKNESS 3 if >= width -
     * CORNER_DRAG_WIDTH 4 if >= width - BORDER_DRAG_THICKNESS 5 otherwise
     *
     * @param spot
     *            Spot.
     * @param width
     *            Width.
     * @return The position of spot in width.
     */
    private int calculatePosition(int spot, int width) {
      if (spot < SubstanceRootPaneUI.BORDER_DRAG_THICKNESS) {
        return 0;
      }
      if (spot < SubstanceRootPaneUI.CORNER_DRAG_WIDTH) {
        return 1;
      }
      if (spot >= (width - SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)) {
        return 4;
      }
      if (spot >= (width - SubstanceRootPaneUI.CORNER_DRAG_WIDTH)) {
        return 3;
      }
      return 2;
    }
  }

  /**
   * Mouse handler on the title pane.
   *
   * @author Kirill Grouchnikov
   */
  private class TitleMouseInputHandler extends MouseInputAdapter {

    /**
     * Pointer location when the mouse was pressed for a drag relative to
     * the upper-lefthand corner of the window.
     */
    private Point dragOffset = new Point(0, 0);

    @Override
    public void mousePressed(MouseEvent ev) {
      JRootPane rootPane = SubstanceRootPaneUI.this.getRootPane();

      if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) {
        return;
      }

      Point dragWindowOffset = ev.getPoint();
      Component source = (Component) ev.getSource();

      Point convertedDragWindowOffset = SwingUtilities.convertPoint(
          source, dragWindowOffset, getTitlePane());

      dragWindowOffset = SwingUtilities.convertPoint(source,
          dragWindowOffset, SubstanceRootPaneUI.this.window);

      if (getTitlePane() != null
          && getTitlePane().contains(convertedDragWindowOffset)) {
        if (SubstanceRootPaneUI.this.window != null) {
          SubstanceRootPaneUI.this.window.toFront();
          dragOffset = dragWindowOffset;
        }
      }
    }

    @Override
    public void mouseDragged(MouseEvent ev) {
      Component source = (Component) ev.getSource();

      // Point pt = SwingUtilities.convertPoint(source, ev.getPoint(),
      // SubstanceRootPaneUI.this.window);

      // fix for issue 198
      Point eventLocationOnScreen = ev.getLocationOnScreen();
      if (eventLocationOnScreen == null) {
        eventLocationOnScreen = new Point(ev.getX()
            + source.getLocationOnScreen().x, ev.getY()
            + source.getLocationOnScreen().y);
      }
      // Fix for issue 192 - disable dragging maximized frame.
      if (SubstanceRootPaneUI.this.window instanceof Frame) {
        Frame f = (Frame) SubstanceRootPaneUI.this.window;
        int frameState = (f != null) ? f.getExtendedState() : 0;
        if ((f != null) && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) {
          SubstanceRootPaneUI.this.window.setLocation(
              eventLocationOnScreen.x - dragOffset.x,
              eventLocationOnScreen.y - dragOffset.y);
        }
      } else {
        // fix for issue 193 - allow dragging decorated dialogs.
        SubstanceRootPaneUI.this.window.setLocation(
            eventLocationOnScreen.x - dragOffset.x,
            eventLocationOnScreen.y - dragOffset.y);
      }

    }

    @Override
    public void mouseClicked(MouseEvent ev) {
      Frame f = null;

      if (SubstanceRootPaneUI.this.window instanceof Frame) {
        f = (Frame) SubstanceRootPaneUI.this.window;
      } else {
        return;
      }

      Point convertedPoint = SwingUtilities.convertPoint(
          SubstanceRootPaneUI.this.window, ev.getPoint(),
          SubstanceRootPaneUI.this.getTitlePane());

      int state = f.getExtendedState();
      if ((SubstanceRootPaneUI.this.getTitlePane() != null)
          && SubstanceRootPaneUI.this.getTitlePane().contains(
              convertedPoint)) {
        if (((ev.getClickCount() % 2) == 0)
            && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) {
          if (f.isResizable()) {
            if ((state & Frame.MAXIMIZED_BOTH) != 0) {
              setMaximized();
              f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
            } else {
              setMaximized();
              f.setExtendedState(state | Frame.MAXIMIZED_BOTH);
            }
            return;
          }
        }
      }
    }
  }

  private void propagateModificationState() {
    JComponent titlePane = getTitlePane();
    if (titlePane instanceof SubstanceTitlePane) {
      ((SubstanceTitlePane) titlePane)
          .getCloseButton()
          .putClientProperty(
              SubstanceLookAndFeel.WINDOW_MODIFIED,
              root
                  .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED));
      return;
    }

    JInternalFrame jif = (JInternalFrame) SwingUtilities
        .getAncestorOfClass(JInternalFrame.class, this.root);
    if (jif != null) {
      SubstanceInternalFrameUI internalFrameUI = (SubstanceInternalFrameUI) jif
          .getUI();
      internalFrameUI.setWindowModified(Boolean.TRUE.equals(root
          .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED)));
    }
  }

  public static boolean hasCustomSkinOnAtLeastOneRootPane() {
    return (rootPanesWithCustomSkin > 0);
  }
}
TOP

Related Classes of org.pushingpixels.substance.internal.ui.SubstanceRootPaneUI$TitleMouseInputHandler

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.