1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.beans.*; 31 32 import javax.swing.*; 33 import javax.swing.border.*; 34 import javax.swing.event.MouseInputAdapter; 35 import javax.swing.plaf.*; 36 import javax.swing.plaf.basic.BasicInternalFrameUI; 37 38 import apple.laf.*; 39 import apple.laf.JRSUIConstants.*; 40 41 import com.apple.laf.AquaUtils.*; 42 import com.apple.laf.AquaUtils.Painter; 43 44 import sun.lwawt.macosx.CPlatformWindow; 45 46 /** 47 * From AquaInternalFrameUI 48 * 49 * InternalFrame implementation for Aqua LAF 50 * 51 * We want to inherit most of the inner classes, but not the base class, 52 * so be very careful about subclassing so you know you get what you want 53 * 54 */ 55 public class AquaInternalFrameUI extends BasicInternalFrameUI implements SwingConstants { 56 protected static final String IS_PALETTE_PROPERTY = "JInternalFrame.isPalette"; 57 private static final String FRAME_TYPE = "JInternalFrame.frameType"; 58 private static final String NORMAL_FRAME = "normal"; 59 private static final String PALETTE_FRAME = "palette"; 60 private static final String OPTION_DIALOG = "optionDialog"; 61 62 // Instance variables 63 PropertyChangeListener fPropertyListener; 64 65 protected Color fSelectedTextColor; 66 protected Color fNotSelectedTextColor; 67 68 AquaInternalFrameBorder fAquaBorder; 69 70 // for button tracking 71 boolean fMouseOverPressedButton; 72 int fWhichButtonPressed = -1; 73 boolean fRollover = false; 74 boolean fDocumentEdited = false; // to indicate whether we should use the dirty document red dot. 75 boolean fIsPallet; 76 77 public int getWhichButtonPressed() { 78 return fWhichButtonPressed; 79 } 80 81 public boolean getMouseOverPressedButton() { 82 return fMouseOverPressedButton; 83 } 84 85 public boolean getRollover() { 86 return fRollover; 87 } 88 89 // ComponentUI Interface Implementation methods 90 public static ComponentUI createUI(final JComponent b) { 91 return new AquaInternalFrameUI((JInternalFrame)b); 92 } 93 94 public AquaInternalFrameUI(final JInternalFrame b) { 95 super(b); 96 } 97 98 /// Inherit (but be careful to check everything they call): 99 public void installUI(final JComponent c) { 100 // super.installUI(c); // Swing 1.1.1 has a bug in installUI - it doesn't check for null northPane 101 frame = (JInternalFrame)c; 102 frame.add(frame.getRootPane(), "Center"); 103 104 installDefaults(); 105 installListeners(); 106 installComponents(); 107 installKeyboardActions(); 108 109 Object paletteProp = c.getClientProperty(IS_PALETTE_PROPERTY); 110 if (paletteProp != null) { 111 setPalette(((Boolean)paletteProp).booleanValue()); 112 } else { 113 paletteProp = c.getClientProperty(FRAME_TYPE); 114 if (paletteProp != null) { 115 setFrameType((String)paletteProp); 116 } else { 117 setFrameType(NORMAL_FRAME); 118 } 119 } 120 121 // We only have a southPane, for grow box room, created in setFrameType 122 frame.setMinimumSize(new Dimension(fIsPallet ? 120 : 150, fIsPallet ? 39 : 65)); 123 frame.setOpaque(false); 124 125 c.setBorder(new CompoundUIBorder(fIsPallet ? paletteWindowShadow.get() : documentWindowShadow.get(), c.getBorder())); 126 } 127 128 protected void installDefaults() { 129 super.installDefaults(); 130 fSelectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground"); 131 fNotSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground"); 132 } 133 134 public void setSouthPane(final JComponent c) { 135 if (southPane != null) { 136 frame.remove(southPane); 137 deinstallMouseHandlers(southPane); 138 } 139 if (c != null) { 140 frame.add(c); 141 installMouseHandlers(c); 142 } 143 southPane = c; 144 } 145 146 static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() { 147 protected Icon getInstance() { 148 return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_CLOSE_BOX); 149 } 150 }; 151 public static Icon exportCloseIcon() { 152 return closeIcon.get(); 153 } 154 155 static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() { 156 protected Icon getInstance() { 157 return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_COLLAPSE_BOX); 158 } 159 }; 160 public static Icon exportMinimizeIcon() { 161 return minimizeIcon.get(); 162 } 163 164 static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() { 165 protected Icon getInstance() { 166 return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_ZOOM_BOX); 167 } 168 }; 169 public static Icon exportZoomIcon() { 170 return zoomIcon.get(); 171 } 172 173 static class AquaInternalFrameButtonIcon extends AquaIcon.JRSUIIcon { 174 public AquaInternalFrameButtonIcon(final Widget widget) { 175 painter.state.set(widget); 176 } 177 178 public void paintIcon(final Component c, final Graphics g, final int x, final int y) { 179 painter.state.set(getStateFor(c)); 180 super.paintIcon(c, g, x, y); 181 } 182 183 State getStateFor(final Component c) { 184 return State.ROLLOVER; 185 } 186 187 public int getIconWidth() { 188 return 19; 189 } 190 191 public int getIconHeight() { 192 return 19; 193 } 194 } 195 196 protected void installKeyboardActions() { 197 } //$ Not Mac-ish - should we support? 198 199 protected ResizeBox resizeBox; 200 protected void installComponents() { 201 final JLayeredPane layeredPane = frame.getLayeredPane(); 202 if (resizeBox != null) { 203 resizeBox.removeListeners(); 204 layeredPane.removeComponentListener(resizeBox); 205 layeredPane.remove(resizeBox); 206 resizeBox = null; 207 } 208 209 resizeBox = new ResizeBox(layeredPane); 210 resizeBox.repositionResizeBox(); 211 212 layeredPane.add(resizeBox); 213 layeredPane.setLayer(resizeBox, JLayeredPane.DRAG_LAYER); 214 layeredPane.addComponentListener(resizeBox); 215 216 resizeBox.addListeners(); 217 resizeBox.setVisible(frame.isResizable()); 218 } 219 220 /// Inherit all the listeners - that's the main reason we subclass Basic! 221 protected void installListeners() { 222 fPropertyListener = new PropertyListener(); 223 frame.addPropertyChangeListener(fPropertyListener); 224 super.installListeners(); 225 } 226 227 // uninstallDefaults 228 // uninstallComponents 229 protected void uninstallListeners() { 230 super.uninstallListeners(); 231 frame.removePropertyChangeListener(fPropertyListener); 232 } 233 234 protected void uninstallKeyboardActions() { 235 } 236 237 // Called when a DesktopIcon replaces an InternalFrame & vice versa 238 //protected void replacePane(JComponent currentPane, JComponent newPane) {} 239 protected void installMouseHandlers(final JComponent c) { 240 c.addMouseListener(borderListener); 241 c.addMouseMotionListener(borderListener); 242 } 243 244 protected void deinstallMouseHandlers(final JComponent c) { 245 c.removeMouseListener(borderListener); 246 c.removeMouseMotionListener(borderListener); 247 } 248 249 ActionMap createActionMap() { 250 final ActionMap map = new ActionMapUIResource(); 251 // add action for the system menu 252 // Set the ActionMap's parent to the Auditory Feedback Action Map 253 final AquaLookAndFeel lf = (AquaLookAndFeel)UIManager.getLookAndFeel(); 254 final ActionMap audioMap = lf.getAudioActionMap(); 255 map.setParent(audioMap); 256 return map; 257 } 258 259 public Dimension getPreferredSize(JComponent x) { 260 Dimension preferredSize = super.getPreferredSize(x); 261 Dimension minimumSize = frame.getMinimumSize(); 262 if (preferredSize.width < minimumSize.width) { 263 preferredSize.width = minimumSize.width; 264 } 265 if (preferredSize.height < minimumSize.height) { 266 preferredSize.height = minimumSize.height; 267 } 268 return preferredSize; 269 } 270 271 public void setNorthPane(final JComponent c) { 272 replacePane(northPane, c); 273 northPane = c; 274 } 275 276 /** 277 * Installs necessary mouse handlers on <code>newPane</code> 278 * and adds it to the frame. 279 * Reverse process for the <code>currentPane</code>. 280 */ 281 protected void replacePane(final JComponent currentPane, final JComponent newPane) { 282 if (currentPane != null) { 283 deinstallMouseHandlers(currentPane); 284 frame.remove(currentPane); 285 } 286 if (newPane != null) { 287 frame.add(newPane); 288 installMouseHandlers(newPane); 289 } 290 } 291 292 // Our "Border" listener is shared by the AquaDesktopIcon 293 protected MouseInputAdapter createBorderListener(final JInternalFrame w) { 294 return new AquaBorderListener(); 295 } 296 297 /** 298 * Mac-specific stuff begins here 299 */ 300 void setFrameType(final String frameType) { 301 // Basic sets the background of the contentPane to null so it can inherit JInternalFrame.setBackground 302 // but if *that's* null, we get the JDesktop, which makes ours look invisible! 303 // So JInternalFrame has to have a background color 304 // See Sun bugs 4268949 & 4320889 305 final Color bg = frame.getBackground(); 306 final boolean replaceColor = (bg == null || bg instanceof UIResource); 307 308 final Font font = frame.getFont(); 309 final boolean replaceFont = (font == null || font instanceof UIResource); 310 311 boolean isPalette = false; 312 if (frameType.equals(OPTION_DIALOG)) { 313 fAquaBorder = AquaInternalFrameBorder.dialog(); 314 if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.optionDialogBackground")); 315 if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.optionDialogTitleFont")); 316 } else if (frameType.equals(PALETTE_FRAME)) { 317 fAquaBorder = AquaInternalFrameBorder.utility(); 318 if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.paletteBackground")); 319 if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.paletteTitleFont")); 320 isPalette = true; 321 } else { 322 fAquaBorder = AquaInternalFrameBorder.window(); 323 if (replaceColor) frame.setBackground(UIManager.getColor("InternalFrame.background")); 324 if (replaceFont) frame.setFont(UIManager.getFont("InternalFrame.titleFont")); 325 } 326 // We don't get the borders from UIManager, in case someone changes them - this class will not work with 327 // different borders. If they want different ones, they have to make their own InternalFrameUI class 328 329 fAquaBorder.setColors(fSelectedTextColor, fNotSelectedTextColor); 330 frame.setBorder(fAquaBorder); 331 332 fIsPallet = isPalette; 333 } 334 335 public void setPalette(final boolean isPalette) { 336 setFrameType(isPalette ? PALETTE_FRAME : NORMAL_FRAME); 337 } 338 339 public boolean isDocumentEdited() { 340 return fDocumentEdited; 341 } 342 343 public void setDocumentEdited(final boolean flag) { 344 fDocumentEdited = flag; 345 } 346 347 /* 348 // helpful debug drawing, shows component and content bounds 349 public void paint(final Graphics g, final JComponent c) { 350 super.paint(g, c); 351 352 g.setColor(Color.green); 353 g.drawRect(0, 0, frame.getWidth() - 1, frame.getHeight() - 1); 354 355 final Insets insets = frame.getInsets(); 356 g.setColor(Color.orange); 357 g.drawRect(insets.left - 2, insets.top - 2, frame.getWidth() - insets.left - insets.right + 4, frame.getHeight() - insets.top - insets.bottom + 4); 358 } 359 */ 360 361 // Border Listener Class 362 /** 363 * Listens for border adjustments. 364 */ 365 protected class AquaBorderListener extends MouseInputAdapter { 366 // _x & _y are the mousePressed location in absolute coordinate system 367 int _x, _y; 368 // __x & __y are the mousePressed location in source view's coordinate system 369 int __x, __y; 370 Rectangle startingBounds; 371 boolean fDraggingFrame; 372 int resizeDir; 373 374 protected final int RESIZE_NONE = 0; 375 private boolean discardRelease = false; 376 377 public void mouseClicked(final MouseEvent e) { 378 if (didForwardEvent(e)) return; 379 380 if (e.getClickCount() <= 1 || e.getSource() != getNorthPane()) return; 381 382 if (frame.isIconifiable() && frame.isIcon()) { 383 try { 384 frame.setIcon(false); 385 } catch(final PropertyVetoException e2) {} 386 } else if (frame.isMaximizable()) { 387 if (!frame.isMaximum()) try { 388 frame.setMaximum(true); 389 } catch(final PropertyVetoException e2) {} 390 else try { 391 frame.setMaximum(false); 392 } catch(final PropertyVetoException e3) {} 393 } 394 } 395 396 public void updateRollover(final MouseEvent e) { 397 final boolean oldRollover = fRollover; 398 final Insets i = frame.getInsets(); 399 fRollover = (isTitleBarDraggableArea(e) && fAquaBorder.getWithinRolloverArea(i, e.getX(), e.getY())); 400 if (fRollover != oldRollover) { 401 repaintButtons(); 402 } 403 } 404 405 public void repaintButtons() { 406 fAquaBorder.repaintButtonArea(frame); 407 } 408 409 public void mouseReleased(final MouseEvent e) { 410 if (didForwardEvent(e)) return; 411 412 fDraggingFrame = false; 413 414 if (fWhichButtonPressed != -1) { 415 final int newButton = fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY()); 416 417 final int buttonPresed = fWhichButtonPressed; 418 fWhichButtonPressed = -1; 419 fMouseOverPressedButton = false; 420 421 if (buttonPresed == newButton) { 422 fMouseOverPressedButton = false; 423 fRollover = false; // not sure if this is needed? 424 425 fAquaBorder.doButtonAction(frame, buttonPresed); 426 } 427 428 updateRollover(e); 429 repaintButtons(); 430 return; 431 } 432 433 if (discardRelease) { 434 discardRelease = false; 435 return; 436 } 437 if (resizeDir == RESIZE_NONE) getDesktopManager().endDraggingFrame(frame); 438 else { 439 final Container c = frame.getTopLevelAncestor(); 440 if (c instanceof JFrame) { 441 ((JFrame)frame.getTopLevelAncestor()).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 442 443 ((JFrame)frame.getTopLevelAncestor()).getGlassPane().setVisible(false); 444 } else if (c instanceof JApplet) { 445 ((JApplet)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 446 ((JApplet)c).getGlassPane().setVisible(false); 447 } else if (c instanceof JWindow) { 448 ((JWindow)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 449 ((JWindow)c).getGlassPane().setVisible(false); 450 } else if (c instanceof JDialog) { 451 ((JDialog)c).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 452 ((JDialog)c).getGlassPane().setVisible(false); 453 } 454 getDesktopManager().endResizingFrame(frame); 455 } 456 _x = 0; 457 _y = 0; 458 __x = 0; 459 __y = 0; 460 startingBounds = null; 461 resizeDir = RESIZE_NONE; 462 } 463 464 public void mousePressed(final MouseEvent e) { 465 if (didForwardEvent(e)) return; 466 467 final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null); 468 __x = e.getX(); 469 __y = e.getY(); 470 _x = p.x; 471 _y = p.y; 472 startingBounds = frame.getBounds(); 473 resizeDir = RESIZE_NONE; 474 475 if (updatePressed(e)) { return; } 476 477 if (!frame.isSelected()) { 478 try { 479 frame.setSelected(true); 480 } catch(final PropertyVetoException e1) {} 481 } 482 483 if (isTitleBarDraggableArea(e)) { 484 getDesktopManager().beginDraggingFrame(frame); 485 fDraggingFrame = true; 486 return; 487 } 488 489 if (e.getSource() == getNorthPane()) { 490 getDesktopManager().beginDraggingFrame(frame); 491 return; 492 } 493 494 if (!frame.isResizable()) { return; } 495 496 if (e.getSource() == frame) { 497 discardRelease = true; 498 return; 499 } 500 } 501 502 // returns true if we have handled the pressed 503 public boolean updatePressed(final MouseEvent e) { 504 // get the component. 505 fWhichButtonPressed = getButtonHit(e); 506 fMouseOverPressedButton = true; 507 repaintButtons(); 508 return (fWhichButtonPressed >= 0); 509 // e.getX(), e.getY() 510 } 511 512 public int getButtonHit(final MouseEvent e) { 513 return fAquaBorder.getWhichButtonHit(frame, e.getX(), e.getY()); 514 } 515 516 public boolean isTitleBarDraggableArea(final MouseEvent e) { 517 if (e.getSource() != frame) return false; 518 519 final Point point = e.getPoint(); 520 final Insets insets = frame.getInsets(); 521 522 if (point.y < insets.top - fAquaBorder.getTitleHeight()) return false; 523 if (point.y > insets.top) return false; 524 if (point.x < insets.left) return false; 525 if (point.x > frame.getWidth() - insets.left - insets.right) return false; 526 527 return true; 528 } 529 530 public void mouseDragged(final MouseEvent e) { 531 // do not forward drags 532 // if (didForwardEvent(e)) return; 533 534 if (startingBounds == null) { 535 // (STEVE) Yucky work around for bug ID 4106552 536 return; 537 } 538 539 if (fWhichButtonPressed != -1) { 540 // track the button we started on. 541 final int newButton = getButtonHit(e); 542 fMouseOverPressedButton = (fWhichButtonPressed == newButton); 543 repaintButtons(); 544 return; 545 } 546 547 final Point p = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), null); 548 final int deltaX = _x - p.x; 549 final int deltaY = _y - p.y; 550 int newX, newY; 551 552 // Handle a MOVE 553 if (!fDraggingFrame && e.getSource() != getNorthPane()) return; 554 555 if (frame.isMaximum() || ((e.getModifiers() & InputEvent.BUTTON1_MASK) != InputEvent.BUTTON1_MASK)) { 556 // don't allow moving of frames if maximixed or left mouse 557 // button was not used. 558 return; 559 } 560 561 final Dimension s = frame.getParent().getSize(); 562 final int pWidth = s.width; 563 final int pHeight = s.height; 564 565 final Insets i = frame.getInsets(); 566 newX = startingBounds.x - deltaX; 567 newY = startingBounds.y - deltaY; 568 569 // Make sure we stay in-bounds 570 if (newX + i.left <= -__x) newX = -__x - i.left; 571 if (newY + i.top <= -__y) newY = -__y - i.top; 572 if (newX + __x + i.right > pWidth) newX = pWidth - __x - i.right; 573 if (newY + __y + i.bottom > pHeight) newY = pHeight - __y - i.bottom; 574 575 getDesktopManager().dragFrame(frame, newX, newY); 576 return; 577 } 578 579 public void mouseMoved(final MouseEvent e) { 580 if (didForwardEvent(e)) return; 581 updateRollover(e); 582 } 583 584 // guards against accidental infinite recursion 585 boolean isTryingToForwardEvent = false; 586 boolean didForwardEvent(final MouseEvent e) { 587 if (isTryingToForwardEvent) return true; // we didn't actually...but we wound up back where we started. 588 589 isTryingToForwardEvent = true; 590 final boolean didForwardEvent = didForwardEventInternal(e); 591 isTryingToForwardEvent = false; 592 593 return didForwardEvent; 594 } 595 596 boolean didForwardEventInternal(final MouseEvent e) { 597 if (fDraggingFrame) return false; 598 599 final Point originalPoint = e.getPoint(); 600 if (!isEventInWindowShadow(originalPoint)) return false; 601 602 final Container parent = frame.getParent(); 603 if (!(parent instanceof JDesktopPane)) return false; 604 final JDesktopPane pane = (JDesktopPane)parent; 605 final Point parentPoint = SwingUtilities.convertPoint(frame, originalPoint, parent); 606 607 /* // debug drawing 608 Graphics g = parent.getGraphics(); 609 g.setColor(Color.red); 610 g.drawLine(parentPoint.x, parentPoint.y, parentPoint.x, parentPoint.y); 611 */ 612 613 final Component hitComponent = findComponentToHitBehindMe(pane, parentPoint); 614 if (hitComponent == null || hitComponent == frame) return false; 615 616 final Point hitComponentPoint = SwingUtilities.convertPoint(pane, parentPoint, hitComponent); 617 hitComponent.dispatchEvent(new MouseEvent(hitComponent, e.getID(), e.getWhen(), e.getModifiers(), hitComponentPoint.x, hitComponentPoint.y, e.getClickCount(), e.isPopupTrigger(), e.getButton())); 618 return true; 619 } 620 621 Component findComponentToHitBehindMe(final JDesktopPane pane, final Point parentPoint) { 622 final JInternalFrame[] allFrames = pane.getAllFrames(); 623 624 boolean foundSelf = false; 625 for (final JInternalFrame f : allFrames) { 626 if (f == frame) { foundSelf = true; continue; } 627 if (!foundSelf) continue; 628 629 final Rectangle bounds = f.getBounds(); 630 if (bounds.contains(parentPoint)) return f; 631 } 632 633 return pane; 634 } 635 636 boolean isEventInWindowShadow(final Point point) { 637 final Rectangle bounds = frame.getBounds(); 638 final Insets insets = frame.getInsets(); 639 insets.top -= fAquaBorder.getTitleHeight(); 640 641 if (point.x < insets.left) return true; 642 if (point.x > bounds.width - insets.right) return true; 643 if (point.y < insets.top) return true; 644 if (point.y > bounds.height - insets.bottom) return true; 645 646 return false; 647 } 648 } 649 650 static void updateComponentTreeUIActivation(final Component c, final Object active) { 651 if (c instanceof javax.swing.JComponent) { 652 ((javax.swing.JComponent)c).putClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY, active); 653 } 654 655 Component[] children = null; 656 657 if (c instanceof javax.swing.JMenu) { 658 children = ((javax.swing.JMenu)c).getMenuComponents(); 659 } else if (c instanceof Container) { 660 children = ((Container)c).getComponents(); 661 } 662 663 if (children != null) { 664 for (final Component element : children) { 665 updateComponentTreeUIActivation(element, active); 666 } 667 } 668 } 669 670 class PropertyListener implements PropertyChangeListener { 671 public void propertyChange(final PropertyChangeEvent e) { 672 final String name = e.getPropertyName(); 673 if (FRAME_TYPE.equals(name)) { 674 if (e.getNewValue() instanceof String) { 675 setFrameType((String)e.getNewValue()); 676 } 677 } else if (IS_PALETTE_PROPERTY.equals(name)) { 678 if (e.getNewValue() != null) { 679 setPalette(((Boolean)e.getNewValue()).booleanValue()); 680 } else { 681 setPalette(false); 682 } 683 // TODO: CPlatformWindow? 684 } else if ("windowModified".equals(name) || CPlatformWindow.WINDOW_DOCUMENT_MODIFIED.equals(name)) { 685 // repaint title bar 686 setDocumentEdited(((Boolean)e.getNewValue()).booleanValue()); 687 frame.repaint(0, 0, frame.getWidth(), frame.getBorder().getBorderInsets(frame).top); 688 } else if ("resizable".equals(name) || "state".equals(name) || "iconable".equals(name) || "maximizable".equals(name) || "closable".equals(name)) { 689 if ("resizable".equals(name)) { 690 frame.revalidate(); 691 } 692 frame.repaint(); 693 } else if ("title".equals(name)) { 694 frame.repaint(); 695 } else if ("componentOrientation".equals(name)) { 696 frame.revalidate(); 697 frame.repaint(); 698 } else if (JInternalFrame.IS_SELECTED_PROPERTY.equals(name)) { 699 final Component source = (Component)(e.getSource()); 700 updateComponentTreeUIActivation(source, frame.isSelected() ? Boolean.TRUE : Boolean.FALSE); 701 } 702 703 } 704 } // end class PaletteListener 705 706 static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() { 707 Border getForegroundShadowBorder() { 708 return new AquaUtils.SlicedShadowBorder(new Painter() { 709 public void paint(final Graphics g, final int x, final int y, final int w, final int h) { 710 g.setColor(new Color(0, 0, 0, 196)); 711 g.fillRoundRect(x, y, w, h, 16, 16); 712 g.fillRect(x, y + h - 16, w, 16); 713 } 714 }, new Painter() { 715 public void paint(final Graphics g, int x, int y, int w, int h) { 716 g.setColor(new Color(0, 0, 0, 64)); 717 g.drawLine(x + 2, y - 8, x + w - 2, y - 8); 718 } 719 }, 720 0, 7, 1.1f, 1.0f, 24, 51, 51, 25, 25, 25, 25); 721 } 722 723 Border getBackgroundShadowBorder() { 724 return new AquaUtils.SlicedShadowBorder(new Painter() { 725 public void paint(final Graphics g, final int x, final int y, final int w, final int h) { 726 g.setColor(new Color(0, 0, 0, 128)); 727 g.fillRoundRect(x - 3, y - 8, w + 6, h, 16, 16); 728 g.fillRect(x - 3, y + h - 20, w + 6, 19); 729 } 730 }, new Painter() { 731 public void paint(final Graphics g, int x, int y, int w, int h) { 732 g.setColor(new Color(0, 0, 0, 32)); 733 g.drawLine(x, y - 11, x + w - 1, y - 11); 734 } 735 }, 736 0, 0, 3.0f, 1.0f, 10, 51, 51, 25, 25, 25, 25); 737 } 738 }; 739 740 static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() { 741 Border getForegroundShadowBorder() { 742 return new AquaUtils.SlicedShadowBorder(new Painter() { 743 public void paint(final Graphics g, final int x, final int y, final int w, final int h) { 744 g.setColor(new Color(0, 0, 0, 128)); 745 g.fillRect(x, y + 3, w, h - 3); 746 } 747 }, null, 748 0, 3, 1.0f, 1.0f, 10, 25, 25, 12, 12, 12, 12); 749 } 750 751 Border getBackgroundShadowBorder() { 752 return getForegroundShadowBorder(); 753 } 754 }; 755 756 @SuppressWarnings("serial") // Superclass is not serializable across versions 757 static class CompoundUIBorder extends CompoundBorder implements UIResource { 758 public CompoundUIBorder(final Border inside, final Border outside) { super(inside, outside); } 759 } 760 761 abstract static class InternalFrameShadow extends RecyclableSingleton<Border> { 762 abstract Border getForegroundShadowBorder(); 763 abstract Border getBackgroundShadowBorder(); 764 765 protected Border getInstance() { 766 final Border fgShadow = getForegroundShadowBorder(); 767 final Border bgShadow = getBackgroundShadowBorder(); 768 769 return new Border() { 770 public Insets getBorderInsets(final Component c) { 771 return fgShadow.getBorderInsets(c); 772 } 773 774 public boolean isBorderOpaque() { 775 return false; 776 } 777 778 public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) { 779 if (((JInternalFrame)c).isSelected()) { 780 fgShadow.paintBorder(c, g, x, y, w, h); 781 } else { 782 bgShadow.paintBorder(c, g, x, y, w, h); 783 } 784 } 785 }; 786 } 787 } 788 789 static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() { 790 protected Icon getInstance() { 791 return new AquaIcon.CachableJRSUIIcon(11, 11) { 792 public void initIconPainter(final AquaPainter<JRSUIState> iconState) { 793 iconState.state.set(Widget.GROW_BOX_TEXTURED); 794 iconState.state.set(WindowType.UTILITY); 795 } 796 }; 797 } 798 }; 799 800 @SuppressWarnings("serial") // Superclass is not serializable across versions 801 class ResizeBox extends JLabel implements MouseListener, MouseMotionListener, MouseWheelListener, ComponentListener, PropertyChangeListener, UIResource { 802 final JLayeredPane layeredPane; 803 Dimension originalSize; 804 Point originalLocation; 805 806 public ResizeBox(final JLayeredPane layeredPane) { 807 super(RESIZE_ICON.get()); 808 setSize(11, 11); 809 this.layeredPane = layeredPane; 810 811 addMouseListener(this); 812 addMouseMotionListener(this); 813 addMouseWheelListener(this); 814 } 815 816 void addListeners() { 817 frame.addPropertyChangeListener("resizable", this); 818 } 819 820 void removeListeners() { 821 frame.removePropertyChangeListener("resizable", this); 822 } 823 824 void repositionResizeBox() { 825 if (frame == null) { setSize(0, 0); } else { setSize(11, 11); } 826 setLocation(layeredPane.getWidth() - 12, layeredPane.getHeight() - 12); 827 } 828 829 void resizeInternalFrame(final Point pt) { 830 if (originalLocation == null || frame == null) return; 831 832 final Container parent = frame.getParent(); 833 if (!(parent instanceof JDesktopPane)) return; 834 835 final Point newPoint = SwingUtilities.convertPoint(this, pt, frame); 836 int deltaX = originalLocation.x - newPoint.x; 837 int deltaY = originalLocation.y - newPoint.y; 838 final Dimension min = frame.getMinimumSize(); 839 final Dimension max = frame.getMaximumSize(); 840 841 final int newX = frame.getX(); 842 final int newY = frame.getY(); 843 int newW = frame.getWidth(); 844 int newH = frame.getHeight(); 845 846 final Rectangle parentBounds = parent.getBounds(); 847 848 if (originalSize.width - deltaX < min.width) { 849 deltaX = originalSize.width - min.width; 850 } else if (originalSize.width - deltaX > max.width) { 851 deltaX = -(max.width - originalSize.width); 852 } 853 854 if (newX + originalSize.width - deltaX > parentBounds.width) { 855 deltaX = newX + originalSize.width - parentBounds.width; 856 } 857 858 if (originalSize.height - deltaY < min.height) { 859 deltaY = originalSize.height - min.height; 860 } else if (originalSize.height - deltaY > max.height) { 861 deltaY = -(max.height - originalSize.height); 862 } 863 864 if (newY + originalSize.height - deltaY > parentBounds.height) { 865 deltaY = newY + originalSize.height - parentBounds.height; 866 } 867 868 newW = originalSize.width - deltaX; 869 newH = originalSize.height - deltaY; 870 871 getDesktopManager().resizeFrame(frame, newX, newY, newW, newH); 872 } 873 874 boolean testGrowboxPoint(final int x, final int y, final int w, final int h) { 875 return (w - x) + (h - y) < 12; 876 } 877 878 void forwardEventToFrame(final MouseEvent e) { 879 final Point pt = new Point(); 880 final Component c = getComponentToForwardTo(e, pt); 881 if (c == null) return; 882 c.dispatchEvent(new MouseEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getButton())); 883 } 884 885 Component getComponentToForwardTo(final MouseEvent e, final Point dst) { 886 if (frame == null) return null; 887 final Container contentPane = frame.getContentPane(); 888 if (contentPane == null) return null; 889 Point pt = SwingUtilities.convertPoint(this, e.getPoint(), contentPane); 890 final Component c = SwingUtilities.getDeepestComponentAt(contentPane, pt.x, pt.y); 891 if (c == null) return null; 892 pt = SwingUtilities.convertPoint(contentPane, pt, c); 893 if (dst != null) dst.setLocation(pt); 894 return c; 895 } 896 897 public void mouseClicked(final MouseEvent e) { 898 forwardEventToFrame(e); 899 } 900 901 public void mouseEntered(final MouseEvent e) { } 902 903 public void mouseExited(final MouseEvent e) { } 904 905 public void mousePressed(final MouseEvent e) { 906 if (frame == null) return; 907 908 if (frame.isResizable() && !frame.isMaximum() && testGrowboxPoint(e.getX(), e.getY(), getWidth(), getHeight())) { 909 originalLocation = SwingUtilities.convertPoint(this, e.getPoint(), frame); 910 originalSize = frame.getSize(); 911 getDesktopManager().beginResizingFrame(frame, SwingConstants.SOUTH_EAST); 912 return; 913 } 914 915 forwardEventToFrame(e); 916 } 917 918 public void mouseReleased(final MouseEvent e) { 919 if (originalLocation != null) { 920 resizeInternalFrame(e.getPoint()); 921 originalLocation = null; 922 getDesktopManager().endResizingFrame(frame); 923 return; 924 } 925 926 forwardEventToFrame(e); 927 } 928 929 public void mouseDragged(final MouseEvent e) { 930 resizeInternalFrame(e.getPoint()); 931 repositionResizeBox(); 932 } 933 934 public void mouseMoved(final MouseEvent e) { } 935 936 public void mouseWheelMoved(final MouseWheelEvent e) { 937 final Point pt = new Point(); 938 final Component c = getComponentToForwardTo(e, pt); 939 if (c == null) return; 940 c.dispatchEvent(new MouseWheelEvent(c, e.getID(), e.getWhen(), e.getModifiers(), pt.x, pt.y, e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation())); 941 } 942 943 public void componentResized(final ComponentEvent e) { 944 repositionResizeBox(); 945 } 946 947 public void componentShown(final ComponentEvent e) { 948 repositionResizeBox(); 949 } 950 951 public void componentMoved(final ComponentEvent e) { 952 repositionResizeBox(); 953 } 954 955 public void componentHidden(final ComponentEvent e) { } 956 957 public void propertyChange(final PropertyChangeEvent evt) { 958 if (!"resizable".equals(evt.getPropertyName())) return; 959 setVisible(Boolean.TRUE.equals(evt.getNewValue())); 960 } 961 } 962 }