Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/gjt/sp/jedit/gui/PanelWindowContainer.java


1   /*
2    * PanelWindowContainer.java - holds dockable windows
3    * :tabSize=8:indentSize=8:noTabs=false:
4    * :folding=explicit:collapseFolds=1:
5    *
6    * Copyright (C) 2000, 2003 Slava Pestov
7    *
8    * This program is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License
10   * as published by the Free Software Foundation; either version 2
11   * of the License, or any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   *
18   * You should have received a copy of the GNU General Public License
19   * along with this program; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21   */
22  
23  package org.gjt.sp.jedit.gui;
24  
25  //{{{ Imports
26  import javax.swing.border.*;
27  import javax.swing.plaf.metal.*;
28  import javax.swing.*;
29  import java.awt.event.*;
30  import java.awt.font.*;
31  import java.awt.geom.AffineTransform;
32  import java.awt.*;
33  import java.util.*;
34  import org.gjt.sp.jedit.*;
35  //}}}
36  
37  /**
38   * A container for dockable windows. This class should never be used
39   * directly.
40   * @author Slava Pestov
41   * @version $Id: PanelWindowContainer.java,v 1.71 2003/06/11 01:15:32 spestov Exp $
42   * @since jEdit 4.0pre1
43   */
44  public class PanelWindowContainer implements DockableWindowContainer
45  {
46    //{{{ PanelWindowContainer constructor
47    public PanelWindowContainer(DockableWindowManager wm, String position,
48      int dimension)
49    {
50      this.wm = wm;
51      this.position = position;
52  
53      //{{{ Button box setup
54      buttonPanel = new JPanel(new ButtonLayout());
55      buttonPanel.setBorder(new EmptyBorder(1,1,1,1));
56  
57      closeBox = new JButton(GUIUtilities.loadIcon("closebox.gif"));
58      closeBox.setRequestFocusEnabled(false);
59      closeBox.setToolTipText(jEdit.getProperty("view.docking.close-tooltip"));
60      if(OperatingSystem.isMacOSLF())
61        closeBox.putClientProperty("JButton.buttonType","toolbar");
62  
63      closeBox.setMargin(new Insets(0,0,0,0));
64  
65      closeBox.addActionListener(new ActionHandler());
66  
67      menuBtn = new JButton(GUIUtilities.loadIcon("ToolbarMenu.gif"));
68      menuBtn.setRequestFocusEnabled(false);
69      menuBtn.setToolTipText(jEdit.getProperty("view.docking.menu-tooltip"));
70      if(OperatingSystem.isMacOSLF())
71        menuBtn.putClientProperty("JButton.buttonType","toolbar");
72  
73      menuBtn.setMargin(new Insets(0,0,0,0));
74  
75      menuBtn.addMouseListener(new MenuMouseHandler());
76  
77      buttonGroup = new ButtonGroup();
78      // JDK 1.4 workaround
79      buttonGroup.add(nullButton = new JToggleButton());
80      //}}}
81  
82      dockables = new ArrayList();
83      buttons = new ArrayList();
84      dockablePanel = new DockablePanel();
85  
86      this.dimension = dimension;
87    } //}}}
88  
89    //{{{ register() method
90    public void register(final DockableWindowManager.Entry entry)
91    {
92      dockables.add(entry);
93  
94      //{{{ Create button
95      int rotation;
96      if(position.equals(DockableWindowManager.TOP)
97        || position.equals(DockableWindowManager.BOTTOM))
98        rotation = RotatedTextIcon.NONE;
99      else if(position.equals(DockableWindowManager.LEFT))
100       rotation = RotatedTextIcon.CCW;
101     else if(position.equals(DockableWindowManager.RIGHT))
102       rotation = RotatedTextIcon.CW;
103     else
104       throw new InternalError("Invalid position: " + position);
105 
106     JToggleButton button = new JToggleButton();
107     button.setMargin(new Insets(0,0,0,0));
108     button.setRequestFocusEnabled(false);
109     button.setIcon(new RotatedTextIcon(rotation,button.getFont(),
110       entry.title));
111     button.setActionCommand(entry.factory.name);
112     button.addActionListener(new ActionHandler());
113     button.addMouseListener(new MenuMouseHandler());
114     if(OperatingSystem.isMacOSLF())
115       button.putClientProperty("JButton.buttonType","toolbar");
116     //}}}
117 
118     buttonGroup.add(button);
119     buttons.add(button);
120     entry.btn = button;
121 
122     wm.revalidate();
123   } //}}}
124 
125   //{{{ unregister() method
126   public void unregister(DockableWindowManager.Entry entry)
127   {
128     if(entry.factory.name.equals(mostRecent))
129       mostRecent = null;
130 
131     buttonPanel.remove(entry.btn);
132     buttons.remove(entry.btn);
133     entry.btn = null;
134 
135     dockables.remove(entry);
136     if(entry.win != null)
137       dockablePanel.remove(entry.win);
138 
139     if(current == entry)
140     {
141       current = null;
142       show(null);
143     }
144     else
145     {
146       wm.revalidate();
147       dockablePanel.repaint();
148     }
149   } //}}}
150 
151   //{{{ remove() method
152   public void remove(final DockableWindowManager.Entry entry)
153   {
154     if(entry.factory.name.equals(mostRecent))
155       mostRecent = null;
156 
157     if(entry.win != null)
158     {
159       dockablePanel.remove(entry.win);
160       entry.win = null;
161     }
162 
163     if(current == entry)
164     {
165       current = null;
166       show(null);
167     }
168     else
169     {
170       wm.revalidate();
171       dockablePanel.repaint();
172     }
173   } //}}}
174 
175   //{{{ showMostRecent() method
176   public void showMostRecent()
177   {
178     if(dockables.size() == 0)
179     {
180       Toolkit.getDefaultToolkit().beep();
181       return;
182     }
183 
184     if(mostRecent == null)
185     {
186       mostRecent = ((DockableWindowManager.Entry)
187         dockables.get(0)).factory.name;
188     }
189 
190     wm.showDockableWindow(mostRecent);
191   } //}}}
192 
193   //{{{ show() method
194   public void show(final DockableWindowManager.Entry entry)
195   {
196     if(current == entry)
197     {
198       if(entry != null)
199       {
200         if(entry.win instanceof DefaultFocusComponent)
201         {
202           ((DefaultFocusComponent)entry.win)
203             .focusOnDefaultComponent();
204         }
205         else
206         {
207           entry.win.requestDefaultFocus();
208         }
209       }
210       return;
211     }
212 
213     if(entry != null)
214     {
215       if(current == null)
216       {
217         // we didn't have a component previously, so
218         // create a border
219         dockablePanel.setBorder(new DockBorder(position));
220       }
221 
222       mostRecent = entry.factory.name;
223       this.current = entry;
224 
225       if(entry.win.getParent() != dockablePanel)
226         dockablePanel.add(entry.factory.name,entry.win);
227 
228       dockablePanel.showDockable(entry.factory.name);
229 
230       entry.btn.setSelected(true);
231 
232       if(entry.win instanceof DefaultFocusComponent)
233       {
234         ((DefaultFocusComponent)entry.win)
235           .focusOnDefaultComponent();
236       }
237       else
238       {
239         entry.win.requestDefaultFocus();
240       }
241     }
242     else
243     {
244       current = null;
245       nullButton.setSelected(true);
246       // removing last component, so remove border
247       dockablePanel.setBorder(null);
248 
249       wm.getView().getTextArea().requestFocus();
250     }
251 
252     wm.revalidate();
253     dockablePanel.repaint();
254   } //}}}
255 
256   //{{{ isVisible() method
257   public boolean isVisible(DockableWindowManager.Entry entry)
258   {
259     return current == entry;
260   } //}}}
261 
262   //{{{ getCurrent() method
263   /**
264    * Returns the name of the dockable in this container.
265    * @since jEdit 4.2pre1
266    */
267   public String getCurrent()
268   {
269     if(current == null)
270       return null;
271     else
272       return current.factory.name;
273   } //}}}
274 
275   //{{{ getDimension() method
276   /**
277    * Returns the width or height (depending on position) of the dockable
278    * window container.
279    * @since jEdit 4.2pre1
280    */
281   public int getDimension()
282   {
283     return dimension;
284   } //}}}
285 
286   //{{{ getDockables() method
287   public String[] getDockables()
288   {
289     String[] retVal = new String[dockables.size()];
290     for(int i = 0; i < dockables.size(); i++)
291     {
292       DockableWindowManager.Entry entry =
293         (DockableWindowManager.Entry) dockables.get(i);
294       retVal[i] = entry.factory.name;
295     }
296     return retVal;
297   } //}}}
298 
299   //{{{ Package-private members
300   static final int SPLITTER_WIDTH = 10;
301   DockablePanel dockablePanel;
302   JPanel buttonPanel;
303 
304   //{{{ save() method
305   void save()
306   {
307     jEdit.setIntegerProperty("view.dock." + position + ".dimension",
308       dimension);
309     if(current == null)
310       jEdit.unsetProperty("view.dock." + position + ".last");
311     else
312     {
313       jEdit.setProperty("view.dock." + position + ".last",
314         current.factory.name);
315     }
316   } //}}}
317 
318   //{{{ setDimension() method
319   void setDimension(int dimension)
320   {
321     if(dimension != 0)
322       this.dimension = dimension - SPLITTER_WIDTH;
323   } //}}}
324 
325   //{{{ sortDockables() method
326   void sortDockables()
327   {
328     buttonPanel.removeAll();
329     buttonPanel.add(closeBox);
330     buttonPanel.add(menuBtn);
331     Collections.sort(buttons,new DockableWindowCompare());
332     for(int i = 0; i < buttons.size(); i++)
333     {
334       buttonPanel.add((AbstractButton)buttons.get(i));
335     }
336   } //}}}
337 
338   //}}}
339 
340   //{{{ Private members
341   private DockableWindowManager wm;
342   private String position;
343   private JButton closeBox;
344   private JButton menuBtn;
345   private ButtonGroup buttonGroup;
346   private JToggleButton nullButton;
347   private int dimension;
348   private ArrayList dockables;
349   private ArrayList buttons;
350   private DockableWindowManager.Entry current;
351   private JPopupMenu popup;
352 
353   // remember the most recent dockable
354   private String mostRecent;
355   //}}}
356 
357   //{{{ Inner classes
358 
359   //{{{ DockableWindowCompare class
360   static class DockableWindowCompare implements Comparator
361   {
362     public int compare(Object o1, Object o2)
363     {
364       String name1 = ((AbstractButton)o1).getActionCommand();
365       String name2 = ((AbstractButton)o2).getActionCommand();
366       return MiscUtilities.compareStrings(
367         jEdit.getProperty(name1 + ".title",""),
368         jEdit.getProperty(name2 + ".title",""),
369         true);
370     }
371   } //}}}
372 
373   //{{{ ActionHandler class
374   class ActionHandler implements ActionListener
375   {
376     public void actionPerformed(ActionEvent evt)
377     {
378       if(popup != null && popup.isVisible())
379         popup.setVisible(false);
380 
381       if(evt.getSource() == closeBox)
382         show(null);
383       else
384       {
385         if(wm.isDockableWindowVisible(evt.getActionCommand()))
386           show(null);
387         else
388           wm.showDockableWindow(evt.getActionCommand());
389       }
390     }
391   } //}}}
392 
393   //{{{ MenuMouseHandler class
394   class MenuMouseHandler extends MouseAdapter
395   {
396     public void mousePressed(MouseEvent evt)
397     {
398       if(popup != null && popup.isVisible())
399       {
400         popup.setVisible(false);
401         return;
402       }
403 
404       Component comp = (Component)evt.getSource();
405       String dockable;
406       if(comp instanceof JToggleButton)
407         dockable = ((JToggleButton)comp).getActionCommand();
408       else
409         dockable = getCurrent();
410 
411       if(comp == menuBtn || GUIUtilities.isPopupTrigger(evt))
412       {
413         if(dockable == null)
414         {
415           popup = wm.createPopupMenu(PanelWindowContainer.this,null,false);
416         }
417         else
418         {
419           popup = wm.createPopupMenu(PanelWindowContainer.this,dockable,false);
420         }
421 
422         int x, y;
423         boolean point;
424         if(comp == menuBtn)
425         {
426           x = 0;
427           y = menuBtn.getHeight();
428           point = false;
429         }
430         else
431         {
432           x = evt.getX();
433           y = evt.getY();
434           point = true;
435         }
436         GUIUtilities.showPopupMenu(popup,
437           comp,x,y,point);
438       }
439     }
440   } //}}}
441 
442   //{{{ DockBorder class
443   static class DockBorder implements Border
444   {
445     String position;
446     Insets insets;
447     Color color1;
448     Color color2;
449     Color color3;
450 
451     //{{{ DockBorder constructor
452     DockBorder(String position)
453     {
454       this.position = position;
455       insets = new Insets(
456         position.equals(DockableWindowManager.BOTTOM)
457           ? SPLITTER_WIDTH : 0,
458         position.equals(DockableWindowManager.RIGHT)
459           ? SPLITTER_WIDTH : 0,
460         position.equals(DockableWindowManager.TOP)
461           ? SPLITTER_WIDTH : 0,
462         position.equals(DockableWindowManager.LEFT)
463           ? SPLITTER_WIDTH : 0);
464     } //}}}
465 
466     //{{{ paintBorder() method
467     public void paintBorder(Component c, Graphics g,
468       int x, int y, int width, int height)
469     {
470       updateColors();
471 
472       if(color1 == null || color2 == null || color3 == null)
473         return;
474 
475       if(position.equals(DockableWindowManager.BOTTOM))
476         paintHorizBorder(g,x,y,width);
477       else if(position.equals(DockableWindowManager.RIGHT))
478         paintVertBorder(g,x,y,height);
479       else if(position.equals(DockableWindowManager.TOP))
480       {
481         paintHorizBorder(g,x,y + height
482           - SPLITTER_WIDTH,width);
483       }
484       else if(position.equals(DockableWindowManager.LEFT))
485       {
486         paintVertBorder(g,x + width
487           - SPLITTER_WIDTH,y,height);
488       }
489     } //}}}
490 
491     //{{{ getBorderInsets() method
492     public Insets getBorderInsets(Component c)
493     {
494       return insets;
495     } //}}}
496 
497     //{{{ isBorderOpaque() method
498     public boolean isBorderOpaque()
499     {
500       return false;
501     } //}}}
502 
503     //{{{ paintHorizBorder() method
504     private void paintHorizBorder(Graphics g, int x, int y, int width)
505     {
506       g.setColor(color3);
507       g.fillRect(x,y,width,SPLITTER_WIDTH);
508 
509       for(int i = 0; i < width / 4 - 1; i++)
510       {
511         g.setColor(color1);
512         g.drawLine(x + i * 4 + 2,y + 3,
513           x + i * 4 + 2,y + 3);
514         g.setColor(color2);
515         g.drawLine(x + i * 4 + 3,y + 4,
516           x + i * 4 + 3,y + 4);
517         g.setColor(color1);
518         g.drawLine(x + i * 4 + 4,y + 5,
519           x + i * 4 + 4,y + 5);
520         g.setColor(color2);
521         g.drawLine(x + i * 4 + 5,y + 6,
522           x + i * 4 + 5,y + 6);
523       }
524     } //}}}
525 
526     //{{{ paintVertBorder() method
527     private void paintVertBorder(Graphics g, int x, int y, int height)
528     {
529       g.setColor(color3);
530       g.fillRect(x,y,SPLITTER_WIDTH,height);
531 
532       for(int i = 0; i < height / 4 - 1; i++)
533       {
534         g.setColor(color1);
535         g.drawLine(x + 3,y + i * 4 + 2,
536           x + 3,y + i * 4 + 2);
537         g.setColor(color2);
538         g.drawLine(x + 4,y + i * 4 + 3,
539           x + 4,y + i * 4 + 3);
540         g.setColor(color1);
541         g.drawLine(x + 5,y + i * 4 + 4,
542           x + 5,y + i * 4 + 4);
543         g.setColor(color2);
544         g.drawLine(x + 6,y + i * 4 + 5,
545           x + 6,y + i * 4 + 5);
546       }
547     } //}}}
548 
549     //{{{ updateColors() method
550     private void updateColors()
551     {
552       if(UIManager.getLookAndFeel() instanceof MetalLookAndFeel)
553       {
554         color1 = MetalLookAndFeel.getControlHighlight();
555         color2 = MetalLookAndFeel.getControlDarkShadow();
556         color3 = MetalLookAndFeel.getControl();
557       }
558       else
559       {
560         color1 = color2 = color3 = null;
561       }
562     } //}}}
563   } //}}}
564 
565   //{{{ RotatedTextIcon class
566   public static class RotatedTextIcon implements Icon
567   {
568     public static final int NONE = 0;
569     public static final int CW = 1;
570     public static final int CCW = 2;
571 
572     //{{{ RotatedTextIcon constructor
573     public RotatedTextIcon(int rotate, Font font, String text)
574     {
575       this.rotate = rotate;
576       this.font = font;
577 
578       FontRenderContext fontRenderContext
579         = new FontRenderContext(null,true,true);
580       this.text = text;
581       glyphs = font.createGlyphVector(fontRenderContext,text);
582       width = (int)glyphs.getLogicalBounds().getWidth() + 4;
583       //height = (int)glyphs.getLogicalBounds().getHeight();
584 
585       LineMetrics lineMetrics = font.getLineMetrics(text,fontRenderContext);
586       ascent = lineMetrics.getAscent();
587       height = (int)lineMetrics.getHeight();
588 
589       renderHints = new RenderingHints(
590         RenderingHints.KEY_ANTIALIASING,
591         RenderingHints.VALUE_ANTIALIAS_ON);
592       renderHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
593         RenderingHints.VALUE_FRACTIONALMETRICS_ON);
594       renderHints.put(RenderingHints.KEY_RENDERING,
595         RenderingHints.VALUE_RENDER_QUALITY);
596     } //}}}
597 
598     //{{{ getIconWidth() method
599     public int getIconWidth()
600     {
601       return (int)(rotate == RotatedTextIcon.CW
602         || rotate == RotatedTextIcon.CCW
603         ? height : width);
604     } //}}}
605 
606     //{{{ getIconHeight() method
607     public int getIconHeight()
608     {
609       return (int)(rotate == RotatedTextIcon.CW
610         || rotate == RotatedTextIcon.CCW
611         ? width : height);
612     } //}}}
613 
614     //{{{ paintIcon() method
615     public void paintIcon(Component c, Graphics g, int x, int y)
616     {
617       Graphics2D g2d = (Graphics2D)g;
618       g2d.setFont(font);
619       AffineTransform oldTransform = g2d.getTransform();
620       RenderingHints oldHints = g2d.getRenderingHints();
621 
622       g2d.setRenderingHints(renderHints);
623       g2d.setColor(c.getForeground());
624 
625       //{{{ No rotation
626       if(rotate == RotatedTextIcon.NONE)
627       {
628         g2d.drawGlyphVector(glyphs,x + 2,y + ascent);
629       } //}}}
630       //{{{ Clockwise rotation
631       else if(rotate == RotatedTextIcon.CW)
632       {
633         AffineTransform trans = new AffineTransform();
634         trans.concatenate(oldTransform);
635         trans.translate(x,y + 2);
636         trans.rotate(Math.PI / 2,
637           height / 2, width / 2);
638         g2d.setTransform(trans);
639         g2d.drawGlyphVector(glyphs,(height - width) / 2,
640           (width - height) / 2
641           + ascent);
642       } //}}}
643       //{{{ Counterclockwise rotation
644       else if(rotate == RotatedTextIcon.CCW)
645       {
646         AffineTransform trans = new AffineTransform();
647         trans.concatenate(oldTransform);
648         trans.translate(x,y - 2);
649         trans.rotate(Math.PI * 3 / 2,
650           height / 2, width / 2);
651         g2d.setTransform(trans);
652         g2d.drawGlyphVector(glyphs,(height - width) / 2,
653           (width - height) / 2
654           + ascent);
655       } //}}}
656 
657       g2d.setTransform(oldTransform);
658       g2d.setRenderingHints(oldHints);
659     } //}}}
660 
661     //{{{ Private members
662     private int rotate;
663     private Font font;
664     private String text;
665     private GlyphVector glyphs;
666     private float width;
667     private float height;
668     private float ascent;
669     private RenderingHints renderHints;
670     //}}}
671   } //}}}
672 
673   //{{{ ButtonLayout class
674   class ButtonLayout implements LayoutManager
675   {
676     //{{{ addLayoutComponent() method
677     public void addLayoutComponent(String name, Component comp) {} //}}}
678 
679     //{{{ removeLayoutComponent() method
680     public void removeLayoutComponent(Component comp) {} //}}}
681 
682     //{{{ preferredLayoutSize() method
683     public Dimension preferredLayoutSize(Container parent)
684     {
685       Insets insets = ((JComponent)parent).getBorder()
686         .getBorderInsets((JComponent)parent);
687 
688       Component[] comp = parent.getComponents();
689       if(comp.length <= 2)
690       {
691         // nothing 'cept close box
692         return new Dimension(0,0);
693       }
694 
695       Dimension dim = comp[2].getPreferredSize();
696 
697       if(position.equals(DockableWindowManager.TOP)
698         || position.equals(DockableWindowManager.BOTTOM))
699       {
700         int width = parent.getWidth() - insets.right;
701         int rowHeight = Math.max(dim.height,closeBox.getPreferredSize().width);
702         int x = rowHeight * 2 + insets.left;
703         Dimension returnValue = new Dimension(0,rowHeight
704           + insets.top + insets.bottom);
705 
706         for(int i = 2; i < comp.length; i++)
707         {
708           int btnWidth = comp[i].getPreferredSize().width;
709           if(btnWidth + x > width)
710           {
711             x = btnWidth + insets.left;
712             returnValue.height += rowHeight;
713           }
714           else
715             x += btnWidth;
716         }
717         return returnValue;
718       }
719       else
720       {
721         int height = parent.getHeight() - insets.bottom;
722         int colWidth = Math.max(dim.width,closeBox.getPreferredSize().height);
723         int y = colWidth * 2 + insets.top;
724         Dimension returnValue = new Dimension(colWidth
725           + insets.left + insets.right,0);
726 
727         for(int i = 2; i < comp.length; i++)
728         {
729           int btnHeight = comp[i].getPreferredSize().height;
730           if(btnHeight + y > height)
731           {
732             returnValue.width += colWidth;
733             y = insets.top;
734           }
735 
736           y += btnHeight;
737         }
738         return returnValue;
739       }
740     } //}}}
741 
742     //{{{ minimumLayoutSize() method
743     public Dimension minimumLayoutSize(Container parent)
744     {
745       return preferredLayoutSize(parent);
746     } //}}}
747 
748     //{{{ layoutContainer() method
749     public void layoutContainer(Container parent)
750     {
751       Insets insets = ((JComponent)parent).getBorder()
752         .getBorderInsets((JComponent)parent);
753 
754       Component[] comp = parent.getComponents();
755       if(comp.length <= 2)
756       {
757         for(int i = 0; i < comp.length; i++)
758         {
759           comp[i].setVisible(false);
760         }
761         return;
762       }
763 
764       comp[0].setVisible(true);
765       comp[1].setVisible(true);
766 
767       Dimension dim = comp[2].getPreferredSize();
768 
769       if(position.equals(DockableWindowManager.TOP)
770         || position.equals(DockableWindowManager.BOTTOM))
771       {
772         int width = parent.getWidth() - insets.right;
773         int rowHeight = Math.max(dim.height,closeBox.getPreferredSize().width);
774         int x = rowHeight * 2 + insets.left;
775         int y = insets.top;
776         closeBox.setBounds(insets.left,insets.top,rowHeight,rowHeight);
777         menuBtn.setBounds(insets.left + rowHeight,insets.top,rowHeight,rowHeight);
778 
779         for(int i = 2; i < comp.length; i++)
780         {
781           int btnWidth = comp[i].getPreferredSize().width;
782           if(btnWidth + x > width)
783           {
784             x = insets.left;
785             y += rowHeight;
786           }
787           comp[i].setBounds(x,y,btnWidth,rowHeight);
788           x += btnWidth;
789         }
790       }
791       else
792       {
793         int height = parent.getHeight() - insets.bottom;
794         int colWidth = Math.max(dim.width,closeBox.getPreferredSize().height);
795         int x = insets.left;
796         int y = colWidth * 2 + insets.top;
797         closeBox.setBounds(insets.left,insets.top,colWidth,colWidth);
798         menuBtn.setBounds(insets.left,insets.top + colWidth,colWidth,colWidth);
799 
800         for(int i = 2; i < comp.length; i++)
801         {
802           int btnHeight = comp[i].getPreferredSize().height;
803           if(btnHeight + y > height)
804           {
805             x += colWidth;
806             y = insets.top;
807           }
808           comp[i].setBounds(x,y,colWidth,btnHeight);
809           y += btnHeight;
810         }
811       }
812     } //}}}
813   } //}}}
814 
815   //{{{ DockablePanel class
816   class DockablePanel extends JPanel
817   {
818     //{{{ DockablePanel constructor
819     DockablePanel()
820     {
821       super(new CardLayout());
822 
823       ResizeMouseHandler resizeMouseHandler = new ResizeMouseHandler();
824       addMouseListener(resizeMouseHandler);
825       addMouseMotionListener(resizeMouseHandler);
826     } //}}}
827 
828     //{{{ getWindowContainer() method
829     PanelWindowContainer getWindowContainer()
830     {
831       return PanelWindowContainer.this;
832     } //}}}
833 
834     //{{{ showDockable() method
835     void showDockable(String name)
836     {
837       ((CardLayout)getLayout()).show(this,name);
838     } //}}}
839 
840     //{{{ getMinimumSize() method
841     public Dimension getMinimumSize()
842     {
843       return new Dimension(0,0);
844     } //}}}
845 
846     //{{{ getPreferredSize() method
847     public Dimension getPreferredSize()
848     {
849       if(current == null)
850         return new Dimension(0,0);
851       else
852       {
853         if(position.equals(DockableWindowManager.TOP)
854           || position.equals(DockableWindowManager.BOTTOM))
855         {
856           if(dimension <= 0)
857           {
858             int height = super.getPreferredSize().height;
859             dimension = height - SPLITTER_WIDTH;
860           }
861           return new Dimension(0,
862             dimension + SPLITTER_WIDTH);
863         }
864         else
865         {
866           if(dimension <= 0)
867           {
868             int width = super.getPreferredSize().width;
869             dimension = width - SPLITTER_WIDTH;
870           }
871           return new Dimension(dimension + SPLITTER_WIDTH,
872             0);
873         }
874       }
875     } //}}}
876 
877     //{{{ setBounds() method
878     public void setBounds(int x, int y, int width, int height)
879     {
880       if(position.equals(DockableWindowManager.TOP) ||
881         position.equals(DockableWindowManager.BOTTOM))
882       {
883         if(dimension != 0 && height <= SPLITTER_WIDTH)
884           PanelWindowContainer.this.show(null);
885         else
886           dimension = height - SPLITTER_WIDTH;
887       }
888       else
889       {
890         if(dimension != 0 && width <= SPLITTER_WIDTH)
891           PanelWindowContainer.this.show(null);
892         else
893           dimension = width - SPLITTER_WIDTH;
894       }
895 
896       super.setBounds(x,y,width,height);
897     } //}}}
898 
899     //{{{ ResizeMouseHandler class
900     class ResizeMouseHandler extends MouseAdapter implements MouseMotionListener
901     {
902       boolean canDrag;
903       Point dragStart;
904 
905       //{{{ mousePressed() method
906       public void mousePressed(MouseEvent evt)
907       {
908         if(canDrag)
909         {
910           wm.resizePos = dimension;
911           wm.setResizePos(PanelWindowContainer.this);
912           dragStart = evt.getPoint();
913         }
914       } //}}}
915 
916       //{{{ mouseReleased() method
917       public void mouseReleased(MouseEvent evt)
918       {
919         if(canDrag)
920         {
921           dimension = wm.resizePos;
922           wm.finishResizing();
923           dragStart = null;
924           wm.revalidate();
925         }
926       } //}}}
927 
928       //{{{ mouseMoved() method
929       public void mouseMoved(MouseEvent evt)
930       {
931         Border border = getBorder();
932         if(border == null)
933         {
934           // collapsed
935           return;
936         }
937 
938         Insets insets = border.getBorderInsets(DockablePanel.this);
939         canDrag = false;
940         //{{{ Top...
941         if(position.equals(DockableWindowManager.TOP))
942         {
943           if(evt.getY() >= getHeight() - insets.bottom)
944             canDrag = true;
945         } //}}}
946         //{{{ Left...
947         else if(position.equals(DockableWindowManager.LEFT))
948         {
949           if(evt.getX() >= getWidth() - insets.right)
950             canDrag = true;
951         } //}}}
952         //{{{ Bottom...
953         else if(position.equals(DockableWindowManager.BOTTOM))
954         {
955           if(evt.getY() <= insets.top)
956             canDrag = true;
957         } //}}}
958         //{{{ Right...
959         else if(position.equals(DockableWindowManager.RIGHT))
960         {
961           if(evt.getX() <= insets.left)
962             canDrag = true;
963         } //}}}
964 
965         if(canDrag)
966         {
967           wm.setCursor(Cursor.getPredefinedCursor(
968             getAppropriateCursor()));
969         }
970         else
971         {
972           wm.setCursor(Cursor.getPredefinedCursor(
973             Cursor.DEFAULT_CURSOR));
974         }
975       } //}}}
976 
977       //{{{ mouseDragged() method
978       public void mouseDragged(MouseEvent evt)
979       {
980         if(!canDrag)
981           return;
982 
983         if(dragStart == null) // can't happen?
984           return;
985 
986         wm.setCursor(Cursor.getPredefinedCursor(
987           getAppropriateCursor()));
988 
989         //{{{ Top...
990         if(position.equals(DockableWindowManager.TOP))
991         {
992           wm.resizePos = evt.getY() - dragStart.y + dimension;
993           wm.setResizePos(PanelWindowContainer.this);
994         } //}}}
995         //{{{ Left...
996         else if(position.equals(DockableWindowManager.LEFT))
997         {
998           wm.resizePos = evt.getX() - dragStart.x + dimension;
999           wm.setResizePos(PanelWindowContainer.this);
1000        } //}}}
1001        //{{{ Bottom...
1002        else if(position.equals(DockableWindowManager.BOTTOM))
1003        {
1004          wm.resizePos = (dimension - evt.getY() + dragStart.y);
1005          wm.setResizePos(PanelWindowContainer.this);
1006        } //}}}
1007        //{{{ Right...
1008        else if(position.equals(DockableWindowManager.RIGHT))
1009        {
1010          wm.resizePos = (dimension - evt.getX() + dragStart.x);
1011          wm.setResizePos(PanelWindowContainer.this);
1012        } //}}}
1013      } //}}}
1014
1015      //{{{ mouseExited() method
1016      public void mouseExited(MouseEvent evt)
1017      {
1018        wm.setCursor(Cursor.getPredefinedCursor(
1019          Cursor.DEFAULT_CURSOR));
1020      } //}}}
1021
1022      //{{{ getCursor() method
1023      private int getAppropriateCursor()
1024      {
1025        if(position.equals(DockableWindowManager.TOP))
1026          return Cursor.N_RESIZE_CURSOR;
1027        else if(position.equals(DockableWindowManager.LEFT))
1028          return Cursor.W_RESIZE_CURSOR;
1029        else if(position.equals(DockableWindowManager.BOTTOM))
1030          return Cursor.S_RESIZE_CURSOR;
1031        else if(position.equals(DockableWindowManager.RIGHT))
1032          return Cursor.E_RESIZE_CURSOR;
1033        else
1034          throw new InternalError();
1035      } //}}}
1036    } //}}}
1037  } //}}}
1038
1039  //}}}
1040}