Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / plaf / basic / BasicInternalFrameUI.java
blobf9653bd2edd15a025fdf4124fd42c15348c3c8d5
1 /* BasicInternalFrameUI.java --
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.plaf.basic;
41 import java.awt.AWTEvent;
42 import java.awt.Color;
43 import java.awt.Component;
44 import java.awt.Container;
45 import java.awt.Dimension;
46 import java.awt.Graphics;
47 import java.awt.Insets;
48 import java.awt.LayoutManager;
49 import java.awt.LayoutManager2;
50 import java.awt.Point;
51 import java.awt.Rectangle;
52 import java.awt.event.ComponentEvent;
53 import java.awt.event.ComponentListener;
54 import java.awt.event.MouseEvent;
55 import java.beans.PropertyChangeEvent;
56 import java.beans.PropertyChangeListener;
57 import java.beans.PropertyVetoException;
58 import java.beans.VetoableChangeListener;
60 import javax.swing.DefaultDesktopManager;
61 import javax.swing.DesktopManager;
62 import javax.swing.JComponent;
63 import javax.swing.JDesktopPane;
64 import javax.swing.JInternalFrame;
65 import javax.swing.KeyStroke;
66 import javax.swing.LookAndFeel;
67 import javax.swing.SwingConstants;
68 import javax.swing.SwingUtilities;
69 import javax.swing.UIManager;
70 import javax.swing.border.AbstractBorder;
71 import javax.swing.event.InternalFrameEvent;
72 import javax.swing.event.InternalFrameListener;
73 import javax.swing.event.MouseInputAdapter;
74 import javax.swing.event.MouseInputListener;
75 import javax.swing.plaf.ComponentUI;
76 import javax.swing.plaf.InternalFrameUI;
77 import javax.swing.plaf.UIResource;
79 /**
80 * This is the UI delegate for the Basic look and feel for JInternalFrames.
82 public class BasicInternalFrameUI extends InternalFrameUI
84 /**
85 * This is a helper class that listens to the JInternalFrame for
86 * InternalFrameEvents.
88 protected class BasicInternalFrameListener implements InternalFrameListener
90 /**
91 * This method is called when the JInternalFrame is activated.
93 * @param e The InternalFrameEvent.
95 public void internalFrameActivated(InternalFrameEvent e)
97 // FIXME: Implement.
101 * This method is called when the JInternalFrame is closed.
103 * @param e The InternalFrameEvent.
105 public void internalFrameClosed(InternalFrameEvent e)
107 // FIXME: Implement.
111 * This method is called when the JInternalFrame is closing.
113 * @param e The InternalFrameEvent.
115 public void internalFrameClosing(InternalFrameEvent e)
117 // FIXME: Implement.
121 * This method is called when the JInternalFrame is deactivated.
123 * @param e The InternalFrameEvent.
125 public void internalFrameDeactivated(InternalFrameEvent e)
127 // FIXME: Implement.
131 * This method is called when the JInternalFrame is deiconified.
133 * @param e The InternalFrameEvent.
135 public void internalFrameDeiconified(InternalFrameEvent e)
137 // FIXME: Implement.
141 * This method is called when the JInternalFrame is iconified.
143 * @param e The InternalFrameEvent.
145 public void internalFrameIconified(InternalFrameEvent e)
147 // FIXME: Implement.
151 * This method is called when the JInternalFrame is opened.
153 * @param e The InternalFrameEvent.
155 public void internalFrameOpened(InternalFrameEvent e)
157 // FIXME: Implement.
162 * This helper class listens to the edges of the JInternalFrame and the
163 * TitlePane for mouse events. It is responsible for dragging and resizing
164 * the JInternalFrame in response to the MouseEvents.
166 protected class BorderListener extends MouseInputAdapter
167 implements SwingConstants
169 /** FIXME: Use for something. */
170 protected final int RESIZE_NONE = 0;
172 /** The x offset from the top left corner of the JInternalFrame. */
173 private transient int xOffset = 0;
175 /** The y offset from the top left corner of the JInternalFrame. */
176 private transient int yOffset = 0;
178 /** The direction that the resize is occuring in. */
179 private transient int direction = -1;
181 /** Cache rectangle that can be reused. */
182 private transient Rectangle cacheRect = new Rectangle();
185 * This method is called when the mouse is clicked.
187 * @param e The MouseEvent.
189 public void mouseClicked(MouseEvent e)
191 // There is nothing to do when the mouse is clicked
192 // on the border.
196 * This method is called when the mouse is dragged. This method is
197 * responsible for resizing or dragging the JInternalFrame.
199 * @param e The MouseEvent.
201 public void mouseDragged(MouseEvent e)
203 // If the frame is maximized, there is nothing that
204 // can be dragged around.
205 if (frame.isMaximum())
206 return;
207 DesktopManager dm = getDesktopManager();
208 Rectangle b = frame.getBounds();
209 Dimension min = frame.getMinimumSize();
210 if (min == null)
211 min = new Dimension(0, 0);
212 Insets insets = frame.getInsets();
213 int x = e.getX();
214 int y = e.getY();
215 if (e.getSource() == frame && frame.isResizable())
217 switch (direction)
219 case NORTH:
220 cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
221 - min.height),
222 b.width, b.height - y);
223 break;
224 case NORTH_EAST:
225 cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
226 - min.height), x,
227 b.height - y);
228 break;
229 case EAST:
230 cacheRect.setBounds(b.x, b.y, x, b.height);
231 break;
232 case SOUTH_EAST:
233 cacheRect.setBounds(b.x, b.y, x, y);
234 break;
235 case SOUTH:
236 cacheRect.setBounds(b.x, b.y, b.width, y);
237 break;
238 case SOUTH_WEST:
239 cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
240 b.y, b.width - x, y);
241 break;
242 case WEST:
243 cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
244 b.y, b.width - x, b.height);
245 break;
246 case NORTH_WEST:
247 cacheRect.setBounds(
248 Math.min(b.x + x, b.x + b.width - min.width),
249 Math.min(b.y + y, b.y + b.height - min.height),
250 b.width - x, b.height - y);
251 break;
253 dm.resizeFrame(frame, cacheRect.x, cacheRect.y,
254 Math.max(min.width, cacheRect.width),
255 Math.max(min.height, cacheRect.height));
257 else if (e.getSource() == titlePane)
259 Rectangle fBounds = frame.getBounds();
261 dm.dragFrame(frame, e.getX() - xOffset + b.x, e.getY() - yOffset
262 + b.y);
267 * This method is called when the mouse exits the JInternalFrame.
269 * @param e The MouseEvent.
271 public void mouseExited(MouseEvent e)
273 // There is nothing to do when the mouse exits
274 // the border area.
278 * This method is called when the mouse is moved inside the
279 * JInternalFrame.
281 * @param e The MouseEvent.
283 public void mouseMoved(MouseEvent e)
285 // There is nothing to do when the mouse moves
286 // over the border area.
290 * This method is called when the mouse is pressed.
292 * @param e The MouseEvent.
294 public void mousePressed(MouseEvent e)
296 activateFrame(frame);
297 DesktopManager dm = getDesktopManager();
298 int x = e.getX();
299 int y = e.getY();
300 Insets insets = frame.getInsets();
302 if (e.getSource() == frame && frame.isResizable())
304 direction = sectionOfClick(x, y);
305 dm.beginResizingFrame(frame, direction);
307 else if (e.getSource() == titlePane)
309 Rectangle tBounds = titlePane.getBounds();
311 xOffset = e.getX() - tBounds.x + insets.left;
312 yOffset = e.getY() - tBounds.y + insets.top;
314 dm.beginDraggingFrame(frame);
319 * This method is called when the mouse is released.
321 * @param e The MouseEvent.
323 public void mouseReleased(MouseEvent e)
325 DesktopManager dm = getDesktopManager();
326 xOffset = 0;
327 yOffset = 0;
328 if (e.getSource() == frame && frame.isResizable())
329 dm.endResizingFrame(frame);
330 else if (e.getSource() == titlePane)
331 dm.endDraggingFrame(frame);
335 * This method determines the direction of the resize based on the
336 * coordinates and the size of the JInternalFrame.
338 * @param x The x coordinate of the MouseEvent.
339 * @param y The y coordinate of the MouseEvent.
341 * @return The direction of the resize (a SwingConstant direction).
343 private int sectionOfClick(int x, int y)
345 Insets insets = frame.getInsets();
346 Rectangle b = frame.getBounds();
347 if (x < insets.left && y < insets.top)
348 return NORTH_WEST;
349 else if (x > b.width - insets.right && y < insets.top)
350 return NORTH_EAST;
351 else if (x > b.width - insets.right && y > b.height - insets.bottom)
352 return SOUTH_EAST;
353 else if (x < insets.left && y > b.height - insets.bottom)
354 return SOUTH_WEST;
355 else if (y < insets.top)
356 return NORTH;
357 else if (x < insets.left)
358 return WEST;
359 else if (y > b.height - insets.bottom)
360 return SOUTH;
361 else if (x > b.width - insets.right)
362 return EAST;
364 return -1;
369 * This helper class listens to the JDesktopPane that parents this
370 * JInternalFrame and listens for resize events and resizes the
371 * JInternalFrame appropriately.
373 protected class ComponentHandler implements ComponentListener
376 * This method is called when the JDesktopPane is hidden.
378 * @param e
379 * The ComponentEvent fired.
381 public void componentHidden(ComponentEvent e)
383 // Do nothing.
387 * This method is called when the JDesktopPane is moved.
389 * @param e
390 * The ComponentEvent fired.
392 public void componentMoved(ComponentEvent e)
394 // Do nothing.
398 * This method is called when the JDesktopPane is resized.
400 * @param e
401 * The ComponentEvent fired.
403 public void componentResized(ComponentEvent e)
405 if (frame.isMaximum())
407 JDesktopPane pane = (JDesktopPane) e.getSource();
408 Insets insets = pane.getInsets();
409 Rectangle bounds = pane.getBounds();
411 frame.setBounds(bounds.x + insets.left, bounds.y + insets.top,
412 bounds.width - insets.left - insets.right,
413 bounds.height - insets.top - insets.bottom);
414 frame.revalidate();
415 frame.repaint();
418 // Sun also resizes the icons. but it doesn't seem to do anything.
422 * This method is called when the JDesktopPane is shown.
424 * @param e
425 * The ComponentEvent fired.
427 public void componentShown(ComponentEvent e)
429 // Do nothing.
434 * This helper class acts as the LayoutManager for JInternalFrames.
436 public class InternalFrameLayout implements LayoutManager
439 * This method is called when the given Component is added to the
440 * JInternalFrame.
442 * @param name
443 * The name of the Component.
444 * @param c
445 * The Component added.
447 public void addLayoutComponent(String name, Component c)
449 // Nothing to do here.
453 * This method is used to set the bounds of the children of the
454 * JInternalFrame.
456 * @param c
457 * The Container to lay out.
459 public void layoutContainer(Container c)
461 Dimension dims = frame.getSize();
462 Insets insets = frame.getInsets();
464 dims.width -= insets.left + insets.right;
465 dims.height -= insets.top + insets.bottom;
467 frame.getRootPane().getGlassPane().setBounds(0, 0, dims.width,
468 dims.height);
469 int nh = 0;
470 int sh = 0;
471 int ew = 0;
472 int ww = 0;
474 if (northPane != null)
476 Dimension nDims = northPane.getPreferredSize();
477 nh = Math.min(nDims.height, dims.height);
479 northPane.setBounds(insets.left, insets.top, dims.width, nh);
482 if (southPane != null)
484 Dimension sDims = southPane.getPreferredSize();
485 sh = Math.min(sDims.height, dims.height - nh);
487 southPane.setBounds(insets.left, insets.top + dims.height - sh,
488 dims.width, sh);
491 int remHeight = dims.height - sh - nh;
493 if (westPane != null)
495 Dimension wDims = westPane.getPreferredSize();
496 ww = Math.min(dims.width, wDims.width);
498 westPane.setBounds(insets.left, insets.top + nh, ww, remHeight);
501 if (eastPane != null)
503 Dimension eDims = eastPane.getPreferredSize();
504 ew = Math.min(eDims.width, dims.width - ww);
506 eastPane.setBounds(insets.left + dims.width - ew, insets.top + nh,
507 ew, remHeight);
510 int remWidth = dims.width - ww - ew;
512 frame.getRootPane().setBounds(insets.left + ww, insets.top + nh,
513 remWidth, remHeight);
517 * This method returns the minimum layout size.
519 * @param c
520 * The Container to find a minimum layout size for.
521 * @return The minimum dimensions for the JInternalFrame.
523 public Dimension minimumLayoutSize(Container c)
525 return getSize(c, true);
529 * This method returns the maximum layout size.
531 * @param c
532 * The Container to find a maximum layout size for.
533 * @return The maximum dimensions for the JInternalFrame.
535 public Dimension maximumLayoutSize(Container c)
537 return preferredLayoutSize(c);
541 * Th8is method returns the preferred layout size.
543 * @param c
544 * The Container to find a preferred layout size for.
545 * @return The preferred dimensions for the JInternalFrame.
547 public Dimension preferredLayoutSize(Container c)
549 return getSize(c, false);
553 * DOCUMENT ME!
555 * @param c
556 * DOCUMENT ME!
557 * @param min
558 * DOCUMENT ME!
559 * @return DOCUMENT ME!
561 private Dimension getSize(Container c, boolean min)
563 Insets insets = frame.getInsets();
565 Dimension contentDims = frame.getContentPane().getPreferredSize();
566 if (min)
567 contentDims.width = contentDims.height = 0;
568 int nWidth = 0;
569 int nHeight = 0;
570 int sWidth = 0;
571 int sHeight = 0;
572 int eWidth = 0;
573 int eHeight = 0;
574 int wWidth = 0;
575 int wHeight = 0;
576 Dimension dims;
578 if (northPane != null)
580 dims = northPane.getPreferredSize();
581 if (dims != null)
583 nWidth = dims.width;
584 nHeight = dims.height;
588 if (southPane != null)
590 dims = southPane.getPreferredSize();
591 if (dims != null)
593 sWidth = dims.width;
594 sHeight = dims.height;
598 if (eastPane != null)
600 dims = eastPane.getPreferredSize();
601 if (dims != null)
603 sWidth = dims.width;
604 sHeight = dims.height;
608 if (westPane != null)
610 dims = westPane.getPreferredSize();
611 if (dims != null)
613 wWidth = dims.width;
614 wHeight = dims.height;
618 int width = Math.max(sWidth, nWidth);
619 width = Math.max(width, contentDims.width + eWidth + wWidth);
621 int height = Math.max(eHeight, wHeight);
622 height = Math.max(height, contentDims.height);
623 height += nHeight + sHeight;
625 width += insets.left + insets.right;
626 height += insets.top + insets.bottom;
628 return new Dimension(width, height);
632 * This method is called when a Component is removed from the
633 * JInternalFrame.
635 * @param c The Component that was removed.
637 public void removeLayoutComponent(Component c)
639 // Nothing to do here.
644 * This helper class is used to listen to the JDesktopPane's glassPane for
645 * MouseEvents. The JInternalFrame can then be selected if a click is
646 * detected on its children.
648 protected class GlassPaneDispatcher implements MouseInputListener
650 /** The MouseEvent target. */
651 private transient Component mouseEventTarget;
653 /** The component pressed. */
654 private transient Component pressedComponent;
656 /** The last component entered. */
657 private transient Component lastComponentEntered;
659 /** Used to store/reset lastComponentEntered. */
660 private transient Component tempComponent;
662 /** The number of presses. */
663 private transient int pressCount;
666 * This method is called when the mouse enters the glass pane.
668 * @param e
669 * The MouseEvent.
671 public void mouseEntered(MouseEvent e)
673 handleEvent(e);
677 * This method is called when the mouse is clicked on the glass pane.
679 * @param e
680 * The MouseEvent.
682 public void mouseClicked(MouseEvent e)
684 handleEvent(e);
688 * This method is called when the mouse is dragged in the glass pane.
690 * @param e
691 * The MouseEvent.
693 public void mouseDragged(MouseEvent e)
695 handleEvent(e);
699 * This method is called when the mouse exits the glass pane.
701 * @param e
702 * The MouseEvent.
704 public void mouseExited(MouseEvent e)
706 handleEvent(e);
710 * This method is called when the mouse is moved in the glass pane.
712 * @param e
713 * The MouseEvent.
715 public void mouseMoved(MouseEvent e)
717 handleEvent(e);
721 * This method is called when the mouse is pressed in the glass pane.
723 * @param e
724 * The MouseEvent.
726 public void mousePressed(MouseEvent e)
728 activateFrame(frame);
729 handleEvent(e);
733 * This method is called when the mouse is released in the glass pane.
735 * @param e
736 * The MouseEvent.
738 public void mouseReleased(MouseEvent e)
740 handleEvent(e);
744 * This method acquires a candidate component to dispatch the MouseEvent to.
746 * @param me
747 * The MouseEvent to acquire a component for.
749 private void acquireComponentForMouseEvent(MouseEvent me)
751 int x = me.getX();
752 int y = me.getY();
754 // Find the candidate which should receive this event.
755 Component parent = frame.getLayeredPane();
756 if (parent == null)
757 return;
758 Component candidate = null;
759 Point p = me.getPoint();
760 while (candidate == null && parent != null)
762 candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
763 if (candidate == null)
765 p = SwingUtilities.convertPoint(parent, p.x, p.y,
766 parent.getParent());
767 parent = parent.getParent();
771 // If the only candidate we found was the native container itself,
772 // don't dispatch any event at all. We only care about the lightweight
773 // children here.
774 if (candidate == frame.getContentPane())
775 candidate = null;
777 // If our candidate is new, inform the old target we're leaving.
778 if (lastComponentEntered != null && lastComponentEntered.isShowing()
779 && lastComponentEntered != candidate)
781 Point tp = SwingUtilities.convertPoint(frame.getContentPane(), x, y,
782 lastComponentEntered);
783 MouseEvent exited = new MouseEvent(lastComponentEntered,
784 MouseEvent.MOUSE_EXITED,
785 me.getWhen(), me.getModifiersEx(),
786 tp.x, tp.y, me.getClickCount(),
787 me.isPopupTrigger(),
788 me.getButton());
789 tempComponent = lastComponentEntered;
790 lastComponentEntered = null;
791 tempComponent.dispatchEvent(exited);
794 // If we have a candidate, maybe enter it.
795 if (candidate != null)
797 mouseEventTarget = candidate;
798 if (candidate.isLightweight() && candidate.isShowing()
799 && candidate != frame.getContentPane()
800 && candidate != lastComponentEntered)
802 lastComponentEntered = mouseEventTarget;
803 Point cp = SwingUtilities.convertPoint(frame.getContentPane(), x,
804 y, lastComponentEntered);
805 MouseEvent entered = new MouseEvent(lastComponentEntered,
806 MouseEvent.MOUSE_ENTERED,
807 me.getWhen(),
808 me.getModifiersEx(), cp.x,
809 cp.y, me.getClickCount(),
810 me.isPopupTrigger(),
811 me.getButton());
812 lastComponentEntered.dispatchEvent(entered);
816 if (me.getID() == MouseEvent.MOUSE_RELEASED
817 || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
818 || me.getID() == MouseEvent.MOUSE_DRAGGED)
819 // If any of the following events occur while a button is held down,
820 // they should be dispatched to the same component to which the
821 // original MOUSE_PRESSED event was dispatched:
822 // - MOUSE_RELEASED
823 // - MOUSE_PRESSED: another button pressed while the first is held down
824 // - MOUSE_DRAGGED
825 mouseEventTarget = pressedComponent;
826 else if (me.getID() == MouseEvent.MOUSE_CLICKED)
828 // Don't dispatch CLICKED events whose target is not the same as the
829 // target for the original PRESSED event.
830 if (candidate != pressedComponent)
831 mouseEventTarget = null;
832 else if (pressCount == 0)
833 pressedComponent = null;
838 * This is a helper method that dispatches the GlassPane MouseEvents to the
839 * proper component.
841 * @param e
842 * The AWTEvent to be dispatched. Usually an instance of
843 * MouseEvent.
845 private void handleEvent(AWTEvent e)
847 if (e instanceof MouseEvent)
849 MouseEvent me = (MouseEvent) e;
850 acquireComponentForMouseEvent(me);
852 //If there is no target, return
853 if (mouseEventTarget == null)
854 return;
856 //Avoid re-dispatching to ourselves and causing an infinite loop
857 if (mouseEventTarget.equals(frame.getGlassPane()))
858 return;
860 // Avoid dispatching ENTERED and EXITED events twice.
861 if (mouseEventTarget.isShowing()
862 && e.getID() != MouseEvent.MOUSE_ENTERED
863 && e.getID() != MouseEvent.MOUSE_EXITED)
865 MouseEvent newEvt = SwingUtilities.convertMouseEvent(
866 frame.getGlassPane(),
868 mouseEventTarget);
869 mouseEventTarget.dispatchEvent(newEvt);
871 switch (e.getID())
873 case MouseEvent.MOUSE_PRESSED:
874 if (pressCount++ == 0)
875 pressedComponent = mouseEventTarget;
876 break;
877 case MouseEvent.MOUSE_RELEASED:
878 // Clear our memory of the original PRESSED event, only if
879 // we're not expecting a CLICKED event after this. If
880 // there is a CLICKED event after this, it will do clean up.
881 if (--pressCount == 0 && mouseEventTarget != pressedComponent)
882 pressedComponent = null;
883 break;
891 * This helper class listens for PropertyChangeEvents from the
892 * JInternalFrame.
894 public class InternalFramePropertyChangeListener implements
895 PropertyChangeListener, VetoableChangeListener
899 * This method is called when one of the JInternalFrame's properties change.
900 * This method is to allow JInternalFrame to veto an attempt to close the
901 * internal frame. This allows JInternalFrame to honour its
902 * defaultCloseOperation if that is DO_NOTHING_ON_CLOSE.
904 public void vetoableChange(PropertyChangeEvent e)
905 throws PropertyVetoException
907 if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY))
909 if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE)
911 frame.setVisible(false);
912 frame.getDesktopPane().repaint();
913 throw new PropertyVetoException(
914 "close operation is HIDE_ON_CLOSE\n",
917 else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE)
918 closeFrame(frame);
919 else
920 throw new PropertyVetoException(
921 "close operation is DO_NOTHING_ON_CLOSE\n",
927 * This method is called when one of the JInternalFrame's properties change.
929 * @param evt
930 * The PropertyChangeEvent.
932 public void propertyChange(PropertyChangeEvent evt)
934 if (evt.getPropertyName().equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
936 if (frame.isMaximum())
937 maximizeFrame(frame);
938 else
939 minimizeFrame(frame);
941 else if (evt.getPropertyName().equals(JInternalFrame.IS_ICON_PROPERTY))
943 if (frame.isIcon())
944 iconifyFrame(frame);
945 else
946 deiconifyFrame(frame);
948 else if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY))
950 if (frame.isSelected())
951 activateFrame(frame);
952 else
953 deactivateFrame(frame);
955 else if (evt.getPropertyName().equals(JInternalFrame.ROOT_PANE_PROPERTY)
956 || evt.getPropertyName().equals(
957 JInternalFrame.GLASS_PANE_PROPERTY))
959 Component old = (Component) evt.getOldValue();
960 old.removeMouseListener(glassPaneDispatcher);
961 old.removeMouseMotionListener(glassPaneDispatcher);
963 Component newPane = (Component) evt.getNewValue();
964 newPane.addMouseListener(glassPaneDispatcher);
965 newPane.addMouseMotionListener(glassPaneDispatcher);
967 frame.revalidate();
970 * FIXME: need to add ancestor properties to JComponents. else if
971 * (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) { if
972 * (desktopPane != null)
973 * desktopPane.removeComponentListener(componentListener); desktopPane =
974 * frame.getDesktopPane(); if (desktopPane != null)
975 * desktopPane.addComponentListener(componentListener); }
981 * This helper class is the border for the JInternalFrame.
983 private class InternalFrameBorder extends AbstractBorder implements
984 UIResource
986 /** The width of the border. */
987 private static final int bSize = 5;
989 /** The size of the corners. */
990 private static final int offset = 10;
993 * This method returns whether the border is opaque.
995 * @return Whether the border is opaque.
997 public boolean isBorderOpaque()
999 return true;
1003 * This method returns the insets of the border.
1005 * @param c
1006 * The Component to find border insets for.
1007 * @return The border insets.
1009 public Insets getBorderInsets(Component c)
1011 return new Insets(bSize, bSize, bSize, bSize);
1015 * This method paints the border.
1017 * @param c
1018 * The Component that owns the border.
1019 * @param g
1020 * The Graphics object to paint with.
1021 * @param x
1022 * The x coordinate to paint at.
1023 * @param y
1024 * The y coordinate to paint at.
1025 * @param width
1026 * The width of the Component.
1027 * @param height
1028 * The height of the Component.
1030 public void paintBorder(Component c, Graphics g, int x, int y, int width,
1031 int height)
1033 g.translate(x, y);
1034 Color saved = g.getColor();
1035 Rectangle b = frame.getBounds();
1037 Color d = c.getBackground();
1038 g.setColor(d);
1039 g.fillRect(0, 0, bSize, b.height);
1040 g.fillRect(0, 0, b.width, bSize);
1041 g.fillRect(0, b.height - bSize, b.width, bSize);
1042 g.fillRect(b.width - bSize, 0, bSize, b.height);
1044 int x1 = 0;
1045 int x2 = bSize;
1046 int x3 = b.width - bSize;
1047 int x4 = b.width;
1049 int y1 = 0;
1050 int y2 = bSize;
1051 int y3 = b.height - bSize;
1052 int y4 = b.height;
1054 g.setColor(Color.GRAY);
1055 g.fillRect(0, 0, bSize, y4);
1056 g.fillRect(0, 0, x4, bSize);
1057 g.fillRect(0, y3, b.width, bSize);
1058 g.fillRect(x3, 0, bSize, b.height);
1060 g.fill3DRect(0, offset, bSize, b.height - 2 * offset, false);
1061 g.fill3DRect(offset, 0, b.width - 2 * offset, bSize, false);
1062 g.fill3DRect(offset, b.height - bSize, b.width - 2 * offset, bSize, false);
1063 g.fill3DRect(b.width - bSize, offset, bSize, b.height - 2 * offset, false);
1065 g.translate(-x, -y);
1066 g.setColor(saved);
1071 * The MouseListener that is responsible for dragging and resizing the
1072 * JInternalFrame in response to MouseEvents.
1074 protected MouseInputAdapter borderListener;
1077 * The ComponentListener that is responsible for resizing the JInternalFrame
1078 * in response to ComponentEvents from the JDesktopPane.
1080 protected ComponentListener componentListener;
1083 * The MouseListener that is responsible for activating the JInternalFrame
1084 * when the mouse press activates one of its descendents.
1086 protected MouseInputListener glassPaneDispatcher;
1089 * The PropertyChangeListener that is responsible for listening to
1090 * PropertyChangeEvents from the JInternalFrame.
1092 protected PropertyChangeListener propertyChangeListener;
1095 * The VetoableChangeListener. Listens to PropertyChangeEvents
1096 * from the JInternalFrame and allows the JInternalFrame to
1097 * veto attempts to close it.
1099 private VetoableChangeListener internalFrameVetoableChangeListener;
1101 /** The InternalFrameListener that listens to the JInternalFrame. */
1102 private transient BasicInternalFrameListener internalFrameListener;
1104 /** The JComponent placed at the east region of the JInternalFrame. */
1105 protected JComponent eastPane;
1107 /** The JComponent placed at the north region of the JInternalFrame. */
1108 protected JComponent northPane;
1110 /** The JComponent placed at the south region of the JInternalFrame. */
1111 protected JComponent southPane;
1113 /** The JComponent placed at the west region of the JInternalFrame. */
1114 protected JComponent westPane;
1117 * The Keystroke bound to open the menu.
1118 * @deprecated
1120 protected KeyStroke openMenuKey;
1122 /** The TitlePane displayed at the top of the JInternalFrame. */
1123 protected BasicInternalFrameTitlePane titlePane;
1125 /** The JInternalFrame this UI is responsible for. */
1126 protected JInternalFrame frame;
1128 /** The LayoutManager used in the JInternalFrame. */
1129 protected LayoutManager internalFrameLayout;
1131 /** The JDesktopPane that is the parent of the JInternalFrame. */
1132 private transient JDesktopPane desktopPane;
1135 * Creates a new BasicInternalFrameUI object.
1137 * @param b The JInternalFrame this UI will represent.
1139 public BasicInternalFrameUI(JInternalFrame b)
1141 // Nothing to do here.
1145 * This method will create a new BasicInternalFrameUI for the given
1146 * JComponent.
1148 * @param b The JComponent to create a BasicInternalFrameUI for.
1150 * @return A new BasicInternalFrameUI.
1152 public static ComponentUI createUI(JComponent b)
1154 return new BasicInternalFrameUI((JInternalFrame) b);
1158 * This method installs a UI for the JInternalFrame.
1160 * @param c The JComponent to install this UI on.
1162 public void installUI(JComponent c)
1164 if (c instanceof JInternalFrame)
1166 frame = (JInternalFrame) c;
1168 ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false);
1169 frame.getRootPane().getGlassPane().setVisible(true);
1171 installDefaults();
1172 installListeners();
1173 installComponents();
1174 installKeyboardActions();
1176 frame.setOpaque(true);
1177 frame.invalidate();
1182 * This method reverses the work done by installUI.
1184 * @param c The JComponent to uninstall this UI for.
1186 public void uninstallUI(JComponent c)
1188 uninstallKeyboardActions();
1189 uninstallComponents();
1190 uninstallListeners();
1191 uninstallDefaults();
1193 ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(true);
1194 frame.getRootPane().getGlassPane().setVisible(false);
1196 frame = null;
1200 * This method installs the defaults specified by the look and feel.
1202 protected void installDefaults()
1204 internalFrameLayout = createLayoutManager();
1205 frame.setLayout(internalFrameLayout);
1206 LookAndFeel.installBorder(frame, "InternalFrame.border");
1207 frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon"));
1208 // InternalFrames are invisible by default.
1209 frame.setVisible(false);
1213 * This method installs the keyboard actions for the JInternalFrame.
1215 protected void installKeyboardActions()
1217 // FIXME: Implement.
1221 * This method installs the Components for the JInternalFrame.
1223 protected void installComponents()
1225 setNorthPane(createNorthPane(frame));
1226 setSouthPane(createSouthPane(frame));
1227 setEastPane(createEastPane(frame));
1228 setWestPane(createWestPane(frame));
1232 * This method installs the listeners for the JInternalFrame.
1234 protected void installListeners()
1236 glassPaneDispatcher = createGlassPaneDispatcher();
1237 createInternalFrameListener();
1238 borderListener = createBorderListener(frame);
1239 componentListener = createComponentListener();
1240 propertyChangeListener = createPropertyChangeListener();
1241 internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener();
1243 frame.addMouseListener(borderListener);
1244 frame.addMouseMotionListener(borderListener);
1245 frame.addInternalFrameListener(internalFrameListener);
1246 frame.addPropertyChangeListener(propertyChangeListener);
1247 frame.addVetoableChangeListener(internalFrameVetoableChangeListener);
1248 frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher);
1249 frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher);
1253 * This method uninstalls the defaults for the JInternalFrame.
1255 protected void uninstallDefaults()
1257 frame.setBorder(null);
1258 frame.setLayout(null);
1259 internalFrameLayout = null;
1263 * This method uninstalls the Components for the JInternalFrame.
1265 protected void uninstallComponents()
1267 setNorthPane(null);
1268 setSouthPane(null);
1269 setEastPane(null);
1270 setWestPane(null);
1274 * This method uninstalls the listeners for the JInternalFrame.
1276 protected void uninstallListeners()
1278 if (desktopPane != null)
1279 desktopPane.removeComponentListener(componentListener);
1281 frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher);
1282 frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher);
1284 frame.removePropertyChangeListener(propertyChangeListener);
1285 frame.removeInternalFrameListener(internalFrameListener);
1286 frame.removeMouseMotionListener(borderListener);
1287 frame.removeMouseListener(borderListener);
1289 propertyChangeListener = null;
1290 componentListener = null;
1291 borderListener = null;
1292 internalFrameListener = null;
1293 glassPaneDispatcher = null;
1297 * This method uninstalls the keyboard actions for the JInternalFrame.
1299 protected void uninstallKeyboardActions()
1301 // FIXME: Implement.
1305 * This method creates a new LayoutManager for the JInternalFrame.
1307 * @return A new LayoutManager for the JInternalFrame.
1309 protected LayoutManager createLayoutManager()
1311 return new InternalFrameLayout();
1315 * This method creates a new PropertyChangeListener for the JInternalFrame.
1317 * @return A new PropertyChangeListener for the JInternalFrame.
1319 protected PropertyChangeListener createPropertyChangeListener()
1321 return new InternalFramePropertyChangeListener();
1325 * This method returns the preferred size of the given JComponent.
1327 * @param x The JComponent to find a preferred size for.
1329 * @return The preferred size.
1331 public Dimension getPreferredSize(JComponent x)
1333 Dimension pref = null;
1334 LayoutManager layout = frame.getLayout();
1335 if (frame == x && layout != null)
1336 pref = layout.preferredLayoutSize(frame);
1337 else
1338 pref = new Dimension(100, 100);
1339 return pref;
1343 * This method returns the minimum size of the given JComponent.
1345 * @param x The JComponent to find a minimum size for.
1347 * @return The minimum size.
1349 public Dimension getMinimumSize(JComponent x)
1351 Dimension min = null;
1352 LayoutManager layout = frame.getLayout();
1353 if (frame == x && layout != null)
1354 min = layout.minimumLayoutSize(frame);
1355 else
1356 min = new Dimension(0, 0);
1357 return min;
1361 * This method returns the maximum size of the given JComponent.
1363 * @param x The JComponent to find a maximum size for.
1365 * @return The maximum size.
1367 public Dimension getMaximumSize(JComponent x)
1369 Dimension max = null;
1370 LayoutManager layout = frame.getLayout();
1371 if (frame == x && layout != null && layout instanceof LayoutManager2)
1372 max = ((LayoutManager2) layout).maximumLayoutSize(frame);
1373 else
1374 max = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1375 return max;
1379 * This method replaces the currentPane with the newPane. When replacing it
1380 * also removes the MouseHandlers for the old pane and installs them on
1381 * the new pane.
1383 * @param currentPane The old pane to remove.
1384 * @param newPane The new pane to install.
1386 protected void replacePane(JComponent currentPane, JComponent newPane)
1388 if (currentPane != null)
1390 deinstallMouseHandlers(currentPane);
1391 frame.remove(currentPane);
1394 if (newPane != null)
1396 installMouseHandlers(newPane);
1397 frame.add(newPane);
1402 * This method removes the necessary MouseListeners from the given
1403 * JComponent.
1405 * @param c The JComponent to remove MouseListeners from.
1407 protected void deinstallMouseHandlers(JComponent c)
1409 c.removeMouseListener(borderListener);
1410 c.removeMouseMotionListener(borderListener);
1414 * This method installs the necessary MouseListeners from the given
1415 * JComponent.
1417 * @param c The JComponent to install MouseListeners on.
1419 protected void installMouseHandlers(JComponent c)
1421 c.addMouseListener(borderListener);
1422 c.addMouseMotionListener(borderListener);
1426 * This method creates the north pane used in the JInternalFrame.
1428 * @param w The JInternalFrame to create a north pane for.
1430 * @return The north pane.
1432 protected JComponent createNorthPane(JInternalFrame w)
1434 titlePane = new BasicInternalFrameTitlePane(w);
1435 return titlePane;
1439 * This method creates the west pane used in the JInternalFrame.
1441 * @param w The JInternalFrame to create a west pane for.
1443 * @return The west pane.
1445 protected JComponent createWestPane(JInternalFrame w)
1447 return null;
1451 * This method creates the south pane used in the JInternalFrame.
1453 * @param w The JInternalFrame to create a south pane for.
1455 * @return The south pane.
1457 protected JComponent createSouthPane(JInternalFrame w)
1459 return null;
1463 * This method creates the east pane used in the JInternalFrame.
1465 * @param w The JInternalFrame to create an east pane for.
1467 * @return The east pane.
1469 protected JComponent createEastPane(JInternalFrame w)
1471 return null;
1475 * This method returns a new BorderListener for the given JInternalFrame.
1477 * @param w The JIntenalFrame to create a BorderListener for.
1479 * @return A new BorderListener.
1481 protected MouseInputAdapter createBorderListener(JInternalFrame w)
1483 return new BorderListener();
1487 * This method creates a new InternalFrameListener for the JInternalFrame.
1489 protected void createInternalFrameListener()
1491 internalFrameListener = new BasicInternalFrameListener();
1495 * DOCUMENT ME!
1497 * @return DOCUMENT ME!
1499 protected final boolean isKeyBindingRegistered()
1501 // FIXME: Implement.
1502 return false;
1506 * DOCUMENT ME!
1508 * @param b DOCUMENT ME!
1510 protected final void setKeyBindingRegistered(boolean b)
1512 // FIXME: Implement.
1516 * DOCUMENT ME!
1518 * @return DOCUMENT ME!
1520 public final boolean isKeyBindingActive()
1522 // FIXME: Implement.
1523 return false;
1527 * DOCUMENT ME!
1529 * @param b DOCUMENT ME!
1531 protected final void setKeyBindingActive(boolean b)
1533 // FIXME: Implement.
1537 * DOCUMENT ME!
1539 protected void setupMenuOpenKey()
1541 // FIXME: Implement.
1545 * DOCUMENT ME!
1547 protected void setupMenuCloseKey()
1549 // FIXME: Implement.
1553 * This method returns the north pane.
1555 * @return The north pane.
1557 public JComponent getNorthPane()
1559 return northPane;
1563 * This method sets the north pane to be the given JComponent.
1565 * @param c The new north pane.
1567 public void setNorthPane(JComponent c)
1569 replacePane(northPane, c);
1570 northPane = c;
1574 * This method returns the south pane.
1576 * @return The south pane.
1578 public JComponent getSouthPane()
1580 return southPane;
1584 * This method sets the south pane to be the given JComponent.
1586 * @param c The new south pane.
1588 public void setSouthPane(JComponent c)
1590 replacePane(southPane, c);
1591 southPane = c;
1595 * This method sets the east pane to be the given JComponent.
1597 * @param c The new east pane.
1599 public void setEastPane(JComponent c)
1601 replacePane(eastPane, c);
1602 eastPane = c;
1606 * This method returns the east pane.
1608 * @return The east pane.
1610 public JComponent getEastPane()
1612 return eastPane;
1616 * This method sets the west pane to be the given JComponent.
1618 * @param c The new west pane.
1620 public void setWestPane(JComponent c)
1622 replacePane(westPane, c);
1623 westPane = c;
1627 * This method returns the west pane.
1629 * @return The west pane.
1631 public JComponent getWestPane()
1633 return westPane;
1637 * This method returns the DesktopManager to use with the JInternalFrame.
1639 * @return The DesktopManager to use with the JInternalFrame.
1641 protected DesktopManager getDesktopManager()
1643 DesktopManager value = null;
1644 JDesktopPane pane = frame.getDesktopPane();
1645 if (pane != null)
1646 value = frame.getDesktopPane().getDesktopManager();
1647 if (value == null)
1648 value = createDesktopManager();
1649 return value;
1653 * This method returns a default DesktopManager that can be used with this
1654 * JInternalFrame.
1656 * @return A default DesktopManager that can be used with this
1657 * JInternalFrame.
1659 protected DesktopManager createDesktopManager()
1661 return new DefaultDesktopManager();
1665 * This is a convenience method that closes the JInternalFrame.
1667 * @param f The JInternalFrame to close.
1669 protected void closeFrame(JInternalFrame f)
1671 getDesktopManager().closeFrame(f);
1675 * This is a convenience method that maximizes the JInternalFrame.
1677 * @param f The JInternalFrame to maximize.
1679 protected void maximizeFrame(JInternalFrame f)
1681 getDesktopManager().maximizeFrame(f);
1685 * This is a convenience method that minimizes the JInternalFrame.
1687 * @param f The JInternalFrame to minimize.
1689 protected void minimizeFrame(JInternalFrame f)
1691 getDesktopManager().minimizeFrame(f);
1695 * This is a convenience method that iconifies the JInternalFrame.
1697 * @param f The JInternalFrame to iconify.
1699 protected void iconifyFrame(JInternalFrame f)
1701 getDesktopManager().iconifyFrame(f);
1705 * This is a convenience method that deiconifies the JInternalFrame.
1707 * @param f The JInternalFrame to deiconify.
1709 protected void deiconifyFrame(JInternalFrame f)
1711 getDesktopManager().deiconifyFrame(f);
1715 * This is a convenience method that activates the JInternalFrame.
1717 * @param f The JInternalFrame to activate.
1719 protected void activateFrame(JInternalFrame f)
1721 getDesktopManager().activateFrame(f);
1725 * This is a convenience method that deactivates the JInternalFrame.
1727 * @param f the JInternalFrame to deactivate
1729 protected void deactivateFrame(JInternalFrame f)
1731 getDesktopManager().deactivateFrame(f);
1735 * This method returns a new ComponentListener for the JDesktopPane.
1737 * @return A new ComponentListener.
1739 protected ComponentListener createComponentListener()
1741 return new ComponentHandler();
1745 * This method returns a new GlassPaneDispatcher.
1747 * @return A new GlassPaneDispatcher.
1749 protected MouseInputListener createGlassPaneDispatcher()
1751 return new GlassPaneDispatcher();