| /* |
| * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.apple.laf; |
| |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.beans.*; |
| |
| import javax.swing.*; |
| import javax.swing.border.*; |
| import javax.swing.event.MouseInputAdapter; |
| import javax.swing.plaf.*; |
| import javax.swing.plaf.basic.BasicInternalFrameUI; |
| |
| import apple.laf.*; |
| import apple.laf.JRSUIConstants.*; |
| |
| import com.apple.laf.AquaUtils.*; |
| import com.apple.laf.AquaUtils.Painter; |
| |
| import sun.lwawt.macosx.CPlatformWindow; |
| |
| /** |
| * From AquaInternalFrameUI |
| * |
| * InternalFrame implementation for Aqua LAF |
| * |
| * We want to inherit most of the inner classes, but not the base class, |
| * so be very careful about subclassing so you know you get what you want |
| * |
| */ |
| public class AquaInternalFrameUI extends BasicInternalFrameUI implements SwingConstants { |
| protected static final String IS_PALETTE_PROPERTY = "JInternalFrame.isPalette"; |
| private static final String FRAME_TYPE = "JInternalFrame.frameType"; |
| private static final String NORMAL_FRAME = "normal"; |
| private static final String PALETTE_FRAME = "palette"; |
| private static final String OPTION_DIALOG = "optionDialog"; |
| |
| // Instance variables |
| PropertyChangeListener fPropertyListener; |
| |
| protected Color fSelectedTextColor; |
| protected Color fNotSelectedTextColor; |
| |
| AquaInternalFrameBorder fAquaBorder; |
| private ResizeBox resizeBox; |
| |
| // for button tracking |
| boolean fMouseOverPressedButton; |
| int fWhichButtonPressed = -1; |
| boolean fRollover = false; |
| boolean fDocumentEdited = false; // to indicate whether we should use the dirty document red dot. |
| boolean fIsPallet; |
| |
| public int getWhichButtonPressed() { |
| return fWhichButtonPressed; |
| } |
| |
| public boolean getMouseOverPressedButton() { |
| return fMouseOverPressedButton; |
| } |
| |
| public boolean getRollover() { |
| return fRollover; |
| } |
| |
| // ComponentUI Interface Implementation methods |
| public static ComponentUI createUI(final JComponent b) { |
| return new AquaInternalFrameUI((JInternalFrame)b); |
| } |
| |
| public AquaInternalFrameUI(final JInternalFrame b) { |
| super(b); |
| } |
| |
| /// Inherit (but be careful to check everything they call): |
| @Override |
| public void installUI(final JComponent c) { |
| // super.installUI(c); // Swing 1.1.1 has a bug in installUI - it doesn't check for null northPane |
| frame = (JInternalFrame)c; |
| frame.add(frame.getRootPane(), "Center"); |
| |
| installDefaults(); |
| installListeners(); |
| installComponents(); |
| installKeyboardActions(); |
| |
| Object paletteProp = c.getClientProperty(IS_PALETTE_PROPERTY); |
| if (paletteProp != null) { |
| setPalette(((Boolean)paletteProp).booleanValue()); |
| } else { |
| paletteProp = c.getClientProperty(FRAME_TYPE); |
| if (paletteProp != null) { |
| setFrameType((String)paletteProp); |
| } else { |
| setFrameType(NORMAL_FRAME); |
| } |
| } |
| |
| // We only have a southPane, for grow box room, created in setFrameType |
| frame.setMinimumSize(new Dimension(fIsPallet ? 120 : 150, fIsPallet ? 39 : 65)); |
| frame.setOpaque(false); |
| |
| c.setBorder(new CompoundUIBorder(fIsPallet ? paletteWindowShadow.get() : documentWindowShadow.get(), c.getBorder())); |
| } |
| |
| @Override |
| protected void installDefaults() { |
| super.installDefaults(); |
| fSelectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground"); |
| fNotSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground"); |
| } |
| |
| @Override |
| public void setSouthPane(final JComponent c) { |
| if (southPane != null) { |
| frame.remove(southPane); |
| deinstallMouseHandlers(southPane); |
| } |
| if (c != null) { |
| frame.add(c); |
| installMouseHandlers(c); |
| } |
| southPane = c; |
| } |
| |
| static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() { |
| @Override |
| protected Icon getInstance() { |
| return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_CLOSE_BOX); |
| } |
| }; |
| public static Icon exportCloseIcon() { |
| return closeIcon.get(); |
| } |
| |
| static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() { |
| @Override |
| protected Icon getInstance() { |
| return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_COLLAPSE_BOX); |
| } |
| }; |
| public static Icon exportMinimizeIcon() { |
| return minimizeIcon.get(); |
| } |
| |
| static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() { |
| @Override |
| protected Icon getInstance() { |
| return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_ZOOM_BOX); |
| } |
| }; |
| public static Icon exportZoomIcon() { |
| return zoomIcon.get(); |
| } |
| |
| static class AquaInternalFrameButtonIcon extends AquaIcon.JRSUIIcon { |
| public AquaInternalFrameButtonIcon(final Widget widget) { |
| painter.state.set(widget); |
| } |
| |
| @Override |
| public void paintIcon(final Component c, final Graphics g, final int x, final int y) { |
| painter.state.set(getStateFor(c)); |
| super.paintIcon(c, g, x, y); |
| } |
| |
| State getStateFor(final Component c) { |
| return State.ROLLOVER; |
| } |
| |
| @Override |
| public int getIconWidth() { |
| return 19; |
| } |
| |
| @Override |
| public int getIconHeight() { |
| return 19; |
| } |
| } |
| |
| @Override |
| protected void installKeyboardActions() { |
| } //$ Not Mac-ish - should we support? |
| |
| @Override |
| protected void installComponents() { |
| final JLayeredPane layeredPane = frame.getLayeredPane(); |
| resizeBox = new ResizeBox(layeredPane); |
| resizeBox.repositionResizeBox(); |
| |
| layeredPane.add(resizeBox); |
| layeredPane.setLayer(resizeBox, JLayeredPane.DRAG_LAYER); |
| layeredPane.addComponentListener(resizeBox); |
| |
| resizeBox.addListeners(); |
| resizeBox.setVisible(frame.isResizable()); |
| } |
| |
| /// Inherit all the listeners - that's the main reason we subclass Basic! |
| @Override |
| protected void installListeners() { |
| fPropertyListener = new PropertyListener(); |
| frame.addPropertyChangeListener(fPropertyListener); |
| super.installListeners(); |
| } |
| |
| // uninstallDefaults |
| |
| @Override |
| protected void uninstallComponents() { |
| super.uninstallComponents(); |
| final JLayeredPane layeredPane = frame.getLayeredPane(); |
| resizeBox.removeListeners(); |
| layeredPane.removeComponentListener(resizeBox); |
| layeredPane.remove(resizeBox); |
| resizeBox = null; |
| } |
| |
| @Override |
| protected void uninstallListeners() { |
| super.uninstallListeners(); |
| frame.removePropertyChangeListener(fPropertyListener); |
| } |
| |
| @Override |
| protected void uninstallKeyboardActions() { |
| } |
| |
| // Called when a DesktopIcon replaces an InternalFrame & vice versa |
| //protected void replacePane(JComponent currentPane, JComponent newPane) {} |
| @Override |
| protected void installMouseHandlers(final JComponent c) { |
| c.addMouseListener(borderListener); |
| c.addMouseMotionListener(borderListener); |
| } |
| |
| @Override |
| protected void deinstallMouseHandlers(final JComponent c) { |
| c.removeMouseListener(borderListener); |
| c.removeMouseMotionListener(borderListener); |
| } |
| |
| ActionMap createActionMap() { |
| final ActionMap map = new ActionMapUIResource(); |
| // add action for the system menu |
| // Set the ActionMap's parent to the Auditory Feedback Action Map |
| final AquaLookAndFeel lf = (AquaLookAndFeel)UIManager.getLookAndFeel(); |
| final ActionMap audioMap = lf.getAudioActionMap(); |
| map.setParent(audioMap); |
| return map; |
| } |
| |
| @Override |
| public Dimension getPreferredSize(JComponent x) { |
| Dimension preferredSize = super.getPreferredSize(x); |
| Dimension minimumSize = frame.getMinimumSize(); |
| if (preferredSize.width < minimumSize.width) { |
| preferredSize.width = minimumSize.width; |
| } |
| if (preferredSize.height < minimumSize.height) { |
| preferredSize.height = minimumSize.height; |
| } |
| return preferredSize; |
| } |
| |
| @Override |
| public void setNorthPane(final JComponent c) { |
| replacePane(northPane, c); |
| northPane = c; |
| } |
| |
| /** |
| * Installs necessary mouse handlers on {@code newPane} |
| * and adds it to the frame. |
| * Reverse process for the {@code currentPane}. |
| */ |
| @Override |
| protected void replacePane(final JComponent currentPane, final JComponent newPane) { |
| if (currentPane != null) { |
| deinstallMouseHandlers(currentPane); |
| frame.remove(currentPane); |
| } |
| if (newPane != null) { |
| frame.add(newPane); |
| installMouseHandlers(newPane); |
| } |
| } |
| |
| // Our "Border" listener is shared by the AquaDesktopIcon |
| @Override |
| protected MouseInputAdapter createBorderListener(final JInternalFrame w) { |
| return new AquaBorderListener(); |
| } |
| |
| /** |
| * Mac-specific stuff begins here |
| */ |
| void setFrameType(final String frameType) { |
| // Basic sets the background of the contentPane to null so it can inherit JInternalFrame.setBackground |
| // but if *that's* null, we get the JDesktop, which makes ours look invisible! |
| // So JInternalFrame has to have a background color |
| // See Sun bugs 4268949 & 4320889 |
| final Color bg = frame.getBackground(); |
| final boolean replaceColor = (bg == null || bg instanceof UIResource); |
| |
| final Font font = frame.getFont(); |
| final boolean replaceFont = (font == null || font instanceof UIResource); |
| |
| boolean isPalette = false; |
| if (frameType.equals(OPTION_DIALOG)) { |
| fAquaBorder = AquaInternalFrameBorder.dialog(); |
| if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.optionDialogBackground")); |
| if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.optionDialogTitleFont")); |
| } else if (frameType.equals(PALETTE_FRAME)) { |
| fAquaBorder = AquaInternalFrameBorder.utility(); |
| if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.paletteBackground")); |
| if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.paletteTitleFont")); |
| isPalette = true; |
| } else { |
| fAquaBorder = AquaInternalFrameBorder.window(); |
| if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.background")); |
| if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.titleFont")); |
| } |
| // We don't get the borders from UIManager, in case someone changes them - this class will not work with |
| // different borders. If they want different ones, they have to make their own InternalFrameUI class |
| |
| fAquaBorder.setColors(fSelectedTextColor, fNotSelectedTextColor); |
| frame.setBorder(fAquaBorder); |
| |
| fIsPallet = isPalette; |
| } |
| |
| public void setPalette(final boolean isPalette) { |
| setFrameType(isPalette ? PALETTE_FRAME : NORMAL_FRAME); |
| } |
| |
| public boolean isDocumentEdited() { |
| return fDocumentEdited; |
| } |
| |
| public void setDocumentEdited(final boolean flag) { |
| fDocumentEdited = flag; |
| } |
| |
| /* |
| // helpful debug drawing, shows component and content bounds |
| public void paint(final Graphics g, final JComponent c) { |
| super.paint(g, c); |
| |
| g.setColor(Color.green); |
| g.drawRect(0, 0, frame.getWidth() - 1, frame.getHeight() - 1); |
| |
| final Insets insets = frame.getInsets(); |
| g.setColor(Color.orange); |
| g.drawRect(insets.left - 2, insets.top - 2, frame.getWidth() - insets.left - insets.right + 4, frame.getHeight() - insets.top - insets.bottom + 4); |
| } |
| */ |
| |
| // Border Listener Class |
| /** |
| * Listens for border adjustments. |
| */ |
| protected class AquaBorderListener extends MouseInputAdapter { |
| // _x & _y are the mousePressed location in absolute coordinate system |
| int _x, _y; |
| // __x & __y are the mousePressed location in source view's coordinate system |
| int __x, __y; |
| Rectangle startingBounds; |
| boolean fDraggingFrame; |
| int resizeDir; |
| |
| protected final int RESIZE_NONE = 0; |
| private boolean discardRelease = false; |
| |
| @Override |
| public void mouseClicked(final MouseEvent e) { |
| if (didForwardEvent(e)) return; |
| |
| if (e.getClickCount() <= 1 || e.getSource() != getNorthPane()) return; |
| |
| if (frame.isIconifiable() && frame.isIcon()) { |
| try { |
| frame.setIcon(false); |
| } catch(final PropertyVetoException e2) {} |
| } else if (frame.isMaximizable()) { |
| if (!frame.isMaximum()) try { |
| frame.setMaximum(true); |
| } catch(final PropertyVetoException e2) {} |
| else try { |
| frame.setMaximum(false); |
| } catch(final PropertyVetoException e3) {} |
| } |
| } |
| |
| public void updateRollover(final MouseEvent e) { |
| final boolean oldRollover = fRollover; |
| final Insets i = frame.getInsets(); |
| fRollover = (isTitleBarDraggableArea(e) && fAquaBorder.getWithinRolloverArea(i, e.getX(), e.getY())); |
| if (fRollover != oldRollover) { |
| repaintButtons(); |
| } |
| } |
| |
| public void repaintButtons() { |
| fAquaBorder.repaintButtonArea(frame); |
| } |
| |
| @Override |
| @SuppressWarnings("deprecation") |
| public void mouseReleased(final MouseEvent e) { |
| if (didForwardEvent(e)) return; |
| |
| fDraggingFrame = false; |
| |
| if (fWhichButtonPressed != -1) { |
| final int newButton = fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY()); |
| |
| final int buttonPresed = fWhichButtonPressed; |
| fWhichButtonPressed = -1; |
| fMouseOverPressedButton = false; |
| |
| if (buttonPresed == newButton) { |
| fMouseOverPressedButton = false; |
| fRollover = false; // not sure if this is needed? |
| |
| fAquaBorder.doButtonAction(frame, buttonPresed); |
| } |
| |
| updateRollover(e); |
| repaintButtons(); |
| return; |
| } |
| |
| if (discardRelease) { |
| discardRelease = false; |
| return; |
| } |
| if (resizeDir == RESIZE_NONE) getDesktopManager().endDraggingFrame(frame); |
| else { |
| final Container c = frame.getTopLevelAncestor(); |
| if (c instanceof JFrame) { |
| ((JFrame)frame.getTopLevelAncestor()).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); |
| |
| ((JFrame)frame.getTopLevelAncestor()).getGlassPane().setVisible(false); |
| } else if (c instanceof JApplet) { |
| ((JApplet)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); |
| ((JApplet)c).getGlassPane().setVisible(false); |
| } else if (c instanceof JWindow) { |
| ((JWindow)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); |
| ((JWindow)c).getGlassPane().setVisible(false); |
| } else if (c instanceof JDialog) { |
| ((JDialog)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); |
| ((JDialog)c).getGlassPane().setVisible(false); |
| } |
| getDesktopManager().endResizingFrame(frame); |
| } |
| _x = 0; |
| _y = 0; |
| __x = 0; |
| __y = 0; |
| startingBounds = null; |
| resizeDir = RESIZE_NONE; |
| } |
| |
| @Override |
| public void mousePressed(final MouseEvent e) { |
| if (didForwardEvent(e)) return; |
| |
| final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null); |
| __x = e.getX(); |
| __y = e.getY(); |
| _x = p.x; |
| _y = p.y; |
| startingBounds = frame.getBounds(); |
| resizeDir = RESIZE_NONE; |
| |
| if (updatePressed(e)) { return; } |
| |
| if (!frame.isSelected()) { |
| try { |
| frame.setSelected(true); |
| } catch(final PropertyVetoException e1) {} |
| } |
| |
| if (isTitleBarDraggableArea(e)) { |
| getDesktopManager().beginDraggingFrame(frame); |
| fDraggingFrame = true; |
| return; |
| } |
| |
| if (e.getSource() == getNorthPane()) { |
| getDesktopManager().beginDraggingFrame(frame); |
| return; |
| } |
| |
| if (!frame.isResizable()) { return; } |
| |
| if (e.getSource() == frame) { |
| discardRelease = true; |
| return; |
| } |
| } |
| |
| // returns true if we have handled the pressed |
| public boolean updatePressed(final MouseEvent e) { |
| // get the component. |
| fWhichButtonPressed = getButtonHit(e); |
| fMouseOverPressedButton = true; |
| repaintButtons(); |
| return (fWhichButtonPressed >= 0); |
| // e.getX(), e.getY() |
| } |
| |
| public int getButtonHit(final MouseEvent e) { |
| return fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY()); |
| } |
| |
| public boolean isTitleBarDraggableArea(final MouseEvent e) { |
| if (e.getSource() != frame) return false; |
| |
| final Point point = e.getPoint(); |
| final Insets insets = frame.getInsets(); |
| |
| if (point.y < insets.top - fAquaBorder.getTitleHeight()) return false; |
| if (point.y > insets.top) return false; |
| if (point.x < insets.left) return false; |
| if (point.x > frame.getWidth() - insets.left - insets.right) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public void mouseDragged(final MouseEvent e) { |
| // do not forward drags |
| // if (didForwardEvent(e)) return; |
| |
| if (startingBounds == null) { |
| // (STEVE) Yucky work around for bug ID 4106552 |
| return; |
| } |
| |
| if (fWhichButtonPressed != -1) { |
| // track the button we started on. |
| final int newButton = getButtonHit(e); |
| fMouseOverPressedButton = (fWhichButtonPressed == newButton); |
| repaintButtons(); |
| return; |
| } |
| |
| final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null); |
| final int deltaX = _x - p.x; |
| final int deltaY = _y - p.y; |
| int newX, newY; |
| |
| // Handle a MOVE |
| if (!fDraggingFrame && e.getSource() != getNorthPane()) return; |
| |
| if (frame.isMaximum() || ((e.getModifiers() & InputEvent.BUTTON1_MASK) != InputEvent.BUTTON1_MASK)) { |
| // don't allow moving of frames if maximixed or left mouse |
| // button was not used. |
| return; |
| } |
| |
| final Dimension s = frame.getParent().getSize(); |
| final int pWidth = s.width; |
| final int pHeight = s.height; |
| |
| final Insets i = frame.getInsets(); |
| newX = startingBounds.x - deltaX; |
| newY = startingBounds.y - deltaY; |
| |
| // Make sure we stay in-bounds |
| if (newX + i.left <= -__x) newX = -__x - i.left; |
| if (newY + i.top <= -__y) newY = -__y - i.top; |
| if (newX + __x + i.right > pWidth) newX = pWidth - __x - i.right; |
| if (newY + __y + i.bottom > pHeight) newY = pHeight - __y - i.bottom; |
| |
| getDesktopManager().dragFrame(frame, newX, newY); |
| return; |
| } |
| |
| @Override |
| public void mouseMoved(final MouseEvent e) { |
| if (didForwardEvent(e)) return; |
| updateRollover(e); |
| } |
| |
| // guards against accidental infinite recursion |
| boolean isTryingToForwardEvent = false; |
| boolean didForwardEvent(final MouseEvent e) { |
| if (isTryingToForwardEvent) return true; // we didn't actually...but we wound up back where we started. |
| |
| isTryingToForwardEvent = true; |
| final boolean didForwardEvent = didForwardEventInternal(e); |
| isTryingToForwardEvent = false; |
| |
| return didForwardEvent; |
| } |
| |
| boolean didForwardEventInternal(final MouseEvent e) { |
| if (fDraggingFrame) return false; |
| |
| final Point originalPoint = e.getPoint(); |
| if (!isEventInWindowShadow(originalPoint)) return false; |
| |
| final Container parent = frame.getParent(); |
| if (!(parent instanceof JDesktopPane)) return false; |
| final JDesktopPane pane = (JDesktopPane)parent; |
| final Point parentPoint = SwingUtilities.convertPoint(frame, originalPoint, parent); |
| |
| /* // debug drawing |
| Graphics g = parent.getGraphics(); |
| g.setColor(Color.red); |
| g.drawLine(parentPoint.x, parentPoint.y, parentPoint.x, parentPoint.y); |
| */ |
| |
| final Component hitComponent = findComponentToHitBehindMe(pane, parentPoint); |
| if (hitComponent == null || hitComponent == frame) return false; |
| |
| final Point hitComponentPoint = SwingUtilities.convertPoint(pane, parentPoint, hitComponent); |
| hitComponent.dispatchEvent( |
| new MouseEvent(hitComponent, e.getID(), e.getWhen(), |
| e.getModifiers(), hitComponentPoint.x, |
| hitComponentPoint.y, e.getClickCount(), |
| e.isPopupTrigger(), e.getButton())); |
| return true; |
| } |
| |
| Component findComponentToHitBehindMe(final JDesktopPane pane, final Point parentPoint) { |
| final JInternalFrame[] allFrames = pane.getAllFrames(); |
| |
| boolean foundSelf = false; |
| for (final JInternalFrame f : allFrames) { |
| if (f == frame) { foundSelf = true; continue; } |
| if (!foundSelf) continue; |
| |
| final Rectangle bounds = f.getBounds(); |
| if (bounds.contains(parentPoint)) return f; |
| } |
| |
| return pane; |
| } |
| |
| boolean isEventInWindowShadow(final Point point) { |
| final Rectangle bounds = frame.getBounds(); |
| final Insets insets = frame.getInsets(); |
| insets.top -= fAquaBorder.getTitleHeight(); |
| |
| if (point.x < insets.left) return true; |
| if (point.x > bounds.width - insets.right) return true; |
| if (point.y < insets.top) return true; |
| if (point.y > bounds.height - insets.bottom) return true; |
| |
| return false; |
| } |
| } |
| |
| static void updateComponentTreeUIActivation(final Component c, final Object active) { |
| if (c instanceof javax.swing.JComponent) { |
| ((javax.swing.JComponent)c).putClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY, active); |
| } |
| |
| Component[] children = null; |
| |
| if (c instanceof javax.swing.JMenu) { |
| children = ((javax.swing.JMenu)c).getMenuComponents(); |
| } else if (c instanceof Container) { |
| children = ((Container)c).getComponents(); |
| } |
| |
| if (children != null) { |
| for (final Component element : children) { |
| updateComponentTreeUIActivation(element, active); |
| } |
| } |
| } |
| |
| class PropertyListener implements PropertyChangeListener { |
| @Override |
| public void propertyChange(final PropertyChangeEvent e) { |
| final String name = e.getPropertyName(); |
| if (FRAME_TYPE.equals(name)) { |
| if (e.getNewValue() instanceof String) { |
| setFrameType((String)e.getNewValue()); |
| } |
| } else if (IS_PALETTE_PROPERTY.equals(name)) { |
| if (e.getNewValue() != null) { |
| setPalette(((Boolean)e.getNewValue()).booleanValue()); |
| } else { |
| setPalette(false); |
| } |
| // TODO: CPlatformWindow? |
| } else if ("windowModified".equals(name) || CPlatformWindow.WINDOW_DOCUMENT_MODIFIED.equals(name)) { |
| // repaint title bar |
| setDocumentEdited(((Boolean)e.getNewValue()).booleanValue()); |
| frame.repaint(0, 0, frame.getWidth(), frame.getBorder().getBorderInsets(frame).top); |
| } else if ("resizable".equals(name) || "state".equals(name) || "iconable".equals(name) || "maximizable".equals(name) || "closable".equals(name)) { |
| if ("resizable".equals(name)) { |
| frame.revalidate(); |
| } |
| frame.repaint(); |
| } else if ("title".equals(name)) { |
| frame.repaint(); |
| } else if ("componentOrientation".equals(name)) { |
| frame.revalidate(); |
| frame.repaint(); |
| } else if (JInternalFrame.IS_SELECTED_PROPERTY.equals(name)) { |
| final Component source = (Component)(e.getSource()); |
| updateComponentTreeUIActivation(source, frame.isSelected() ? Boolean.TRUE : Boolean.FALSE); |
| } |
| |
| } |
| } // end class PaletteListener |
| |
| static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() { |
| @Override |
| Border getForegroundShadowBorder() { |
| return new AquaUtils.SlicedShadowBorder(new Painter() { |
| @Override |
| public void paint(final Graphics g, final int x, final int y, final int w, final int h) { |
| g.setColor(new Color(0, 0, 0, 196)); |
| g.fillRoundRect(x, y, w, h, 16, 16); |
| g.fillRect(x, y + h - 16, w, 16); |
| } |
| }, new Painter() { |
| @Override |
| public void paint(final Graphics g, int x, int y, int w, int h) { |
| g.setColor(new Color(0, 0, 0, 64)); |
| g.drawLine(x + 2, y - 8, x + w - 2, y - 8); |
| } |
| }, |
| 0, 7, 1.1f, 1.0f, 24, 51, 51, 25, 25, 25, 25); |
| } |
| |
| @Override |
| Border getBackgroundShadowBorder() { |
| return new AquaUtils.SlicedShadowBorder(new Painter() { |
| @Override |
| public void paint(final Graphics g, final int x, final int y, final int w, final int h) { |
| g.setColor(new Color(0, 0, 0, 128)); |
| g.fillRoundRect(x - 3, y - 8, w + 6, h, 16, 16); |
| g.fillRect(x - 3, y + h - 20, w + 6, 19); |
| } |
| }, new Painter() { |
| @Override |
| public void paint(final Graphics g, int x, int y, int w, int h) { |
| g.setColor(new Color(0, 0, 0, 32)); |
| g.drawLine(x, y - 11, x + w - 1, y - 11); |
| } |
| }, |
| 0, 0, 3.0f, 1.0f, 10, 51, 51, 25, 25, 25, 25); |
| } |
| }; |
| |
| static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() { |
| @Override |
| Border getForegroundShadowBorder() { |
| return new AquaUtils.SlicedShadowBorder(new Painter() { |
| @Override |
| public void paint(final Graphics g, final int x, final int y, final int w, final int h) { |
| g.setColor(new Color(0, 0, 0, 128)); |
| g.fillRect(x, y + 3, w, h - 3); |
| } |
| }, null, |
| 0, 3, 1.0f, 1.0f, 10, 25, 25, 12, 12, 12, 12); |
| } |
| |
| @Override |
| Border getBackgroundShadowBorder() { |
| return getForegroundShadowBorder(); |
| } |
| }; |
| |
| @SuppressWarnings("serial") // Superclass is not serializable across versions |
| static class CompoundUIBorder extends CompoundBorder implements UIResource { |
| public CompoundUIBorder(final Border inside, final Border outside) { super(inside, outside); } |
| } |
| |
| abstract static class InternalFrameShadow extends RecyclableSingleton<Border> { |
| abstract Border getForegroundShadowBorder(); |
| abstract Border getBackgroundShadowBorder(); |
| |
| @Override |
| protected Border getInstance() { |
| final Border fgShadow = getForegroundShadowBorder(); |
| final Border bgShadow = getBackgroundShadowBorder(); |
| |
| return new Border() { |
| @Override |
| public Insets getBorderInsets(final Component c) { |
| return fgShadow.getBorderInsets(c); |
| } |
| |
| @Override |
| public boolean isBorderOpaque() { |
| return false; |
| } |
| |
| @Override |
| public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) { |
| if (((JInternalFrame)c).isSelected()) { |
| fgShadow.paintBorder(c, g, x, y, w, h); |
| } else { |
| bgShadow.paintBorder(c, g, x, y, w, h); |
| } |
| } |
| }; |
| } |
| } |
| |
| static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() { |
| @Override |
| protected Icon getInstance() { |
| return new AquaIcon.ScalingJRSUIIcon(11, 11) { |
| @Override |
| public void initIconPainter(final AquaPainter<JRSUIState> iconState) { |
| iconState.state.set(Widget.GROW_BOX_TEXTURED); |
| iconState.state.set(WindowType.UTILITY); |
| } |
| }; |
| } |
| }; |
| |
| @SuppressWarnings("serial") // Superclass is not serializable across versions |
| private final class ResizeBox extends JLabel |
| implements MouseListener, MouseMotionListener, MouseWheelListener, |
| ComponentListener, PropertyChangeListener, UIResource { |
| |
| private final JLayeredPane layeredPane; |
| private Dimension originalSize; |
| private Point originalLocation; |
| |
| ResizeBox(final JLayeredPane layeredPane) { |
| super(RESIZE_ICON.get()); |
| setSize(11, 11); |
| this.layeredPane = layeredPane; |
| |
| addMouseListener(this); |
| addMouseMotionListener(this); |
| addMouseWheelListener(this); |
| } |
| |
| void addListeners() { |
| frame.addPropertyChangeListener("resizable", this); |
| } |
| |
| void removeListeners() { |
| frame.removePropertyChangeListener("resizable", this); |
| } |
| |
| void repositionResizeBox() { |
| if (frame == null) { setSize(0, 0); } else { setSize(11, 11); } |
| setLocation(layeredPane.getWidth() - 12, layeredPane.getHeight() - 12); |
| } |
| |
| void resizeInternalFrame(final Point pt) { |
| if (originalLocation == null || frame == null) return; |
| |
| final Container parent = frame.getParent(); |
| if (!(parent instanceof JDesktopPane)) return; |
| |
| final Point newPoint = SwingUtilities.convertPoint(this, pt, frame); |
| int deltaX = originalLocation.x - newPoint.x; |
| int deltaY = originalLocation.y - newPoint.y; |
| final Dimension min = frame.getMinimumSize(); |
| final Dimension max = frame.getMaximumSize(); |
| |
| final int newX = frame.getX(); |
| final int newY = frame.getY(); |
| int newW = frame.getWidth(); |
| int newH = frame.getHeight(); |
| |
| final Rectangle parentBounds = parent.getBounds(); |
| |
| if (originalSize.width - deltaX < min.width) { |
| deltaX = originalSize.width - min.width; |
| } else if (originalSize.width - deltaX > max.width) { |
| deltaX = -(max.width - originalSize.width); |
| } |
| |
| if (newX + originalSize.width - deltaX > parentBounds.width) { |
| deltaX = newX + originalSize.width - parentBounds.width; |
| } |
| |
| if (originalSize.height - deltaY < min.height) { |
| deltaY = originalSize.height - min.height; |
| } else if (originalSize.height - deltaY > max.height) { |
| deltaY = -(max.height - originalSize.height); |
| } |
| |
| if (newY + originalSize.height - deltaY > parentBounds.height) { |
| deltaY = newY + originalSize.height - parentBounds.height; |
| } |
| |
| newW = originalSize.width - deltaX; |
| newH = originalSize.height - deltaY; |
| |
| getDesktopManager().resizeFrame(frame, newX, newY, newW, newH); |
| } |
| |
| boolean testGrowboxPoint(final int x, final int y, final int w, final int h) { |
| return (w - x) + (h - y) < 12; |
| } |
| |
| void forwardEventToFrame(final MouseEvent e) { |
| final Point pt = new Point(); |
| final Component c = getComponentToForwardTo(e, pt); |
| if (c == null) return; |
| c.dispatchEvent(new MouseEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getButton())); |
| } |
| |
| Component getComponentToForwardTo(final MouseEvent e, final Point dst) { |
| if (frame == null) return null; |
| final Container contentPane = frame.getContentPane(); |
| if (contentPane == null) return null; |
| Point pt = SwingUtilities.convertPoint(this, e.getPoint(), contentPane); |
| final Component c = SwingUtilities.getDeepestComponentAt(contentPane, pt.x, pt.y); |
| if (c == null) return null; |
| pt = SwingUtilities.convertPoint(contentPane, pt, c); |
| if (dst != null) dst.setLocation(pt); |
| return c; |
| } |
| |
| @Override |
| public void mouseClicked(final MouseEvent e) { |
| forwardEventToFrame(e); |
| } |
| |
| @Override |
| public void mouseEntered(final MouseEvent e) { } |
| |
| @Override |
| public void mouseExited(final MouseEvent e) { } |
| |
| @Override |
| public void mousePressed(final MouseEvent e) { |
| if (frame == null) return; |
| |
| if (frame.isResizable() && !frame.isMaximum() && testGrowboxPoint(e.getX(), e.getY(), getWidth(), getHeight())) { |
| originalLocation = SwingUtilities.convertPoint(this, e.getPoint(), frame); |
| originalSize = frame.getSize(); |
| getDesktopManager().beginResizingFrame(frame, SwingConstants.SOUTH_EAST); |
| return; |
| } |
| |
| forwardEventToFrame(e); |
| } |
| |
| @Override |
| public void mouseReleased(final MouseEvent e) { |
| if (originalLocation != null) { |
| resizeInternalFrame(e.getPoint()); |
| originalLocation = null; |
| getDesktopManager().endResizingFrame(frame); |
| return; |
| } |
| |
| forwardEventToFrame(e); |
| } |
| |
| @Override |
| public void mouseDragged(final MouseEvent e) { |
| resizeInternalFrame(e.getPoint()); |
| repositionResizeBox(); |
| } |
| |
| @Override |
| public void mouseMoved(final MouseEvent e) { } |
| |
| @Override |
| public void mouseWheelMoved(final MouseWheelEvent e) { |
| final Point pt = new Point(); |
| final Component c = getComponentToForwardTo(e, pt); |
| if (c == null) return; |
| c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(), |
| e.getModifiers(), pt.x, pt.y, e.getXOnScreen(), e.getYOnScreen(), |
| e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), |
| e.getScrollAmount(), e.getWheelRotation(), |
| e.getPreciseWheelRotation())); |
| } |
| |
| @Override |
| public void componentResized(final ComponentEvent e) { |
| repositionResizeBox(); |
| } |
| |
| @Override |
| public void componentShown(final ComponentEvent e) { |
| repositionResizeBox(); |
| } |
| |
| @Override |
| public void componentMoved(final ComponentEvent e) { |
| repositionResizeBox(); |
| } |
| |
| @Override |
| public void componentHidden(final ComponentEvent e) { } |
| |
| @Override |
| public void propertyChange(final PropertyChangeEvent evt) { |
| if (!"resizable".equals(evt.getPropertyName())) return; |
| setVisible(Boolean.TRUE.equals(evt.getNewValue())); |
| } |
| } |
| } |