/*
* PluginManager.java - Plugin manager window
* :tabSize=4:indentSize=4:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 2002-2013 Slava Pestov, Matthieu Casanova, Kris Kopicki,
* Shlomy Reinstein, Alan Ezust, Björn "Vampire" Kautler
*
* 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.pluginmgr;
//{{{ Imports
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import org.gjt.sp.jedit.EditBus.EBHandler;
import org.gjt.sp.jedit.msg.*;
import org.gjt.sp.jedit.options.*;
import org.gjt.sp.jedit.pluginmgr.PluginList.Branch;
import org.gjt.sp.jedit.pluginmgr.PluginList.Dependency;
import org.gjt.sp.jedit.pluginmgr.PluginList.Plugin;
import org.gjt.sp.jedit.*;
import org.gjt.sp.util.Log;
import org.gjt.sp.util.StandardUtilities;
import org.gjt.sp.util.Task;
import org.gjt.sp.util.ThreadUtilities;
//}}}
/**
* @version $Id$
*/
public class PluginManager extends JFrame
{
//{{{ getInstance() method
/**
* Returns the currently visible plugin manager window, or null.
* @since jEdit 4.2pre2
*/
public static PluginManager getInstance()
{
return instance;
} //}}}
//{{{ dispose() method
@Override
public void dispose()
{
instance = null;
EditBus.removeFromBus(this);
EditBus.removeFromBus(installer);
super.dispose();
} //}}}
//{{{ handlePropertiesChanged() method
@EBHandler
public void handlePropertiesChanged(PropertiesChanged message)
{
if (pluginList != null && shouldUpdatePluginList())
{
pluginList = null;
updatePluginList();
}
} //}}}
//{{{ handlePluginUpdate() method
@EBHandler
public void handlePluginUpdate(PluginUpdate msg)
{
if(!queuedUpdate)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
queuedUpdate = false;
manager.update();
}
});
queuedUpdate = true;
}
} //}}}
//{{{ showPluginManager() method
public static void showPluginManager(Frame parent)
{
if (instance == null)
instance = new PluginManager(parent);
instance.toFront();
} //}}}
//{{{ ok() method
public void ok()
{
dispose();
} //}}}
//{{{ cancel() method
public void cancel()
{
dispose();
} //}}}
//{{{ getPluginList() method
PluginList getPluginList()
{
return pluginList;
} //}}}
//{{{ Private members
private static PluginManager instance;
//{{{ Instance variables
private JTabbedPane tabPane;
private JButton done;
private JButton mgrOptions;
private JButton pluginOptions;
private InstallPanel installer;
private InstallPanel updater;
private ManagePanel manager;
private PluginList pluginList;
private boolean queuedUpdate;
private boolean downloadingPluginList;
private final Frame parent;
//}}}
public static final String PROPERTY_PLUGINSET = "plugin-manager.pluginset.path";
//{{{ pluginRemoved() method
/**
* A callback called by the @link ManagePanel} when a plugin is removed.
* In that case, if the plugin had an update, the updater has to remove it,
* and the installer panel has to show the plugin again.
*/
void pluginRemoved()
{
updater.updateModel();
installer.updateModel();
} //}}}
//{{{ PluginManager constructor
private PluginManager(Frame parent)
{
super(jEdit.getProperty("plugin-manager.title"));
this.parent = parent;
init();
} //}}}
//{{{ init() method
private void init()
{
EditBus.addToBus(this);
/* Setup panes */
JPanel content = new JPanel(new BorderLayout(12,12));
content.setBorder(new EmptyBorder(12,12,12,12));
setContentPane(content);
tabPane = new JTabbedPane();
tabPane.addTab(jEdit.getProperty("manage-plugins.title"),
manager = new ManagePanel(this));
tabPane.addTab(jEdit.getProperty("update-plugins.title"),
updater = new InstallPanel(this,true));
tabPane.addTab(jEdit.getProperty("install-plugins.title"),
installer = new InstallPanel(this,false));
EditBus.addToBus(installer);
content.add(BorderLayout.CENTER,tabPane);
tabPane.addChangeListener(new ListUpdater());
/* Create the buttons */
Box buttons = new Box(BoxLayout.X_AXIS);
ActionListener al = new ActionHandler();
mgrOptions = new JButton(jEdit.getProperty("plugin-manager.mgr-options"));
mgrOptions.addActionListener(al);
pluginOptions = new JButton(jEdit.getProperty("plugin-manager.plugin-options"));
pluginOptions.addActionListener(al);
done = new JButton(jEdit.getProperty("plugin-manager.done"));
done.addActionListener(al);
buttons.add(Box.createGlue());
buttons.add(mgrOptions);
buttons.add(Box.createHorizontalStrut(6));
buttons.add(pluginOptions);
buttons.add(Box.createHorizontalStrut(6));
buttons.add(done);
getRootPane().setDefaultButton(done);
content.add(BorderLayout.SOUTH,buttons);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setIconImage(GUIUtilities.getPluginIcon());
pack();
GUIUtilities.loadGeometry(this, parent, "plugin-manager");
GUIUtilities.addSizeSaver(this, parent, "plugin-manager");
setVisible(true);
} //}}}
//{{{ shouldUpdatePluginList()
/**
* Check if the plugin list should be updated.
* It will return <code>true</code> if the pluginList is <code>null</code>
* or if the mirror id of the current plugin list is not the current preferred mirror id
* and will return always false if the plugin list is currently downloading
*
* @return true if the plugin list should be updated
*/
private boolean shouldUpdatePluginList()
{
return (pluginList == null ||
!pluginList.getMirrorId().equals(jEdit.getProperty("plugin-manager.mirror.id"))) &&
!downloadingPluginList;
} //}}}
//{{{ updatePluginList() method
private void updatePluginList()
{
if(jEdit.getSettingsDirectory() == null
&& jEdit.getJEditHome() == null)
{
GUIUtilities.error(this,"no-settings",null);
return;
}
if (!shouldUpdatePluginList())
{
return;
}
installer.loading();
updater.loading();
ThreadUtilities.runInBackground(new Task()
{
@Override
public void _run()
{
try
{
downloadingPluginList = true;
setStatus(jEdit.getProperty(
"plugin-manager.list-download-connect"));
pluginList = new PluginList(this);
}
finally
{
downloadingPluginList = false;
}
ThreadUtilities.runInDispatchThread(new Runnable()
{
public void run()
{
pluginListUpdated();
}
});
}
});
} //}}}
//{{{ checkForObsoletePlugins()
/** Checks for obsolete plugins, and marks them as unsupported.
* <p>
* An obsolete plugin branch can be marked as inactive, or
* an individual release can have a max jEdit version that is
* lower than the running version. If no later version/branch exists
* that supports this jEdit version, the plugin is unsupported.
* @since jEdit 5.1pre1
* @author Alan Ezust
*/
public void checkForObsoletePlugins()
{
if ((pluginList == null) || (pluginList.plugins == null)) return;
// for each plugin that is installed:
for (PluginJAR jar: jEdit.getPluginJARs())
{
EditPlugin eplugin = jar.getPlugin();
if (eplugin == null) continue;
String installedVersion = jEdit.getProperty("plugin." + eplugin.getClassName() + ".version");
// find corresponding entry in pluginList:
for (Plugin plugin: pluginList.plugins)
if (MiscUtilities.pathsEqual(plugin.jar, MiscUtilities.getFileName(jar.getPath())))
{
// find the branch with latest version greater than or equal to installedVersion
Branch lastBranch = null;
String latestVersion = "0";
for (Branch branch: plugin.branches)
if (StandardUtilities.compareStrings(branch.version, installedVersion, false) >= 0)
if (StandardUtilities.compareStrings(branch.version, latestVersion, false) >= 0)
{
latestVersion = branch.version;
lastBranch = branch;
}
if (lastBranch != null)
if (lastBranch.obsolete) disablePlugin(jar, plugin.name);
else for (Dependency dep: lastBranch.deps)
// if there is a max jEdit version, check if we're higher:
if (dep.what.equals("jedit") && (dep.to != null))
if (StandardUtilities.compareStrings(jEdit.getBuild(), dep.to, false) > 0)
disablePlugin(jar, plugin.name);
}
}
} //}}}
//{{{ disablePlugin()
private void disablePlugin(PluginJAR jar, String name)
{
Log.log(Log.ERROR, this, "Plugin: " + name +
" is not supported on this version of jEdit! ");
if (!jEdit.getBooleanProperty("plugin-manager.disable-obsolete", true)) return;
jEdit.removePluginJAR(jar,false);
String jarName = MiscUtilities.getFileName(jar.getPath());
// Stop it from getting loaded on startup:
jEdit.setBooleanProperty("plugin-blacklist."+ jarName, true);
// show as 'Unsupported' in Manage Panel:
jEdit.setBooleanProperty("plugin." + jarName + ".disabled", true);
jEdit.propertiesChanged();
}//}}}
//{{{ pluginListUpdated() method
private void pluginListUpdated()
{
Component selected = tabPane.getSelectedComponent();
if(selected == installer || selected == updater)
{
installer.updateModel();
updater.updateModel();
}
checkForObsoletePlugins();
} //}}}
//{{{ processKeyEvent() method
public void processKeyEvents(KeyEvent ke)
{
if ((ke.getID() == KeyEvent.KEY_PRESSED) &&
(ke.getKeyCode() == KeyEvent.VK_ESCAPE))
{
cancel();
ke.consume();
}
} //}}}
//}}}
//{{{ Inner classes
//{{{ ActionHandler class
@SuppressWarnings("deprecation")
class ActionHandler implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
// TODO: update this, use CombinedOptins instead of GlobalOptions
// and PluginOptions
Object source = evt.getSource();
if(source == done)
ok();
else if (source == mgrOptions)
new GlobalOptions(PluginManager.this,"plugin-manager");
else if (source == pluginOptions)
new PluginOptions(PluginManager.this);
}
} //}}}
//{{{ ListUpdater class
class ListUpdater implements ChangeListener
{
public void stateChanged(ChangeEvent e)
{
Component selected = tabPane.getSelectedComponent();
if(selected == installer || selected == updater)
{
updatePluginList();
}
else if(selected == manager)
manager.update();
}
} //}}}
//}}}
}