001/* BasicInternalFrameUI.java --
002   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.basic;
040
041import java.awt.Color;
042import java.awt.Component;
043import java.awt.Container;
044import java.awt.Cursor;
045import java.awt.Dimension;
046import java.awt.Graphics;
047import java.awt.Insets;
048import java.awt.LayoutManager;
049import java.awt.LayoutManager2;
050import java.awt.Point;
051import java.awt.Rectangle;
052import java.awt.event.ActionEvent;
053import java.awt.event.ComponentEvent;
054import java.awt.event.ComponentListener;
055import java.awt.event.MouseEvent;
056import java.beans.PropertyChangeEvent;
057import java.beans.PropertyChangeListener;
058import java.beans.PropertyVetoException;
059
060import javax.swing.AbstractAction;
061import javax.swing.ActionMap;
062import javax.swing.DefaultDesktopManager;
063import javax.swing.DesktopManager;
064import javax.swing.JComponent;
065import javax.swing.JDesktopPane;
066import javax.swing.JInternalFrame;
067import javax.swing.KeyStroke;
068import javax.swing.LookAndFeel;
069import javax.swing.SwingConstants;
070import javax.swing.SwingUtilities;
071import javax.swing.UIManager;
072import javax.swing.border.AbstractBorder;
073import javax.swing.event.InternalFrameEvent;
074import javax.swing.event.InternalFrameListener;
075import javax.swing.event.MouseInputAdapter;
076import javax.swing.event.MouseInputListener;
077import javax.swing.plaf.ActionMapUIResource;
078import javax.swing.plaf.ComponentUI;
079import javax.swing.plaf.InternalFrameUI;
080import javax.swing.plaf.UIResource;
081
082/**
083 * This is the UI delegate for the Basic look and feel for JInternalFrames.
084 */
085public 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}