📄 abstractpluggableguiapplication.java
字号:
/*
* 04/25/2005
*
* AbstractPluggableGUIApplication.java - A GUI application able to be extended
* by plugins.
* Copyright (C) 2005 Robert Futrell
* email@address.com
* www.website.com
*
* 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.fife.ui.app;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Paint;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.fife.ui.OptionsDialog;
import org.fife.ui.SplashScreen;
/**
* An extension of <code>AbstractGUIApplication</code> adding the ability to
* add/remove plugins.
*/
public abstract class AbstractPluggableGUIApplication
extends AbstractGUIApplication {
/**
* List of installed plugins.
*/
private List pluginList;
/**
* The options dialog for plugins.
*/
private PluginOptionsDialog pluginOptionsDialog;
/**
* The class loader used for plugin stuff.
*/
private PluginClassLoader pluginClassLoader;
private static final Color pluginTitlePanelBG1 = new Color(40, 93, 220);
private static final Color pluginTitlePanelBG2 = new Color(200, 200, 255);
/*****************************************************************************/
/**
* Constructor.
*
* @param jarFile The name (not full path) of the JAR file containing the
* main class of this application (e.g. "Foobar.jar").
*/
public AbstractPluggableGUIApplication(String jarFile) {
super(jarFile);
}
/*****************************************************************************/
/**
* Constructor.
*
* @param title The title for this frame.
* @param jarFile The name (not full path) of the JAR file containing
* the main class of this application (e.g. "Foobar.jar").
*/
public AbstractPluggableGUIApplication(String title, String jarFile) {
super(title, jarFile);
}
/*****************************************************************************/
/**
* Constructor. This constructor is useful when you are making a clone of
* the current application (e.g., "Open in New Window...") and you want
* the two instances to have the same properties.
*
* @param title The title for this frame.
* @param jarFile The name (not full path) of the JAR file containing the
* main class of this application (e.g. "Foobar.jar").
* @param prefs The preferences with which to initialize this application.
*/
public AbstractPluggableGUIApplication(String title, String jarFile,
GUIApplicationPreferences prefs) {
super(title, jarFile, prefs);
}
/*****************************************************************************/
/**
* Adds a plugin to this GUI application.
*
* @param plugin The plugin to add.
* @see #handleInstallPlugin
* @see #removePlugin
*/
public final void addPlugin(Plugin plugin) {
if (pluginList == null) {
pluginList = new ArrayList(1);
}
pluginList.add(plugin);
// If it's a GUI plugin, we'll physically add it to
// the GUI for you...
if (plugin instanceof GUIPlugin) {
GUIPlugin gp = (GUIPlugin) plugin;
( (MainContentPanel) mainContentPanel).addPlugin(gp);
}
else if (plugin instanceof StatusBarPlugin) {
// FIXME: Get the constraints from the plugin itself.
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 0.0;
getStatusBar().addStatusBarComponent(
(StatusBarPlugin) plugin, 0, c);
}
// And we let the plugin register any listeners, etc...
plugin.install(this);
// But your subclass must do everything else.
handleInstallPlugin(plugin);
}
/*****************************************************************************/
/**
* Creates the panel that contains the main content (via the
* <code>actualContentPane</code>. The returned panel also contains
* any GUI plugins.
*
* @param actualContentPane The panel that will contain the program's
* content. This panel should be added to the returned panel.
* @return The panel.
*/
JPanel createMainContentPanel(JPanel actualContentPane) {
MainContentPanel mcp = new MainContentPanel();
mcp.setContentPanel(actualContentPane);
return mcp;
}
/*****************************************************************************/
/**
* This is called in the GUI application's constructor. It is a chance
* for subclasses to do initialization of stuff that will be needed by
* their menu bar before it gets created.
*
* @param prefs The preferences of the application.
* @param splashScreen The "splash screen" for this application. This
* value may be <code>null</code>.
*/
protected void preMenuBarInit(GUIApplicationPreferences prefs,
SplashScreen splashScreen) {
try {
pluginClassLoader = new PluginClassLoader(this);
}
catch (IOException ioe) {
displayException(ioe);
}
}
/*****************************************************************************/
/**
* Returns an options dialog containing options for all installed
* plugins. This dialog is lazily created the first time this method
* is called.
*
* @return The options dialog.
*/
public synchronized OptionsDialog getPluginOptionsDialog() {
return getPluginOptionsDialog(true);
}
/*****************************************************************************/
/**
* Workaround for an apparant javac bug - I could not simply make
* <code>pluginOptionsDialog</code> protected and call
* <code>pluginOptionsDialog.pack()</code> in a subclass without getting
* a compiler warning about "Method pack is not public and cannot be
* accessed outside of package"... But, I'd like a way for subclasses to
* get to <code>pluginOptionsDialog</code> without it being created if it
* hasn't already been.
*
* @param create Whether or not to create the dialog if it hasn't already
* been.
* @return The plugin options dialog.
*/
protected synchronized OptionsDialog getPluginOptionsDialog(
boolean create) {
if (pluginOptionsDialog == null && create) {
pluginOptionsDialog = new PluginOptionsDialog(this);
}
if (pluginOptionsDialog != null) {
pluginOptionsDialog.initialize();
}
return pluginOptionsDialog;
}
/*****************************************************************************/
/**
* Returns all installed plugins. Note that this returns the actual
* plugins and not deep copies, so any changes made to the plugin
* array will affect the application itself.
*
* @return All installed plugins. If no plugins are installed, a
* zero-length array is returned.
* @see #addPlugin
* @see #removePlugin
*/
public Plugin[] getPlugins() {
int count = pluginList == null ? 0 : pluginList.size();
Plugin[] plugins = new Plugin[count];
if (count > 0) {
plugins = (Plugin[]) pluginList.toArray(plugins);
}
return plugins;
}
/*****************************************************************************/
/**
* Returns the location of the divider of the specified split pane.
*
* @param splitPane One of <code>GUIApplicationConstants.TOP</code>,
* <code>LEFT</code>, <code>BOTTOM</code>, or <code>RIGHT</code>.
* @throws IllegalArgumentException If <code>splitPane</code> is
* invalid.
* @see #setSplitPaneDividerLocation
*/
public int getSplitPaneDividerLocation(int splitPane) {
int dividerLocation = 0;
switch (splitPane) {
case TOP:
case BOTTOM:
case LEFT:
case RIGHT:
dividerLocation = ( (MainContentPanel) mainContentPanel).
getDividerLocation(splitPane);
break;
default:
throw new IllegalArgumentException("Bad splitPane value");
}
return dividerLocation;
}
/*****************************************************************************/
/**
* Does the dirty work of actually installing a plugin. This method
* should be overridden by subclasses to do stuff as appropriate for
* a plugin. A subclass of {@link org.fife.ui.app.GUIPlugin} will
* already have been added to the GUI; everything else (such as adding
* the plugin's popup menu to your menu bar) you must do yourself.
* This default version of the method does nothing.
*
* @param plugin The plugin to install.
*/
protected void handleInstallPlugin(Plugin plugin) {
}
/*****************************************************************************/
/**
* Tries to uninstall and remove the specified plugin.
*
* @param plugin The plugin to remove.
* @return Whether the uninstall was successful.
*/
public boolean removePlugin(Plugin plugin) {
pluginList.remove(plugin);
// If it's a GUI plugin...
if (plugin instanceof GUIPlugin) {
GUIPlugin gp = (GUIPlugin) plugin;
return ( (MainContentPanel) mainContentPanel).removePlugin(gp);
}
else {
throw new IllegalArgumentException(
"Only GUIPlugins are currently supported");
}
}
/*****************************************************************************/
/**
* This method sets the content pane. It is overridden so it does not
* meddle with the status bar, toolbar, etc.
*
* @param contentPane The new content pane.
* @see #getContentPane
*/
public void setContentPane(Container contentPane) {
if (contentPane != null && !contentPane.equals(actualContentPane)) {
MainContentPanel mcp = (MainContentPanel) mainContentPanel;
if (actualContentPane != null) {
mcp.removeContentPanel(actualContentPane);
}
mcp.setContentPanel(contentPane);
}
}
/*****************************************************************************/
/**
* Sets the position of the divider for the specified split pane. Note
* that if no plugins are docked at the specified location (and thus no
* split pane is there), this method does nothing.
*
* @param splitPane The split pane for which to set the divider
* location; one of <code>GUIApplicationConstants.TOP</code>,
* <code>LEFT</code>, <code>BOTTOM</code> or
* <code>RIGHT</code>.
* @param pos The new position for the divider.
* @see #getSplitPaneDividerLocation
*/
public void setSplitPaneDividerLocation(int splitPane, int pos) {
MainContentPanel mcp = (MainContentPanel) mainContentPanel;
mcp.setDividerLocation(splitPane, pos);
}
/*****************************************************************************/
/************************* INNER CLASSES *************************************/
/*****************************************************************************/
/**
* A panel containing a bunch of <code>GUIPlugin</code>s contained
* in a tabbed pane.
*/
private final class PluginPanel
extends JPanel {
/**
*
*/
private static final long serialVersionUID = 5660451096830838506L;
private JTabbedPane tabbedPane;
private PluginTitlePanel titlePanel;
public PluginPanel() {
setLayout(new BorderLayout());
// tabbedPane = new JTabbedPane();
tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM) {
public void setUI(javax.swing.plaf.TabbedPaneUI ui) {
// Keep using tabbed pane ui so laf stays the same,
// but need to set a new one to pick up new tabbed
// pane colors, fonts, etc.
super.setUI(new PluginTabbedPaneUI());
}
};
add(tabbedPane);
titlePanel = new PluginTitlePanel("Hello world");
tabbedPane.addChangeListener(titlePanel);
add(titlePanel, BorderLayout.NORTH);
}
public boolean addPlugin(GUIPlugin plugin) {
tabbedPane.addTab(plugin.getName(), plugin.getIcon(), plugin);
return true;
}
public int containsPlugin(GUIPlugin plugin) {
int count = tabbedPane.getTabCount();
for (int i = 0; i < count; i++) {
Component c = tabbedPane.getComponentAt(i);
if (c.equals(plugin)) {
return i;
}
}
return -1; // Doesn't contain the specified plugin.
}
public int getPluginCount() {
return tabbedPane.getTabCount();
}
public Plugin[] getPlugins() {
int count = tabbedPane.getTabCount();
Plugin[] plugins = new Plugin[count];
for (int i = 0; i < count; i++) {
plugins[i] = (Plugin)
tabbedPane.getComponentAt(i);
}
return plugins;
}
public boolean removePlugin(GUIPlugin plugin) {
int index = containsPlugin(plugin);
if (index > -1) {
tabbedPane.removeTabAt(index);
return true;
}
return false;
}
}
/*****************************************************************************/
/**
* Panel that displays the currently-active plugin in a plugin panel.
*/
private static class PluginTitlePanel
extends JPanel
implements ChangeListener {
private JLabel label;
public PluginTitlePanel(String title) {
super(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
label = new JLabel(title);
label.setForeground(Color.WHITE);
add(label);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -