alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 * DockableWindowManager.java - manages dockable windows
 * :tabSize=8:indentSize=8:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Copyright (C) 2000, 2004 Slava Pestov
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package org.gjt.sp.jedit.gui;

//{{{ Imports
 import bsh.*;
 import com.microstar.xml.*;
 import javax.swing.*;
 import java.awt.event.*;
 import java.awt.*;
 import java.io.*;
 import java.net.URL;
 import java.util.*;
 import org.gjt.sp.jedit.msg.*;
 import org.gjt.sp.jedit.*;
 import org.gjt.sp.util.Log;
//}}}

/**
 * The DockableWindowManager keeps track of dockable windows.
 * Each {@link org.gjt.sp.jedit.View} has an instance of this class.

* * dockables.xml:

* * Dockable window definitions are read from dockables.xml files * contained inside plugin JARs. A dockable definition file has the following * form: * *

<?xml version="1.0"?>
 *<!DOCTYPE DOCKABLES SYSTEM "dockables.dtd">
 *<DOCKABLES>
 *    <DOCKABLE NAME="name">
 *        // Code to create the dockable
 *    </DOCKABLE>
 *</DOCKABLES>
* * More than one <DOCKABLE> tag may be present. The code that * creates the dockable can reference any BeanShell built-in variable * (see {@link org.gjt.sp.jedit.BeanShell}), along with a variable * position whose value is one of * {@link #FLOATING}, {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, * and {@link #RIGHT}.

* * The following properties must be defined for each dockable window: * *

    *
  • name.title - the string to show in the title bar * of the dockable.
  • *
  • name.label - the dockable's menu item label.
  • *
* * A number of actions are automatically created for each dockable window: * *
    *
  • name - opens the dockable window.
  • *
  • name-toggle - toggles the dockable window's visibility.
  • *
  • name-float - opens the dockable window in a new * floating window.
  • *
* * Note that only the first action needs a label property, the * rest have automatically-generated labels. * * Implementation details:

* * When an instance of this class is initialized by the {@link org.gjt.sp.jedit.View} * class, it * iterates through the list of registered dockable windows (from jEdit itself, * and any loaded plugins) and * examines options supplied by the user in the Global * Options dialog box. Any plugins designated for one of the * four docking positions are displayed.

* * To create an instance of a dockable window, the DockableWindowManager * finds and executes the BeanShell code extracted from the appropriate * dockables.xml file. This code will typically consist of a call * to the constructor of the dockable window component. The result of the * BeanShell expression, typically a newly constructed component, is placed * in a window managed by this class. * * @see org.gjt.sp.jedit.View#getDockableWindowManager() * * @author Slava Pestov * @author John Gellene (API documentation) * @version $Id: DockableWindowManager.java,v 1.98 2004/06/09 16:48:40 spestov Exp $ * @since jEdit 2.6pre3 */ public class DockableWindowManager extends JPanel implements EBComponent { //{{{ Static part of class //{{{ Constants /** * Floating position. * @since jEdit 2.6pre3 */ public static final String FLOATING = "floating"; /** * Top position. * @since jEdit 2.6pre3 */ public static final String TOP = "top"; /** * Left position. * @since jEdit 2.6pre3 */ public static final String LEFT = "left"; /** * Bottom position. * @since jEdit 2.6pre3 */ public static final String BOTTOM = "bottom"; /** * Right position. * @since jEdit 2.6pre3 */ public static final String RIGHT = "right"; //}}} //{{{ loadDockableWindows() method /** * Plugins shouldn't need to call this method. * @since jEdit 4.2pre1 */ public static void loadDockableWindows(PluginJAR plugin, URL uri, PluginJAR.PluginCacheEntry cache) { Reader in = null; try { Log.log(Log.DEBUG,DockableWindowManager.class, "Loading dockables from " + uri); DockableListHandler dh = new DockableListHandler(plugin,uri); in = new BufferedReader( new InputStreamReader( uri.openStream())); XmlParser parser = new XmlParser(); parser.setHandler(dh); parser.parse(null, null, in); if(cache != null) { cache.cachedDockableNames = dh.getCachedDockableNames(); cache.cachedDockableActionFlags = dh.getCachedDockableActionFlags(); } } catch(XmlException xe) { int line = xe.getLine(); String message = xe.getMessage(); Log.log(Log.ERROR,DockableWindowManager.class,uri + ":" + line + ": " + message); } catch(Exception e) { Log.log(Log.ERROR,DockableWindowManager.class,e); } finally { try { if(in != null) in.close(); } catch(IOException io) { Log.log(Log.ERROR,DockableWindowManager.class,io); } } } //}}} //{{{ unloadDockableWindows() method /** * Plugins shouldn't need to call this method. * @since jEdit 4.2pre1 */ public static void unloadDockableWindows(PluginJAR plugin) { Iterator entries = dockableWindowFactories.entrySet().iterator(); while(entries.hasNext()) { Map.Entry entry = (Map.Entry)entries.next(); Factory factory = (Factory)entry.getValue(); if(factory.plugin == plugin) entries.remove(); } } //}}} //{{{ cacheDockableWindows() method /** * @since jEdit 4.2pre1 */ public static void cacheDockableWindows(PluginJAR plugin, String[] name, boolean[] actions) { for(int i = 0; i < name.length; i++) { Factory factory = new Factory(plugin, name[i],null,actions[i]); dockableWindowFactories.put(name[i],factory); } } //}}} //{{{ registerDockableWindow() method public static void registerDockableWindow(PluginJAR plugin, String name, String code, boolean actions) { Factory factory = (Factory)dockableWindowFactories.get(name); if(factory != null) { factory.code = code; factory.loaded = true; } else { factory = new Factory(plugin,name,code,actions); dockableWindowFactories.put(name,factory); } } //}}} //{{{ getRegisteredDockableWindows() method public static String[] getRegisteredDockableWindows() { String[] retVal = new String[dockableWindowFactories.size()]; Iterator entries = dockableWindowFactories.values().iterator(); int i = 0; while(entries.hasNext()) { Factory factory = (Factory)entries.next(); retVal[i++] = factory.name; } return retVal; } //}}} //{{{ DockableListHandler class static class DockableListHandler extends HandlerBase { //{{{ DockableListHandler constructor DockableListHandler(PluginJAR plugin, URL uri) { this.plugin = plugin; this.uri = uri; stateStack = new Stack(); actions = true; cachedDockableNames = new LinkedList(); cachedDockableActionFlags = new LinkedList(); } //}}} //{{{ resolveEntity() method public Object resolveEntity(String publicId, String systemId) { if("dockables.dtd".equals(systemId)) { // this will result in a slight speed up, since we // don't need to read the DTD anyway, as AElfred is // non-validating return new StringReader(""); /* try { return new BufferedReader(new InputStreamReader( getClass().getResourceAsStream ("/org/gjt/sp/jedit/dockables.dtd"))); } catch(Exception e) { Log.log(Log.ERROR,this,"Error while opening" + " dockables.dtd:"); Log.log(Log.ERROR,this,e); } */ } return null; } //}}} //{{{ attribute() method public void attribute(String aname, String value, boolean isSpecified) { aname = (aname == null) ? null : aname.intern(); value = (value == null) ? null : value.intern(); if(aname == "NAME") dockableName = value; else if(aname == "NO_ACTIONS") actions = (value == "FALSE"); } //}}} //{{{ doctypeDecl() method public void doctypeDecl(String name, String publicId, String systemId) throws Exception { if("DOCKABLES".equals(name)) return; Log.log(Log.ERROR,this,uri + ": DOCTYPE must be DOCKABLES"); } //}}} //{{{ charData() method public void charData(char[] c, int off, int len) { String tag = peekElement(); String text = new String(c, off, len); if (tag == "DOCKABLE") { code = text; } } //}}} //{{{ startElement() method public void startElement(String tag) { tag = pushElement(tag); } //}}} //{{{ endElement() method public void endElement(String name) { if(name == null) return; String tag = peekElement(); if(name.equals(tag)) { if(tag == "DOCKABLE") { registerDockableWindow(plugin, dockableName,code,actions); cachedDockableNames.add(dockableName); cachedDockableActionFlags.add( new Boolean(actions)); // make default be true for the next // action actions = true; } popElement(); } else { // can't happen throw new InternalError(); } } //}}} //{{{ startDocument() method public void startDocument() { try { pushElement(null); } catch (Exception e) { e.printStackTrace(); } } //}}} //{{{ getCachedDockableNames() method public String[] getCachedDockableNames() { return (String[])cachedDockableNames.toArray(new String[cachedDockableNames.size()]); } //}}} //{{{ getCachedDockableActionFlags() method public boolean[] getCachedDockableActionFlags() { boolean[] returnValue = new boolean[ cachedDockableActionFlags.size()]; Iterator iter = cachedDockableActionFlags.iterator(); int i = 0; while(iter.hasNext()) { boolean flag = ((Boolean)iter.next()) .booleanValue(); returnValue[i++] = flag; } return returnValue; } //}}} //{{{ Private members //{{{ Instance variables private PluginJAR plugin; private URL uri; private java.util.List cachedDockableNames; private java.util.List cachedDockableActionFlags; private String dockableName; private String code; private boolean actions; private Stack stateStack; //}}} //{{{ pushElement() method private String pushElement(String name) { name = (name == null) ? null : name.intern(); stateStack.push(name); return name; } //}}} //{{{ peekElement() method private String peekElement() { return (String) stateStack.peek(); } //}}} //{{{ popElement() method private String popElement() { return (String) stateStack.pop(); } //}}} //}}} } //}}} //{{{ Factory class static class Factory { PluginJAR plugin; String name; String code; boolean loaded; //{{{ Factory constructor Factory(PluginJAR plugin, String name, String code, boolean actions) { this.plugin = plugin; this.name = name; this.code = code; if(code != null) loaded = true; if(actions) { ActionSet actionSet = (plugin == null ? jEdit.getBuiltInActionSet() : plugin.getActionSet()); actionSet.addAction(new OpenAction(name)); actionSet.addAction(new ToggleAction(name)); actionSet.addAction(new FloatAction(name)); String label = jEdit.getProperty(name + ".label"); if(label == null) label = "NO LABEL PROPERTY: " + name; String[] args = { label }; jEdit.setTemporaryProperty(name + ".label", label); jEdit.setTemporaryProperty(name + "-toggle.label", jEdit.getProperty( "view.docking.toggle.label",args)); jEdit.setTemporaryProperty(name + "-toggle.toggle","true"); jEdit.setTemporaryProperty(name + "-float.label", jEdit.getProperty( "view.docking.float.label",args)); } } //}}} //{{{ load() method void load() { if(loaded) return; loadDockableWindows(plugin,plugin.getDockablesURI(),null); } //}}} //{{{ createDockableWindow() method JComponent createDockableWindow(View view, String position) { load(); if(!loaded) { Log.log(Log.WARNING,this,"Outdated cache"); return null; } NameSpace nameSpace = new NameSpace( BeanShell.getNameSpace(), "DockableWindowManager.Factory" + ".createDockableWindow()"); try { nameSpace.setVariable( "position",position); } catch(UtilEvalError e) { Log.log(Log.ERROR,this,e); } JComponent win = (JComponent)BeanShell.eval(view, nameSpace,code); return win; } //}}} //{{{ OpenAction class static class OpenAction extends EditAction { private String dockable; //{{{ OpenAction constructor OpenAction(String name) { super(name); this.dockable = name; } //}}} //{{{ invoke() method public void invoke(View view) { view.getDockableWindowManager() .showDockableWindow(dockable); } //}}} //{{{ getCode() method public String getCode() { return "view.getDockableWindowManager()" + ".showDockableWindow(\"" + dockable + "\");"; } //}}} } //}}} //{{{ ToggleAction class static class ToggleAction extends EditAction { private String dockable; //{{{ ToggleAction constructor ToggleAction(String name) { super(name + "-toggle"); this.dockable = name; } //}}} //{{{ invoke() method public void invoke(View view) { view.getDockableWindowManager() .toggleDockableWindow(dockable); } //}}} //{{{ isSelected() method public boolean isSelected(View view) { return view.getDockableWindowManager() .isDockableWindowVisible(dockable); } //}}} //{{{ getCode() method public String getCode() { return "view.getDockableWindowManager()" + ".toggleDockableWindow(\"" + dockable + "\");"; } //}}} } //}}} //{{{ FloatAction class static class FloatAction extends EditAction { private String dockable; //{{{ FloatAction constructor FloatAction(String name) { super(name + "-float"); this.dockable = name; } //}}} //{{{ invoke() method public void invoke(View view) { view.getDockableWindowManager() .floatDockableWindow(dockable); } //}}} //{{{ getCode() method public String getCode() { return "view.getDockableWindowManager()" + ".floatDockableWindow(\"" + dockable + "\");"; } //}}} } //}}} } //}}} private static HashMap dockableWindowFactories; //{{{ Static initializer static { dockableWindowFactories = new HashMap(); } //}}} //}}} //{{{ Instance part of class //{{{ DockableWindowManager constructor /** * Creates a new dockable window manager. * @param view The view * @since jEdit 2.6pre3 */ public DockableWindowManager(View view, View.ViewConfig config) { setLayout(new DockableLayout()); this.view = view; windows = new Hashtable(); clones = new ArrayList(); top = new PanelWindowContainer(this,TOP,config.topPos); left = new PanelWindowContainer(this,LEFT,config.leftPos); bottom = new PanelWindowContainer(this,BOTTOM,config.bottomPos); right = new PanelWindowContainer(this,RIGHT,config.rightPos); add(DockableLayout.TOP_BUTTONS,top.buttonPanel); add(DockableLayout.LEFT_BUTTONS,left.buttonPanel); add(DockableLayout.BOTTOM_BUTTONS,bottom.buttonPanel); add(DockableLayout.RIGHT_BUTTONS,right.buttonPanel); add(TOP,top.dockablePanel); add(LEFT,left.dockablePanel); add(BOTTOM,bottom.dockablePanel); add(RIGHT,right.dockablePanel); } //}}} //{{{ init() method /** * Initialises dockable window manager. Do not call this method directly. */ public void init() { EditBus.addToBus(this); Iterator entries = dockableWindowFactories.values().iterator(); while(entries.hasNext()) addEntry((Factory)entries.next()); propertiesChanged(); } //}}} //{{{ getView() method /** * Returns this dockable window manager's view. * @since jEdit 4.0pre2 */ public View getView() { return view; } //}}} //{{{ floatDockableWindow() method /** * Opens a new instance of the specified dockable window in a floating * container. * @param name The dockable window name * @return The new dockable window instance * @since jEdit 4.1pre2 */ public JComponent floatDockableWindow(String name) { Entry entry = (Entry)windows.get(name); if(entry == null) { Log.log(Log.ERROR,this,"Unknown dockable window: " + name); return null; } // create a copy of this dockable window and float it Entry newEntry = new Entry(entry.factory,FLOATING); newEntry.win = newEntry.factory.createDockableWindow(view,FLOATING); if(newEntry.win != null) { newEntry.container = new FloatingWindowContainer(this,true); newEntry.container.register(newEntry); newEntry.container.show(newEntry); } clones.add(newEntry); return newEntry.win; } //}}} //{{{ showDockableWindow() method /** * Opens the specified dockable window. * @param name The dockable window name * @since jEdit 2.6pre3 */ public void showDockableWindow(String name) { Entry entry = (Entry)windows.get(name); if(entry == null) { Log.log(Log.ERROR,this,"Unknown dockable window: " + name); return; } if(entry.win == null) { entry.win = entry.factory.createDockableWindow( view,entry.position); } if(entry.win != null) { if(entry.position.equals(FLOATING) && entry.container == null) { entry.container = new FloatingWindowContainer( this,view.isPlainView()); entry.container.register(entry); } entry.container.show(entry); } else /* an error occurred */; } //}}} //{{{ addDockableWindow() method /** * Opens the specified dockable window. As of jEdit 4.0pre1, has the * same effect as calling showDockableWindow(). * @param name The dockable window name * @since jEdit 2.6pre3 */ public void addDockableWindow(String name) { showDockableWindow(name); } //}}} //{{{ hideDockableWindow() method /** * Hides the specified dockable window. * @param name The dockable window name * @since jEdit 2.6pre3 */ public void hideDockableWindow(String name) { Entry entry = (Entry)windows.get(name); if(entry == null) { Log.log(Log.ERROR,this,"Unknown dockable window: " + name); return; } if(entry.win == null) return; entry.container.show(null); } //}}} //{{{ removeDockableWindow() method /** * Hides the specified dockable window. As of jEdit 4.2pre1, has the * same effect as calling hideDockableWindow(). * @param name The dockable window name * @since jEdit 4.2pre1 */ public void removeDockableWindow(String name) { hideDockableWindow(name); } //}}} //{{{ toggleDockableWindow() method /** * Toggles the visibility of the specified dockable window. * @param name The dockable window name */ public void toggleDockableWindow(String name) { if(isDockableWindowVisible(name)) removeDockableWindow(name); else addDockableWindow(name); } //}}} //{{{ getDockableWindow() method /** * Returns the specified dockable window. * * Note that this method * will return null if the dockable has not been added yet. * Make sure you call {@link #addDockableWindow(String)} first. * * @param name The name of the dockable window * @since jEdit 4.1pre2 */ public JComponent getDockableWindow(String name) { return getDockable(name); } //}}} //{{{ getDockable() method /** * Returns the specified dockable window. * * Note that this method * will return null if the dockable has not been added yet. * Make sure you call {@link #addDockableWindow(String)} first. * * For historical reasons, this * does the same thing as {@link #getDockableWindow(String)}. * * @param name The name of the dockable window * @since jEdit 4.0pre1 */ public JComponent getDockable(String name) { Entry entry = (Entry)windows.get(name); if(entry == null || entry.win == null) return null; else return entry.win; } //}}} //{{{ getDockableTitle() method /** * Returns the title of the specified dockable window. * @param name The name of the dockable window. * @since jEdit 4.1pre5 */ public String getDockableTitle(String name) { String title = jEdit.getProperty(name + ".title"); if(title == null) return "NO TITLE PROPERTY: " + name; else return title; } //}}} //{{{ isDockableWindowVisible() method /** * Returns if the specified dockable window is visible. * @param name The dockable window name */ public boolean isDockableWindowVisible(String name) { Entry entry = (Entry)windows.get(name); if(entry == null || entry.win == null) return false; else return entry.container.isVisible(entry); } //}}} //{{{ isDockableWindowDocked() method /** * Returns if the specified dockable window is docked into the * view. * @param name The dockable's name * @since jEdit 4.0pre2 */ public boolean isDockableWindowDocked(String name) { Entry entry = (Entry)windows.get(name); if(entry == null) return false; else return !entry.position.equals(FLOATING); } //}}} //{{{ closeCurrentArea() method /** * Closes the currently focused docking area. * @since jEdit 4.1pre3 */ public void closeCurrentArea() { // I don't know of any other way to fix this, since invoking this // command from a menu results in the focus owner being the menu // until the menu goes away. SwingUtilities.invokeLater(new Runnable() { public void run() { Component comp = view.getFocusOwner(); while(comp != null) { //System.err.println(comp.getClass()); if(comp instanceof PanelWindowContainer .DockablePanel) { PanelWindowContainer container = ((PanelWindowContainer.DockablePanel) comp).getWindowContainer(); container.show(null); return; } comp = comp.getParent(); } getToolkit().beep(); } }); } //}}} //{{{ close() method /** * Called when the view is being closed. * @since jEdit 2.6pre3 */ public void close() { EditBus.removeFromBus(this); Iterator iter = windows.values().iterator(); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.win != null) { entry.container.unregister(entry); } } iter = clones.iterator(); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.win != null) { entry.container.unregister(entry); } } } //}}} //{{{ getTopDockingArea() method public PanelWindowContainer getTopDockingArea() { return top; } //}}} //{{{ getLeftDockingArea() method public PanelWindowContainer getLeftDockingArea() { return left; } //}}} //{{{ getBottomDockingArea() method public PanelWindowContainer getBottomDockingArea() { return bottom; } //}}} //{{{ getRightDockingArea() method public PanelWindowContainer getRightDockingArea() { return right; } //}}} //{{{ createPopupMenu() method public JPopupMenu createPopupMenu( final DockableWindowContainer container, final String dockable, final boolean clone) { JPopupMenu popup = new JPopupMenu(); if(dockable == null && container instanceof PanelWindowContainer) { ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent evt) { showDockableWindow(evt.getActionCommand()); } }; String[] dockables = ((PanelWindowContainer) container).getDockables(); for(int i = 0; i < dockables.length; i++) { String name = dockables[i]; JMenuItem item = new JMenuItem(getDockableTitle(name)); item.setActionCommand(name); item.addActionListener(listener); popup.add(item); } } else { JMenuItem caption = new JMenuItem(getDockableTitle(dockable)); caption.setEnabled(false); popup.add(caption); popup.addSeparator(); String currentPos = jEdit.getProperty(dockable + ".dock-position",FLOATING); if(!clone) { String[] positions = { FLOATING, TOP, LEFT, BOTTOM, RIGHT }; for(int i = 0; i < positions.length; i++) { final String pos = positions[i]; if(pos.equals(currentPos)) continue; JMenuItem moveMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-" + pos)); moveMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jEdit.setProperty(dockable + ".dock-position",pos); EditBus.send(new DockableWindowUpdate( DockableWindowManager.this, DockableWindowUpdate.PROPERTIES_CHANGED, null )); showDockableWindow(dockable); } }); popup.add(moveMenuItem); } popup.addSeparator(); } JMenuItem cloneMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-clone")); cloneMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { floatDockableWindow(dockable); } }); popup.add(cloneMenuItem); popup.addSeparator(); JMenuItem closeMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-close")); closeMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(clone) ((FloatingWindowContainer)container).dispose(); else removeDockableWindow(dockable); } }); popup.add(closeMenuItem); if(!(clone || currentPos.equals(FLOATING))) { JMenuItem undockMenuItem = new JMenuItem(jEdit.getProperty("view.docking.menu-undock")); undockMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { jEdit.setProperty(dockable + ".dock-position",FLOATING); EditBus.send(new DockableWindowUpdate( DockableWindowManager.this, DockableWindowUpdate.PROPERTIES_CHANGED, null )); } }); popup.add(undockMenuItem); } } return popup; } //}}} //{{{ paintChildren() method public void paintChildren(Graphics g) { super.paintChildren(g); if(resizeRect != null) { g.setColor(Color.darkGray); g.fillRect(resizeRect.x,resizeRect.y, resizeRect.width,resizeRect.height); } } //}}} //{{{ handleMessage() method public void handleMessage(EBMessage msg) { if(msg instanceof DockableWindowUpdate) { if(((DockableWindowUpdate)msg).getWhat() == DockableWindowUpdate.PROPERTIES_CHANGED) propertiesChanged(); } else if(msg instanceof PropertiesChanged) propertiesChanged(); else if(msg instanceof PluginUpdate) { PluginUpdate pmsg = (PluginUpdate)msg; if(pmsg.getWhat() == PluginUpdate.LOADED) { Iterator iter = dockableWindowFactories .values().iterator(); while(iter.hasNext()) { Factory factory = (Factory)iter.next(); if(factory.plugin == pmsg.getPluginJAR()) addEntry(factory); } propertiesChanged(); } else if(pmsg.isExiting()) { // we don't care } else if(pmsg.getWhat() == PluginUpdate.DEACTIVATED) { Iterator iter = getAllPluginEntries( pmsg.getPluginJAR(),false); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.container != null) entry.container.remove(entry); } } else if(pmsg.getWhat() == PluginUpdate.UNLOADED) { Iterator iter = getAllPluginEntries( pmsg.getPluginJAR(),true); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.container != null) { entry.container.unregister(entry); entry.win = null; entry.container = null; } } } } } //}}} //{{{ Package-private members int resizePos; Rectangle resizeRect; //{{{ setResizePos() method void setResizePos(int resizePos, PanelWindowContainer resizing) { this.resizePos = resizePos; if(resizePos < 0) resizePos = 0; Rectangle newResizeRect = new Rectangle(0,0, PanelWindowContainer.SPLITTER_WIDTH - 2, PanelWindowContainer.SPLITTER_WIDTH - 2); if(resizing == top) { resizePos = Math.min(resizePos,getHeight() - top.buttonPanel.getHeight() - bottom.dockablePanel.getHeight() - bottom.buttonPanel.getHeight() - PanelWindowContainer.SPLITTER_WIDTH); newResizeRect.x = top.dockablePanel.getX() + 1; newResizeRect.y = resizePos + top.buttonPanel.getHeight() + 1; newResizeRect.width = top.dockablePanel.getWidth() - 2; } else if(resizing == left) { resizePos = Math.min(resizePos,getWidth() - left.buttonPanel.getWidth() - right.dockablePanel.getWidth() - right.buttonPanel.getWidth() - PanelWindowContainer.SPLITTER_WIDTH); newResizeRect.x = resizePos + left.buttonPanel.getWidth() + 1; newResizeRect.y = left.dockablePanel.getY() + 1; newResizeRect.height = left.dockablePanel.getHeight() - 2; } else if(resizing == bottom) { resizePos = Math.min(resizePos,getHeight() - bottom.buttonPanel.getHeight() - top.dockablePanel.getHeight() - top.buttonPanel.getHeight() - PanelWindowContainer.SPLITTER_WIDTH); newResizeRect.x = bottom.dockablePanel.getX() + 1; newResizeRect.y = getHeight() - bottom.buttonPanel.getHeight() - resizePos - PanelWindowContainer.SPLITTER_WIDTH + 2; newResizeRect.width = bottom.dockablePanel.getWidth() - 2; } else if(resizing == right) { resizePos = Math.min(resizePos,getWidth() - right.buttonPanel.getWidth() - left.dockablePanel.getWidth() - left.buttonPanel.getWidth() - PanelWindowContainer.SPLITTER_WIDTH); newResizeRect.x = getWidth() - right.buttonPanel.getWidth() - resizePos - PanelWindowContainer.SPLITTER_WIDTH + 1; newResizeRect.y = right.dockablePanel.getY() + 1; newResizeRect.height = right.dockablePanel.getHeight() - 2; } Rectangle toRepaint; if(resizeRect == null) toRepaint = newResizeRect; else toRepaint = resizeRect.union(newResizeRect); resizeRect = newResizeRect; repaint(toRepaint); } //}}} //{{{ finishResizing() method void finishResizing() { resizeRect = null; repaint(); } //}}} //}}} //{{{ Private members private View view; private Hashtable windows; private boolean alternateLayout; private PanelWindowContainer left; private PanelWindowContainer right; private PanelWindowContainer top; private PanelWindowContainer bottom; private ArrayList clones; //{{{ propertiesChanged() method private void propertiesChanged() { if(view.isPlainView()) return; alternateLayout = jEdit.getBooleanProperty("view.docking.alternateLayout"); String[] windowList = getRegisteredDockableWindows(); for(int i = 0; i < windowList.length; i++) { String dockable = windowList[i]; Entry entry = (Entry)windows.get(dockable); String newPosition = jEdit.getProperty(dockable + ".dock-position",FLOATING); if(newPosition.equals(entry.position)) { continue; } entry.position = newPosition; if(entry.container != null) { entry.container.unregister(entry); entry.container = null; entry.win = null; } if(newPosition.equals(FLOATING)) /* do nothing */; else { if(newPosition.equals(TOP)) entry.container = top; else if(newPosition.equals(LEFT)) entry.container = left; else if(newPosition.equals(BOTTOM)) entry.container = bottom; else if(newPosition.equals(RIGHT)) entry.container = right; else { Log.log(Log.WARNING,this, "Unknown position: " + newPosition); continue; } entry.container.register(entry); } } top.sortDockables(); left.sortDockables(); bottom.sortDockables(); right.sortDockables(); revalidate(); repaint(); } //}}} //{{{ addEntry() method private void addEntry(Factory factory) { Entry e; if(view.isPlainView()) { // don't show menu items to dock into a plain view e = new Entry(factory,FLOATING); } else { e = new Entry(factory); if(e.position.equals(FLOATING)) /* nothing to do */; else if(e.position.equals(TOP)) e.container = top; else if(e.position.equals(LEFT)) e.container = left; else if(e.position.equals(BOTTOM)) e.container = bottom; else if(e.position.equals(RIGHT)) e.container = right; else { Log.log(Log.WARNING,this, "Unknown position: " + e.position); } if(e.container != null) e.container.register(e); } windows.put(factory.name,e); } //}}} //{{{ getAllPluginEntries() method /** * If remove is false, only remove from clones list, otherwise remove * from both entries and clones. */ private Iterator getAllPluginEntries(PluginJAR plugin, boolean remove) { java.util.List returnValue = new LinkedList(); Iterator iter = windows.values().iterator(); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.factory.plugin == plugin) { returnValue.add(entry); if(remove) iter.remove(); } } iter = clones.iterator(); while(iter.hasNext()) { Entry entry = (Entry)iter.next(); if(entry.factory.plugin == plugin) { returnValue.add(entry); iter.remove(); } } return returnValue.iterator(); } //}}} //}}} //}}} //{{{ DockableLayout class public class DockableLayout implements LayoutManager2 { // for backwards compatibility with plugins that fiddle with // jEdit's UI layout static final String CENTER = BorderLayout.CENTER; public static final String TOP_TOOLBARS = "top-toolbars"; public static final String BOTTOM_TOOLBARS = "bottom-toolbars"; static final String TOP_BUTTONS = "top-buttons"; static final String LEFT_BUTTONS = "left-buttons"; static final String BOTTOM_BUTTONS = "bottom-buttons"; static final String RIGHT_BUTTONS = "right-buttons"; Component topToolbars, bottomToolbars; Component center; Component top, left, bottom, right; Component topButtons, leftButtons, bottomButtons, rightButtons; //{{{ addLayoutComponent() method public void addLayoutComponent(String name, Component comp) { addLayoutComponent(comp,name); } //}}} //{{{ addLayoutComponent() method public void addLayoutComponent(Component comp, Object cons) { if(cons == null || CENTER.equals(cons)) center = comp; else if(TOP_TOOLBARS.equals(cons)) topToolbars = comp; else if(BOTTOM_TOOLBARS.equals(cons)) bottomToolbars = comp; else if(TOP.equals(cons)) top = comp; else if(LEFT.equals(cons)) left = comp; else if(BOTTOM.equals(cons)) bottom = comp; else if(RIGHT.equals(cons)) right = comp; else if(TOP_BUTTONS.equals(cons)) topButtons = comp; else if(LEFT_BUTTONS.equals(cons)) leftButtons = comp; else if(BOTTOM_BUTTONS.equals(cons)) bottomButtons = comp; else if(RIGHT_BUTTONS.equals(cons)) rightButtons = comp; } //}}} //{{{ removeLayoutComponent() method public void removeLayoutComponent(Component comp) { if(center == comp) center = null; if(comp == topToolbars) topToolbars = null; if(comp == bottomToolbars) bottomToolbars = null; { // none of the others are ever meant to be // removed. retarded, eh? this needs to be // fixed eventually, for plugins might // want to do weird stuff to jEdit's UI } } //}}} //{{{ preferredLayoutSize() method public Dimension preferredLayoutSize(Container parent) { Dimension prefSize = new Dimension(0,0); Dimension _top = top.getPreferredSize(); Dimension _left = left.getPreferredSize(); Dimension _bottom = bottom.getPreferredSize(); Dimension _right = right.getPreferredSize(); Dimension _topButtons = topButtons.getPreferredSize(); Dimension _leftButtons = leftButtons.getPreferredSize(); Dimension _bottomButtons = bottomButtons.getPreferredSize(); Dimension _rightButtons = rightButtons.getPreferredSize(); Dimension _center = (center == null ? new Dimension(0,0) : center.getPreferredSize()); Dimension _topToolbars = (topToolbars == null ? new Dimension(0,0) : topToolbars.getPreferredSize()); Dimension _bottomToolbars = (bottomToolbars == null ? new Dimension(0,0) : bottomToolbars.getPreferredSize()); prefSize.height = _top.height + _bottom.height + _center.height + _topButtons.height + _bottomButtons.height + _topToolbars.height + _bottomToolbars.height; prefSize.width = _left.width + _right.width + Math.max(_center.width, Math.max(_topToolbars.width,_bottomToolbars.width)) + _leftButtons.width + _rightButtons.width; return prefSize; } //}}} //{{{ minimumLayoutSize() method public Dimension minimumLayoutSize(Container parent) { // I'm lazy return preferredLayoutSize(parent); } //}}} //{{{ maximumLayoutSize() method public Dimension maximumLayoutSize(Container parent) { return new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE); } //}}} //{{{ layoutContainer() method public void layoutContainer(Container parent) { Dimension size = parent.getSize(); Dimension _topToolbars = (topToolbars == null ? new Dimension(0,0) : topToolbars.getPreferredSize()); Dimension _bottomToolbars = (bottomToolbars == null ? new Dimension(0,0) : bottomToolbars.getPreferredSize()); int topButtonHeight = -1; int bottomButtonHeight = -1; int leftButtonWidth = -1; int rightButtonWidth = -1; Dimension _top = top.getPreferredSize(); Dimension _left = left.getPreferredSize(); Dimension _bottom = bottom.getPreferredSize(); Dimension _right = right.getPreferredSize(); int topHeight = _top.height; int bottomHeight = _bottom.height; int leftWidth = _left.width; int rightWidth = _right.width; boolean topEmpty = ((Container)topButtons) .getComponentCount() <= 2; boolean leftEmpty = ((Container)leftButtons) .getComponentCount() <= 2; boolean bottomEmpty = ((Container)bottomButtons) .getComponentCount() <= 2; boolean rightEmpty = ((Container)rightButtons) .getComponentCount() <= 2; Dimension closeBoxSize; if(((Container)topButtons).getComponentCount() == 0) closeBoxSize = new Dimension(0,0); else { closeBoxSize = ((Container)topButtons) .getComponent(0).getPreferredSize(); } int closeBoxWidth = Math.max(closeBoxSize.width, closeBoxSize.height) + 1; if(alternateLayout) { //{{{ Lay out independent buttons int _width = size.width; int padding = (leftEmpty&&rightEmpty) ? 0 : closeBoxWidth; topButtonHeight = DockableWindowManager.this. top.getWrappedDimension(_width - closeBoxWidth * 2); topButtons.setBounds( padding, 0, size.width - padding * 2, topButtonHeight); bottomButtonHeight = DockableWindowManager.this. bottom.getWrappedDimension(_width); bottomButtons.setBounds( padding, size.height - bottomButtonHeight, size.width - padding * 2, bottomButtonHeight); int _height = size.height - topButtonHeight - bottomButtonHeight; //}}} //{{{ Lay out dependent buttons leftButtonWidth = DockableWindowManager.this. left.getWrappedDimension(_height); leftButtons.setBounds( 0, topHeight + topButtonHeight, leftButtonWidth, _height - topHeight - bottomHeight); rightButtonWidth = DockableWindowManager.this. right.getWrappedDimension(_height); rightButtons.setBounds( size.width - rightButtonWidth, topHeight + topButtonHeight, rightButtonWidth, _height - topHeight - bottomHeight); //}}} int[] dimensions = adjustDockingAreasToFit( size, topHeight, leftWidth, bottomHeight, rightWidth, topButtonHeight, leftButtonWidth, bottomButtonHeight, rightButtonWidth, _topToolbars, _bottomToolbars); topHeight = dimensions[0]; leftWidth = dimensions[1]; bottomHeight = dimensions[2]; rightWidth = dimensions[3]; //{{{ Lay out docking areas top.setBounds( 0, topButtonHeight, size.width, topHeight); bottom.setBounds( 0, size.height - bottomHeight - bottomButtonHeight, size.width, bottomHeight); left.setBounds( leftButtonWidth, topButtonHeight + topHeight, leftWidth, _height - topHeight - bottomHeight); right.setBounds( _width - rightButtonWidth - rightWidth, topButtonHeight + topHeight, rightWidth, _height - topHeight - bottomHeight); //}}} } else { //{{{ Lay out independent buttons int _height = size.height; int padding = (topEmpty && bottomEmpty ? 0 : closeBoxWidth); leftButtonWidth = DockableWindowManager.this. left.getWrappedDimension(_height - closeBoxWidth * 2); leftButtons.setBounds( 0, padding, leftButtonWidth, _height - padding * 2); rightButtonWidth = DockableWindowManager.this. right.getWrappedDimension(_height); rightButtons.setBounds( size.width - rightButtonWidth, padding, rightButtonWidth, _height - padding * 2); int _width = size.width - leftButtonWidth - rightButtonWidth; //}}} //{{{ Lay out dependent buttons topButtonHeight = DockableWindowManager.this. top.getWrappedDimension(_width); topButtons.setBounds( leftButtonWidth + leftWidth, 0, _width - leftWidth - rightWidth, topButtonHeight); bottomButtonHeight = DockableWindowManager.this. bottom.getWrappedDimension(_width); bottomButtons.setBounds( leftButtonWidth + leftWidth, _height - bottomButtonHeight, _width - leftWidth - rightWidth, bottomButtonHeight); //}}} int[] dimensions = adjustDockingAreasToFit( size, topHeight, leftWidth, bottomHeight, rightWidth, topButtonHeight, leftButtonWidth, bottomButtonHeight, rightButtonWidth, _topToolbars, _bottomToolbars); topHeight = dimensions[0]; leftWidth = dimensions[1]; bottomHeight = dimensions[2]; rightWidth = dimensions[3]; //{{{ Lay out docking areas top.setBounds( leftButtonWidth + leftWidth, topButtonHeight, _width - leftWidth - rightWidth, topHeight); bottom.setBounds( leftButtonWidth + leftWidth, size.height - bottomHeight - bottomButtonHeight, _width - leftWidth - rightWidth, bottomHeight); left.setBounds( leftButtonWidth, 0, leftWidth, _height); right.setBounds( size.width - rightWidth - rightButtonWidth, 0, rightWidth, _height); //}}} } //{{{ Position tool bars if they are managed by us if(topToolbars != null) { topToolbars.setBounds( leftButtonWidth + leftWidth, topButtonHeight + topHeight, size.width - leftWidth - rightWidth - leftButtonWidth - rightButtonWidth, _topToolbars.height); } if(bottomToolbars != null) { bottomToolbars.setBounds( leftButtonWidth + leftWidth, size.height - bottomHeight - bottomButtonHeight - _bottomToolbars.height + topButtonHeight + topHeight, size.width - leftWidth - rightWidth - leftButtonWidth - rightButtonWidth, _bottomToolbars.height); } //}}} //{{{ Position center (edit pane, or split pane) if(center != null) { center.setBounds( leftButtonWidth + leftWidth, topButtonHeight + topHeight + _topToolbars.height, size.width - leftWidth - rightWidth - leftButtonWidth - rightButtonWidth, size.height - topHeight - topButtonHeight - bottomHeight - bottomButtonHeight - _topToolbars.height - _bottomToolbars.height); } //}}} } //}}} //{{{ adjustDockingAreasToFit() method private int[] adjustDockingAreasToFit( Dimension size, int topHeight, int leftWidth, int bottomHeight, int rightWidth, int topButtonHeight, int leftButtonWidth, int bottomButtonHeight, int rightButtonWidth, Dimension _topToolbars, Dimension _bottomToolbars) { int maxTopHeight = size.height - bottomHeight - topButtonHeight - bottomButtonHeight - _topToolbars.height - _bottomToolbars.height; topHeight = Math.min(Math.max(0,maxTopHeight), topHeight); leftWidth = Math.min(Math.max(0, size.width - leftButtonWidth - rightButtonWidth - rightWidth),leftWidth); int maxBottomHeight = size.height - topHeight - topButtonHeight - bottomButtonHeight - _topToolbars.height - _bottomToolbars.height; bottomHeight = Math.min(Math.max(0,maxBottomHeight), bottomHeight); rightWidth = Math.min(Math.max(0, size.width - leftButtonWidth - rightButtonWidth - leftWidth),rightWidth); DockableWindowManager.this.top.setDimension(topHeight); DockableWindowManager.this.left.setDimension(leftWidth); DockableWindowManager.this.bottom.setDimension(bottomHeight); DockableWindowManager.this.right.setDimension(rightWidth); return new int[] { topHeight, leftWidth, bottomHeight, rightWidth }; } //}}} //{{{ getLayoutAlignmentX() method public float getLayoutAlignmentX(Container target) { return 0.5f; } //}}} //{{{ getLayoutAlignmentY() method public float getLayoutAlignmentY(Container target) { return 0.5f; } //}}} //{{{ invalidateLayout() method public void invalidateLayout(Container target) {} //}}} } //}}} //{{{ Entry class class Entry { Factory factory; String title; String position; DockableWindowContainer container; // only set if open JComponent win; // only for docked AbstractButton btn; //{{{ Entry constructor Entry(Factory factory) { this(factory,jEdit.getProperty(factory.name + ".dock-position",FLOATING)); } //}}} //{{{ Entry constructor Entry(Factory factory, String position) { this.factory = factory; this.position = position; // get the title here, not in the factory constructor, // since the factory might be created before a plugin's // props are loaded title = getDockableTitle(factory.name); } //}}} } //}}} }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.