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}