PageRenderTime 188ms CodeModel.GetById 154ms app.highlight 27ms RepoModel.GetById 3ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/gui/DockableWindowManager.java

#
Java | 1001 lines | 620 code | 102 blank | 279 comment | 115 complexity | 019d0dfb602ed8d32d349095a530f2f9 MD5 | raw file
   1/*
   2 * DockableWindowManager.java - manages dockable windows
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 2000, 2005 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 bsh.*;
  27import javax.swing.*;
  28import java.awt.event.*;
  29import java.awt.*;
  30import java.io.*;
  31import java.net.URL;
  32import java.util.*;
  33import org.gjt.sp.jedit.msg.*;
  34import org.gjt.sp.jedit.*;
  35import org.gjt.sp.util.Log;
  36//}}}
  37
  38/**
  39 * The <code>DockableWindowManager</code> keeps track of dockable windows.
  40 * Each {@link org.gjt.sp.jedit.View} has an instance of this class.<p>
  41 *
  42 * <b>dockables.xml:</b><p>
  43 *
  44 * Dockable window definitions are read from <code>dockables.xml</code> files
  45 * contained inside plugin JARs. A dockable definition file has the following
  46 * form:
  47 *
  48 * <pre>&lt;?xml version="1.0"?&gt;
  49 *&lt;!DOCTYPE DOCKABLES SYSTEM "dockables.dtd"&gt;
  50 *&lt;DOCKABLES&gt;
  51 *    &lt;DOCKABLE NAME="name"&gt;
  52 *        // Code to create the dockable
  53 *    &lt;/DOCKABLE&gt;
  54 *&lt;/DOCKABLES&gt;</pre>
  55 *
  56 * More than one <code>&lt;DOCKABLE&gt;<code> tag may be present. The code that
  57 * creates the dockable can reference any BeanShell built-in variable
  58 * (see {@link org.gjt.sp.jedit.BeanShell}), along with a variable
  59 * <code>position</code> whose value is one of
  60 * {@link #FLOATING}, {@link #TOP}, {@link #LEFT}, {@link #BOTTOM},
  61 * and {@link #RIGHT}.<p>
  62 *
  63 * The following properties must be defined for each dockable window:
  64 *
  65 * <ul>
  66 * <li><code><i>name</i>.title</code> - the string to show in the title bar
  67 * of the dockable.</li>
  68 * <li><code><i>name</i>.label</code> - the dockable's menu item label.</li>
  69 * </ul>
  70 *
  71 * A number of actions are automatically created for each dockable window:
  72 *
  73 * <ul>
  74 * <li><code><i>name</i></code> - opens the dockable window.</li>
  75 * <li><code><i>name</i>-toggle</code> - toggles the dockable window's visibility.</li>
  76 * <li><code><i>name</i>-float</code> - opens the dockable window in a new
  77 * floating window.</li>
  78 * </ul>
  79 *
  80 * Note that only the first action needs a <code>label</code> property, the
  81 * rest have automatically-generated labels.
  82 *
  83 * <b>Implementation details:</b><p>
  84 *
  85 * When an instance of this class is initialized by the {@link org.gjt.sp.jedit.View}
  86 * class, it
  87 * iterates through the list of registered dockable windows (from jEdit itself,
  88 * and any loaded plugins) and
  89 * examines options supplied by the user in the <b>Global
  90 * Options</b> dialog box. Any plugins designated for one of the
  91 * four docking positions are displayed.<p>
  92 *
  93 * To create an instance of a dockable window, the <code>DockableWindowManager</code>
  94 * finds and executes the BeanShell code extracted from the appropriate
  95 * <code>dockables.xml</code> file. This code will typically consist of a call
  96 * to the constructor of the dockable window component. The result of the
  97 * BeanShell expression, typically a newly constructed component, is placed
  98 * in a window managed by this class.
  99 *
 100 * @see org.gjt.sp.jedit.View#getDockableWindowManager()
 101 *
 102 * @author Slava Pestov
 103 * @author John Gellene (API documentation)
 104 * @version $Id: DockableWindowManager.java 5519 2006-07-03 17:38:56Z ezust $
 105 * @since jEdit 2.6pre3
 106 */
 107public class DockableWindowManager extends JPanel implements EBComponent
 108{
 109	//{{{ Constants
 110	/**
 111	 * Floating position.
 112	 * @since jEdit 2.6pre3
 113	 */
 114	public static final String FLOATING = "floating";
 115
 116	/**
 117	 * Top position.
 118	 * @since jEdit 2.6pre3
 119	 */
 120	public static final String TOP = "top";
 121
 122	/**
 123	 * Left position.
 124	 * @since jEdit 2.6pre3
 125	 */
 126	public static final String LEFT = "left";
 127
 128	/**
 129	 * Bottom position.
 130	 * @since jEdit 2.6pre3
 131	 */
 132	public static final String BOTTOM = "bottom";
 133
 134	/**
 135	 * Right position.
 136	 * @since jEdit 2.6pre3
 137	 */
 138	public static final String RIGHT = "right";
 139	//}}}
 140
 141	//{{{ getRegisteredDockableWindows() method
 142	/**
 143	 * @since jEdit 4.3pre2
 144	 */
 145	public static String[] getRegisteredDockableWindows()
 146	{
 147		return DockableWindowFactory.getInstance()
 148			.getRegisteredDockableWindows();
 149	} //}}}
 150
 151	//{{{ DockableWindowManager constructor
 152	/**
 153	 * Creates a new dockable window manager.
 154	 * @param view The view
 155	 * @param factory A {@link DockableWindowFactory}, usually
 156	 * <code>DockableWindowFactory.getInstance()</code>.
 157	 * @param config A docking configuration
 158	 * @since jEdit 2.6pre3
 159	 */
 160	public DockableWindowManager(View view, DockableWindowFactory factory,
 161		View.ViewConfig config)
 162	{
 163		setLayout(new DockableLayout());
 164		this.view = view;
 165		this.factory = factory;
 166
 167		windows = new Hashtable();
 168		clones = new ArrayList();
 169
 170		top = new PanelWindowContainer(this,TOP,config.topPos);
 171		left = new PanelWindowContainer(this,LEFT,config.leftPos);
 172		bottom = new PanelWindowContainer(this,BOTTOM,config.bottomPos);
 173		right = new PanelWindowContainer(this,RIGHT,config.rightPos);
 174
 175		add(DockableLayout.TOP_BUTTONS,top.buttonPanel);
 176		add(DockableLayout.LEFT_BUTTONS,left.buttonPanel);
 177		add(DockableLayout.BOTTOM_BUTTONS,bottom.buttonPanel);
 178		add(DockableLayout.RIGHT_BUTTONS,right.buttonPanel);
 179
 180		add(TOP,top.dockablePanel);
 181		add(LEFT,left.dockablePanel);
 182		add(BOTTOM,bottom.dockablePanel);
 183		add(RIGHT,right.dockablePanel);
 184	} //}}}
 185
 186	//{{{ init() method
 187	/**
 188	 * Initialises dockable window manager. Do not call this method directly.
 189	 */
 190	public void init()
 191	{
 192		EditBus.addToBus(this);
 193
 194		Iterator entries = factory.getDockableWindowIterator();
 195
 196		while(entries.hasNext())
 197			addEntry((DockableWindowFactory.Window)entries.next());
 198
 199		propertiesChanged();
 200	} //}}}
 201
 202	//{{{ getView() method
 203	/**
 204	 * Returns this dockable window manager's view.
 205	 * @since jEdit 4.0pre2
 206	 */
 207	public View getView()
 208	{
 209		return view;
 210	} //}}}
 211
 212	//{{{ floatDockableWindow() method
 213	/**
 214	 * Opens a new instance of the specified dockable window in a floating
 215	 * container.
 216	 * @param name The dockable window name
 217	 * @return The new dockable window instance
 218	 * @since jEdit 4.1pre2
 219	 */
 220	public JComponent floatDockableWindow(String name)
 221	{
 222		Entry entry = (Entry)windows.get(name);
 223		if(entry == null)
 224		{
 225			Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
 226			return null;
 227		}
 228		
 229		// create a copy of this dockable window and float it
 230		Entry newEntry = new Entry(entry.factory,FLOATING);
 231		newEntry.win = newEntry.factory.createDockableWindow(view,FLOATING);
 232		if(newEntry.win != null)
 233		{
 234			newEntry.container = new FloatingWindowContainer(this,true);
 235			newEntry.container.register(newEntry);
 236			newEntry.container.show(newEntry);
 237		}
 238
 239		clones.add(newEntry);
 240		return newEntry.win;
 241	} //}}}
 242
 243	//{{{ showDockableWindow() method
 244	/**
 245	 * Opens the specified dockable window.
 246	 * @param name The dockable window name
 247	 * @since jEdit 2.6pre3
 248	 */
 249	public void showDockableWindow(String name)
 250	{
 251		Entry entry = (Entry)windows.get(name);
 252		if(entry == null)
 253		{
 254			Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
 255			return;
 256		}
 257
 258		if(entry.win == null)
 259		{
 260			entry.win = entry.factory.createDockableWindow(
 261				view,entry.position);
 262		}
 263
 264		if(entry.win != null)
 265		{
 266			if(entry.position.equals(FLOATING)
 267				&& entry.container == null)
 268			{
 269				entry.container = new FloatingWindowContainer(
 270					this,view.isPlainView());
 271				entry.container.register(entry);
 272			}
 273
 274			entry.container.show(entry);
 275			Object reason = DockableWindowUpdate.ACTIVATED;
 276			EditBus.send(new DockableWindowUpdate(this, reason, name));
 277		}
 278		else
 279			/* an error occurred */;
 280	} //}}}
 281
 282	//{{{ addDockableWindow() method
 283	/**
 284	 * Opens the specified dockable window. As of jEdit 4.0pre1, has the
 285	 * same effect as calling showDockableWindow().
 286	 * @param name The dockable window name
 287	 * @since jEdit 2.6pre3
 288	 */
 289	public void addDockableWindow(String name)
 290	{
 291		showDockableWindow(name);
 292	} //}}}
 293
 294	//{{{ hideDockableWindow() method
 295	/**
 296	 * Hides the specified dockable window.
 297	 * @param name The dockable window name
 298	 * @since jEdit 2.6pre3
 299	 */
 300	public void hideDockableWindow(String name)
 301	{
 302
 303		Entry entry = (Entry)windows.get(name);
 304		if(entry == null)
 305		{
 306			Log.log(Log.ERROR,this,"Unknown dockable window: " + name);
 307			return;
 308		}
 309
 310
 311
 312		if(entry.win == null)
 313			return;
 314		Object reason = DockableWindowUpdate.DEACTIVATED;
 315		EditBus.send(new DockableWindowUpdate(this, reason, name));
 316
 317		entry.container.show(null);
 318	} //}}}
 319
 320	//{{{ removeDockableWindow() method
 321	/**
 322	 * Hides the specified dockable window. As of jEdit 4.2pre1, has the
 323	 * same effect as calling hideDockableWindow().
 324	 * @param name The dockable window name
 325	 * @since jEdit 4.2pre1
 326	 */
 327	public void removeDockableWindow(String name)
 328	{
 329		hideDockableWindow(name);
 330	} //}}}
 331
 332	//{{{ toggleDockableWindow() method
 333	/**
 334	 * Toggles the visibility of the specified dockable window.
 335	 * @param name The dockable window name
 336	 */
 337	public void toggleDockableWindow(String name)
 338	{
 339		if(isDockableWindowVisible(name))
 340			removeDockableWindow(name);
 341		else
 342			addDockableWindow(name);
 343	} //}}}
 344
 345	//{{{ getDockableWindow() method
 346	/**
 347	 * Returns the specified dockable window.
 348	 *
 349	 * Note that this method
 350	 * will return null if the dockable has not been added yet.
 351	 * Make sure you call {@link #addDockableWindow(String)} first.
 352	 *
 353	 * @param name The name of the dockable window
 354	 * @since jEdit 4.1pre2
 355	 */
 356	public JComponent getDockableWindow(String name)
 357	{
 358		return getDockable(name);
 359	} //}}}
 360
 361	//{{{ getDockable() method
 362	/**
 363	 * Returns the specified dockable window.
 364	 *
 365	 * Note that this method
 366	 * will return null if the dockable has not been added yet.
 367	 * Make sure you call {@link #addDockableWindow(String)} first.
 368	 *
 369	 * For historical reasons, this
 370	 * does the same thing as {@link #getDockableWindow(String)}.
 371	 *
 372	 * @param name The name of the dockable window
 373	 * @since jEdit 4.0pre1
 374	 */
 375	public JComponent getDockable(String name)
 376	{
 377		Entry entry = (Entry)windows.get(name);
 378		if(entry == null || entry.win == null)
 379			return null;
 380		else
 381			return entry.win;
 382	} //}}}
 383
 384	//{{{ getDockableTitle() method
 385	/**
 386	 * Returns the title of the specified dockable window.
 387	 * @param name The name of the dockable window.
 388	 * @since jEdit 4.1pre5
 389	 */
 390	public String getDockableTitle(String name)
 391	{
 392		String title = jEdit.getProperty(name + ".title");
 393		if(title == null)
 394			return "NO TITLE PROPERTY: " + name;
 395		else
 396			return title;
 397	} //}}}
 398
 399	/**
 400	 * Changes the title string of a floating dockable.
 401	 * 
 402	 * @param dockableName the name of the dockable, as specified in the dockables.xml
 403	 * @param newTitle the new title you want to see above it. This is prefixed by the
 404	 *        Dockable's label.
 405	 * @since 4.3pre5
 406	 * 
 407	 */
 408	public void  setDockableTitle(String dockableName, String newTitle) {
 409		String propName = dockableName + ".title";
 410		Entry entry = (Entry)windows.get(dockableName);
 411		String dockLabel = entry.label();
 412		newTitle = dockLabel + ": " + newTitle;
 413		String oldTitle = jEdit.getProperty(propName);
 414		jEdit.setProperty(propName, newTitle);
 415		firePropertyChange(propName, oldTitle, newTitle);
 416	}
 417	
 418	//{{{ isDockableWindowVisible() method
 419	/**
 420	 * Returns if the specified dockable window is visible.
 421	 * @param name The dockable window name
 422	 */
 423	public boolean isDockableWindowVisible(String name)
 424	{
 425		Entry entry = (Entry)windows.get(name);
 426		if(entry == null || entry.win == null)
 427			return false;
 428		else
 429			return entry.container.isVisible(entry);
 430	} //}}}
 431
 432	//{{{ isDockableWindowDocked() method
 433	/**
 434	 * Returns if the specified dockable window is docked into the
 435	 * view.
 436	 * @param name The dockable's name
 437	 * @since jEdit 4.0pre2
 438	 */
 439	public boolean isDockableWindowDocked(String name)
 440	{
 441		Entry entry = (Entry)windows.get(name);
 442		if(entry == null)
 443			return false;
 444		else
 445			return !entry.position.equals(FLOATING);
 446	} //}}}
 447
 448	//{{{ closeCurrentArea() method
 449	/**
 450	 * Closes the currently focused docking area.
 451	 * @since jEdit 4.1pre3
 452	 */
 453	public void closeCurrentArea()
 454	{
 455		// I don't know of any other way to fix this, since invoking this
 456		// command from a menu results in the focus owner being the menu
 457		// until the menu goes away.
 458		SwingUtilities.invokeLater(new Runnable()
 459		{
 460			public void run()
 461			{
 462				Component comp = view.getFocusOwner();
 463				while(comp != null)
 464				{
 465					//System.err.println(comp.getClass());
 466					if(comp instanceof DockablePanel)
 467					{
 468						PanelWindowContainer container =
 469							((DockablePanel)comp)
 470							.getWindowContainer();
 471						container.show(null);
 472						return;
 473					}
 474
 475					comp = comp.getParent();
 476				}
 477
 478				getToolkit().beep();
 479			}
 480		});
 481	} //}}}
 482
 483	//{{{ close() method
 484	/**
 485	 * Called when the view is being closed.
 486	 * @since jEdit 2.6pre3
 487	 */
 488	public void close()
 489	{
 490		EditBus.removeFromBus(this);
 491
 492		Iterator iter = windows.values().iterator();
 493		while(iter.hasNext())
 494		{
 495			Entry entry = (Entry)iter.next();
 496			if(entry.win != null)
 497			{
 498				entry.container.unregister(entry);
 499			}
 500		}
 501
 502		iter = clones.iterator();
 503		while(iter.hasNext())
 504		{
 505			Entry entry = (Entry)iter.next();
 506			if(entry.win != null)
 507			{
 508				entry.container.unregister(entry);
 509			}
 510		}
 511	} //}}}
 512
 513	//{{{ getTopDockingArea() method
 514	public PanelWindowContainer getTopDockingArea()
 515	{
 516		return top;
 517	} //}}}
 518
 519	//{{{ getLeftDockingArea() method
 520	public PanelWindowContainer getLeftDockingArea()
 521	{
 522		return left;
 523	} //}}}
 524
 525	//{{{ getBottomDockingArea() method
 526	public PanelWindowContainer getBottomDockingArea()
 527	{
 528		return bottom;
 529	} //}}}
 530
 531	//{{{ getRightDockingArea() method
 532	public PanelWindowContainer getRightDockingArea()
 533	{
 534		return right;
 535	} //}}}
 536
 537	//{{{ createPopupMenu() method
 538	public JPopupMenu createPopupMenu(
 539		final DockableWindowContainer container,
 540		final String dockable,
 541		final boolean clone)
 542	{
 543		JPopupMenu popup = new JPopupMenu();
 544		if(dockable == null && container instanceof PanelWindowContainer)
 545		{
 546			ActionListener listener = new ActionListener()
 547			{
 548				public void actionPerformed(ActionEvent evt)
 549				{
 550					showDockableWindow(evt.getActionCommand());
 551				}
 552			};
 553
 554			String[] dockables = ((PanelWindowContainer)
 555				container).getDockables();
 556			for(int i = 0; i < dockables.length; i++)
 557			{
 558				String name = dockables[i];
 559				JMenuItem item = new JMenuItem(getDockableTitle(name));
 560				item.setActionCommand(name);
 561				item.addActionListener(listener);
 562				popup.add(item);
 563			}
 564		}
 565		else
 566		{
 567			JMenuItem caption = new JMenuItem(getDockableTitle(dockable));
 568			caption.setEnabled(false);
 569			popup.add(caption);
 570			popup.addSeparator();
 571			String currentPos = jEdit.getProperty(dockable + ".dock-position",FLOATING);
 572			if(!clone)
 573			{
 574				String[] positions = { FLOATING, TOP, LEFT, BOTTOM, RIGHT };
 575				for(int i = 0; i < positions.length; i++)
 576				{
 577					final String pos = positions[i];
 578					if(pos.equals(currentPos))
 579						continue;
 580
 581					JMenuItem moveMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-"
 582						+ pos));
 583
 584					moveMenuItem.addActionListener(new ActionListener()
 585					{
 586						public void actionPerformed(ActionEvent evt)
 587						{
 588							jEdit.setProperty(dockable + ".dock-position",pos);
 589							EditBus.send(new DockableWindowUpdate(
 590								DockableWindowManager.this,
 591								DockableWindowUpdate.PROPERTIES_CHANGED,
 592								null
 593							));
 594							showDockableWindow(dockable);
 595						}
 596					});
 597					popup.add(moveMenuItem);
 598				}
 599
 600				popup.addSeparator();
 601			}
 602
 603			JMenuItem cloneMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-clone"));
 604
 605			cloneMenuItem.addActionListener(new ActionListener()
 606			{
 607				public void actionPerformed(ActionEvent evt)
 608				{
 609					floatDockableWindow(dockable);
 610				}
 611			});
 612			popup.add(cloneMenuItem);
 613
 614			popup.addSeparator();
 615
 616			JMenuItem closeMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-close"));
 617
 618			closeMenuItem.addActionListener(new ActionListener()
 619			{
 620				public void actionPerformed(ActionEvent evt)
 621				{
 622					if(clone)
 623						((FloatingWindowContainer)container).dispose();
 624					else
 625						removeDockableWindow(dockable);
 626				}
 627			});
 628			popup.add(closeMenuItem);
 629
 630			if(!(clone || currentPos.equals(FLOATING)))
 631			{
 632				JMenuItem undockMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-undock"));
 633
 634				undockMenuItem.addActionListener(new ActionListener()
 635				{
 636					public void actionPerformed(ActionEvent evt)
 637					{
 638						jEdit.setProperty(dockable + ".dock-position",FLOATING);
 639						EditBus.send(new DockableWindowUpdate(
 640							DockableWindowManager.this,
 641							DockableWindowUpdate.PROPERTIES_CHANGED,
 642							null
 643						));
 644					}
 645				});
 646				popup.add(undockMenuItem);
 647			}
 648		}
 649
 650		return popup;
 651	} //}}}
 652
 653	//{{{ paintChildren() method
 654	public void paintChildren(Graphics g)
 655	{
 656		super.paintChildren(g);
 657
 658		if(resizeRect != null)
 659		{
 660			g.setColor(Color.darkGray);
 661			g.fillRect(resizeRect.x,resizeRect.y,
 662				resizeRect.width,resizeRect.height);
 663		}
 664	} //}}}
 665
 666	//{{{ handleMessage() method
 667	public void handleMessage(EBMessage msg)
 668	{
 669		if(msg instanceof DockableWindowUpdate)
 670		{
 671			if(((DockableWindowUpdate)msg).getWhat()
 672				== DockableWindowUpdate.PROPERTIES_CHANGED)
 673				propertiesChanged();
 674		}
 675		else if(msg instanceof PropertiesChanged)
 676			propertiesChanged();
 677		else if(msg instanceof PluginUpdate)
 678		{
 679			PluginUpdate pmsg = (PluginUpdate)msg;
 680			if(pmsg.getWhat() == PluginUpdate.LOADED)
 681			{
 682				Iterator iter = factory.getDockableWindowIterator();
 683
 684				while(iter.hasNext())
 685				{
 686					DockableWindowFactory.Window w = (DockableWindowFactory.Window)iter.next();
 687					if(w.plugin == pmsg.getPluginJAR())
 688						addEntry(w);
 689				}
 690
 691				propertiesChanged();
 692			}
 693			else if(pmsg.isExiting())
 694			{
 695				// we don't care
 696			}
 697			else if(pmsg.getWhat() == PluginUpdate.DEACTIVATED)
 698			{
 699				Iterator iter = getAllPluginEntries(
 700					pmsg.getPluginJAR(),false);
 701				while(iter.hasNext())
 702				{
 703					Entry entry = (Entry)iter.next();
 704					if(entry.container != null)
 705						entry.container.remove(entry);
 706				}
 707			}
 708			else if(pmsg.getWhat() == PluginUpdate.UNLOADED)
 709			{
 710				Iterator iter = getAllPluginEntries(
 711					pmsg.getPluginJAR(),true);
 712				while(iter.hasNext())
 713				{
 714					Entry entry = (Entry)iter.next();
 715					if(entry.container != null)
 716					{
 717						entry.container.unregister(entry);
 718						entry.win = null;
 719						entry.container = null;
 720					}
 721				}
 722			}
 723		}
 724	} //}}}
 725
 726	//{{{ Package-private members
 727	int resizePos;
 728	Rectangle resizeRect;
 729
 730	//{{{ setResizePos() method
 731	void setResizePos(int resizePos, PanelWindowContainer resizing)
 732	{
 733		this.resizePos = resizePos;
 734
 735		if(resizePos < 0)
 736			resizePos = 0;
 737
 738		Rectangle newResizeRect = new Rectangle(0,0,
 739			PanelWindowContainer.SPLITTER_WIDTH - 2,
 740			PanelWindowContainer.SPLITTER_WIDTH - 2);
 741		if(resizing == top)
 742		{
 743			resizePos = Math.min(resizePos,getHeight()
 744				- top.buttonPanel.getHeight()
 745				- bottom.dockablePanel.getHeight()
 746				- bottom.buttonPanel.getHeight()
 747				- PanelWindowContainer.SPLITTER_WIDTH);
 748			newResizeRect.x = top.dockablePanel.getX() + 1;
 749			newResizeRect.y = resizePos + top.buttonPanel.getHeight() + 1;
 750			newResizeRect.width = top.dockablePanel.getWidth() - 2;
 751		}
 752		else if(resizing == left)
 753		{
 754			resizePos = Math.min(resizePos,getWidth()
 755				- left.buttonPanel.getWidth()
 756				- right.dockablePanel.getWidth()
 757				- right.buttonPanel.getWidth()
 758				- PanelWindowContainer.SPLITTER_WIDTH);
 759			newResizeRect.x = resizePos + left.buttonPanel.getWidth() + 1;
 760			newResizeRect.y = left.dockablePanel.getY() + 1;
 761			newResizeRect.height = left.dockablePanel.getHeight() - 2;
 762		}
 763		else if(resizing == bottom)
 764		{
 765			resizePos = Math.min(resizePos,getHeight()
 766				- bottom.buttonPanel.getHeight()
 767				- top.dockablePanel.getHeight()
 768				- top.buttonPanel.getHeight()
 769				- PanelWindowContainer.SPLITTER_WIDTH);
 770			newResizeRect.x = bottom.dockablePanel.getX() + 1;
 771			newResizeRect.y = getHeight() - bottom.buttonPanel.getHeight() - resizePos
 772				- PanelWindowContainer.SPLITTER_WIDTH + 2;
 773			newResizeRect.width = bottom.dockablePanel.getWidth() - 2;
 774		}
 775		else if(resizing == right)
 776		{
 777			resizePos = Math.min(resizePos,getWidth()
 778				- right.buttonPanel.getWidth()
 779				- left.dockablePanel.getWidth()
 780				- left.buttonPanel.getWidth()
 781				- PanelWindowContainer.SPLITTER_WIDTH);
 782			newResizeRect.x = getWidth() - right.buttonPanel.getWidth() - resizePos
 783				- PanelWindowContainer.SPLITTER_WIDTH + 1;
 784			newResizeRect.y = right.dockablePanel.getY() + 1;
 785			newResizeRect.height = right.dockablePanel.getHeight() - 2;
 786		}
 787
 788		Rectangle toRepaint;
 789		if(resizeRect == null)
 790			toRepaint = newResizeRect;
 791		else
 792			toRepaint = resizeRect.union(newResizeRect);
 793		resizeRect = newResizeRect;
 794		repaint(toRepaint);
 795	} //}}}
 796
 797	//{{{ finishResizing() method
 798	void finishResizing()
 799	{
 800		resizeRect = null;
 801		repaint();
 802	} //}}}
 803
 804	//}}}
 805
 806	//{{{ Private members
 807	private View view;
 808	private DockableWindowFactory factory;
 809	private Hashtable windows;
 810	private PanelWindowContainer left;
 811	private PanelWindowContainer right;
 812	private PanelWindowContainer top;
 813	private PanelWindowContainer bottom;
 814	private ArrayList clones;
 815
 816	//{{{ propertiesChanged() method
 817	private void propertiesChanged()
 818	{
 819		if(view.isPlainView())
 820			return;
 821
 822		((DockableLayout)getLayout()).setAlternateLayout(
 823			jEdit.getBooleanProperty("view.docking.alternateLayout"));
 824
 825		String[] windowList = factory.getRegisteredDockableWindows();
 826
 827		for(int i = 0; i < windowList.length; i++)
 828		{
 829			String dockable = windowList[i];
 830			Entry entry = (Entry)windows.get(dockable);
 831
 832			String newPosition = jEdit.getProperty(dockable
 833				+ ".dock-position",FLOATING);
 834			if(newPosition.equals(entry.position))
 835			{
 836				continue;
 837			}
 838
 839			entry.position = newPosition;
 840			if(entry.container != null)
 841			{
 842				entry.container.unregister(entry);
 843				entry.container = null;
 844				entry.win = null;
 845			}
 846
 847			if(newPosition.equals(FLOATING)) {
 848
 849			}
 850				
 851			else
 852			{
 853				if(newPosition.equals(TOP))
 854					entry.container = top;
 855				else if(newPosition.equals(LEFT))
 856					entry.container = left;
 857				else if(newPosition.equals(BOTTOM))
 858					entry.container = bottom;
 859				else if(newPosition.equals(RIGHT))
 860					entry.container = right;
 861				else
 862				{
 863					Log.log(Log.WARNING,this,
 864						"Unknown position: "
 865						+ newPosition);
 866					continue;
 867				}
 868
 869				entry.container.register(entry);
 870			}
 871		}
 872
 873		top.sortDockables();
 874		left.sortDockables();
 875		bottom.sortDockables();
 876		right.sortDockables();
 877
 878		revalidate();
 879		repaint();
 880	} //}}}
 881
 882	//{{{ addEntry() method
 883	private void addEntry(DockableWindowFactory.Window factory)
 884	{
 885		Entry e;
 886		if(view.isPlainView())
 887		{
 888			// don't show menu items to dock into a plain view
 889			e = new Entry(factory,FLOATING);
 890		}
 891		else
 892		{
 893			e = new Entry(factory);
 894			if(e.position.equals(FLOATING))
 895				/* nothing to do */;
 896			else if(e.position.equals(TOP))
 897				e.container = top;
 898			else if(e.position.equals(LEFT))
 899				e.container = left;
 900			else if(e.position.equals(BOTTOM))
 901				e.container = bottom;
 902			else if(e.position.equals(RIGHT))
 903				e.container = right;
 904			else
 905			{
 906				Log.log(Log.WARNING,this,
 907					"Unknown position: "
 908					+ e.position);
 909			}
 910
 911			if(e.container != null)
 912				e.container.register(e);
 913		}
 914		windows.put(factory.name,e);
 915	} //}}}
 916
 917	//{{{ getAllPluginEntries() method
 918	/**
 919	 * If remove is false, only remove from clones list, otherwise remove
 920	 * from both entries and clones.
 921	 */
 922	private Iterator getAllPluginEntries(PluginJAR plugin, boolean remove)
 923	{
 924		java.util.List returnValue = new LinkedList();
 925		Iterator iter = windows.values().iterator();
 926		while(iter.hasNext())
 927		{
 928			Entry entry = (Entry)iter.next();
 929			if(entry.factory.plugin == plugin)
 930			{
 931				returnValue.add(entry);
 932				if(remove)
 933					iter.remove();
 934			}
 935		}
 936
 937		iter = clones.iterator();
 938		while(iter.hasNext())
 939		{
 940			Entry entry = (Entry)iter.next();
 941			if(entry.factory.plugin == plugin)
 942			{
 943				returnValue.add(entry);
 944				iter.remove();
 945			}
 946		}
 947
 948		return returnValue.iterator();
 949	} //}}}
 950
 951	//}}}
 952
 953	//{{{ Entry class
 954	class Entry
 955	{
 956		DockableWindowFactory.Window factory;
 957
 958//		String title;
 959		String position;
 960		DockableWindowContainer container;
 961
 962		// only set if open
 963		JComponent win;
 964
 965		// only for docked
 966		AbstractButton btn;
 967
 968		//{{{ Entry constructor
 969		Entry(DockableWindowFactory.Window factory)
 970		{
 971			this(factory,jEdit.getProperty(factory.name
 972				+ ".dock-position",FLOATING));
 973		} //}}}
 974
 975		/**
 976		 * @return The title for the floating dockable window
 977		 */
 978		public String title() {
 979			return getDockableTitle(factory.name);
 980		}
 981		/**
 982		 * @return A label appropriate for the title on the dock buttons.
 983		 */
 984		public String label() {
 985			String retval = jEdit.getProperty(factory.name + ".label");
 986			retval = retval.replaceAll("\\$", "");
 987			return retval; 
 988		}
 989		//{{{ Entry constructor
 990		Entry(DockableWindowFactory.Window factory, String position)
 991		{
 992			this.factory = factory;
 993			this.position = position;
 994
 995			// get the title here, not in the factory constructor,
 996			// since the factory might be created before a plugin's
 997			// props are loaded
 998			
 999		} //}}}
1000	} //}}}
1001}