PageRenderTime 203ms CodeModel.GetById 124ms app.highlight 68ms RepoModel.GetById 2ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/gui/PanelWindowContainer.java

#
Java | 1130 lines | 860 code | 130 blank | 140 comment | 159 complexity | 7602fa35c0ad2c1a712be275106966aa MD5 | raw file
   1/*
   2 * PanelWindowContainer.java - holds dockable windows
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 2000, 2004 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
  23package org.gjt.sp.jedit.gui;
  24
  25//{{{ Imports
  26import javax.swing.border.*;
  27import javax.swing.plaf.metal.*;
  28import javax.swing.*;
  29import java.awt.event.*;
  30import java.awt.font.*;
  31import java.awt.geom.AffineTransform;
  32import java.awt.*;
  33import java.util.*;
  34import 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 4997 2004-03-19 22:42:21Z spestov $
  42 * @since jEdit 4.0pre1
  43 */
  44public 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(1,1,1,1));
 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			buttonPanel.repaint();
 149		}
 150	} //}}}
 151
 152	//{{{ remove() method
 153	public void remove(final DockableWindowManager.Entry entry)
 154	{
 155		if(entry.factory.name.equals(mostRecent))
 156			mostRecent = null;
 157
 158		if(entry.win != null)
 159		{
 160			dockablePanel.remove(entry.win);
 161			entry.win = null;
 162		}
 163
 164		if(current == entry)
 165		{
 166			current = null;
 167			show(null);
 168		}
 169		else
 170		{
 171			wm.revalidate();
 172			dockablePanel.repaint();
 173		}
 174	} //}}}
 175
 176	//{{{ showMostRecent() method
 177	public void showMostRecent()
 178	{
 179		if(dockables.size() == 0)
 180		{
 181			Toolkit.getDefaultToolkit().beep();
 182			return;
 183		}
 184
 185		if(mostRecent == null)
 186		{
 187			mostRecent = ((DockableWindowManager.Entry)
 188				dockables.get(0)).factory.name;
 189		}
 190
 191		wm.showDockableWindow(mostRecent);
 192	} //}}}
 193
 194	//{{{ show() method
 195	public void show(final DockableWindowManager.Entry entry)
 196	{
 197		if(current == entry)
 198		{
 199			if(entry != null)
 200			{
 201				if(entry.win instanceof DefaultFocusComponent)
 202				{
 203					((DefaultFocusComponent)entry.win)
 204						.focusOnDefaultComponent();
 205				}
 206				else
 207				{
 208					entry.win.requestDefaultFocus();
 209				}
 210			}
 211			return;
 212		}
 213
 214		if(entry != null)
 215		{
 216			if(current == null)
 217			{
 218				// we didn't have a component previously, so
 219				// create a border
 220				dockablePanel.setBorder(new DockBorder(position));
 221			}
 222
 223			mostRecent = entry.factory.name;
 224			this.current = entry;
 225
 226			if(entry.win.getParent() != dockablePanel)
 227				dockablePanel.add(entry.factory.name,entry.win);
 228
 229			dockablePanel.showDockable(entry.factory.name);
 230
 231			entry.btn.setSelected(true);
 232
 233			if(entry.win instanceof DefaultFocusComponent)
 234			{
 235				((DefaultFocusComponent)entry.win)
 236					.focusOnDefaultComponent();
 237			}
 238			else
 239			{
 240				entry.win.requestDefaultFocus();
 241			}
 242		}
 243		else
 244		{
 245			current = null;
 246			nullButton.setSelected(true);
 247			// removing last component, so remove border
 248			dockablePanel.setBorder(null);
 249
 250			wm.getView().getTextArea().requestFocus();
 251		}
 252
 253		wm.revalidate();
 254		dockablePanel.repaint();
 255	} //}}}
 256
 257	//{{{ isVisible() method
 258	public boolean isVisible(DockableWindowManager.Entry entry)
 259	{
 260		return current == entry;
 261	} //}}}
 262
 263	//{{{ getCurrent() method
 264	/**
 265	 * Returns the name of the dockable in this container.
 266	 * @since jEdit 4.2pre1
 267	 */
 268	public String getCurrent()
 269	{
 270		if(current == null)
 271			return null;
 272		else
 273			return current.factory.name;
 274	} //}}}
 275
 276	//{{{ getDimension() method
 277	/**
 278	 * Returns the width or height (depending on position) of the dockable
 279	 * window container.
 280	 * @since jEdit 4.2pre1
 281	 */
 282	public int getDimension()
 283	{
 284		return dimension;
 285	} //}}}
 286
 287	//{{{ getDockables() method
 288	public String[] getDockables()
 289	{
 290		String[] retVal = new String[dockables.size()];
 291		for(int i = 0; i < dockables.size(); i++)
 292		{
 293			DockableWindowManager.Entry entry =
 294				(DockableWindowManager.Entry) dockables.get(i);
 295			retVal[i] = entry.factory.name;
 296		}
 297		return retVal;
 298	} //}}}
 299
 300	//{{{ Package-private members
 301	static final int SPLITTER_WIDTH = 10;
 302	DockablePanel dockablePanel;
 303	JPanel buttonPanel;
 304
 305	//{{{ save() method
 306	void save()
 307	{
 308		jEdit.setIntegerProperty("view.dock." + position + ".dimension",
 309			dimension);
 310		if(current == null)
 311			jEdit.unsetProperty("view.dock." + position + ".last");
 312		else
 313		{
 314			jEdit.setProperty("view.dock." + position + ".last",
 315				current.factory.name);
 316		}
 317	} //}}}
 318
 319	//{{{ setDimension() method
 320	void setDimension(int dimension)
 321	{
 322		if(dimension != 0)
 323			this.dimension = dimension - SPLITTER_WIDTH;
 324	} //}}}
 325
 326	//{{{ sortDockables() method
 327	void sortDockables()
 328	{
 329		buttonPanel.removeAll();
 330		buttonPanel.add(closeBox);
 331		buttonPanel.add(menuBtn);
 332		Collections.sort(buttons,new DockableWindowCompare());
 333		for(int i = 0; i < buttons.size(); i++)
 334		{
 335			buttonPanel.add((AbstractButton)buttons.get(i));
 336		}
 337	} //}}}
 338
 339	//{{{ getWrappedDimension() method
 340	/**
 341	 * Returns the width or height of wrapped rows or columns.
 342	 */
 343	int getWrappedDimension(int dimension)
 344	{
 345		return ((ButtonLayout)buttonPanel.getLayout())
 346			.getWrappedDimension(buttonPanel,dimension);
 347	} //}}}
 348
 349	//}}}
 350
 351	//{{{ Private members
 352	private DockableWindowManager wm;
 353	private String position;
 354	private JButton closeBox;
 355	private JButton menuBtn;
 356	private ButtonGroup buttonGroup;
 357	private JToggleButton nullButton;
 358	private int dimension;
 359	private ArrayList dockables;
 360	private ArrayList buttons;
 361	private DockableWindowManager.Entry current;
 362	private JPopupMenu popup;
 363
 364	// remember the most recent dockable
 365	private String mostRecent;
 366	//}}}
 367
 368	//{{{ Inner classes
 369
 370	//{{{ DockableWindowCompare class
 371	static class DockableWindowCompare implements Comparator
 372	{
 373		public int compare(Object o1, Object o2)
 374		{
 375			String name1 = ((AbstractButton)o1).getActionCommand();
 376			String name2 = ((AbstractButton)o2).getActionCommand();
 377			return MiscUtilities.compareStrings(
 378				jEdit.getProperty(name1 + ".title",""),
 379				jEdit.getProperty(name2 + ".title",""),
 380				true);
 381		}
 382	} //}}}
 383
 384	//{{{ ActionHandler class
 385	class ActionHandler implements ActionListener
 386	{
 387		public void actionPerformed(ActionEvent evt)
 388		{
 389			if(popup != null && popup.isVisible())
 390				popup.setVisible(false);
 391
 392			if(evt.getSource() == closeBox)
 393				show(null);
 394			else
 395			{
 396				if(wm.isDockableWindowVisible(evt.getActionCommand()))
 397					show(null);
 398				else
 399					wm.showDockableWindow(evt.getActionCommand());
 400			}
 401		}
 402	} //}}}
 403
 404	//{{{ MenuMouseHandler class
 405	class MenuMouseHandler extends MouseAdapter
 406	{
 407		public void mousePressed(MouseEvent evt)
 408		{
 409			if(popup != null && popup.isVisible())
 410			{
 411				popup.setVisible(false);
 412				return;
 413			}
 414
 415			Component comp = (Component)evt.getSource();
 416			String dockable;
 417			if(comp instanceof JToggleButton)
 418				dockable = ((JToggleButton)comp).getActionCommand();
 419			else
 420				dockable = getCurrent();
 421
 422			if(comp == menuBtn || GUIUtilities.isPopupTrigger(evt))
 423			{
 424				if(dockable == null)
 425				{
 426					popup = wm.createPopupMenu(PanelWindowContainer.this,null,false);
 427				}
 428				else
 429				{
 430					popup = wm.createPopupMenu(PanelWindowContainer.this,dockable,false);
 431				}
 432
 433				int x, y;
 434				boolean point;
 435				if(comp == menuBtn)
 436				{
 437					x = 0;
 438					y = menuBtn.getHeight();
 439					point = false;
 440				}
 441				else
 442				{
 443					x = evt.getX();
 444					y = evt.getY();
 445					point = true;
 446				}
 447				GUIUtilities.showPopupMenu(popup,
 448					comp,x,y,point);
 449			}
 450		}
 451	} //}}}
 452
 453	//{{{ DockBorder class
 454	static class DockBorder implements Border
 455	{
 456		String position;
 457		Insets insets;
 458		Color color1;
 459		Color color2;
 460		Color color3;
 461
 462		//{{{ DockBorder constructor
 463		DockBorder(String position)
 464		{
 465			this.position = position;
 466			insets = new Insets(
 467				position.equals(DockableWindowManager.BOTTOM)
 468					? SPLITTER_WIDTH : 0,
 469				position.equals(DockableWindowManager.RIGHT)
 470					? SPLITTER_WIDTH : 0,
 471				position.equals(DockableWindowManager.TOP)
 472					? SPLITTER_WIDTH : 0,
 473				position.equals(DockableWindowManager.LEFT)
 474					? SPLITTER_WIDTH : 0);
 475		} //}}}
 476
 477		//{{{ paintBorder() method
 478		public void paintBorder(Component c, Graphics g,
 479			int x, int y, int width, int height)
 480		{
 481			updateColors();
 482
 483			if(color1 == null || color2 == null || color3 == null)
 484				return;
 485
 486			if(position.equals(DockableWindowManager.BOTTOM))
 487				paintHorizBorder(g,x,y,width);
 488			else if(position.equals(DockableWindowManager.RIGHT))
 489				paintVertBorder(g,x,y,height);
 490			else if(position.equals(DockableWindowManager.TOP))
 491			{
 492				paintHorizBorder(g,x,y + height
 493					- SPLITTER_WIDTH,width);
 494			}
 495			else if(position.equals(DockableWindowManager.LEFT))
 496			{
 497				paintVertBorder(g,x + width
 498					- SPLITTER_WIDTH,y,height);
 499			}
 500		} //}}}
 501
 502		//{{{ getBorderInsets() method
 503		public Insets getBorderInsets(Component c)
 504		{
 505			return insets;
 506		} //}}}
 507
 508		//{{{ isBorderOpaque() method
 509		public boolean isBorderOpaque()
 510		{
 511			return false;
 512		} //}}}
 513
 514		//{{{ paintHorizBorder() method
 515		private void paintHorizBorder(Graphics g, int x, int y, int width)
 516		{
 517			g.setColor(color3);
 518			g.fillRect(x,y,width,SPLITTER_WIDTH);
 519
 520			for(int i = 0; i < width / 4 - 1; i++)
 521			{
 522				g.setColor(color1);
 523				g.drawLine(x + i * 4 + 2,y + 3,
 524					x + i * 4 + 2,y + 3);
 525				g.setColor(color2);
 526				g.drawLine(x + i * 4 + 3,y + 4,
 527					x + i * 4 + 3,y + 4);
 528				g.setColor(color1);
 529				g.drawLine(x + i * 4 + 4,y + 5,
 530					x + i * 4 + 4,y + 5);
 531				g.setColor(color2);
 532				g.drawLine(x + i * 4 + 5,y + 6,
 533					x + i * 4 + 5,y + 6);
 534			}
 535		} //}}}
 536
 537		//{{{ paintVertBorder() method
 538		private void paintVertBorder(Graphics g, int x, int y, int height)
 539		{
 540			g.setColor(color3);
 541			g.fillRect(x,y,SPLITTER_WIDTH,height);
 542
 543			for(int i = 0; i < height / 4 - 1; i++)
 544			{
 545				g.setColor(color1);
 546				g.drawLine(x + 3,y + i * 4 + 2,
 547					x + 3,y + i * 4 + 2);
 548				g.setColor(color2);
 549				g.drawLine(x + 4,y + i * 4 + 3,
 550					x + 4,y + i * 4 + 3);
 551				g.setColor(color1);
 552				g.drawLine(x + 5,y + i * 4 + 4,
 553					x + 5,y + i * 4 + 4);
 554				g.setColor(color2);
 555				g.drawLine(x + 6,y + i * 4 + 5,
 556					x + 6,y + i * 4 + 5);
 557			}
 558		} //}}}
 559
 560		//{{{ updateColors() method
 561		private void updateColors()
 562		{
 563			if(UIManager.getLookAndFeel() instanceof MetalLookAndFeel)
 564			{
 565				color1 = MetalLookAndFeel.getControlHighlight();
 566				color2 = MetalLookAndFeel.getControlDarkShadow();
 567				color3 = MetalLookAndFeel.getControl();
 568			}
 569			else
 570			{
 571				color1 = color2 = color3 = null;
 572			}
 573		} //}}}
 574	} //}}}
 575
 576	//{{{ RotatedTextIcon class
 577	public static class RotatedTextIcon implements Icon
 578	{
 579		public static final int NONE = 0;
 580		public static final int CW = 1;
 581		public static final int CCW = 2;
 582
 583		//{{{ RotatedTextIcon constructor
 584		public RotatedTextIcon(int rotate, Font font, String text)
 585		{
 586			this.rotate = rotate;
 587			this.font = font;
 588
 589			FontRenderContext fontRenderContext
 590				= new FontRenderContext(null,true,true);
 591			this.text = text;
 592			glyphs = font.createGlyphVector(fontRenderContext,text);
 593			width = (int)glyphs.getLogicalBounds().getWidth() + 4;
 594			//height = (int)glyphs.getLogicalBounds().getHeight();
 595
 596			LineMetrics lineMetrics = font.getLineMetrics(text,fontRenderContext);
 597			ascent = lineMetrics.getAscent();
 598			height = (int)lineMetrics.getHeight();
 599
 600			renderHints = new RenderingHints(
 601				RenderingHints.KEY_ANTIALIASING,
 602				RenderingHints.VALUE_ANTIALIAS_ON);
 603			renderHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
 604				RenderingHints.VALUE_FRACTIONALMETRICS_ON);
 605			renderHints.put(RenderingHints.KEY_RENDERING,
 606				RenderingHints.VALUE_RENDER_QUALITY);
 607		} //}}}
 608
 609		//{{{ getIconWidth() method
 610		public int getIconWidth()
 611		{
 612			return (int)(rotate == RotatedTextIcon.CW
 613				|| rotate == RotatedTextIcon.CCW
 614				? height : width);
 615		} //}}}
 616
 617		//{{{ getIconHeight() method
 618		public int getIconHeight()
 619		{
 620			return (int)(rotate == RotatedTextIcon.CW
 621				|| rotate == RotatedTextIcon.CCW
 622				? width : height);
 623		} //}}}
 624
 625		//{{{ paintIcon() method
 626		public void paintIcon(Component c, Graphics g, int x, int y)
 627		{
 628			Graphics2D g2d = (Graphics2D)g;
 629			g2d.setFont(font);
 630			AffineTransform oldTransform = g2d.getTransform();
 631			RenderingHints oldHints = g2d.getRenderingHints();
 632
 633			g2d.setRenderingHints(renderHints);
 634			g2d.setColor(c.getForeground());
 635
 636			//{{{ No rotation
 637			if(rotate == RotatedTextIcon.NONE)
 638			{
 639				g2d.drawGlyphVector(glyphs,x + 2,y + ascent);
 640			} //}}}
 641			//{{{ Clockwise rotation
 642			else if(rotate == RotatedTextIcon.CW)
 643			{
 644				AffineTransform trans = new AffineTransform();
 645				trans.concatenate(oldTransform);
 646				trans.translate(x,y + 2);
 647				trans.rotate(Math.PI / 2,
 648					height / 2, width / 2);
 649				g2d.setTransform(trans);
 650				g2d.drawGlyphVector(glyphs,(height - width) / 2,
 651					(width - height) / 2
 652					+ ascent);
 653			} //}}}
 654			//{{{ Counterclockwise rotation
 655			else if(rotate == RotatedTextIcon.CCW)
 656			{
 657				AffineTransform trans = new AffineTransform();
 658				trans.concatenate(oldTransform);
 659				trans.translate(x,y - 2);
 660				trans.rotate(Math.PI * 3 / 2,
 661					height / 2, width / 2);
 662				g2d.setTransform(trans);
 663				g2d.drawGlyphVector(glyphs,(height - width) / 2,
 664					(width - height) / 2
 665					+ ascent);
 666			} //}}}
 667
 668			g2d.setTransform(oldTransform);
 669			g2d.setRenderingHints(oldHints);
 670		} //}}}
 671
 672		//{{{ Private members
 673		private int rotate;
 674		private Font font;
 675		private String text;
 676		private GlyphVector glyphs;
 677		private float width;
 678		private float height;
 679		private float ascent;
 680		private RenderingHints renderHints;
 681		//}}}
 682	} //}}}
 683
 684	//{{{ ButtonLayout class
 685	class ButtonLayout implements LayoutManager
 686	{
 687		//{{{ addLayoutComponent() method
 688		public void addLayoutComponent(String name, Component comp) {} //}}}
 689
 690		//{{{ removeLayoutComponent() method
 691		public void removeLayoutComponent(Component comp) {} //}}}
 692
 693		//{{{ getWrappedDimension() method
 694		/**
 695		 * Returns the width or height of wrapped rows or columns.
 696		 */
 697		int getWrappedDimension(JComponent parent, int dimension)
 698		{
 699			Insets insets = ((JComponent)parent).getBorder()
 700				.getBorderInsets((JComponent)parent);
 701
 702			Component[] comp = parent.getComponents();
 703			if(comp.length <= 2)
 704				return 0;
 705
 706			Dimension dim = comp[2].getPreferredSize();
 707
 708			if(position.equals(DockableWindowManager.TOP)
 709				|| position.equals(DockableWindowManager.BOTTOM))
 710			{
 711				int width = dimension - insets.right;
 712				int rowHeight = Math.max(dim.height,closeBox.getPreferredSize().width);
 713				int x = rowHeight * 2 + insets.left;
 714				Dimension returnValue = new Dimension(0,rowHeight
 715					+ insets.top + insets.bottom);
 716
 717				for(int i = 2; i < comp.length; i++)
 718				{
 719					int btnWidth = comp[i].getPreferredSize().width;
 720					if(btnWidth + x > width)
 721					{
 722						returnValue.height += rowHeight;
 723						x = insets.left;
 724					}
 725
 726					x += btnWidth;
 727				}
 728				return returnValue.height;
 729			}
 730			else
 731			{
 732				int height = dimension - insets.bottom;
 733				int colWidth = Math.max(dim.width,closeBox.getPreferredSize().height);
 734				int y = colWidth * 2 + insets.top;
 735				Dimension returnValue = new Dimension(colWidth
 736					+ insets.left + insets.right,0);
 737
 738				for(int i = 2; i < comp.length; i++)
 739				{
 740					int btnHeight = comp[i].getPreferredSize().height;
 741					if(btnHeight + y > height)
 742					{
 743						returnValue.width += colWidth;
 744						y = insets.top;
 745					}
 746
 747					y += btnHeight;
 748				}
 749				return returnValue.width;
 750			}
 751		} //}}}
 752
 753		//{{{ preferredLayoutSize() method
 754		public Dimension preferredLayoutSize(Container parent)
 755		{
 756			Insets insets = ((JComponent)parent).getBorder()
 757				.getBorderInsets((JComponent)parent);
 758
 759			Component[] comp = parent.getComponents();
 760			if(comp.length <= 2)
 761			{
 762				// nothing 'cept close box
 763				return new Dimension(0,0);
 764			}
 765
 766			Dimension dim = comp[2].getPreferredSize();
 767
 768			if(position.equals(DockableWindowManager.TOP)
 769				|| position.equals(DockableWindowManager.BOTTOM))
 770			{
 771				int width = parent.getWidth() - insets.right;
 772				int rowHeight = Math.max(dim.height,closeBox.getPreferredSize().width);
 773				int x = rowHeight * 2 + insets.left;
 774				Dimension returnValue = new Dimension(0,rowHeight
 775					+ insets.top + insets.bottom);
 776
 777				for(int i = 2; i < comp.length; i++)
 778				{
 779					int btnWidth = comp[i].getPreferredSize().width;
 780					if(btnWidth + x > width)
 781					{
 782						returnValue.height += rowHeight;
 783						x = insets.left;
 784					}
 785
 786					x += btnWidth;
 787				}
 788				return returnValue;
 789			}
 790			else
 791			{
 792				int height = parent.getHeight() - insets.bottom;
 793				int colWidth = Math.max(dim.width,closeBox.getPreferredSize().height);
 794				int y = colWidth * 2 + insets.top;
 795				Dimension returnValue = new Dimension(colWidth
 796					+ insets.left + insets.right,0);
 797
 798				for(int i = 2; i < comp.length; i++)
 799				{
 800					int btnHeight = comp[i].getPreferredSize().height;
 801					if(btnHeight + y > height)
 802					{
 803						returnValue.width += colWidth;
 804						y = insets.top;
 805					}
 806
 807					y += btnHeight;
 808				}
 809				return returnValue;
 810			}
 811		} //}}}
 812
 813		//{{{ minimumLayoutSize() method
 814		public Dimension minimumLayoutSize(Container parent)
 815		{
 816			return preferredLayoutSize(parent);
 817		} //}}}
 818
 819		//{{{ layoutContainer() method
 820		public void layoutContainer(Container parent)
 821		{
 822			Insets insets = ((JComponent)parent).getBorder()
 823				.getBorderInsets((JComponent)parent);
 824
 825			Component[] comp = parent.getComponents();
 826			if(comp.length <= 2)
 827			{
 828				for(int i = 0; i < comp.length; i++)
 829				{
 830					comp[i].setVisible(false);
 831				}
 832				return;
 833			}
 834
 835			comp[0].setVisible(true);
 836			comp[1].setVisible(true);
 837
 838			Dimension dim = comp[2].getPreferredSize();
 839
 840			if(position.equals(DockableWindowManager.TOP)
 841				|| position.equals(DockableWindowManager.BOTTOM))
 842			{
 843				int width = parent.getWidth() - insets.right;
 844				int rowHeight = Math.max(dim.height,closeBox.getPreferredSize().width);
 845				int x = rowHeight * 2 + insets.left;
 846				int y = insets.top;
 847				closeBox.setBounds(insets.left,insets.top,rowHeight,rowHeight);
 848				menuBtn.setBounds(insets.left + rowHeight,insets.top,rowHeight,rowHeight);
 849
 850				for(int i = 2; i < comp.length; i++)
 851				{
 852					int btnWidth = comp[i].getPreferredSize().width;
 853					if(btnWidth + x > width)
 854					{
 855						x = insets.left;
 856						y += rowHeight;
 857					}
 858					comp[i].setBounds(x,y,btnWidth,rowHeight);
 859					x += btnWidth;
 860				}
 861
 862				/* if(y + rowHeight != parent.getHeight())
 863				{
 864					parent.setSize(
 865						parent.getWidth(),
 866						y + rowHeight);
 867					((JComponent)parent).revalidate();
 868				} */
 869			}
 870			else
 871			{
 872				int height = parent.getHeight() - insets.bottom;
 873				int colWidth = Math.max(dim.width,closeBox.getPreferredSize().height);
 874				int x = insets.left;
 875				int y = colWidth * 2 + insets.top;
 876				closeBox.setBounds(insets.left,insets.top,colWidth,colWidth);
 877				menuBtn.setBounds(insets.left,insets.top + colWidth,colWidth,colWidth);
 878
 879				for(int i = 2; i < comp.length; i++)
 880				{
 881					int btnHeight = comp[i].getPreferredSize().height;
 882					if(btnHeight + y > height)
 883					{
 884						x += colWidth;
 885						y = insets.top;
 886					}
 887					comp[i].setBounds(x,y,colWidth,btnHeight);
 888					y += btnHeight;
 889				}
 890
 891				/* if(x + colWidth != parent.getWidth())
 892				{
 893					parent.setSize(x + colWidth,
 894						parent.getHeight());
 895					((JComponent)parent).revalidate();
 896				} */
 897			}
 898		} //}}}
 899	} //}}}
 900
 901	//{{{ DockablePanel class
 902	class DockablePanel extends JPanel
 903	{
 904		//{{{ DockablePanel constructor
 905		DockablePanel()
 906		{
 907			super(new CardLayout());
 908
 909			ResizeMouseHandler resizeMouseHandler = new ResizeMouseHandler();
 910			addMouseListener(resizeMouseHandler);
 911			addMouseMotionListener(resizeMouseHandler);
 912		} //}}}
 913
 914		//{{{ getWindowContainer() method
 915		PanelWindowContainer getWindowContainer()
 916		{
 917			return PanelWindowContainer.this;
 918		} //}}}
 919
 920		//{{{ showDockable() method
 921		void showDockable(String name)
 922		{
 923			((CardLayout)getLayout()).show(this,name);
 924		} //}}}
 925
 926		//{{{ getMinimumSize() method
 927		public Dimension getMinimumSize()
 928		{
 929			return new Dimension(0,0);
 930		} //}}}
 931
 932		//{{{ getPreferredSize() method
 933		public Dimension getPreferredSize()
 934		{
 935			if(current == null)
 936				return new Dimension(0,0);
 937			else
 938			{
 939				if(position.equals(DockableWindowManager.TOP)
 940					|| position.equals(DockableWindowManager.BOTTOM))
 941				{
 942					if(dimension <= 0)
 943					{
 944						int height = super.getPreferredSize().height;
 945						dimension = height - SPLITTER_WIDTH;
 946					}
 947					return new Dimension(0,
 948						dimension + SPLITTER_WIDTH);
 949				}
 950				else
 951				{
 952					if(dimension <= 0)
 953					{
 954						int width = super.getPreferredSize().width;
 955						dimension = width - SPLITTER_WIDTH;
 956					}
 957					return new Dimension(dimension + SPLITTER_WIDTH,
 958						0);
 959				}
 960			}
 961		} //}}}
 962
 963		//{{{ setBounds() method
 964		public void setBounds(int x, int y, int width, int height)
 965		{
 966			if(position.equals(DockableWindowManager.TOP) ||
 967				position.equals(DockableWindowManager.BOTTOM))
 968			{
 969				if(dimension != 0 && height <= SPLITTER_WIDTH)
 970					PanelWindowContainer.this.show(null);
 971				else
 972					dimension = height - SPLITTER_WIDTH;
 973			}
 974			else
 975			{
 976				if(dimension != 0 && width <= SPLITTER_WIDTH)
 977					PanelWindowContainer.this.show(null);
 978				else
 979					dimension = width - SPLITTER_WIDTH;
 980			}
 981
 982			super.setBounds(x,y,width,height);
 983		} //}}}
 984
 985		//{{{ ResizeMouseHandler class
 986		class ResizeMouseHandler extends MouseAdapter implements MouseMotionListener
 987		{
 988			boolean canDrag;
 989			Point dragStart;
 990
 991			//{{{ mousePressed() method
 992			public void mousePressed(MouseEvent evt)
 993			{
 994				if(canDrag)
 995				{
 996					wm.setResizePos(dimension,PanelWindowContainer.this);
 997					dragStart = evt.getPoint();
 998				}
 999			} //}}}
1000
1001			//{{{ mouseReleased() method
1002			public void mouseReleased(MouseEvent evt)
1003			{
1004				if(canDrag)
1005				{
1006					dimension = wm.resizePos;
1007					wm.finishResizing();
1008					dragStart = null;
1009					wm.revalidate();
1010				}
1011			} //}}}
1012
1013			//{{{ mouseMoved() method
1014			public void mouseMoved(MouseEvent evt)
1015			{
1016				Border border = getBorder();
1017				if(border == null)
1018				{
1019					// collapsed
1020					return;
1021				}
1022
1023				Insets insets = border.getBorderInsets(DockablePanel.this);
1024				canDrag = false;
1025				//{{{ Top...
1026				if(position.equals(DockableWindowManager.TOP))
1027				{
1028					if(evt.getY() >= getHeight() - insets.bottom)
1029						canDrag = true;
1030				} //}}}
1031				//{{{ Left...
1032				else if(position.equals(DockableWindowManager.LEFT))
1033				{
1034					if(evt.getX() >= getWidth() - insets.right)
1035						canDrag = true;
1036				} //}}}
1037				//{{{ Bottom...
1038				else if(position.equals(DockableWindowManager.BOTTOM))
1039				{
1040					if(evt.getY() <= insets.top)
1041						canDrag = true;
1042				} //}}}
1043				//{{{ Right...
1044				else if(position.equals(DockableWindowManager.RIGHT))
1045				{
1046					if(evt.getX() <= insets.left)
1047						canDrag = true;
1048				} //}}}
1049
1050				if(canDrag)
1051				{
1052					wm.setCursor(Cursor.getPredefinedCursor(
1053						getAppropriateCursor()));
1054				}
1055				else
1056				{
1057					wm.setCursor(Cursor.getPredefinedCursor(
1058						Cursor.DEFAULT_CURSOR));
1059				}
1060			} //}}}
1061
1062			//{{{ mouseDragged() method
1063			public void mouseDragged(MouseEvent evt)
1064			{
1065				if(!canDrag)
1066					return;
1067
1068				if(dragStart == null) // can't happen?
1069					return;
1070
1071				wm.setCursor(Cursor.getPredefinedCursor(
1072					getAppropriateCursor()));
1073
1074				//{{{ Top...
1075				if(position.equals(DockableWindowManager.TOP))
1076				{
1077					wm.setResizePos(
1078						evt.getY() - dragStart.y
1079						+ dimension,
1080						PanelWindowContainer.this);
1081				} //}}}
1082				//{{{ Left...
1083				else if(position.equals(DockableWindowManager.LEFT))
1084				{
1085					wm.setResizePos(evt.getX() - dragStart.x
1086						+ dimension,
1087						PanelWindowContainer.this);
1088				} //}}}
1089				//{{{ Bottom...
1090				else if(position.equals(DockableWindowManager.BOTTOM))
1091				{
1092					wm.setResizePos(dimension - evt.getY()
1093						+ dragStart.y,
1094						PanelWindowContainer.this);
1095				} //}}}
1096				//{{{ Right...
1097				else if(position.equals(DockableWindowManager.RIGHT))
1098				{
1099					wm.setResizePos(dimension - evt.getX()
1100						+ dragStart.x,
1101						PanelWindowContainer.this);
1102				} //}}}
1103			} //}}}
1104
1105			//{{{ mouseExited() method
1106			public void mouseExited(MouseEvent evt)
1107			{
1108				wm.setCursor(Cursor.getPredefinedCursor(
1109					Cursor.DEFAULT_CURSOR));
1110			} //}}}
1111
1112			//{{{ getCursor() method
1113			private int getAppropriateCursor()
1114			{
1115				if(position.equals(DockableWindowManager.TOP))
1116					return Cursor.N_RESIZE_CURSOR;
1117				else if(position.equals(DockableWindowManager.LEFT))
1118					return Cursor.W_RESIZE_CURSOR;
1119				else if(position.equals(DockableWindowManager.BOTTOM))
1120					return Cursor.S_RESIZE_CURSOR;
1121				else if(position.equals(DockableWindowManager.RIGHT))
1122					return Cursor.E_RESIZE_CURSOR;
1123				else
1124					throw new InternalError();
1125			} //}}}
1126		} //}}}
1127	} //}}}
1128
1129	//}}}
1130}