Path: blob/master/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java
41154 views
/*1* Copyright (c) 2011, 2021, 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;68private ResizeBox resizeBox;6970// for button tracking71boolean fMouseOverPressedButton;72int fWhichButtonPressed = -1;73boolean fRollover = false;74boolean fDocumentEdited = false; // to indicate whether we should use the dirty document red dot.75boolean fIsPallet;7677public int getWhichButtonPressed() {78return fWhichButtonPressed;79}8081public boolean getMouseOverPressedButton() {82return fMouseOverPressedButton;83}8485public boolean getRollover() {86return fRollover;87}8889// ComponentUI Interface Implementation methods90public static ComponentUI createUI(final JComponent b) {91return new AquaInternalFrameUI((JInternalFrame)b);92}9394public AquaInternalFrameUI(final JInternalFrame b) {95super(b);96}9798/// Inherit (but be careful to check everything they call):99@Override100public void installUI(final JComponent c) {101// super.installUI(c); // Swing 1.1.1 has a bug in installUI - it doesn't check for null northPane102frame = (JInternalFrame)c;103frame.add(frame.getRootPane(), "Center");104105installDefaults();106installListeners();107installComponents();108installKeyboardActions();109110Object paletteProp = c.getClientProperty(IS_PALETTE_PROPERTY);111if (paletteProp != null) {112setPalette(((Boolean)paletteProp).booleanValue());113} else {114paletteProp = c.getClientProperty(FRAME_TYPE);115if (paletteProp != null) {116setFrameType((String)paletteProp);117} else {118setFrameType(NORMAL_FRAME);119}120}121122// We only have a southPane, for grow box room, created in setFrameType123frame.setMinimumSize(new Dimension(fIsPallet ? 120 : 150, fIsPallet ? 39 : 65));124frame.setOpaque(false);125126c.setBorder(new CompoundUIBorder(fIsPallet ? paletteWindowShadow.get() : documentWindowShadow.get(), c.getBorder()));127}128129@Override130protected void installDefaults() {131super.installDefaults();132fSelectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");133fNotSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");134}135136@Override137public void setSouthPane(final JComponent c) {138if (southPane != null) {139frame.remove(southPane);140deinstallMouseHandlers(southPane);141}142if (c != null) {143frame.add(c);144installMouseHandlers(c);145}146southPane = c;147}148149private static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() {150@Override151protected Icon getInstance() {152return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_CLOSE_BOX);153}154};155public static Icon exportCloseIcon() {156return closeIcon.get();157}158159private static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() {160@Override161protected Icon getInstance() {162return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_COLLAPSE_BOX);163}164};165public static Icon exportMinimizeIcon() {166return minimizeIcon.get();167}168169private static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() {170@Override171protected Icon getInstance() {172return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_ZOOM_BOX);173}174};175public static Icon exportZoomIcon() {176return zoomIcon.get();177}178179static class AquaInternalFrameButtonIcon extends AquaIcon.JRSUIIcon {180public AquaInternalFrameButtonIcon(final Widget widget) {181painter.state.set(widget);182}183184@Override185public void paintIcon(final Component c, final Graphics g, final int x, final int y) {186painter.state.set(getStateFor(c));187super.paintIcon(c, g, x, y);188}189190State getStateFor(final Component c) {191return State.ROLLOVER;192}193194@Override195public int getIconWidth() {196return 19;197}198199@Override200public int getIconHeight() {201return 19;202}203}204205@Override206protected void installKeyboardActions() {207} //$ Not Mac-ish - should we support?208209@Override210protected void installComponents() {211final JLayeredPane layeredPane = frame.getLayeredPane();212resizeBox = new ResizeBox(layeredPane);213resizeBox.repositionResizeBox();214215layeredPane.add(resizeBox);216layeredPane.setLayer(resizeBox, JLayeredPane.DRAG_LAYER);217layeredPane.addComponentListener(resizeBox);218219resizeBox.addListeners();220resizeBox.setVisible(frame.isResizable());221}222223/// Inherit all the listeners - that's the main reason we subclass Basic!224@Override225protected void installListeners() {226fPropertyListener = new PropertyListener();227frame.addPropertyChangeListener(fPropertyListener);228super.installListeners();229}230231// uninstallDefaults232233@Override234protected void uninstallComponents() {235super.uninstallComponents();236final JLayeredPane layeredPane = frame.getLayeredPane();237resizeBox.removeListeners();238layeredPane.removeComponentListener(resizeBox);239layeredPane.remove(resizeBox);240resizeBox = null;241}242243@Override244protected void uninstallListeners() {245super.uninstallListeners();246frame.removePropertyChangeListener(fPropertyListener);247}248249@Override250protected void uninstallKeyboardActions() {251}252253// Called when a DesktopIcon replaces an InternalFrame & vice versa254//protected void replacePane(JComponent currentPane, JComponent newPane) {}255@Override256protected void installMouseHandlers(final JComponent c) {257c.addMouseListener(borderListener);258c.addMouseMotionListener(borderListener);259}260261@Override262protected void deinstallMouseHandlers(final JComponent c) {263c.removeMouseListener(borderListener);264c.removeMouseMotionListener(borderListener);265}266267ActionMap createActionMap() {268final ActionMap map = new ActionMapUIResource();269// add action for the system menu270// Set the ActionMap's parent to the Auditory Feedback Action Map271final AquaLookAndFeel lf = (AquaLookAndFeel)UIManager.getLookAndFeel();272final ActionMap audioMap = lf.getAudioActionMap();273map.setParent(audioMap);274return map;275}276277@Override278public Dimension getPreferredSize(JComponent x) {279Dimension preferredSize = super.getPreferredSize(x);280Dimension minimumSize = frame.getMinimumSize();281if (preferredSize.width < minimumSize.width) {282preferredSize.width = minimumSize.width;283}284if (preferredSize.height < minimumSize.height) {285preferredSize.height = minimumSize.height;286}287return preferredSize;288}289290@Override291public void setNorthPane(final JComponent c) {292replacePane(northPane, c);293northPane = c;294}295296/**297* Installs necessary mouse handlers on {@code newPane}298* and adds it to the frame.299* Reverse process for the {@code currentPane}.300*/301@Override302protected void replacePane(final JComponent currentPane, final JComponent newPane) {303if (currentPane != null) {304deinstallMouseHandlers(currentPane);305frame.remove(currentPane);306}307if (newPane != null) {308frame.add(newPane);309installMouseHandlers(newPane);310}311}312313// Our "Border" listener is shared by the AquaDesktopIcon314@Override315protected MouseInputAdapter createBorderListener(final JInternalFrame w) {316return new AquaBorderListener();317}318319/**320* Mac-specific stuff begins here321*/322void setFrameType(final String frameType) {323// Basic sets the background of the contentPane to null so it can inherit JInternalFrame.setBackground324// but if *that's* null, we get the JDesktop, which makes ours look invisible!325// So JInternalFrame has to have a background color326// See Sun bugs 4268949 & 4320889327final Color bg = frame.getBackground();328final boolean replaceColor = (bg == null || bg instanceof UIResource);329330final Font font = frame.getFont();331final boolean replaceFont = (font == null || font instanceof UIResource);332333boolean isPalette = false;334if (frameType.equals(OPTION_DIALOG)) {335fAquaBorder = AquaInternalFrameBorder.dialog();336if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.optionDialogBackground"));337if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.optionDialogTitleFont"));338} else if (frameType.equals(PALETTE_FRAME)) {339fAquaBorder = AquaInternalFrameBorder.utility();340if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.paletteBackground"));341if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.paletteTitleFont"));342isPalette = true;343} else {344fAquaBorder = AquaInternalFrameBorder.window();345if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.background"));346if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.titleFont"));347}348// We don't get the borders from UIManager, in case someone changes them - this class will not work with349// different borders. If they want different ones, they have to make their own InternalFrameUI class350351fAquaBorder.setColors(fSelectedTextColor, fNotSelectedTextColor);352frame.setBorder(fAquaBorder);353354fIsPallet = isPalette;355}356357public void setPalette(final boolean isPalette) {358setFrameType(isPalette ? PALETTE_FRAME : NORMAL_FRAME);359}360361public boolean isDocumentEdited() {362return fDocumentEdited;363}364365public void setDocumentEdited(final boolean flag) {366fDocumentEdited = flag;367}368369/*370// helpful debug drawing, shows component and content bounds371public void paint(final Graphics g, final JComponent c) {372super.paint(g, c);373374g.setColor(Color.green);375g.drawRect(0, 0, frame.getWidth() - 1, frame.getHeight() - 1);376377final Insets insets = frame.getInsets();378g.setColor(Color.orange);379g.drawRect(insets.left - 2, insets.top - 2, frame.getWidth() - insets.left - insets.right + 4, frame.getHeight() - insets.top - insets.bottom + 4);380}381*/382383// Border Listener Class384/**385* Listens for border adjustments.386*/387protected class AquaBorderListener extends MouseInputAdapter {388// _x & _y are the mousePressed location in absolute coordinate system389int _x, _y;390// __x & __y are the mousePressed location in source view's coordinate system391int __x, __y;392Rectangle startingBounds;393boolean fDraggingFrame;394int resizeDir;395396protected final int RESIZE_NONE = 0;397private boolean discardRelease = false;398399@Override400public void mouseClicked(final MouseEvent e) {401if (didForwardEvent(e)) return;402403if (e.getClickCount() <= 1 || e.getSource() != getNorthPane()) return;404405if (frame.isIconifiable() && frame.isIcon()) {406try {407frame.setIcon(false);408} catch(final PropertyVetoException e2) {}409} else if (frame.isMaximizable()) {410if (!frame.isMaximum()) try {411frame.setMaximum(true);412} catch(final PropertyVetoException e2) {}413else try {414frame.setMaximum(false);415} catch(final PropertyVetoException e3) {}416}417}418419public void updateRollover(final MouseEvent e) {420final boolean oldRollover = fRollover;421final Insets i = frame.getInsets();422fRollover = (isTitleBarDraggableArea(e) && fAquaBorder.getWithinRolloverArea(i, e.getX(), e.getY()));423if (fRollover != oldRollover) {424repaintButtons();425}426}427428public void repaintButtons() {429fAquaBorder.repaintButtonArea(frame);430}431432@Override433@SuppressWarnings("removal")434public void mouseReleased(final MouseEvent e) {435if (didForwardEvent(e)) return;436437fDraggingFrame = false;438439if (fWhichButtonPressed != -1) {440final int newButton = fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY());441442final int buttonPresed = fWhichButtonPressed;443fWhichButtonPressed = -1;444fMouseOverPressedButton = false;445446if (buttonPresed == newButton) {447fMouseOverPressedButton = false;448fRollover = false; // not sure if this is needed?449450fAquaBorder.doButtonAction(frame, buttonPresed);451}452453updateRollover(e);454repaintButtons();455return;456}457458if (discardRelease) {459discardRelease = false;460return;461}462if (resizeDir == RESIZE_NONE) getDesktopManager().endDraggingFrame(frame);463else {464final Container c = frame.getTopLevelAncestor();465if (c instanceof JFrame) {466((JFrame)frame.getTopLevelAncestor()).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));467468((JFrame)frame.getTopLevelAncestor()).getGlassPane().setVisible(false);469} else if (c instanceof JApplet) {470((JApplet)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));471((JApplet)c).getGlassPane().setVisible(false);472} else if (c instanceof JWindow) {473((JWindow)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));474((JWindow)c).getGlassPane().setVisible(false);475} else if (c instanceof JDialog) {476((JDialog)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));477((JDialog)c).getGlassPane().setVisible(false);478}479getDesktopManager().endResizingFrame(frame);480}481_x = 0;482_y = 0;483__x = 0;484__y = 0;485startingBounds = null;486resizeDir = RESIZE_NONE;487}488489@Override490public void mousePressed(final MouseEvent e) {491if (didForwardEvent(e)) return;492493final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null);494__x = e.getX();495__y = e.getY();496_x = p.x;497_y = p.y;498startingBounds = frame.getBounds();499resizeDir = RESIZE_NONE;500501if (updatePressed(e)) { return; }502503if (!frame.isSelected()) {504try {505frame.setSelected(true);506} catch(final PropertyVetoException e1) {}507}508509if (isTitleBarDraggableArea(e)) {510getDesktopManager().beginDraggingFrame(frame);511fDraggingFrame = true;512return;513}514515if (e.getSource() == getNorthPane()) {516getDesktopManager().beginDraggingFrame(frame);517return;518}519520if (!frame.isResizable()) { return; }521522if (e.getSource() == frame) {523discardRelease = true;524return;525}526}527528// returns true if we have handled the pressed529public boolean updatePressed(final MouseEvent e) {530// get the component.531fWhichButtonPressed = getButtonHit(e);532fMouseOverPressedButton = true;533repaintButtons();534return (fWhichButtonPressed >= 0);535// e.getX(), e.getY()536}537538public int getButtonHit(final MouseEvent e) {539return fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY());540}541542public boolean isTitleBarDraggableArea(final MouseEvent e) {543if (e.getSource() != frame) return false;544545final Point point = e.getPoint();546final Insets insets = frame.getInsets();547548if (point.y < insets.top - fAquaBorder.getTitleHeight()) return false;549if (point.y > insets.top) return false;550if (point.x < insets.left) return false;551if (point.x > frame.getWidth() - insets.left - insets.right) return false;552553return true;554}555556@Override557@SuppressWarnings("deprecation")558public void mouseDragged(final MouseEvent e) {559// do not forward drags560// if (didForwardEvent(e)) return;561562if (startingBounds == null) {563// (STEVE) Yucky work around for bug ID 4106552564return;565}566567if (fWhichButtonPressed != -1) {568// track the button we started on.569final int newButton = getButtonHit(e);570fMouseOverPressedButton = (fWhichButtonPressed == newButton);571repaintButtons();572return;573}574575final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null);576final int deltaX = _x - p.x;577final int deltaY = _y - p.y;578int newX, newY;579580// Handle a MOVE581if (!fDraggingFrame && e.getSource() != getNorthPane()) return;582583if (frame.isMaximum() || ((e.getModifiers() & InputEvent.BUTTON1_MASK) != InputEvent.BUTTON1_MASK)) {584// don't allow moving of frames if maximixed or left mouse585// button was not used.586return;587}588589final Dimension s = frame.getParent().getSize();590final int pWidth = s.width;591final int pHeight = s.height;592593final Insets i = frame.getInsets();594newX = startingBounds.x - deltaX;595newY = startingBounds.y - deltaY;596597// Make sure we stay in-bounds598if (newX + i.left <= -__x) newX = -__x - i.left;599if (newY + i.top <= -__y) newY = -__y - i.top;600if (newX + __x + i.right > pWidth) newX = pWidth - __x - i.right;601if (newY + __y + i.bottom > pHeight) newY = pHeight - __y - i.bottom;602603getDesktopManager().dragFrame(frame, newX, newY);604return;605}606607@Override608public void mouseMoved(final MouseEvent e) {609if (didForwardEvent(e)) return;610updateRollover(e);611}612613// guards against accidental infinite recursion614boolean isTryingToForwardEvent = false;615boolean didForwardEvent(final MouseEvent e) {616if (isTryingToForwardEvent) return true; // we didn't actually...but we wound up back where we started.617618isTryingToForwardEvent = true;619final boolean didForwardEvent = didForwardEventInternal(e);620isTryingToForwardEvent = false;621622return didForwardEvent;623}624@SuppressWarnings("deprecation")625boolean didForwardEventInternal(final MouseEvent e) {626if (fDraggingFrame) return false;627628final Point originalPoint = e.getPoint();629if (!isEventInWindowShadow(originalPoint)) return false;630631final Container parent = frame.getParent();632if (!(parent instanceof JDesktopPane)) return false;633final JDesktopPane pane = (JDesktopPane)parent;634final Point parentPoint = SwingUtilities.convertPoint(frame, originalPoint, parent);635636/* // debug drawing637Graphics g = parent.getGraphics();638g.setColor(Color.red);639g.drawLine(parentPoint.x, parentPoint.y, parentPoint.x, parentPoint.y);640*/641642final Component hitComponent = findComponentToHitBehindMe(pane, parentPoint);643if (hitComponent == null || hitComponent == frame) return false;644645final Point hitComponentPoint = SwingUtilities.convertPoint(pane, parentPoint, hitComponent);646hitComponent.dispatchEvent(647new MouseEvent(hitComponent, e.getID(), e.getWhen(),648e.getModifiers(), hitComponentPoint.x,649hitComponentPoint.y, e.getClickCount(),650e.isPopupTrigger(), e.getButton()));651return true;652}653654Component findComponentToHitBehindMe(final JDesktopPane pane, final Point parentPoint) {655final JInternalFrame[] allFrames = pane.getAllFrames();656657boolean foundSelf = false;658for (final JInternalFrame f : allFrames) {659if (f == frame) { foundSelf = true; continue; }660if (!foundSelf) continue;661662final Rectangle bounds = f.getBounds();663if (bounds.contains(parentPoint)) return f;664}665666return pane;667}668669boolean isEventInWindowShadow(final Point point) {670final Rectangle bounds = frame.getBounds();671final Insets insets = frame.getInsets();672insets.top -= fAquaBorder.getTitleHeight();673674if (point.x < insets.left) return true;675if (point.x > bounds.width - insets.right) return true;676if (point.y < insets.top) return true;677if (point.y > bounds.height - insets.bottom) return true;678679return false;680}681}682683static void updateComponentTreeUIActivation(final Component c, final Object active) {684if (c instanceof javax.swing.JComponent) {685((javax.swing.JComponent)c).putClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY, active);686}687688Component[] children = null;689690if (c instanceof javax.swing.JMenu) {691children = ((javax.swing.JMenu)c).getMenuComponents();692} else if (c instanceof Container) {693children = ((Container)c).getComponents();694}695696if (children != null) {697for (final Component element : children) {698updateComponentTreeUIActivation(element, active);699}700}701}702703class PropertyListener implements PropertyChangeListener {704@Override705public void propertyChange(final PropertyChangeEvent e) {706final String name = e.getPropertyName();707if (FRAME_TYPE.equals(name)) {708if (e.getNewValue() instanceof String) {709setFrameType((String)e.getNewValue());710}711} else if (IS_PALETTE_PROPERTY.equals(name)) {712if (e.getNewValue() != null) {713setPalette(((Boolean)e.getNewValue()).booleanValue());714} else {715setPalette(false);716}717// TODO: CPlatformWindow?718} else if ("windowModified".equals(name) || CPlatformWindow.WINDOW_DOCUMENT_MODIFIED.equals(name)) {719// repaint title bar720setDocumentEdited(((Boolean)e.getNewValue()).booleanValue());721frame.repaint(0, 0, frame.getWidth(), frame.getBorder().getBorderInsets(frame).top);722} else if ("resizable".equals(name) || "state".equals(name) || "iconable".equals(name) || "maximizable".equals(name) || "closable".equals(name)) {723if ("resizable".equals(name)) {724frame.revalidate();725}726frame.repaint();727} else if ("title".equals(name)) {728frame.repaint();729} else if ("componentOrientation".equals(name)) {730frame.revalidate();731frame.repaint();732} else if (JInternalFrame.IS_SELECTED_PROPERTY.equals(name)) {733final Component source = (Component)(e.getSource());734updateComponentTreeUIActivation(source, frame.isSelected() ? Boolean.TRUE : Boolean.FALSE);735}736737}738} // end class PaletteListener739740private static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() {741@Override742Border getForegroundShadowBorder() {743return new AquaUtils.SlicedShadowBorder(new Painter() {744@Override745public void paint(final Graphics g, final int x, final int y, final int w, final int h) {746g.setColor(new Color(0, 0, 0, 196));747g.fillRoundRect(x, y, w, h, 16, 16);748g.fillRect(x, y + h - 16, w, 16);749}750}, new Painter() {751@Override752public void paint(final Graphics g, int x, int y, int w, int h) {753g.setColor(new Color(0, 0, 0, 64));754g.drawLine(x + 2, y - 8, x + w - 2, y - 8);755}756},7570, 7, 1.1f, 1.0f, 24, 51, 51, 25, 25, 25, 25);758}759760@Override761Border getBackgroundShadowBorder() {762return new AquaUtils.SlicedShadowBorder(new Painter() {763@Override764public void paint(final Graphics g, final int x, final int y, final int w, final int h) {765g.setColor(new Color(0, 0, 0, 128));766g.fillRoundRect(x - 3, y - 8, w + 6, h, 16, 16);767g.fillRect(x - 3, y + h - 20, w + 6, 19);768}769}, new Painter() {770@Override771public void paint(final Graphics g, int x, int y, int w, int h) {772g.setColor(new Color(0, 0, 0, 32));773g.drawLine(x, y - 11, x + w - 1, y - 11);774}775},7760, 0, 3.0f, 1.0f, 10, 51, 51, 25, 25, 25, 25);777}778};779780private static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() {781@Override782Border getForegroundShadowBorder() {783return new AquaUtils.SlicedShadowBorder(new Painter() {784@Override785public void paint(final Graphics g, final int x, final int y, final int w, final int h) {786g.setColor(new Color(0, 0, 0, 128));787g.fillRect(x, y + 3, w, h - 3);788}789}, null,7900, 3, 1.0f, 1.0f, 10, 25, 25, 12, 12, 12, 12);791}792793@Override794Border getBackgroundShadowBorder() {795return getForegroundShadowBorder();796}797};798799@SuppressWarnings("serial") // Superclass is not serializable across versions800static class CompoundUIBorder extends CompoundBorder implements UIResource {801public CompoundUIBorder(final Border inside, final Border outside) { super(inside, outside); }802}803804abstract static class InternalFrameShadow extends RecyclableSingleton<Border> {805abstract Border getForegroundShadowBorder();806abstract Border getBackgroundShadowBorder();807808@Override809protected Border getInstance() {810final Border fgShadow = getForegroundShadowBorder();811final Border bgShadow = getBackgroundShadowBorder();812813return new Border() {814@Override815public Insets getBorderInsets(final Component c) {816return fgShadow.getBorderInsets(c);817}818819@Override820public boolean isBorderOpaque() {821return false;822}823824@Override825public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) {826if (((JInternalFrame)c).isSelected()) {827fgShadow.paintBorder(c, g, x, y, w, h);828} else {829bgShadow.paintBorder(c, g, x, y, w, h);830}831}832};833}834}835836private static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() {837@Override838protected Icon getInstance() {839return new AquaIcon.ScalingJRSUIIcon(11, 11) {840@Override841public void initIconPainter(final AquaPainter<JRSUIState> iconState) {842iconState.state.set(Widget.GROW_BOX_TEXTURED);843iconState.state.set(WindowType.UTILITY);844}845};846}847};848849@SuppressWarnings("serial") // Superclass is not serializable across versions850private final class ResizeBox extends JLabel851implements MouseListener, MouseMotionListener, MouseWheelListener,852ComponentListener, PropertyChangeListener, UIResource {853854private final JLayeredPane layeredPane;855private Dimension originalSize;856private Point originalLocation;857858ResizeBox(final JLayeredPane layeredPane) {859super(RESIZE_ICON.get());860setSize(11, 11);861this.layeredPane = layeredPane;862863addMouseListener(this);864addMouseMotionListener(this);865addMouseWheelListener(this);866}867868void addListeners() {869frame.addPropertyChangeListener("resizable", this);870}871872void removeListeners() {873frame.removePropertyChangeListener("resizable", this);874}875876void repositionResizeBox() {877if (frame == null) { setSize(0, 0); } else { setSize(11, 11); }878setLocation(layeredPane.getWidth() - 12, layeredPane.getHeight() - 12);879}880881void resizeInternalFrame(final Point pt) {882if (originalLocation == null || frame == null) return;883884final Container parent = frame.getParent();885if (!(parent instanceof JDesktopPane)) return;886887final Point newPoint = SwingUtilities.convertPoint(this, pt, frame);888int deltaX = originalLocation.x - newPoint.x;889int deltaY = originalLocation.y - newPoint.y;890final Dimension min = frame.getMinimumSize();891final Dimension max = frame.getMaximumSize();892893final int newX = frame.getX();894final int newY = frame.getY();895int newW = frame.getWidth();896int newH = frame.getHeight();897898final Rectangle parentBounds = parent.getBounds();899900if (originalSize.width - deltaX < min.width) {901deltaX = originalSize.width - min.width;902} else if (originalSize.width - deltaX > max.width) {903deltaX = -(max.width - originalSize.width);904}905906if (newX + originalSize.width - deltaX > parentBounds.width) {907deltaX = newX + originalSize.width - parentBounds.width;908}909910if (originalSize.height - deltaY < min.height) {911deltaY = originalSize.height - min.height;912} else if (originalSize.height - deltaY > max.height) {913deltaY = -(max.height - originalSize.height);914}915916if (newY + originalSize.height - deltaY > parentBounds.height) {917deltaY = newY + originalSize.height - parentBounds.height;918}919920newW = originalSize.width - deltaX;921newH = originalSize.height - deltaY;922923getDesktopManager().resizeFrame(frame, newX, newY, newW, newH);924}925926boolean testGrowboxPoint(final int x, final int y, final int w, final int h) {927return (w - x) + (h - y) < 12;928}929930@SuppressWarnings("deprecation")931void forwardEventToFrame(final MouseEvent e) {932final Point pt = new Point();933final Component c = getComponentToForwardTo(e, pt);934if (c == null) return;935c.dispatchEvent(936new MouseEvent(c, e.getID(), e.getWhen(), e.getModifiers(),937pt.x, pt.y, e.getClickCount(),938e.isPopupTrigger(), e.getButton()));939}940941Component getComponentToForwardTo(final MouseEvent e, final Point dst) {942if (frame == null) return null;943final Container contentPane = frame.getContentPane();944if (contentPane == null) return null;945Point pt = SwingUtilities.convertPoint(this, e.getPoint(), contentPane);946final Component c = SwingUtilities.getDeepestComponentAt(contentPane, pt.x, pt.y);947if (c == null) return null;948pt = SwingUtilities.convertPoint(contentPane, pt, c);949if (dst != null) dst.setLocation(pt);950return c;951}952953@Override954public void mouseClicked(final MouseEvent e) {955forwardEventToFrame(e);956}957958@Override959public void mouseEntered(final MouseEvent e) { }960961@Override962public void mouseExited(final MouseEvent e) { }963964@Override965public void mousePressed(final MouseEvent e) {966if (frame == null) return;967968if (frame.isResizable() && !frame.isMaximum() && testGrowboxPoint(e.getX(), e.getY(), getWidth(), getHeight())) {969originalLocation = SwingUtilities.convertPoint(this, e.getPoint(), frame);970originalSize = frame.getSize();971getDesktopManager().beginResizingFrame(frame, SwingConstants.SOUTH_EAST);972return;973}974975forwardEventToFrame(e);976}977978@Override979public void mouseReleased(final MouseEvent e) {980if (originalLocation != null) {981resizeInternalFrame(e.getPoint());982originalLocation = null;983getDesktopManager().endResizingFrame(frame);984return;985}986987forwardEventToFrame(e);988}989990@Override991public void mouseDragged(final MouseEvent e) {992resizeInternalFrame(e.getPoint());993repositionResizeBox();994}995996@Override997public void mouseMoved(final MouseEvent e) { }998999@Override1000@SuppressWarnings("deprecation")1001public void mouseWheelMoved(final MouseWheelEvent e) {1002final Point pt = new Point();1003final Component c = getComponentToForwardTo(e, pt);1004if (c == null) return;1005c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(),1006e.getModifiers(), pt.x, pt.y, e.getXOnScreen(), e.getYOnScreen(),1007e.getClickCount(), e.isPopupTrigger(), e.getScrollType(),1008e.getScrollAmount(), e.getWheelRotation(),1009e.getPreciseWheelRotation()));1010}10111012@Override1013public void componentResized(final ComponentEvent e) {1014repositionResizeBox();1015}10161017@Override1018public void componentShown(final ComponentEvent e) {1019repositionResizeBox();1020}10211022@Override1023public void componentMoved(final ComponentEvent e) {1024repositionResizeBox();1025}10261027@Override1028public void componentHidden(final ComponentEvent e) { }10291030@Override1031public void propertyChange(final PropertyChangeEvent evt) {1032if (!"resizable".equals(evt.getPropertyName())) return;1033setVisible(Boolean.TRUE.equals(evt.getNewValue()));1034}1035}1036}103710381039