Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/macosx/classes/com/apple/laf/AquaInternalFrameUI.java
38831 views
/*1* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.apple.laf;2627import java.awt.*;28import java.awt.event.*;29import java.beans.*;3031import javax.swing.*;32import javax.swing.border.*;33import javax.swing.event.MouseInputAdapter;34import javax.swing.plaf.*;35import javax.swing.plaf.basic.BasicInternalFrameUI;3637import apple.laf.*;38import apple.laf.JRSUIConstants.*;3940import com.apple.laf.AquaUtils.*;41import com.apple.laf.AquaUtils.Painter;4243import sun.lwawt.macosx.CPlatformWindow;4445/**46* From AquaInternalFrameUI47*48* InternalFrame implementation for Aqua LAF49*50* We want to inherit most of the inner classes, but not the base class,51* so be very careful about subclassing so you know you get what you want52*53*/54public class AquaInternalFrameUI extends BasicInternalFrameUI implements SwingConstants {55protected static final String IS_PALETTE_PROPERTY = "JInternalFrame.isPalette";56private static final String FRAME_TYPE = "JInternalFrame.frameType";57private static final String NORMAL_FRAME = "normal";58private static final String PALETTE_FRAME = "palette";59private static final String OPTION_DIALOG = "optionDialog";6061// Instance variables62PropertyChangeListener fPropertyListener;6364protected Color fSelectedTextColor;65protected Color fNotSelectedTextColor;6667AquaInternalFrameBorder fAquaBorder;6869// for button tracking70boolean fMouseOverPressedButton;71int fWhichButtonPressed = -1;72boolean fRollover = false;73boolean fDocumentEdited = false; // to indicate whether we should use the dirty document red dot.74boolean fIsPallet;7576public int getWhichButtonPressed() {77return fWhichButtonPressed;78}7980public boolean getMouseOverPressedButton() {81return fMouseOverPressedButton;82}8384public boolean getRollover() {85return fRollover;86}8788// ComponentUI Interface Implementation methods89public static ComponentUI createUI(final JComponent b) {90return new AquaInternalFrameUI((JInternalFrame)b);91}9293public AquaInternalFrameUI(final JInternalFrame b) {94super(b);95}9697/// Inherit (but be careful to check everything they call):98public void installUI(final JComponent c) {99// super.installUI(c); // Swing 1.1.1 has a bug in installUI - it doesn't check for null northPane100frame = (JInternalFrame)c;101frame.add(frame.getRootPane(), "Center");102103installDefaults();104installListeners();105installComponents();106installKeyboardActions();107108Object paletteProp = c.getClientProperty(IS_PALETTE_PROPERTY);109if (paletteProp != null) {110setPalette(((Boolean)paletteProp).booleanValue());111} else {112paletteProp = c.getClientProperty(FRAME_TYPE);113if (paletteProp != null) {114setFrameType((String)paletteProp);115} else {116setFrameType(NORMAL_FRAME);117}118}119120// We only have a southPane, for grow box room, created in setFrameType121frame.setMinimumSize(new Dimension(fIsPallet ? 120 : 150, fIsPallet ? 39 : 65));122frame.setOpaque(false);123124c.setBorder(new CompoundUIBorder(fIsPallet ? paletteWindowShadow.get() : documentWindowShadow.get(), c.getBorder()));125}126127protected void installDefaults() {128super.installDefaults();129fSelectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");130fNotSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");131}132133public void setSouthPane(final JComponent c) {134if (southPane != null) {135frame.remove(southPane);136deinstallMouseHandlers(southPane);137}138if (c != null) {139frame.add(c);140installMouseHandlers(c);141}142southPane = c;143}144145static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() {146protected Icon getInstance() {147return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_CLOSE_BOX);148}149};150public static Icon exportCloseIcon() {151return closeIcon.get();152}153154static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() {155protected Icon getInstance() {156return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_COLLAPSE_BOX);157}158};159public static Icon exportMinimizeIcon() {160return minimizeIcon.get();161}162163static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() {164protected Icon getInstance() {165return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_ZOOM_BOX);166}167};168public static Icon exportZoomIcon() {169return zoomIcon.get();170}171172static class AquaInternalFrameButtonIcon extends AquaIcon.JRSUIIcon {173public AquaInternalFrameButtonIcon(final Widget widget) {174painter.state.set(widget);175}176177public void paintIcon(final Component c, final Graphics g, final int x, final int y) {178painter.state.set(getStateFor(c));179super.paintIcon(c, g, x, y);180}181182State getStateFor(final Component c) {183return State.ROLLOVER;184}185186public int getIconWidth() {187return 19;188}189190public int getIconHeight() {191return 19;192}193}194195protected void installKeyboardActions() {196} //$ Not Mac-ish - should we support?197198protected ResizeBox resizeBox;199protected void installComponents() {200final JLayeredPane layeredPane = frame.getLayeredPane();201if (resizeBox != null) {202resizeBox.removeListeners();203layeredPane.removeComponentListener(resizeBox);204layeredPane.remove(resizeBox);205resizeBox = null;206}207208resizeBox = new ResizeBox(layeredPane);209resizeBox.repositionResizeBox();210211layeredPane.add(resizeBox);212layeredPane.setLayer(resizeBox, JLayeredPane.DRAG_LAYER);213layeredPane.addComponentListener(resizeBox);214215resizeBox.addListeners();216resizeBox.setVisible(frame.isResizable());217}218219/// Inherit all the listeners - that's the main reason we subclass Basic!220protected void installListeners() {221fPropertyListener = new PropertyListener();222frame.addPropertyChangeListener(fPropertyListener);223super.installListeners();224}225226// uninstallDefaults227// uninstallComponents228protected void uninstallListeners() {229super.uninstallListeners();230frame.removePropertyChangeListener(fPropertyListener);231}232233protected void uninstallKeyboardActions() {234}235236// Called when a DesktopIcon replaces an InternalFrame & vice versa237//protected void replacePane(JComponent currentPane, JComponent newPane) {}238protected void installMouseHandlers(final JComponent c) {239c.addMouseListener(borderListener);240c.addMouseMotionListener(borderListener);241}242243protected void deinstallMouseHandlers(final JComponent c) {244c.removeMouseListener(borderListener);245c.removeMouseMotionListener(borderListener);246}247248ActionMap createActionMap() {249final ActionMap map = new ActionMapUIResource();250// add action for the system menu251// Set the ActionMap's parent to the Auditory Feedback Action Map252final AquaLookAndFeel lf = (AquaLookAndFeel)UIManager.getLookAndFeel();253final ActionMap audioMap = lf.getAudioActionMap();254map.setParent(audioMap);255return map;256}257258public Dimension getPreferredSize(JComponent x) {259Dimension preferredSize = super.getPreferredSize(x);260Dimension minimumSize = frame.getMinimumSize();261if (preferredSize.width < minimumSize.width) {262preferredSize.width = minimumSize.width;263}264if (preferredSize.height < minimumSize.height) {265preferredSize.height = minimumSize.height;266}267return preferredSize;268}269270public void setNorthPane(final JComponent c) {271replacePane(northPane, c);272northPane = c;273}274275/**276* Installs necessary mouse handlers on <code>newPane</code>277* and adds it to the frame.278* Reverse process for the <code>currentPane</code>.279*/280protected void replacePane(final JComponent currentPane, final JComponent newPane) {281if (currentPane != null) {282deinstallMouseHandlers(currentPane);283frame.remove(currentPane);284}285if (newPane != null) {286frame.add(newPane);287installMouseHandlers(newPane);288}289}290291// Our "Border" listener is shared by the AquaDesktopIcon292protected MouseInputAdapter createBorderListener(final JInternalFrame w) {293return new AquaBorderListener();294}295296/**297* Mac-specific stuff begins here298*/299void setFrameType(final String frameType) {300// Basic sets the background of the contentPane to null so it can inherit JInternalFrame.setBackground301// but if *that's* null, we get the JDesktop, which makes ours look invisible!302// So JInternalFrame has to have a background color303// See Sun bugs 4268949 & 4320889304final Color bg = frame.getBackground();305final boolean replaceColor = (bg == null || bg instanceof UIResource);306307final Font font = frame.getFont();308final boolean replaceFont = (font == null || font instanceof UIResource);309310boolean isPalette = false;311if (frameType.equals(OPTION_DIALOG)) {312fAquaBorder = AquaInternalFrameBorder.dialog();313if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.optionDialogBackground"));314if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.optionDialogTitleFont"));315} else if (frameType.equals(PALETTE_FRAME)) {316fAquaBorder = AquaInternalFrameBorder.utility();317if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.paletteBackground"));318if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.paletteTitleFont"));319isPalette = true;320} else {321fAquaBorder = AquaInternalFrameBorder.window();322if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.background"));323if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.titleFont"));324}325// We don't get the borders from UIManager, in case someone changes them - this class will not work with326// different borders. If they want different ones, they have to make their own InternalFrameUI class327328fAquaBorder.setColors(fSelectedTextColor, fNotSelectedTextColor);329frame.setBorder(fAquaBorder);330331fIsPallet = isPalette;332}333334public void setPalette(final boolean isPalette) {335setFrameType(isPalette ? PALETTE_FRAME : NORMAL_FRAME);336}337338public boolean isDocumentEdited() {339return fDocumentEdited;340}341342public void setDocumentEdited(final boolean flag) {343fDocumentEdited = flag;344}345346/*347// helpful debug drawing, shows component and content bounds348public void paint(final Graphics g, final JComponent c) {349super.paint(g, c);350351g.setColor(Color.green);352g.drawRect(0, 0, frame.getWidth() - 1, frame.getHeight() - 1);353354final Insets insets = frame.getInsets();355g.setColor(Color.orange);356g.drawRect(insets.left - 2, insets.top - 2, frame.getWidth() - insets.left - insets.right + 4, frame.getHeight() - insets.top - insets.bottom + 4);357}358*/359360// Border Listener Class361/**362* Listens for border adjustments.363*/364protected class AquaBorderListener extends MouseInputAdapter {365// _x & _y are the mousePressed location in absolute coordinate system366int _x, _y;367// __x & __y are the mousePressed location in source view's coordinate system368int __x, __y;369Rectangle startingBounds;370boolean fDraggingFrame;371int resizeDir;372373protected final int RESIZE_NONE = 0;374private boolean discardRelease = false;375376public void mouseClicked(final MouseEvent e) {377if (didForwardEvent(e)) return;378379if (e.getClickCount() <= 1 || e.getSource() != getNorthPane()) return;380381if (frame.isIconifiable() && frame.isIcon()) {382try {383frame.setIcon(false);384} catch(final PropertyVetoException e2) {}385} else if (frame.isMaximizable()) {386if (!frame.isMaximum()) try {387frame.setMaximum(true);388} catch(final PropertyVetoException e2) {}389else try {390frame.setMaximum(false);391} catch(final PropertyVetoException e3) {}392}393}394395public void updateRollover(final MouseEvent e) {396final boolean oldRollover = fRollover;397final Insets i = frame.getInsets();398fRollover = (isTitleBarDraggableArea(e) && fAquaBorder.getWithinRolloverArea(i, e.getX(), e.getY()));399if (fRollover != oldRollover) {400repaintButtons();401}402}403404public void repaintButtons() {405fAquaBorder.repaintButtonArea(frame);406}407408public void mouseReleased(final MouseEvent e) {409if (didForwardEvent(e)) return;410411fDraggingFrame = false;412413if (fWhichButtonPressed != -1) {414final int newButton = fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY());415416final int buttonPresed = fWhichButtonPressed;417fWhichButtonPressed = -1;418fMouseOverPressedButton = false;419420if (buttonPresed == newButton) {421fMouseOverPressedButton = false;422fRollover = false; // not sure if this is needed?423424fAquaBorder.doButtonAction(frame, buttonPresed);425}426427updateRollover(e);428repaintButtons();429return;430}431432if (discardRelease) {433discardRelease = false;434return;435}436if (resizeDir == RESIZE_NONE) getDesktopManager().endDraggingFrame(frame);437else {438final Container c = frame.getTopLevelAncestor();439if (c instanceof JFrame) {440((JFrame)frame.getTopLevelAncestor()).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));441442((JFrame)frame.getTopLevelAncestor()).getGlassPane().setVisible(false);443} else if (c instanceof JApplet) {444((JApplet)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));445((JApplet)c).getGlassPane().setVisible(false);446} else if (c instanceof JWindow) {447((JWindow)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));448((JWindow)c).getGlassPane().setVisible(false);449} else if (c instanceof JDialog) {450((JDialog)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));451((JDialog)c).getGlassPane().setVisible(false);452}453getDesktopManager().endResizingFrame(frame);454}455_x = 0;456_y = 0;457__x = 0;458__y = 0;459startingBounds = null;460resizeDir = RESIZE_NONE;461}462463public void mousePressed(final MouseEvent e) {464if (didForwardEvent(e)) return;465466final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null);467__x = e.getX();468__y = e.getY();469_x = p.x;470_y = p.y;471startingBounds = frame.getBounds();472resizeDir = RESIZE_NONE;473474if (updatePressed(e)) { return; }475476if (!frame.isSelected()) {477try {478frame.setSelected(true);479} catch(final PropertyVetoException e1) {}480}481482if (isTitleBarDraggableArea(e)) {483getDesktopManager().beginDraggingFrame(frame);484fDraggingFrame = true;485return;486}487488if (e.getSource() == getNorthPane()) {489getDesktopManager().beginDraggingFrame(frame);490return;491}492493if (!frame.isResizable()) { return; }494495if (e.getSource() == frame) {496discardRelease = true;497return;498}499}500501// returns true if we have handled the pressed502public boolean updatePressed(final MouseEvent e) {503// get the component.504fWhichButtonPressed = getButtonHit(e);505fMouseOverPressedButton = true;506repaintButtons();507return (fWhichButtonPressed >= 0);508// e.getX(), e.getY()509}510511public int getButtonHit(final MouseEvent e) {512return fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY());513}514515public boolean isTitleBarDraggableArea(final MouseEvent e) {516if (e.getSource() != frame) return false;517518final Point point = e.getPoint();519final Insets insets = frame.getInsets();520521if (point.y < insets.top - fAquaBorder.getTitleHeight()) return false;522if (point.y > insets.top) return false;523if (point.x < insets.left) return false;524if (point.x > frame.getWidth() - insets.left - insets.right) return false;525526return true;527}528529public void mouseDragged(final MouseEvent e) {530// do not forward drags531// if (didForwardEvent(e)) return;532533if (startingBounds == null) {534// (STEVE) Yucky work around for bug ID 4106552535return;536}537538if (fWhichButtonPressed != -1) {539// track the button we started on.540final int newButton = getButtonHit(e);541fMouseOverPressedButton = (fWhichButtonPressed == newButton);542repaintButtons();543return;544}545546final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null);547final int deltaX = _x - p.x;548final int deltaY = _y - p.y;549int newX, newY;550551// Handle a MOVE552if (!fDraggingFrame && e.getSource() != getNorthPane()) return;553554if (frame.isMaximum() || ((e.getModifiers() & InputEvent.BUTTON1_MASK) != InputEvent.BUTTON1_MASK)) {555// don't allow moving of frames if maximixed or left mouse556// button was not used.557return;558}559560final Dimension s = frame.getParent().getSize();561final int pWidth = s.width;562final int pHeight = s.height;563564final Insets i = frame.getInsets();565newX = startingBounds.x - deltaX;566newY = startingBounds.y - deltaY;567568// Make sure we stay in-bounds569if (newX + i.left <= -__x) newX = -__x - i.left;570if (newY + i.top <= -__y) newY = -__y - i.top;571if (newX + __x + i.right > pWidth) newX = pWidth - __x - i.right;572if (newY + __y + i.bottom > pHeight) newY = pHeight - __y - i.bottom;573574getDesktopManager().dragFrame(frame, newX, newY);575return;576}577578public void mouseMoved(final MouseEvent e) {579if (didForwardEvent(e)) return;580updateRollover(e);581}582583// guards against accidental infinite recursion584boolean isTryingToForwardEvent = false;585boolean didForwardEvent(final MouseEvent e) {586if (isTryingToForwardEvent) return true; // we didn't actually...but we wound up back where we started.587588isTryingToForwardEvent = true;589final boolean didForwardEvent = didForwardEventInternal(e);590isTryingToForwardEvent = false;591592return didForwardEvent;593}594595boolean didForwardEventInternal(final MouseEvent e) {596if (fDraggingFrame) return false;597598final Point originalPoint = e.getPoint();599if (!isEventInWindowShadow(originalPoint)) return false;600601final Container parent = frame.getParent();602if (!(parent instanceof JDesktopPane)) return false;603final JDesktopPane pane = (JDesktopPane)parent;604final Point parentPoint = SwingUtilities.convertPoint(frame, originalPoint, parent);605606/* // debug drawing607Graphics g = parent.getGraphics();608g.setColor(Color.red);609g.drawLine(parentPoint.x, parentPoint.y, parentPoint.x, parentPoint.y);610*/611612final Component hitComponent = findComponentToHitBehindMe(pane, parentPoint);613if (hitComponent == null || hitComponent == frame) return false;614615final Point hitComponentPoint = SwingUtilities.convertPoint(pane, parentPoint, hitComponent);616hitComponent.dispatchEvent(new MouseEvent(hitComponent, e.getID(), e.getWhen(), e.getModifiers(), hitComponentPoint.x, hitComponentPoint.y, e.getClickCount(), e.isPopupTrigger(), e.getButton()));617return true;618}619620Component findComponentToHitBehindMe(final JDesktopPane pane, final Point parentPoint) {621final JInternalFrame[] allFrames = pane.getAllFrames();622623boolean foundSelf = false;624for (final JInternalFrame f : allFrames) {625if (f == frame) { foundSelf = true; continue; }626if (!foundSelf) continue;627628final Rectangle bounds = f.getBounds();629if (bounds.contains(parentPoint)) return f;630}631632return pane;633}634635boolean isEventInWindowShadow(final Point point) {636final Rectangle bounds = frame.getBounds();637final Insets insets = frame.getInsets();638insets.top -= fAquaBorder.getTitleHeight();639640if (point.x < insets.left) return true;641if (point.x > bounds.width - insets.right) return true;642if (point.y < insets.top) return true;643if (point.y > bounds.height - insets.bottom) return true;644645return false;646}647}648649static void updateComponentTreeUIActivation(final Component c, final Object active) {650if (c instanceof javax.swing.JComponent) {651((javax.swing.JComponent)c).putClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY, active);652}653654Component[] children = null;655656if (c instanceof javax.swing.JMenu) {657children = ((javax.swing.JMenu)c).getMenuComponents();658} else if (c instanceof Container) {659children = ((Container)c).getComponents();660}661662if (children != null) {663for (final Component element : children) {664updateComponentTreeUIActivation(element, active);665}666}667}668669class PropertyListener implements PropertyChangeListener {670public void propertyChange(final PropertyChangeEvent e) {671final String name = e.getPropertyName();672if (FRAME_TYPE.equals(name)) {673if (e.getNewValue() instanceof String) {674setFrameType((String)e.getNewValue());675}676} else if (IS_PALETTE_PROPERTY.equals(name)) {677if (e.getNewValue() != null) {678setPalette(((Boolean)e.getNewValue()).booleanValue());679} else {680setPalette(false);681}682// TODO: CPlatformWindow?683} else if ("windowModified".equals(name) || CPlatformWindow.WINDOW_DOCUMENT_MODIFIED.equals(name)) {684// repaint title bar685setDocumentEdited(((Boolean)e.getNewValue()).booleanValue());686frame.repaint(0, 0, frame.getWidth(), frame.getBorder().getBorderInsets(frame).top);687} else if ("resizable".equals(name) || "state".equals(name) || "iconable".equals(name) || "maximizable".equals(name) || "closable".equals(name)) {688if ("resizable".equals(name)) {689frame.revalidate();690}691frame.repaint();692} else if ("title".equals(name)) {693frame.repaint();694} else if ("componentOrientation".equals(name)) {695frame.revalidate();696frame.repaint();697} else if (JInternalFrame.IS_SELECTED_PROPERTY.equals(name)) {698final Component source = (Component)(e.getSource());699updateComponentTreeUIActivation(source, frame.isSelected() ? Boolean.TRUE : Boolean.FALSE);700}701702}703} // end class PaletteListener704705static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() {706Border getForegroundShadowBorder() {707return new AquaUtils.SlicedShadowBorder(new Painter() {708public void paint(final Graphics g, final int x, final int y, final int w, final int h) {709g.setColor(new Color(0, 0, 0, 196));710g.fillRoundRect(x, y, w, h, 16, 16);711g.fillRect(x, y + h - 16, w, 16);712}713}, new Painter() {714public void paint(final Graphics g, int x, int y, int w, int h) {715g.setColor(new Color(0, 0, 0, 64));716g.drawLine(x + 2, y - 8, x + w - 2, y - 8);717}718},7190, 7, 1.1f, 1.0f, 24, 51, 51, 25, 25, 25, 25);720}721722Border getBackgroundShadowBorder() {723return new AquaUtils.SlicedShadowBorder(new Painter() {724public void paint(final Graphics g, final int x, final int y, final int w, final int h) {725g.setColor(new Color(0, 0, 0, 128));726g.fillRoundRect(x - 3, y - 8, w + 6, h, 16, 16);727g.fillRect(x - 3, y + h - 20, w + 6, 19);728}729}, new Painter() {730public void paint(final Graphics g, int x, int y, int w, int h) {731g.setColor(new Color(0, 0, 0, 32));732g.drawLine(x, y - 11, x + w - 1, y - 11);733}734},7350, 0, 3.0f, 1.0f, 10, 51, 51, 25, 25, 25, 25);736}737};738739static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() {740Border getForegroundShadowBorder() {741return new AquaUtils.SlicedShadowBorder(new Painter() {742public void paint(final Graphics g, final int x, final int y, final int w, final int h) {743g.setColor(new Color(0, 0, 0, 128));744g.fillRect(x, y + 3, w, h - 3);745}746}, null,7470, 3, 1.0f, 1.0f, 10, 25, 25, 12, 12, 12, 12);748}749750Border getBackgroundShadowBorder() {751return getForegroundShadowBorder();752}753};754755static class CompoundUIBorder extends CompoundBorder implements UIResource {756public CompoundUIBorder(final Border inside, final Border outside) { super(inside, outside); }757}758759abstract static class InternalFrameShadow extends RecyclableSingleton<Border> {760abstract Border getForegroundShadowBorder();761abstract Border getBackgroundShadowBorder();762763protected Border getInstance() {764final Border fgShadow = getForegroundShadowBorder();765final Border bgShadow = getBackgroundShadowBorder();766767return new Border() {768public Insets getBorderInsets(final Component c) {769return fgShadow.getBorderInsets(c);770}771772public boolean isBorderOpaque() {773return false;774}775776public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) {777if (((JInternalFrame)c).isSelected()) {778fgShadow.paintBorder(c, g, x, y, w, h);779} else {780bgShadow.paintBorder(c, g, x, y, w, h);781}782}783};784}785}786787static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() {788@Override789protected Icon getInstance() {790return new AquaIcon.ScalingJRSUIIcon(11, 11) {791public void initIconPainter(final AquaPainter<JRSUIState> iconState) {792iconState.state.set(Widget.GROW_BOX_TEXTURED);793iconState.state.set(WindowType.UTILITY);794}795};796}797};798799class ResizeBox extends JLabel implements MouseListener, MouseMotionListener, MouseWheelListener, ComponentListener, PropertyChangeListener, UIResource {800final JLayeredPane layeredPane;801Dimension originalSize;802Point originalLocation;803804public ResizeBox(final JLayeredPane layeredPane) {805super(RESIZE_ICON.get());806setSize(11, 11);807this.layeredPane = layeredPane;808809addMouseListener(this);810addMouseMotionListener(this);811addMouseWheelListener(this);812}813814void addListeners() {815frame.addPropertyChangeListener("resizable", this);816}817818void removeListeners() {819frame.removePropertyChangeListener("resizable", this);820}821822void repositionResizeBox() {823if (frame == null) { setSize(0, 0); } else { setSize(11, 11); }824setLocation(layeredPane.getWidth() - 12, layeredPane.getHeight() - 12);825}826827void resizeInternalFrame(final Point pt) {828if (originalLocation == null || frame == null) return;829830final Container parent = frame.getParent();831if (!(parent instanceof JDesktopPane)) return;832833final Point newPoint = SwingUtilities.convertPoint(this, pt, frame);834int deltaX = originalLocation.x - newPoint.x;835int deltaY = originalLocation.y - newPoint.y;836final Dimension min = frame.getMinimumSize();837final Dimension max = frame.getMaximumSize();838839final int newX = frame.getX();840final int newY = frame.getY();841int newW = frame.getWidth();842int newH = frame.getHeight();843844final Rectangle parentBounds = parent.getBounds();845846if (originalSize.width - deltaX < min.width) {847deltaX = originalSize.width - min.width;848} else if (originalSize.width - deltaX > max.width) {849deltaX = -(max.width - originalSize.width);850}851852if (newX + originalSize.width - deltaX > parentBounds.width) {853deltaX = newX + originalSize.width - parentBounds.width;854}855856if (originalSize.height - deltaY < min.height) {857deltaY = originalSize.height - min.height;858} else if (originalSize.height - deltaY > max.height) {859deltaY = -(max.height - originalSize.height);860}861862if (newY + originalSize.height - deltaY > parentBounds.height) {863deltaY = newY + originalSize.height - parentBounds.height;864}865866newW = originalSize.width - deltaX;867newH = originalSize.height - deltaY;868869getDesktopManager().resizeFrame(frame, newX, newY, newW, newH);870}871872boolean testGrowboxPoint(final int x, final int y, final int w, final int h) {873return (w - x) + (h - y) < 12;874}875876void forwardEventToFrame(final MouseEvent e) {877final Point pt = new Point();878final Component c = getComponentToForwardTo(e, pt);879if (c == null) return;880c.dispatchEvent(new MouseEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getButton()));881}882883Component getComponentToForwardTo(final MouseEvent e, final Point dst) {884if (frame == null) return null;885final Container contentPane = frame.getContentPane();886if (contentPane == null) return null;887Point pt = SwingUtilities.convertPoint(this, e.getPoint(), contentPane);888final Component c = SwingUtilities.getDeepestComponentAt(contentPane, pt.x, pt.y);889if (c == null) return null;890pt = SwingUtilities.convertPoint(contentPane, pt, c);891if (dst != null) dst.setLocation(pt);892return c;893}894895public void mouseClicked(final MouseEvent e) {896forwardEventToFrame(e);897}898899public void mouseEntered(final MouseEvent e) { }900901public void mouseExited(final MouseEvent e) { }902903public void mousePressed(final MouseEvent e) {904if (frame == null) return;905906if (frame.isResizable() && !frame.isMaximum() && testGrowboxPoint(e.getX(), e.getY(), getWidth(), getHeight())) {907originalLocation = SwingUtilities.convertPoint(this, e.getPoint(), frame);908originalSize = frame.getSize();909getDesktopManager().beginResizingFrame(frame, SwingConstants.SOUTH_EAST);910return;911}912913forwardEventToFrame(e);914}915916public void mouseReleased(final MouseEvent e) {917if (originalLocation != null) {918resizeInternalFrame(e.getPoint());919originalLocation = null;920getDesktopManager().endResizingFrame(frame);921return;922}923924forwardEventToFrame(e);925}926927public void mouseDragged(final MouseEvent e) {928resizeInternalFrame(e.getPoint());929repositionResizeBox();930}931932public void mouseMoved(final MouseEvent e) { }933934public void mouseWheelMoved(final MouseWheelEvent e) {935final Point pt = new Point();936final Component c = getComponentToForwardTo(e, pt);937if (c == null) return;938c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation()));939}940941public void componentResized(final ComponentEvent e) {942repositionResizeBox();943}944945public void componentShown(final ComponentEvent e) {946repositionResizeBox();947}948949public void componentMoved(final ComponentEvent e) {950repositionResizeBox();951}952953public void componentHidden(final ComponentEvent e) { }954955public void propertyChange(final PropertyChangeEvent evt) {956if (!"resizable".equals(evt.getPropertyName())) return;957setVisible(Boolean.TRUE.equals(evt.getNewValue()));958}959}960}961962963