001    /* BasicInternalFrameUI.java --
002       Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.plaf.basic;
040    
041    import java.awt.Color;
042    import java.awt.Component;
043    import java.awt.Container;
044    import java.awt.Cursor;
045    import java.awt.Dimension;
046    import java.awt.Graphics;
047    import java.awt.Insets;
048    import java.awt.LayoutManager;
049    import java.awt.LayoutManager2;
050    import java.awt.Point;
051    import java.awt.Rectangle;
052    import java.awt.event.ActionEvent;
053    import java.awt.event.ComponentEvent;
054    import java.awt.event.ComponentListener;
055    import java.awt.event.MouseEvent;
056    import java.beans.PropertyChangeEvent;
057    import java.beans.PropertyChangeListener;
058    import java.beans.PropertyVetoException;
059    
060    import javax.swing.AbstractAction;
061    import javax.swing.ActionMap;
062    import javax.swing.DefaultDesktopManager;
063    import javax.swing.DesktopManager;
064    import javax.swing.JComponent;
065    import javax.swing.JDesktopPane;
066    import javax.swing.JInternalFrame;
067    import javax.swing.KeyStroke;
068    import javax.swing.LookAndFeel;
069    import javax.swing.SwingConstants;
070    import javax.swing.SwingUtilities;
071    import javax.swing.UIManager;
072    import javax.swing.border.AbstractBorder;
073    import javax.swing.event.InternalFrameEvent;
074    import javax.swing.event.InternalFrameListener;
075    import javax.swing.event.MouseInputAdapter;
076    import javax.swing.event.MouseInputListener;
077    import javax.swing.plaf.ActionMapUIResource;
078    import javax.swing.plaf.ComponentUI;
079    import javax.swing.plaf.InternalFrameUI;
080    import javax.swing.plaf.UIResource;
081    
082    /**
083     * This is the UI delegate for the Basic look and feel for JInternalFrames.
084     */
085    public class BasicInternalFrameUI extends InternalFrameUI
086    {
087      /**
088       * This is a helper class that listens to the JInternalFrame for
089       * InternalFrameEvents.
090       */
091      protected class BasicInternalFrameListener implements InternalFrameListener
092      {
093        /**
094         * This method is called when the JInternalFrame is activated.
095         *
096         * @param e The InternalFrameEvent.
097         */
098        public void internalFrameActivated(InternalFrameEvent e)
099        {
100          frame.getGlassPane().setVisible(false);
101        }
102    
103        /**
104         * This method is called when the JInternalFrame is closed.
105         *
106         * @param e The InternalFrameEvent.
107         */
108        public void internalFrameClosed(InternalFrameEvent e)
109        {
110          // FIXME: Implement.
111        }
112    
113        /**
114         * This method is called when the JInternalFrame is closing.
115         *
116         * @param e The InternalFrameEvent.
117         */
118        public void internalFrameClosing(InternalFrameEvent e)
119        {
120          // FIXME: Implement.
121        }
122    
123        /**
124         * This method is called when the JInternalFrame is deactivated.
125         *
126         * @param e The InternalFrameEvent.
127         */
128        public void internalFrameDeactivated(InternalFrameEvent e)
129        {
130          frame.getGlassPane().setVisible(true);
131        }
132    
133        /**
134         * This method is called when the JInternalFrame is  deiconified.
135         *
136         * @param e The InternalFrameEvent.
137         */
138        public void internalFrameDeiconified(InternalFrameEvent e)
139        {
140          // FIXME: Implement.
141        }
142    
143        /**
144         * This method is called when the JInternalFrame is  iconified.
145         *
146         * @param e The InternalFrameEvent.
147         */
148        public void internalFrameIconified(InternalFrameEvent e)
149        {
150          // FIXME: Implement.
151        }
152    
153        /**
154         * This method is called when the JInternalFrame is opened.
155         *
156         * @param e The InternalFrameEvent.
157         */
158        public void internalFrameOpened(InternalFrameEvent e)
159        {
160          // FIXME: Implement.
161        }
162      }
163    
164      /**
165       * This helper class listens to the edges of the JInternalFrame and the
166       * TitlePane for mouse events. It is responsible for dragging  and resizing
167       * the JInternalFrame in response to the MouseEvents.
168       */
169      protected class BorderListener extends MouseInputAdapter
170        implements SwingConstants
171      {
172        /**
173         * The current shape of the cursor.
174         */
175        transient int showingCursor;
176    
177        /** FIXME: Use for something. */
178        protected final int RESIZE_NONE = 0;
179    
180        /** The x offset from the top left corner of the JInternalFrame. */
181        private transient int xOffset;
182    
183        /** The y offset from the top left corner of the JInternalFrame. */
184        private transient int yOffset;
185    
186        /** The direction that the resize is occuring in. */
187        private transient int direction = -1;
188    
189        /** Cache rectangle that can be reused. */
190        private transient Rectangle cacheRect = new Rectangle();
191    
192        /**
193         * This method is called when the mouse is clicked.
194         *
195         * @param e The MouseEvent.
196         */
197        public void mouseClicked(MouseEvent e)
198        {
199          // Do minimization/maximization when double-clicking in the title pane.
200          if (e.getSource() == titlePane && e.getClickCount() == 2)
201            try
202              {
203                if (frame.isMaximizable() && ! frame.isMaximum())
204                  frame.setMaximum(true);
205                else if (frame.isMaximum())
206                  frame.setMaximum(false);
207              }
208            catch (PropertyVetoException pve)
209              {
210                // We do nothing if the attempt has been vetoed.
211              }
212    
213          // There is nothing to do when the mouse is clicked
214          // on the border.
215        }
216    
217        /**
218         * This method is called when the mouse is dragged. This method is
219         * responsible for resizing or dragging the JInternalFrame.
220         *
221         * @param e The MouseEvent.
222         */
223        public void mouseDragged(MouseEvent e)
224        {
225          // If the frame is maximized, there is nothing that
226          // can be dragged around.
227          if (frame.isMaximum())
228            return;
229          DesktopManager dm = getDesktopManager();
230          Rectangle b = frame.getBounds();
231          Dimension min = frame.getMinimumSize();
232          if (min == null)
233            min = new Dimension(0, 0);
234          Insets insets = frame.getInsets();
235          int x = e.getX();
236          int y = e.getY();
237          if (e.getSource() == frame && frame.isResizable())
238            {
239              switch (direction)
240                {
241                case Cursor.N_RESIZE_CURSOR:
242                  cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
243                                                             - min.height),
244                                      b.width, b.height - y);
245                  break;
246                case Cursor.NE_RESIZE_CURSOR:
247                  cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
248                                                             - min.height), x + 1,
249                                      b.height - y);
250                  break;
251                case Cursor.E_RESIZE_CURSOR:
252                  cacheRect.setBounds(b.x, b.y, x + 1, b.height);
253                  break;
254                case Cursor.SE_RESIZE_CURSOR:
255                  cacheRect.setBounds(b.x, b.y, x + 1, y + 1);
256                  break;
257                case Cursor.S_RESIZE_CURSOR:
258                  cacheRect.setBounds(b.x, b.y, b.width, y + 1);
259                  break;
260                case Cursor.SW_RESIZE_CURSOR:
261                  cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
262                                      b.y, b.width - x, y + 1);
263                  break;
264                case Cursor.W_RESIZE_CURSOR:
265                  cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
266                                      b.y, b.width - x, b.height);
267                  break;
268                case Cursor.NW_RESIZE_CURSOR:
269                  cacheRect.setBounds(
270                                      Math.min(b.x + x, b.x + b.width - min.width),
271                                      Math.min(b.y + y, b.y + b.height - min.height),
272                                      b.width - x, b.height - y);
273                  break;
274                }
275              dm.resizeFrame(frame, cacheRect.x, cacheRect.y,
276                             Math.max(min.width, cacheRect.width),
277                             Math.max(min.height, cacheRect.height));
278              setCursor(e);
279            }
280          else if (e.getSource() == titlePane)
281            {
282              Rectangle fBounds = frame.getBounds();
283              frame.putClientProperty("bufferedDragging", Boolean.TRUE);
284              dm.dragFrame(frame, e.getX() - xOffset + b.x, e.getY() - yOffset
285                                                            + b.y);
286            }
287        }
288    
289        /**
290         * This method is called when the mouse exits the JInternalFrame.
291         *
292         * @param e The MouseEvent.
293         */
294        public void mouseExited(MouseEvent e)
295        {
296          if (showingCursor != Cursor.DEFAULT_CURSOR)
297            {
298              frame.setCursor(Cursor.getDefaultCursor());
299              showingCursor = Cursor.DEFAULT_CURSOR;
300            }
301        }
302    
303        /**
304         * This method is called when the mouse is moved inside the JInternalFrame.
305         *
306         * @param e The MouseEvent.
307         */
308        public void mouseMoved(MouseEvent e)
309        {
310          // Turn off the resize cursor if we are in the frame header.
311          if (showingCursor != Cursor.DEFAULT_CURSOR && e.getSource() != frame)
312            {
313              frame.setCursor(Cursor.getDefaultCursor());
314              showingCursor = Cursor.DEFAULT_CURSOR;
315            }
316          else if (e.getSource() == frame && frame.isResizable())
317            {
318              setCursor(e);
319            }
320        }
321    
322        /**
323         * Set the mouse cursor, how applicable.
324         *
325         * @param e the current mouse event.
326         */
327        void setCursor(MouseEvent e)
328        {
329          int cursor = sectionOfClick(e.getX(), e.getY());
330          if (cursor != showingCursor)
331            {
332              Cursor resize = Cursor.getPredefinedCursor(cursor);
333              frame.setCursor(resize);
334              showingCursor = cursor;
335            }
336        }
337    
338        /**
339         * This method is called when the mouse is pressed.
340         *
341         * @param e The MouseEvent.
342         */
343        public void mousePressed(MouseEvent e)
344        {
345          activateFrame(frame);
346          DesktopManager dm = getDesktopManager();
347          int x = e.getX();
348          int y = e.getY();
349          Insets insets = frame.getInsets();
350    
351          if (e.getSource() == frame && frame.isResizable())
352            {
353              direction = sectionOfClick(x, y);
354              dm.beginResizingFrame(frame, direction);
355            }
356          else if (e.getSource() == titlePane)
357            {
358              Rectangle tBounds = titlePane.getBounds();
359    
360              xOffset = e.getX() - tBounds.x + insets.left;
361              yOffset = e.getY() - tBounds.y + insets.top;
362    
363              dm.beginDraggingFrame(frame);
364            }
365        }
366    
367        /**
368         * This method is called when the mouse is released.
369         *
370         * @param e The MouseEvent.
371         */
372        public void mouseReleased(MouseEvent e)
373        {
374          DesktopManager dm = getDesktopManager();
375          xOffset = 0;
376          yOffset = 0;
377          if (e.getSource() == frame && frame.isResizable())
378            dm.endResizingFrame(frame);
379          else if (e.getSource() == titlePane)
380            {
381              dm.endDraggingFrame(frame);
382              frame.putClientProperty("bufferedDragging", null);
383            }
384    
385          setCursor(e);
386        }
387    
388        /**
389         * This method determines the direction of the resize based on the
390         * coordinates and the size of the JInternalFrame.
391         *
392         * @param x The x coordinate of the MouseEvent.
393         * @param y The y coordinate of the MouseEvent.
394         *
395         * @return The cursor constant, determining the resizing direction.
396         */
397        private int sectionOfClick(int x, int y)
398        {
399          Rectangle b = frame.getBounds();
400          int corner = InternalFrameBorder.cornerSize;
401    
402          if (x < corner && y < corner)
403            return Cursor.NW_RESIZE_CURSOR;
404          else if (x > b.width - corner && y < corner)
405            return Cursor.NE_RESIZE_CURSOR;
406          else if (x > b.width - corner && y > b.height - corner)
407            return Cursor.SE_RESIZE_CURSOR;
408          else if (x < corner && y > b.height - corner)
409            return Cursor.SW_RESIZE_CURSOR;
410          else if (y < corner)
411            return Cursor.N_RESIZE_CURSOR;
412          else if (x < corner)
413            return Cursor.W_RESIZE_CURSOR;
414          else if (y > b.height - corner)
415            return Cursor.S_RESIZE_CURSOR;
416          else if (x > b.width - corner)
417            return Cursor.E_RESIZE_CURSOR;
418    
419          return Cursor.DEFAULT_CURSOR;
420        }
421      }
422    
423      /**
424       * This helper class listens to the JDesktopPane that parents this
425       * JInternalFrame and listens for resize events and resizes the
426       * JInternalFrame appropriately.
427       */
428      protected class ComponentHandler implements ComponentListener
429      {
430        /**
431         * This method is called when the JDesktopPane is hidden.
432         *
433         * @param e
434         *          The ComponentEvent fired.
435         */
436        public void componentHidden(ComponentEvent e)
437        {
438          // Do nothing.
439        }
440    
441        /**
442         * This method is called when the JDesktopPane is moved.
443         *
444         * @param e
445         *          The ComponentEvent fired.
446         */
447        public void componentMoved(ComponentEvent e)
448        {
449          // Do nothing.
450        }
451    
452        /**
453         * This method is called when the JDesktopPane is resized.
454         *
455         * @param e
456         *          The ComponentEvent fired.
457         */
458        public void componentResized(ComponentEvent e)
459        {
460          if (frame.isMaximum())
461            {
462              Container parent = frame.getParent();
463              Insets i = parent.getInsets();
464              int width = parent.getWidth() - i.left - i.right;
465              int height = parent.getHeight() - i.top - i.bottom;
466              frame.setBounds(0, 0, width, height);
467            }
468        }
469    
470        /**
471         * This method is called when the JDesktopPane is shown.
472         *
473         * @param e
474         *          The ComponentEvent fired.
475         */
476        public void componentShown(ComponentEvent e)
477        {
478          // Do nothing.
479        }
480      }
481    
482      /**
483       * This helper class acts as the LayoutManager for JInternalFrames.
484       */
485      public class InternalFrameLayout implements LayoutManager
486      {
487        /**
488         * This method is called when the given Component is added to the
489         * JInternalFrame.
490         *
491         * @param name
492         *          The name of the Component.
493         * @param c
494         *          The Component added.
495         */
496        public void addLayoutComponent(String name, Component c)
497        {
498          // Nothing to do here.
499        }
500    
501        /**
502         * This method is used to set the bounds of the children of the
503         * JInternalFrame.
504         *
505         * @param c
506         *          The Container to lay out.
507         */
508        public void layoutContainer(Container c)
509        {
510          Dimension dims = frame.getSize();
511          Insets insets = frame.getInsets();
512    
513          dims.width -= insets.left + insets.right;
514          dims.height -= insets.top + insets.bottom;
515    
516          int nh = 0;
517          int sh = 0;
518          int ew = 0;
519          int ww = 0;
520    
521          if (northPane != null)
522            {
523              Dimension nDims = northPane.getPreferredSize();
524              nh = Math.min(nDims.height, dims.height);
525    
526              northPane.setBounds(insets.left, insets.top, dims.width, nh);
527            }
528    
529          if (southPane != null)
530            {
531              Dimension sDims = southPane.getPreferredSize();
532              sh = Math.min(sDims.height, dims.height - nh);
533    
534              southPane.setBounds(insets.left, insets.top + dims.height - sh,
535                                  dims.width, sh);
536            }
537    
538          int remHeight = dims.height - sh - nh;
539    
540          if (westPane != null)
541            {
542              Dimension wDims = westPane.getPreferredSize();
543              ww = Math.min(dims.width, wDims.width);
544    
545              westPane.setBounds(insets.left, insets.top + nh, ww, remHeight);
546            }
547    
548          if (eastPane != null)
549            {
550              Dimension eDims = eastPane.getPreferredSize();
551              ew = Math.min(eDims.width, dims.width - ww);
552    
553              eastPane.setBounds(insets.left + dims.width - ew, insets.top + nh,
554                                 ew, remHeight);
555            }
556    
557          int remWidth = dims.width - ww - ew;
558    
559          frame.getRootPane().setBounds(insets.left + ww, insets.top + nh,
560                                        remWidth, remHeight);
561        }
562    
563        /**
564         * This method returns the minimum layout size.
565         *
566         * @param c
567         *          The Container to find a minimum layout size for.
568         * @return The minimum dimensions for the JInternalFrame.
569         */
570        public Dimension minimumLayoutSize(Container c)
571        {
572          return getSize(c, true);
573        }
574    
575        /**
576         * Th8is method returns the preferred layout size.
577         *
578         * @param c
579         *          The Container to find a preferred layout size for.
580         * @return The preferred dimensions for the JInternalFrame.
581         */
582        public Dimension preferredLayoutSize(Container c)
583        {
584          return getSize(c, false);
585        }
586    
587        /**
588         * DOCUMENT ME!
589         *
590         * @param c
591         *          DOCUMENT ME!
592         * @param min
593         *          DOCUMENT ME!
594         * @return DOCUMENT ME!
595         */
596        private Dimension getSize(Container c, boolean min)
597        {
598          Insets insets = frame.getInsets();
599    
600          Dimension contentDims = frame.getContentPane().getPreferredSize();
601          if (min)
602            contentDims.width = contentDims.height = 0;
603          int nWidth = 0;
604          int nHeight = 0;
605          int sWidth = 0;
606          int sHeight = 0;
607          int eWidth = 0;
608          int eHeight = 0;
609          int wWidth = 0;
610          int wHeight = 0;
611          Dimension dims;
612    
613          if (northPane != null)
614            {
615              dims = northPane.getPreferredSize();
616              if (dims != null)
617                {
618                  nWidth = dims.width;
619                  nHeight = dims.height;
620                }
621            }
622    
623          if (southPane != null)
624            {
625              dims = southPane.getPreferredSize();
626              if (dims != null)
627                {
628                  sWidth = dims.width;
629                  sHeight = dims.height;
630                }
631            }
632    
633          if (eastPane != null)
634            {
635              dims = eastPane.getPreferredSize();
636              if (dims != null)
637                {
638                  sWidth = dims.width;
639                  sHeight = dims.height;
640                }
641            }
642    
643          if (westPane != null)
644            {
645              dims = westPane.getPreferredSize();
646              if (dims != null)
647                {
648                  wWidth = dims.width;
649                  wHeight = dims.height;
650                }
651            }
652    
653          int width = Math.max(sWidth, nWidth);
654          width = Math.max(width, contentDims.width + eWidth + wWidth);
655    
656          int height = Math.max(eHeight, wHeight);
657          height = Math.max(height, contentDims.height);
658          height += nHeight + sHeight;
659    
660          width += insets.left + insets.right;
661          height += insets.top + insets.bottom;
662    
663          return new Dimension(width, height);
664        }
665    
666        /**
667         * This method is called when a Component is removed from the
668         * JInternalFrame.
669         *
670         * @param c The Component that was removed.
671         */
672        public void removeLayoutComponent(Component c)
673        {
674          // Nothing to do here.
675        }
676      }
677    
678      /**
679       * This helper class is used to listen to the JDesktopPane's glassPane for
680       * MouseEvents. The JInternalFrame can then be selected if a click is
681       * detected on its children.
682       */
683      protected class GlassPaneDispatcher implements MouseInputListener
684      {
685        /** The MouseEvent target. */
686        private transient Component mouseEventTarget;
687    
688        private Component dragTarget;
689    
690        /**
691         * Indicates if we are currently in a dragging operation or not.
692         */
693        private boolean isDragging;
694    
695        /**
696         * This method is called when the mouse enters the glass pane.
697         *
698         * @param e
699         *          The MouseEvent.
700         */
701        public void mouseEntered(MouseEvent e)
702        {
703          handleEvent(e);
704        }
705    
706        /**
707         * This method is called when the mouse is clicked on the glass pane.
708         *
709         * @param e
710         *          The MouseEvent.
711         */
712        public void mouseClicked(MouseEvent e)
713        {
714          handleEvent(e);
715        }
716    
717        /**
718         * This method is called when the mouse is dragged in the glass pane.
719         *
720         * @param e
721         *          The MouseEvent.
722         */
723        public void mouseDragged(MouseEvent e)
724        {
725          handleEvent(e);
726        }
727    
728        /**
729         * This method is called when the mouse exits the glass pane.
730         *
731         * @param e
732         *          The MouseEvent.
733         */
734        public void mouseExited(MouseEvent e)
735        {
736          handleEvent(e);
737        }
738    
739        /**
740         * This method is called when the mouse is moved in the glass pane.
741         *
742         * @param e
743         *          The MouseEvent.
744         */
745        public void mouseMoved(MouseEvent e)
746        {
747          handleEvent(e);
748        }
749    
750        /**
751         * This method is called when the mouse is pressed in the glass pane.
752         *
753         * @param e
754         *          The MouseEvent.
755         */
756        public void mousePressed(MouseEvent e)
757        {
758          // Experiments show that this seems to call the
759          // borderListener.mousePressed() method to activate the frame.
760          if (borderListener != null)
761            borderListener.mousePressed(e);
762          handleEvent(e);
763        }
764    
765        /**
766         * This method is called when the mouse is released in the glass pane.
767         *
768         * @param e
769         *          The MouseEvent.
770         */
771        public void mouseReleased(MouseEvent e)
772        {
773          handleEvent(e);
774        }
775    
776        /**
777         * This is a helper method that dispatches the GlassPane MouseEvents to the
778         * proper component.
779         *
780         * @param e the mouse event to be dispatched
781         */
782        private void handleEvent(MouseEvent e)
783        {
784          // Find candidate component inside the JInternalFrame.
785          Component target = frame.getLayeredPane().findComponentAt(e.getX(),
786                                                                    e.getY());
787    
788          // Now search upwards to find a component that actually has
789          // a MouseListener attached.
790          while (target != null
791                 && target.getMouseListeners().length == 0
792                 && target.getMouseMotionListeners().length == 0
793                 && target.getMouseWheelListeners().length == 0)
794            {
795              target = target.getParent();
796            }
797    
798          if (target != null)
799            {
800              int id = e.getID();
801              switch (id)
802              {
803                case MouseEvent.MOUSE_ENTERED:
804                  // Now redispatch the thing.
805                  if (! isDragging || frame.isSelected())
806                    {
807                      mouseEventTarget = target;
808                      redispatch(id, e, mouseEventTarget);
809                    }
810                  break;
811                case MouseEvent.MOUSE_EXITED:
812                  if (! isDragging || frame.isSelected())
813                    {
814                      redispatch(id, e, mouseEventTarget);
815                    }
816                  break;
817                case MouseEvent.MOUSE_PRESSED:
818                  mouseEventTarget = target;
819                  redispatch(id, e, mouseEventTarget);
820                  // Start dragging.
821                  dragTarget = target;
822                  break;
823                case MouseEvent.MOUSE_RELEASED:
824                  if (isDragging)
825                    {
826                      redispatch(id, e, dragTarget);
827                      isDragging = false;
828                    }
829                  else
830                    redispatch(id, e, mouseEventTarget);
831                  break;
832                case MouseEvent.MOUSE_CLICKED:
833                  redispatch(id, e, mouseEventTarget);
834                  break;
835                case MouseEvent.MOUSE_MOVED:
836                  if (target != mouseEventTarget)
837                    {
838                      // Create additional MOUSE_EXITED/MOUSE_ENTERED pairs.
839                      redispatch(MouseEvent.MOUSE_EXITED, e, mouseEventTarget);
840                      mouseEventTarget = target;
841                      redispatch(MouseEvent.MOUSE_ENTERED, e, mouseEventTarget);
842                    }
843                  redispatch(id, e, mouseEventTarget);
844                  break;
845                case MouseEvent.MOUSE_DRAGGED:
846                  if (! isDragging)
847                    isDragging = true;
848                  redispatch(id, e, mouseEventTarget);
849                  break;
850                case MouseEvent.MOUSE_WHEEL:
851                  redispatch(id, e, mouseEventTarget);
852                  break;
853                default:
854                  assert false : "Must not reach here";
855              }
856            }
857        }
858    
859        /**
860         * Redispatches the event to the real target with the specified id.
861         *
862         * @param id the new event ID
863         * @param e the original event
864         * @param target the real event target
865         */
866        private void redispatch(int id, MouseEvent e, Component target)
867        {
868          Point p = SwingUtilities.convertPoint(frame.getLayeredPane(), e.getX(),
869                                                e.getY(), target);
870          MouseEvent ev = new MouseEvent(target, id, e.getWhen(),
871                                         e.getModifiers() | e.getModifiersEx(),
872                                         p.x, p.y, e.getClickCount(),
873                                         e.isPopupTrigger());
874          target.dispatchEvent(ev);
875        }
876      }
877    
878      /**
879       * This helper class listens for PropertyChangeEvents from the
880       * JInternalFrame.
881       */
882      public class InternalFramePropertyChangeListener
883        implements PropertyChangeListener
884      {
885    
886        /**
887         * This method is called when one of the JInternalFrame's properties change.
888         *
889         * @param evt
890         *          The PropertyChangeEvent.
891         */
892        public void propertyChange(PropertyChangeEvent evt)
893        {
894          String property = evt.getPropertyName();
895          if (property.equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
896            {
897              if (frame.isMaximum())
898                maximizeFrame(frame);
899              else
900                minimizeFrame(frame);
901            }
902          else if (property.equals(JInternalFrame.IS_ICON_PROPERTY))
903            {
904              if (frame.isIcon())
905                iconifyFrame(frame);
906              else
907                deiconifyFrame(frame);
908            }
909          else if (property.equals(JInternalFrame.IS_SELECTED_PROPERTY))
910            {
911              Component glassPane = frame.getGlassPane();
912              if (frame.isSelected())
913                {
914                  activateFrame(frame);
915                  glassPane.setVisible(false);
916                }
917              else
918                {
919                  deactivateFrame(frame);
920                  glassPane.setVisible(true);
921                }
922            }
923          else if (property.equals(JInternalFrame.ROOT_PANE_PROPERTY)
924                   || property.equals(JInternalFrame.GLASS_PANE_PROPERTY))
925            {
926              Component old = (Component) evt.getOldValue();
927              if (old != null)
928                {
929                  old.removeMouseListener(glassPaneDispatcher);
930                  old.removeMouseMotionListener(glassPaneDispatcher);
931                }
932    
933              Component newPane = (Component) evt.getNewValue();
934              if (newPane != null)
935                {
936                  newPane.addMouseListener(glassPaneDispatcher);
937                  newPane.addMouseMotionListener(glassPaneDispatcher);
938                }
939    
940              frame.revalidate();
941            }
942          else if (property.equals(JInternalFrame.IS_CLOSED_PROPERTY))
943            {
944              if (evt.getNewValue() == Boolean.TRUE)
945                {
946                  Container parent = frame.getParent();
947                  if (parent != null)
948                    parent.removeComponentListener(componentListener);
949                  closeFrame(frame);
950                }
951            }
952          else if (property.equals("ancestor"))
953            {
954              Container newParent = (Container) evt.getNewValue();
955              Container oldParent = (Container) evt.getOldValue();
956              if (newParent != null)
957                {
958                  newParent.addComponentListener(componentListener);
959                }
960              else if (oldParent != null)
961                {
962                  oldParent.removeComponentListener(componentListener);
963                }
964            }
965        }
966      }
967    
968      /**
969       * This helper class is the border for the JInternalFrame.
970       */
971      class InternalFrameBorder extends AbstractBorder implements
972          UIResource
973      {
974        /**
975         * The width of the border.
976         */
977        static final int bSize = 5;
978    
979        /**
980         * The size of the corners (also used by the mouse listener).
981         */
982        static final int cornerSize = 10;
983    
984        /**
985         * This method returns whether the border is opaque.
986         *
987         * @return Whether the border is opaque.
988         */
989        public boolean isBorderOpaque()
990        {
991          return true;
992        }
993    
994        /**
995         * This method returns the insets of the border.
996         *
997         * @param c
998         *          The Component to find border insets for.
999         * @return The border insets.
1000         */
1001        public Insets getBorderInsets(Component c)
1002        {
1003          return new Insets(bSize, bSize, bSize, bSize);
1004        }
1005    
1006        /**
1007         * This method paints the border.
1008         *
1009         * @param c
1010         *          The Component that owns the border.
1011         * @param g
1012         *          The Graphics object to paint with.
1013         * @param x
1014         *          The x coordinate to paint at.
1015         * @param y
1016         *          The y coordinate to paint at.
1017         * @param width
1018         *          The width of the Component.
1019         * @param height
1020         *          The height of the Component.
1021         */
1022        public void paintBorder(Component c, Graphics g, int x, int y, int width,
1023                                int height)
1024        {
1025          g.translate(x, y);
1026          Color saved = g.getColor();
1027          Rectangle b = frame.getBounds();
1028    
1029          Color d = c.getBackground();
1030          g.setColor(d);
1031          g.fillRect(0, 0, bSize, b.height);
1032          g.fillRect(0, 0, b.width, bSize);
1033          g.fillRect(0, b.height - bSize, b.width, bSize);
1034          g.fillRect(b.width - bSize, 0, bSize, b.height);
1035    
1036          int x1 = 0;
1037          int x2 = bSize;
1038          int x3 = b.width - bSize;
1039          int x4 = b.width;
1040    
1041          int y1 = 0;
1042          int y2 = bSize;
1043          int y3 = b.height - bSize;
1044          int y4 = b.height;
1045    
1046          g.setColor(Color.GRAY);
1047          g.fillRect(0, 0, bSize, y4);
1048          g.fillRect(0, 0, x4, bSize);
1049          g.fillRect(0, y3, b.width, bSize);
1050          g.fillRect(x3, 0, bSize, b.height);
1051    
1052          g.fill3DRect(0, cornerSize, bSize, b.height - 2 * cornerSize, false);
1053          g.fill3DRect(cornerSize, 0, b.width - 2 * cornerSize, bSize, false);
1054          g.fill3DRect(cornerSize, b.height - bSize, b.width - 2 * cornerSize,
1055                       bSize, false);
1056          g.fill3DRect(b.width - bSize, cornerSize, bSize,
1057                       b.height - 2 * cornerSize, false);
1058    
1059          g.translate(-x, -y);
1060          g.setColor(saved);
1061        }
1062      }
1063    
1064      /**
1065       * This action triggers the system menu.
1066       *
1067       * @author Roman Kennke (kennke@aicas.com)
1068       */
1069      private class ShowSystemMenuAction
1070        extends AbstractAction
1071      {
1072        public void actionPerformed(ActionEvent e)
1073        {
1074          if (titlePane != null)
1075            {
1076              titlePane.showSystemMenu();
1077            }
1078        }
1079      }
1080    
1081      /**
1082       * The MouseListener that is responsible for dragging and resizing the
1083       * JInternalFrame in response to MouseEvents.
1084       */
1085      protected MouseInputAdapter borderListener;
1086    
1087      /**
1088       * The ComponentListener that is responsible for resizing the JInternalFrame
1089       * in response to ComponentEvents from the JDesktopPane.
1090       */
1091      protected ComponentListener componentListener;
1092    
1093      /**
1094       * The MouseListener that is responsible for activating the JInternalFrame
1095       * when the mouse press activates one of its descendents.
1096       */
1097      protected MouseInputListener glassPaneDispatcher;
1098    
1099      /**
1100       * The PropertyChangeListener that is responsible for listening to
1101       * PropertyChangeEvents from the JInternalFrame.
1102       */
1103      protected PropertyChangeListener propertyChangeListener;
1104    
1105      /** The InternalFrameListener that listens to the JInternalFrame. */
1106      private transient BasicInternalFrameListener internalFrameListener;
1107    
1108      /** The JComponent placed at the east region of the JInternalFrame. */
1109      protected JComponent eastPane;
1110    
1111      /** The JComponent placed at the north region of the JInternalFrame. */
1112      protected JComponent northPane;
1113    
1114      /** The JComponent placed at the south region of the JInternalFrame. */
1115      protected JComponent southPane;
1116    
1117      /** The JComponent placed at the west region of the JInternalFrame. */
1118      protected JComponent westPane;
1119    
1120      /**
1121       * The Keystroke bound to open the menu.
1122       * @deprecated
1123       */
1124      protected KeyStroke openMenuKey;
1125    
1126      /** The TitlePane displayed at the top of the JInternalFrame. */
1127      protected BasicInternalFrameTitlePane titlePane;
1128    
1129      /** The JInternalFrame this UI is responsible for. */
1130      protected JInternalFrame frame;
1131    
1132      /** The LayoutManager used in the JInternalFrame. */
1133      protected LayoutManager internalFrameLayout;
1134    
1135      /** The JDesktopPane that is the parent of the JInternalFrame. */
1136      private transient JDesktopPane desktopPane;
1137    
1138      /**
1139       * Creates a new BasicInternalFrameUI object.
1140       *
1141       * @param b The JInternalFrame this UI will represent.
1142       */
1143      public BasicInternalFrameUI(JInternalFrame b)
1144      {
1145        // Nothing to do here.
1146      }
1147    
1148      /**
1149       * This method will create a new BasicInternalFrameUI for the given
1150       * JComponent.
1151       *
1152       * @param b The JComponent to create a BasicInternalFrameUI for.
1153       *
1154       * @return A new BasicInternalFrameUI.
1155       */
1156      public static ComponentUI createUI(JComponent b)
1157      {
1158        return new BasicInternalFrameUI((JInternalFrame) b);
1159      }
1160    
1161      /**
1162       * This method installs a UI for the JInternalFrame.
1163       *
1164       * @param c The JComponent to install this UI on.
1165       */
1166      public void installUI(JComponent c)
1167      {
1168        if (c instanceof JInternalFrame)
1169          {
1170            frame = (JInternalFrame) c;
1171    
1172            installDefaults();
1173            installListeners();
1174            installComponents();
1175            installKeyboardActions();
1176    
1177            if (! frame.isSelected())
1178              frame.getGlassPane().setVisible(true);
1179          }
1180      }
1181    
1182      /**
1183       * This method reverses the work done by installUI.
1184       *
1185       * @param c The JComponent to uninstall this UI for.
1186       */
1187      public void uninstallUI(JComponent c)
1188      {
1189        uninstallKeyboardActions();
1190        uninstallComponents();
1191        uninstallListeners();
1192        uninstallDefaults();
1193    
1194        frame.getRootPane().getGlassPane().setVisible(false);
1195        frame = null;
1196      }
1197    
1198      /**
1199       * This method installs the defaults specified by the look and feel.
1200       */
1201      protected void installDefaults()
1202        {
1203          internalFrameLayout = createLayoutManager();
1204          frame.setLayout(internalFrameLayout);
1205          LookAndFeel.installBorder(frame, "InternalFrame.border");
1206          frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon"));
1207    
1208          // Let the content pane inherit the background color from its
1209          // frame by setting the background to null.
1210          Component contentPane = frame.getContentPane();
1211          if (contentPane != null
1212              && contentPane.getBackground() instanceof UIResource)
1213            {
1214              contentPane.setBackground(null);
1215            }
1216      }
1217    
1218      /**
1219       * This method installs the keyboard actions for the JInternalFrame.
1220       */
1221      protected void installKeyboardActions()
1222      {
1223        ActionMapUIResource am = new ActionMapUIResource();
1224        am.put("showSystemMenu", new ShowSystemMenuAction());
1225    
1226        // The RI impl installs the audio actions as parent of the UI action map,
1227        // so do we.
1228        BasicLookAndFeel blaf = (BasicLookAndFeel) UIManager.getLookAndFeel();
1229        ActionMap audioActionMap = blaf.getAudioActionMap();
1230        am.setParent(audioActionMap);
1231    
1232        SwingUtilities.replaceUIActionMap(frame, am);
1233      }
1234    
1235      /**
1236       * This method installs the Components for the JInternalFrame.
1237       */
1238      protected void installComponents()
1239      {
1240        setNorthPane(createNorthPane(frame));
1241        setSouthPane(createSouthPane(frame));
1242        setEastPane(createEastPane(frame));
1243        setWestPane(createWestPane(frame));
1244      }
1245    
1246      /**
1247       * This method installs the listeners for the JInternalFrame.
1248       */
1249      protected void installListeners()
1250      {
1251        glassPaneDispatcher = createGlassPaneDispatcher();
1252        createInternalFrameListener();
1253        borderListener = createBorderListener(frame);
1254        componentListener = createComponentListener();
1255        propertyChangeListener = createPropertyChangeListener();
1256    
1257        frame.addMouseListener(borderListener);
1258        frame.addMouseMotionListener(borderListener);
1259        frame.addInternalFrameListener(internalFrameListener);
1260        frame.addPropertyChangeListener(propertyChangeListener);
1261        frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher);
1262        frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher);
1263    
1264        Container parent = frame.getParent();
1265        if (parent != null)
1266          {
1267            parent.addComponentListener(componentListener);
1268          }
1269      }
1270    
1271      /**
1272       * This method uninstalls the defaults for the JInternalFrame.
1273       */
1274      protected void uninstallDefaults()
1275      {
1276        frame.setBorder(null);
1277        frame.setLayout(null);
1278        internalFrameLayout = null;
1279      }
1280    
1281      /**
1282       * This method uninstalls the Components for the JInternalFrame.
1283       */
1284      protected void uninstallComponents()
1285      {
1286        setNorthPane(null);
1287        setSouthPane(null);
1288        setEastPane(null);
1289        setWestPane(null);
1290      }
1291    
1292      /**
1293       * This method uninstalls the listeners for the JInternalFrame.
1294       */
1295      protected void uninstallListeners()
1296      {
1297    
1298        Container parent = frame.getParent();
1299        if (parent != null)
1300          {
1301            parent.removeComponentListener(componentListener);
1302          }
1303        componentListener = null;
1304    
1305        frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher);
1306        frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher);
1307    
1308        frame.removePropertyChangeListener(propertyChangeListener);
1309        frame.removeInternalFrameListener(internalFrameListener);
1310        frame.removeMouseMotionListener(borderListener);
1311        frame.removeMouseListener(borderListener);
1312    
1313        propertyChangeListener = null;
1314    
1315        borderListener = null;
1316        internalFrameListener = null;
1317        glassPaneDispatcher = null;
1318      }
1319    
1320      /**
1321       * This method uninstalls the keyboard actions for the JInternalFrame.
1322       */
1323      protected void uninstallKeyboardActions()
1324      {
1325        SwingUtilities.replaceUIActionMap(frame, null);
1326        SwingUtilities.replaceUIInputMap(frame, JComponent.WHEN_IN_FOCUSED_WINDOW,
1327                                         null);
1328      }
1329    
1330      /**
1331       * This method creates a new LayoutManager for the JInternalFrame.
1332       *
1333       * @return A new LayoutManager for the JInternalFrame.
1334       */
1335      protected LayoutManager createLayoutManager()
1336      {
1337        return new InternalFrameLayout();
1338      }
1339    
1340      /**
1341       * This method creates a new PropertyChangeListener for the JInternalFrame.
1342       *
1343       * @return A new PropertyChangeListener for the JInternalFrame.
1344       */
1345      protected PropertyChangeListener createPropertyChangeListener()
1346      {
1347        return new InternalFramePropertyChangeListener();
1348      }
1349    
1350      /**
1351       * This method returns the preferred size of the given JComponent.
1352       *
1353       * @param x The JComponent to find a preferred size for.
1354       *
1355       * @return The preferred size.
1356       */
1357      public Dimension getPreferredSize(JComponent x)
1358      {
1359        Dimension pref = null;
1360        LayoutManager layout = frame.getLayout();
1361        if (frame == x && layout != null)
1362          pref = layout.preferredLayoutSize(frame);
1363        else
1364          pref = new Dimension(100, 100);
1365        return pref;
1366      }
1367    
1368      /**
1369       * This method returns the minimum size of the given JComponent.
1370       *
1371       * @param x The JComponent to find a minimum size for.
1372       *
1373       * @return The minimum size.
1374       */
1375      public Dimension getMinimumSize(JComponent x)
1376      {
1377        Dimension min = null;
1378        LayoutManager layout = frame.getLayout();
1379        if (frame == x && layout != null)
1380          min = layout.minimumLayoutSize(frame);
1381        else
1382          min = new Dimension(0, 0);
1383        return min;
1384      }
1385    
1386      /**
1387       * This method returns the maximum size of the given JComponent.
1388       *
1389       * @param x The JComponent to find a maximum size for.
1390       *
1391       * @return The maximum size.
1392       */
1393      public Dimension getMaximumSize(JComponent x)
1394      {
1395        Dimension max = null;
1396        LayoutManager layout = frame.getLayout();
1397        if (frame == x && layout != null && layout instanceof LayoutManager2)
1398          max = ((LayoutManager2) layout).maximumLayoutSize(frame);
1399        else
1400          max = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1401        return max;
1402      }
1403    
1404      /**
1405       * This method replaces the currentPane with the newPane. When replacing it
1406       * also removes the MouseHandlers for the old pane and installs  them on
1407       * the new pane.
1408       *
1409       * @param currentPane The old pane to remove.
1410       * @param newPane The new pane to install.
1411       */
1412      protected void replacePane(JComponent currentPane, JComponent newPane)
1413      {
1414        if (currentPane != null)
1415          {
1416            deinstallMouseHandlers(currentPane);
1417            frame.remove(currentPane);
1418          }
1419    
1420        if (newPane != null)
1421          {
1422            installMouseHandlers(newPane);
1423            frame.add(newPane);
1424          }
1425      }
1426    
1427      /**
1428       * This method removes the necessary MouseListeners from the given
1429       * JComponent.
1430       *
1431       * @param c The JComponent to remove MouseListeners from.
1432       */
1433      protected void deinstallMouseHandlers(JComponent c)
1434      {
1435        c.removeMouseListener(borderListener);
1436        c.removeMouseMotionListener(borderListener);
1437      }
1438    
1439      /**
1440       * This method installs the necessary MouseListeners from the given
1441       * JComponent.
1442       *
1443       * @param c The JComponent to install MouseListeners on.
1444       */
1445      protected void installMouseHandlers(JComponent c)
1446      {
1447        c.addMouseListener(borderListener);
1448        c.addMouseMotionListener(borderListener);
1449      }
1450    
1451      /**
1452       * This method creates the north pane used in the JInternalFrame.
1453       *
1454       * @param w The JInternalFrame to create a north pane for.
1455       *
1456       * @return The north pane.
1457       */
1458      protected JComponent createNorthPane(JInternalFrame w)
1459      {
1460        titlePane = new BasicInternalFrameTitlePane(w);
1461        return titlePane;
1462      }
1463    
1464      /**
1465       * This method creates the west pane used in the JInternalFrame.
1466       *
1467       * @param w The JInternalFrame to create a west pane for.
1468       *
1469       * @return The west pane.
1470       */
1471      protected JComponent createWestPane(JInternalFrame w)
1472      {
1473        return null;
1474      }
1475    
1476      /**
1477       * This method creates the south pane used in the JInternalFrame.
1478       *
1479       * @param w The JInternalFrame to create a south pane for.
1480       *
1481       * @return The south pane.
1482       */
1483      protected JComponent createSouthPane(JInternalFrame w)
1484      {
1485        return null;
1486      }
1487    
1488      /**
1489       * This method creates the east pane used in the JInternalFrame.
1490       *
1491       * @param w The JInternalFrame to create an east pane for.
1492       *
1493       * @return The east pane.
1494       */
1495      protected JComponent createEastPane(JInternalFrame w)
1496      {
1497        return null;
1498      }
1499    
1500      /**
1501       * This method returns a new BorderListener for the given JInternalFrame.
1502       *
1503       * @param w The JIntenalFrame to create a BorderListener for.
1504       *
1505       * @return A new BorderListener.
1506       */
1507      protected MouseInputAdapter createBorderListener(JInternalFrame w)
1508      {
1509        return new BorderListener();
1510      }
1511    
1512      /**
1513       * This method creates a new InternalFrameListener for the JInternalFrame.
1514       */
1515      protected void createInternalFrameListener()
1516      {
1517        internalFrameListener = new BasicInternalFrameListener();
1518      }
1519    
1520      /**
1521       * DOCUMENT ME!
1522       *
1523       * @return DOCUMENT ME!
1524       */
1525      protected final boolean isKeyBindingRegistered()
1526      {
1527        // FIXME: Implement.
1528        return false;
1529      }
1530    
1531      /**
1532       * DOCUMENT ME!
1533       *
1534       * @param b DOCUMENT ME!
1535       */
1536      protected final void setKeyBindingRegistered(boolean b)
1537      {
1538        // FIXME: Implement.
1539      }
1540    
1541      /**
1542       * DOCUMENT ME!
1543       *
1544       * @return DOCUMENT ME!
1545       */
1546      public final boolean isKeyBindingActive()
1547      {
1548        // FIXME: Implement.
1549        return false;
1550      }
1551    
1552      /**
1553       * DOCUMENT ME!
1554       *
1555       * @param b DOCUMENT ME!
1556       */
1557      protected final void setKeyBindingActive(boolean b)
1558      {
1559        // FIXME: Implement.
1560      }
1561    
1562      /**
1563       * DOCUMENT ME!
1564       */
1565      protected void setupMenuOpenKey()
1566      {
1567        // FIXME: Implement.
1568      }
1569    
1570      /**
1571       * DOCUMENT ME!
1572       */
1573      protected void setupMenuCloseKey()
1574      {
1575        // FIXME: Implement.
1576      }
1577    
1578      /**
1579       * This method returns the north pane.
1580       *
1581       * @return The north pane.
1582       */
1583      public JComponent getNorthPane()
1584      {
1585        return northPane;
1586      }
1587    
1588      /**
1589       * This method sets the north pane to be the given JComponent.
1590       *
1591       * @param c The new north pane.
1592       */
1593      public void setNorthPane(JComponent c)
1594      {
1595        replacePane(northPane, c);
1596        northPane = c;
1597        // the following is needed to make internal frames draggable when using
1598        // the JGoodies PlasticLookAndFeel, because it overrides the
1599        // createNorthPane() method and doesn't assign anything to the titlePane
1600        // field.  It is possible there is another way to make this work, but
1601        // I didn't find it...
1602        if (c instanceof BasicInternalFrameTitlePane)
1603          titlePane = (BasicInternalFrameTitlePane) c;
1604      }
1605    
1606      /**
1607       * This method returns the south pane.
1608       *
1609       * @return The south pane.
1610       */
1611      public JComponent getSouthPane()
1612      {
1613        return southPane;
1614      }
1615    
1616      /**
1617       * This method sets the south pane to be the given JComponent.
1618       *
1619       * @param c The new south pane.
1620       */
1621      public void setSouthPane(JComponent c)
1622      {
1623        replacePane(southPane, c);
1624        southPane = c;
1625      }
1626    
1627      /**
1628       * This method sets the east pane to be the given JComponent.
1629       *
1630       * @param c The new east pane.
1631       */
1632      public void setEastPane(JComponent c)
1633      {
1634        replacePane(eastPane, c);
1635        eastPane = c;
1636      }
1637    
1638      /**
1639       * This method returns the east pane.
1640       *
1641       * @return The east pane.
1642       */
1643      public JComponent getEastPane()
1644      {
1645        return eastPane;
1646      }
1647    
1648      /**
1649       * This method sets the west pane to be the given JComponent.
1650       *
1651       * @param c The new west pane.
1652       */
1653      public void setWestPane(JComponent c)
1654      {
1655        replacePane(westPane, c);
1656        westPane = c;
1657      }
1658    
1659      /**
1660       * This method returns the west pane.
1661       *
1662       * @return The west pane.
1663       */
1664      public JComponent getWestPane()
1665      {
1666        return westPane;
1667      }
1668    
1669      /**
1670       * This method returns the DesktopManager to use with the JInternalFrame.
1671       *
1672       * @return The DesktopManager to use with the JInternalFrame.
1673       */
1674      protected DesktopManager getDesktopManager()
1675      {
1676        DesktopManager value = null;
1677        JDesktopPane pane = frame.getDesktopPane();
1678        if (pane != null)
1679          value = frame.getDesktopPane().getDesktopManager();
1680        if (value == null)
1681          value = createDesktopManager();
1682        return value;
1683      }
1684    
1685      /**
1686       * This method returns a default DesktopManager that can be used with this
1687       * JInternalFrame.
1688       *
1689       * @return A default DesktopManager that can be used with this
1690       *         JInternalFrame.
1691       */
1692      protected DesktopManager createDesktopManager()
1693      {
1694        return new DefaultDesktopManager();
1695      }
1696    
1697      /**
1698       * This is a convenience method that closes the JInternalFrame.
1699       *
1700       * @param f The JInternalFrame to close.
1701       */
1702      protected void closeFrame(JInternalFrame f)
1703      {
1704        getDesktopManager().closeFrame(f);
1705      }
1706    
1707      /**
1708       * This is a convenience method that maximizes the JInternalFrame.
1709       *
1710       * @param f The JInternalFrame to maximize.
1711       */
1712      protected void maximizeFrame(JInternalFrame f)
1713      {
1714        getDesktopManager().maximizeFrame(f);
1715      }
1716    
1717      /**
1718       * This is a convenience method that minimizes the JInternalFrame.
1719       *
1720       * @param f The JInternalFrame to minimize.
1721       */
1722      protected void minimizeFrame(JInternalFrame f)
1723      {
1724        getDesktopManager().minimizeFrame(f);
1725      }
1726    
1727      /**
1728       * This is a convenience method that iconifies the JInternalFrame.
1729       *
1730       * @param f The JInternalFrame to iconify.
1731       */
1732      protected void iconifyFrame(JInternalFrame f)
1733      {
1734        getDesktopManager().iconifyFrame(f);
1735      }
1736    
1737      /**
1738       * This is a convenience method that deiconifies the JInternalFrame.
1739       *
1740       * @param f The JInternalFrame to deiconify.
1741       */
1742      protected void deiconifyFrame(JInternalFrame f)
1743      {
1744        getDesktopManager().deiconifyFrame(f);
1745      }
1746    
1747      /**
1748       * This is a convenience method that activates the JInternalFrame.
1749       *
1750       * @param f The JInternalFrame to activate.
1751       */
1752      protected void activateFrame(JInternalFrame f)
1753      {
1754        getDesktopManager().activateFrame(f);
1755      }
1756    
1757      /**
1758       * This is a convenience method that deactivates the JInternalFrame.
1759       *
1760       * @param f the JInternalFrame to deactivate
1761       */
1762      protected void deactivateFrame(JInternalFrame f)
1763      {
1764        getDesktopManager().deactivateFrame(f);
1765      }
1766    
1767      /**
1768       * This method returns a new ComponentListener for the JDesktopPane.
1769       *
1770       * @return A new ComponentListener.
1771       */
1772      protected ComponentListener createComponentListener()
1773      {
1774        return new ComponentHandler();
1775      }
1776    
1777      /**
1778       * This method returns a new GlassPaneDispatcher.
1779       *
1780       * @return A new GlassPaneDispatcher.
1781       */
1782      protected MouseInputListener createGlassPaneDispatcher()
1783      {
1784        return new GlassPaneDispatcher();
1785      }
1786    }