0001: /*
0002: * ManagePanel.java - Manages plugins
0003: * :tabSize=8:indentSize=8:noTabs=false:
0004: * :folding=explicit:collapseFolds=1:
0005: *
0006: * Copyright (C) 2002 Kris Kopicki
0007: *
0008: * This program is free software; you can redistribute it and/or
0009: * modify it under the terms of the GNU General Public License
0010: * as published by the Free Software Foundation; either version 2
0011: * of the License, or any later version.
0012: *
0013: * This program is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: * GNU General Public License for more details.
0017: *
0018: * You should have received a copy of the GNU General Public License
0019: * along with this program; if not, write to the Free Software
0020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0021: */
0022:
0023: package org.gjt.sp.jedit.pluginmgr;
0024:
0025: //{{{ Imports
0026: import java.awt.*;
0027:
0028: import java.awt.event.ActionEvent;
0029: import java.awt.event.ActionListener;
0030: import java.awt.event.FocusAdapter;
0031: import java.awt.event.FocusEvent;
0032: import java.awt.event.InputEvent;
0033: import java.awt.event.KeyEvent;
0034: import java.awt.event.MouseAdapter;
0035: import java.awt.event.MouseEvent;
0036:
0037: import java.net.URL;
0038:
0039: import java.util.*;
0040: import java.util.List;
0041:
0042: import javax.swing.*;
0043:
0044: import javax.swing.border.EmptyBorder;
0045:
0046: import javax.swing.event.ListSelectionEvent;
0047: import javax.swing.event.ListSelectionListener;
0048: import javax.swing.event.TableModelEvent;
0049:
0050: import javax.swing.table.AbstractTableModel;
0051: import javax.swing.table.DefaultTableCellRenderer;
0052: import javax.swing.table.JTableHeader;
0053: import javax.swing.table.TableColumn;
0054:
0055: import org.gjt.sp.jedit.*;
0056: import org.gjt.sp.jedit.io.FileVFS;
0057: import org.gjt.sp.jedit.io.VFS;
0058: import org.gjt.sp.jedit.io.VFSManager;
0059: import org.gjt.sp.jedit.msg.PropertiesChanged;
0060:
0061: import java.util.concurrent.ConcurrentHashMap;
0062: import java.io.*;
0063:
0064: import org.gjt.sp.jedit.browser.VFSBrowser;
0065: import org.gjt.sp.jedit.browser.VFSFileChooserDialog;
0066: import org.gjt.sp.jedit.gui.RolloverButton;
0067: import org.gjt.sp.jedit.help.*;
0068:
0069: import org.gjt.sp.util.Log;
0070: import org.gjt.sp.util.IOUtilities; //}}}
0071: import org.gjt.sp.util.XMLUtilities;
0072: import org.xml.sax.Attributes;
0073: import org.xml.sax.SAXException;
0074: import org.xml.sax.helpers.DefaultHandler;
0075:
0076: /**
0077: * The ManagePanel is the JPanel that shows the installed plugins.
0078: */
0079: public class ManagePanel extends JPanel {
0080: //{{{ Private members
0081: private final JCheckBox hideLibraries;
0082: private final JTable table;
0083: private final JScrollPane scrollpane;
0084: private final PluginTableModel pluginModel;
0085: private final PluginManager window;
0086: private JPopupMenu popup;
0087: private HashSet<String> selectedPlugins = null;
0088: private HashSet<String> jarNames = null;
0089:
0090: //}}}
0091:
0092: //{{{ ManagePanel constructor
0093: public ManagePanel(PluginManager window) {
0094: super (new BorderLayout(12, 12));
0095:
0096: this .window = window;
0097:
0098: setBorder(new EmptyBorder(12, 12, 12, 12));
0099:
0100: Box topBox = new Box(BoxLayout.X_AXIS);
0101: topBox.add(hideLibraries = new HideLibrariesButton());
0102: add(BorderLayout.NORTH, topBox);
0103:
0104: /* Create the plugin table */
0105: table = new JTable(pluginModel = new PluginTableModel());
0106: table.setShowGrid(false);
0107: table.setIntercellSpacing(new Dimension(0, 0));
0108: table.setRowHeight(table.getRowHeight() + 2);
0109: table
0110: .setPreferredScrollableViewportSize(new Dimension(500,
0111: 300));
0112: table.setDefaultRenderer(Object.class, new TextRenderer(
0113: (DefaultTableCellRenderer) table
0114: .getDefaultRenderer(Object.class)));
0115: table.addFocusListener(new TableFocusHandler());
0116: InputMap tableInputMap = table
0117: .getInputMap(JComponent.WHEN_FOCUSED);
0118: ActionMap tableActionMap = table.getActionMap();
0119: tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
0120: "tabOutForward");
0121: tableActionMap.put("tabOutForward", new KeyboardAction(
0122: KeyboardCommand.TAB_OUT_FORWARD));
0123: tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0124: InputEvent.SHIFT_MASK), "tabOutBack");
0125: tableActionMap.put("tabOutBack", new KeyboardAction(
0126: KeyboardCommand.TAB_OUT_BACK));
0127: tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
0128: "editPlugin");
0129: tableActionMap.put("editPlugin", new KeyboardAction(
0130: KeyboardCommand.EDIT_PLUGIN));
0131: tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
0132: "closePluginManager");
0133: tableActionMap.put("closePluginManager", new KeyboardAction(
0134: KeyboardCommand.CLOSE_PLUGIN_MANAGER));
0135:
0136: TableColumn col1 = table.getColumnModel().getColumn(0);
0137: TableColumn col2 = table.getColumnModel().getColumn(1);
0138: TableColumn col3 = table.getColumnModel().getColumn(2);
0139: TableColumn col4 = table.getColumnModel().getColumn(3);
0140:
0141: col1.setPreferredWidth(30);
0142: col1.setMinWidth(30);
0143: col1.setMaxWidth(30);
0144: col1.setResizable(false);
0145:
0146: col2.setPreferredWidth(300);
0147: col3.setPreferredWidth(100);
0148: col4.setPreferredWidth(100);
0149:
0150: JTableHeader header = table.getTableHeader();
0151: header.setReorderingAllowed(false);
0152: HeaderMouseHandler mouseHandler = new HeaderMouseHandler();
0153: header.addMouseListener(mouseHandler);
0154: table.addMouseListener(mouseHandler);
0155: scrollpane = new JScrollPane(table);
0156: scrollpane.getViewport().setBackground(table.getBackground());
0157: add(BorderLayout.CENTER, scrollpane);
0158:
0159: /* Create button panel */
0160: Box buttons = new Box(BoxLayout.X_AXIS);
0161:
0162: buttons.add(new RemoveButton());
0163: buttons.add(new SaveButton());
0164: buttons.add(new RestoreButton());
0165: buttons.add(new FindOrphan());
0166: buttons.add(Box.createGlue());
0167: buttons.add(new HelpButton());
0168:
0169: add(BorderLayout.SOUTH, buttons);
0170:
0171: pluginModel.update();
0172: } //}}}
0173:
0174: //{{{ update() method
0175: public void update() {
0176: pluginModel.update();
0177: } //}}}
0178:
0179: // {{{ class ManagePanelRestoreHandler
0180: /**
0181: * For handling the XML parse events of a plugin set.
0182: * Selects the same plugins that are in that set.
0183: * @since jEdit 4.3pre10
0184: */
0185: class ManagePanelRestoreHandler extends DefaultHandler {
0186: ManagePanelRestoreHandler() {
0187: selectedPlugins = new HashSet<String>();
0188: jarNames = new HashSet<String>();
0189: }
0190:
0191: public void startElement(String uri, String localName,
0192: String qName, Attributes attrs) throws SAXException {
0193: if (localName.equals("plugin")) {
0194: String jarName = attrs.getValue("jar");
0195: String name = attrs.getValue("name");
0196: Entry e = new Entry(jarName);
0197: e.name = name;
0198: selectedPlugins.add(name);
0199: jarNames.add(jarName);
0200: }
0201: }
0202: }//}}}
0203:
0204: //{{{ loadPluginSet() method
0205: boolean loadPluginSet(String path) {
0206: VFS vfs = VFSManager.getVFSForPath(path);
0207: Object session = vfs.createVFSSession(path, ManagePanel.this );
0208: try {
0209: InputStream is = vfs._createInputStream(session, path,
0210: false, ManagePanel.this );
0211: XMLUtilities.parseXML(is, new ManagePanelRestoreHandler());
0212: is.close();
0213: int rowCount = pluginModel.getRowCount();
0214: for (int i = 0; i < rowCount; i++) {
0215: Entry ent = pluginModel.getEntry(i);
0216: String name = ent.name;
0217: if (name != null) {
0218: pluginModel.setValueAt(selectedPlugins
0219: .contains(name), i, 0);
0220: } else {
0221: String jarPath = ent.jar;
0222: String jarName = jarPath.substring(1 + jarPath
0223: .lastIndexOf(File.separatorChar));
0224: try {
0225: pluginModel.setValueAt(jarNames
0226: .contains(jarName), i, 0);
0227: } catch (Exception e) {
0228: Log.log(Log.WARNING, this ,
0229: "Exception thrown loading: " + jarName);
0230: }
0231: }
0232: }
0233: } catch (Exception e) {
0234: Log.log(Log.ERROR, this , "Loading Pluginset Error", e);
0235: return false;
0236: }
0237: pluginModel.update();
0238: return true;
0239: }//}}}
0240:
0241: //{{{ getDeclaredJars() method
0242: /**
0243: * Returns a collection of declared jars in the plugin.
0244: * If the plugin is loaded use {@link org.gjt.sp.jedit.PluginJAR#getRequiredJars()}
0245: * instead
0246: *
0247: * @param jarName the jar name of the plugin
0248: * @return a collection containing jars path
0249: * @throws IOException if jEdit cannot generate cache
0250: * @since jEdit 4.3pre12
0251: */
0252: private Collection<String> getDeclaredJars(String jarName)
0253: throws IOException {
0254: Collection<String> jarList = new ArrayList<String>();
0255: PluginJAR pluginJAR = new PluginJAR(new File(jarName));
0256: PluginJAR.PluginCacheEntry pluginCacheEntry = PluginJAR
0257: .getPluginCache(pluginJAR);
0258: if (pluginCacheEntry == null) {
0259: pluginCacheEntry = pluginJAR.generateCache();
0260: }
0261: Properties cachedProperties = pluginCacheEntry.cachedProperties;
0262:
0263: String jars = cachedProperties.getProperty("plugin."
0264: + pluginCacheEntry.pluginClass + ".jars");
0265:
0266: if (jars != null) {
0267: String dir = MiscUtilities.getParentOfPath(pluginJAR
0268: .getPath());
0269: StringTokenizer st = new StringTokenizer(jars);
0270: while (st.hasMoreTokens()) {
0271: String _jarPath = MiscUtilities.constructPath(dir, st
0272: .nextToken());
0273: if (new File(_jarPath).exists())
0274: jarList.add(_jarPath);
0275: }
0276: }
0277: jarList.add(jarName);
0278: return jarList;
0279: }//}}}
0280:
0281: //}}}
0282: //{{{ Inner classes
0283:
0284: //{{{ KeyboardCommand enum
0285: public enum KeyboardCommand {
0286: NONE, TAB_OUT_FORWARD, TAB_OUT_BACK, EDIT_PLUGIN, CLOSE_PLUGIN_MANAGER
0287: } //}}}
0288:
0289: //{{{ Entry class
0290: static class Entry {
0291: static final String ERROR = "error";
0292: static final String LOADED = "loaded";
0293: static final String NOT_LOADED = "not-loaded";
0294:
0295: final String status;
0296: /** The jar path. */
0297: final String jar;
0298:
0299: String clazz, name, version, author, docs;
0300:
0301: EditPlugin plugin;
0302: /**
0303: * The jars referenced in the props file of the plugin.
0304: * plugin.clazz.jars property and
0305: * plugin.clazz.files property
0306: */
0307: final List<String> jars;
0308:
0309: /** The data size. */
0310: String dataSize;
0311:
0312: /**
0313: * Constructor used for jars that aren't loaded.
0314: *
0315: * @param jar jar file name
0316: */
0317: Entry(String jar) {
0318: jars = new LinkedList<String>();
0319: this .jar = jar;
0320: jars.add(this .jar);
0321: status = NOT_LOADED;
0322: }
0323:
0324: /**
0325: * Constructor used for loaded jars.
0326: *
0327: * @param jar the pluginJar
0328: */
0329: Entry(PluginJAR jar) {
0330: jars = new LinkedList<String>();
0331: this .jar = jar.getPath();
0332: jars.add(this .jar);
0333:
0334: plugin = jar.getPlugin();
0335: if (plugin != null) {
0336: status = plugin instanceof EditPlugin.Broken ? ERROR
0337: : LOADED;
0338: clazz = plugin.getClassName();
0339: name = jEdit.getProperty("plugin." + clazz + ".name");
0340: version = jEdit.getProperty("plugin." + clazz
0341: + ".version");
0342: author = jEdit.getProperty("plugin." + clazz
0343: + ".author");
0344: docs = jEdit.getProperty("plugin." + clazz + ".docs");
0345:
0346: String jarsProp = jEdit.getProperty("plugin." + clazz
0347: + ".jars");
0348:
0349: if (jarsProp != null) {
0350: String directory = MiscUtilities
0351: .getParentOfPath(this .jar);
0352:
0353: StringTokenizer st = new StringTokenizer(jarsProp);
0354: while (st.hasMoreElements()) {
0355: jars.add(MiscUtilities.constructPath(directory,
0356: st.nextToken()));
0357: }
0358: }
0359:
0360: String filesProp = jEdit.getProperty("plugin." + clazz
0361: + ".files");
0362:
0363: if (filesProp != null) {
0364: String directory = MiscUtilities
0365: .getParentOfPath(this .jar);
0366:
0367: StringTokenizer st = new StringTokenizer(filesProp);
0368: while (st.hasMoreElements()) {
0369: jars.add(MiscUtilities.constructPath(directory,
0370: st.nextToken()));
0371: }
0372: }
0373: } else {
0374: status = LOADED;
0375: }
0376: }
0377: } //}}}
0378:
0379: //{{{ PluginTableModel class
0380: class PluginTableModel extends AbstractTableModel {
0381: private final List<Entry> entries;
0382: private int sortType = EntryCompare.NAME;
0383: private ConcurrentHashMap<String, Object> unloaded;
0384:
0385: // private HashSet<String> unloaded;
0386:
0387: //{{{ Constructor
0388: PluginTableModel() {
0389: entries = new ArrayList<Entry>();
0390: } //}}}
0391:
0392: //{{{ getColumnCount() method
0393: public int getColumnCount() {
0394: return 5;
0395: } //}}}
0396:
0397: //{{{ getColumnClass() method
0398: public Class getColumnClass(int columnIndex) {
0399: switch (columnIndex) {
0400: case 0:
0401: return Boolean.class;
0402: default:
0403: return Object.class;
0404: }
0405: } //}}}
0406:
0407: //{{{ getColumnName() method
0408: public String getColumnName(int column) {
0409: switch (column) {
0410: case 0:
0411: return " ";
0412: case 1:
0413: return jEdit.getProperty("manage-plugins.info.name");
0414: case 2:
0415: return jEdit.getProperty("manage-plugins.info.version");
0416: case 3:
0417: return jEdit.getProperty("manage-plugins.info.status");
0418: case 4:
0419: return jEdit.getProperty("manage-plugins.info.data");
0420: default:
0421: throw new Error("Column out of range");
0422: }
0423: } //}}}
0424:
0425: //{{{ getEntry() method
0426: public Entry getEntry(int rowIndex) {
0427: return entries.get(rowIndex);
0428: } //}}}
0429:
0430: //{{{ getRowCount() method
0431: public int getRowCount() {
0432: return entries.size();
0433: } //}}}
0434:
0435: //{{{ getValueAt() method
0436: public Object getValueAt(int rowIndex, int columnIndex) {
0437: Entry entry = entries.get(rowIndex);
0438: switch (columnIndex) {
0439: case 0:
0440: return Boolean.valueOf(!entry.status
0441: .equals(Entry.NOT_LOADED));
0442: case 1:
0443: if (entry.name == null) {
0444: return MiscUtilities.getFileName(entry.jar);
0445: } else {
0446: return entry.name;
0447: }
0448: case 2:
0449: return entry.version;
0450: case 3:
0451: return jEdit.getProperty("plugin-manager.status."
0452: + entry.status);
0453: case 4:
0454: if (entry.dataSize == null && entry.plugin != null) {
0455: File pluginDirectory = entry.plugin.getPluginHome();
0456: if (null == pluginDirectory) {
0457: return null;
0458: }
0459: if (pluginDirectory.exists()) {
0460: entry.dataSize = MiscUtilities
0461: .formatFileSize(IOUtilities
0462: .fileLength(pluginDirectory));
0463: } else {
0464: if (jEdit.getBooleanProperty("plugin."
0465: + entry.clazz + ".usePluginHome")) {
0466: entry.dataSize = MiscUtilities
0467: .formatFileSize(0);
0468: } else {
0469: entry.dataSize = jEdit
0470: .getProperty("manage-plugins.data-size.unknown");
0471: }
0472:
0473: }
0474: }
0475: return entry.dataSize;
0476: default:
0477: throw new Error("Column out of range");
0478: }
0479: } //}}}
0480:
0481: //{{{ isCellEditable() method
0482: public boolean isCellEditable(int rowIndex, int columnIndex) {
0483: return columnIndex == 0;
0484: } //}}}
0485:
0486: //{{{ setValueAt() method
0487: public void setValueAt(Object value, int rowIndex,
0488: int columnIndex) {
0489: Entry entry = entries.get(rowIndex);
0490: if (columnIndex == 0) {
0491: PluginJAR jar = jEdit.getPluginJAR(entry.jar);
0492: if (jar == null) {
0493: if (value.equals(Boolean.FALSE))
0494: return;
0495:
0496: PluginJAR.load(entry.jar, true);
0497: } else {
0498: if (value.equals(Boolean.TRUE))
0499: return;
0500:
0501: unloadPluginJARWithDialog(jar);
0502: }
0503: }
0504:
0505: update();
0506: } //}}}
0507:
0508: //{{{ setSortType() method
0509: public void setSortType(int type) {
0510: sortType = type;
0511: sort(type);
0512: } //}}}
0513:
0514: //{{{ sort() method
0515: public void sort(int type) {
0516: ArrayList<String> savedSelection = new ArrayList<String>();
0517: saveSelection(savedSelection);
0518: Collections.sort(entries, new EntryCompare(type));
0519: fireTableChanged(new TableModelEvent(this ));
0520: restoreSelection(savedSelection);
0521: }
0522:
0523: //}}}
0524:
0525: //{{{ update() method
0526: public void update() {
0527: ArrayList<String> savedSelection = new ArrayList<String>();
0528: saveSelection(savedSelection);
0529: entries.clear();
0530:
0531: String systemJarDir = MiscUtilities.constructPath(jEdit
0532: .getJEditHome(), "jars");
0533: String userJarDir;
0534: String settingsDirectory = jEdit.getSettingsDirectory();
0535: if (settingsDirectory == null)
0536: userJarDir = null;
0537: else {
0538: userJarDir = MiscUtilities.constructPath(
0539: settingsDirectory, "jars");
0540: }
0541:
0542: PluginJAR[] plugins = jEdit.getPluginJARs();
0543: for (int i = 0; i < plugins.length; i++) {
0544: String path = plugins[i].getPath();
0545: if (path.startsWith(systemJarDir)
0546: || (userJarDir != null && path
0547: .startsWith(userJarDir))) {
0548: Entry e = new Entry(plugins[i]);
0549: if (!hideLibraries.isSelected() || e.clazz != null) {
0550: entries.add(e);
0551: }
0552: }
0553: }
0554:
0555: String[] newPlugins = jEdit.getNotLoadedPluginJARs();
0556: for (int i = 0; i < newPlugins.length; i++) {
0557: Entry e = new Entry(newPlugins[i]);
0558: entries.add(e);
0559: }
0560:
0561: sort(sortType);
0562: restoreSelection(savedSelection);
0563: } //}}}
0564:
0565: //{{{ unloadPluginJARWithDialog() method
0566: // Perhaps this should also be moved to PluginJAR class?
0567: private void unloadPluginJARWithDialog(PluginJAR jar) {
0568: // unloaded = new HashSet<String>();
0569: unloaded = new ConcurrentHashMap<String, Object>();
0570: String[] dependents = jar.getDependentPlugins();
0571: if (dependents.length == 0)
0572: unloadPluginJAR(jar);
0573: else {
0574: List<String> closureSet = new LinkedList<String>();
0575: PluginJAR.transitiveClosure(dependents, closureSet);
0576: ArrayList<String> listModel = new ArrayList<String>();
0577: listModel.addAll(closureSet);
0578: Collections.sort(listModel,
0579: new MiscUtilities.StringICaseCompare());
0580:
0581: int button = GUIUtilities.listConfirm(window,
0582: "plugin-manager.dependency", new String[] { jar
0583: .getFile().getName() }, listModel
0584: .toArray());
0585: if (button == JOptionPane.YES_OPTION)
0586: unloadPluginJAR(jar);
0587: }
0588: } //}}}
0589:
0590: //{{{ unloadPluginJAR() method
0591: private void unloadPluginJAR(PluginJAR jar) {
0592: String[] dependents = jar.getDependentPlugins();
0593: for (String dependent : dependents) {
0594: if (!unloaded.containsKey(dependent)) {
0595: unloaded.put(dependent, Boolean.TRUE);
0596: PluginJAR _jar = jEdit.getPluginJAR(dependent);
0597: if (_jar != null)
0598: unloadPluginJAR(_jar);
0599: }
0600: }
0601: jEdit.removePluginJAR(jar, false);
0602: jEdit.setBooleanProperty("plugin-blacklist."
0603: + MiscUtilities.getFileName(jar.getPath()), true);
0604: } //}}}
0605:
0606: //{{{ saveSelection() method
0607: /**
0608: * Save the selection in the given list.
0609: * The list will be filled with the jar names of the selected entries
0610: *
0611: * @param savedSelection the list where to save the selection
0612: */
0613: public void saveSelection(List<String> savedSelection) {
0614: if (table != null) {
0615: int[] rows = table.getSelectedRows();
0616: for (int i = 0; i < rows.length; i++) {
0617: savedSelection.add(entries.get(rows[i]).jar);
0618: }
0619: }
0620: } //}}}
0621:
0622: //{{{ restoreSelection() method
0623: /**
0624: * Restore the selection.
0625: *
0626: * @param savedSelection the selection list that contains the jar names of the selected items
0627: */
0628: public void restoreSelection(List<String> savedSelection) {
0629: if (null != table) {
0630: table.setColumnSelectionInterval(0, 0);
0631: if (!savedSelection.isEmpty()) {
0632: int i = 0;
0633: int rowCount = getRowCount();
0634: for (; i < rowCount; i++) {
0635: if (savedSelection.contains(entries.get(i).jar)) {
0636: table.setRowSelectionInterval(i, i);
0637: break;
0638: }
0639: }
0640: ListSelectionModel lsm = table.getSelectionModel();
0641: for (; i < rowCount; i++) {
0642: if (savedSelection.contains(entries.get(i).jar)) {
0643: lsm.addSelectionInterval(i, i);
0644: }
0645: }
0646: } else {
0647: if (table.getRowCount() != 0)
0648: table.setRowSelectionInterval(0, 0);
0649: JScrollBar scrollbar = scrollpane
0650: .getVerticalScrollBar();
0651: scrollbar.setValue(scrollbar.getMinimum());
0652: }
0653: }
0654: } //}}}
0655: } //}}}
0656:
0657: //{{{ TextRenderer class
0658: class TextRenderer extends DefaultTableCellRenderer {
0659: private final DefaultTableCellRenderer tcr;
0660:
0661: TextRenderer(DefaultTableCellRenderer tcr) {
0662: this .tcr = tcr;
0663: }
0664:
0665: public Component getTableCellRendererComponent(JTable table,
0666: Object value, boolean isSelected, boolean hasFocus,
0667: int row, int column) {
0668: Entry entry = pluginModel.getEntry(row);
0669: if (entry.status.equals(Entry.ERROR))
0670: tcr.setForeground(Color.red);
0671: else
0672: tcr.setForeground(UIManager
0673: .getColor("Table.foreground"));
0674: return tcr.getTableCellRendererComponent(table, value,
0675: isSelected, false, row, column);
0676: }
0677: } //}}}
0678:
0679: //{{{ HideLibrariesButton class
0680: class HideLibrariesButton extends JCheckBox implements
0681: ActionListener {
0682: HideLibrariesButton() {
0683: super (jEdit.getProperty("plugin-manager.hide-libraries"));
0684: setSelected(jEdit
0685: .getBooleanProperty("plugin-manager.hide-libraries.toggle"));
0686: addActionListener(this );
0687: }
0688:
0689: public void actionPerformed(ActionEvent evt) {
0690: jEdit.setBooleanProperty(
0691: "plugin-manager.hide-libraries.toggle",
0692: isSelected());
0693: ManagePanel.this .update();
0694: }
0695: } //}}}
0696:
0697: //{{{ RestoreButton class
0698: /**
0699: * Permits the user to restore the state of the ManagePanel
0700: * based on a PluginSet.
0701: *
0702: * Selects all loaded plugins that appear in an .XML file, and deselects
0703: * all others, and also sets the pluginset to that .XML file. Does not install any plugins
0704: * that were not previously installed.
0705: *
0706: * @since jEdit 4.3pre10
0707: * @author Alan Ezust
0708: */
0709: class RestoreButton extends RolloverButton implements
0710: ActionListener {
0711: RestoreButton() {
0712: setIcon(GUIUtilities.loadIcon("OpenFile.png"));
0713: addActionListener(this );
0714: setToolTipText("Choose a PluginSet, select/deselect plugins based on set.");
0715: }
0716:
0717: public void actionPerformed(ActionEvent e) {
0718: String path = jEdit.getProperty(
0719: PluginManager.PROPERTY_PLUGINSET, jEdit
0720: .getSettingsDirectory()
0721: + File.separator);
0722: String[] selectedFiles = GUIUtilities.showVFSFileDialog(
0723: ManagePanel.this .window, jEdit.getActiveView(),
0724: path, VFSBrowser.OPEN_DIALOG, false);
0725: if (selectedFiles == null || selectedFiles.length != 1)
0726: return;
0727: path = selectedFiles[0];
0728: boolean success = loadPluginSet(path);
0729: if (success) {
0730: jEdit.setProperty(PluginManager.PROPERTY_PLUGINSET,
0731: path);
0732: EditBus.send(new PropertiesChanged(PluginManager
0733: .getInstance()));
0734: }
0735:
0736: }
0737: }//}}}
0738:
0739: //{{{ SaveButton class
0740: /**
0741: * Permits the user to save the state of the ManagePanel,
0742: * which in this case, is nothing more than a list of
0743: * all plugins currently loaded.
0744: * @since jEdit 4.3pre10
0745: * @author Alan Ezust
0746: */
0747: class SaveButton extends RolloverButton implements ActionListener {
0748: SaveButton() {
0749: setIcon(GUIUtilities.loadIcon("Save.png"));
0750: setToolTipText("Save Currently Checked Plugins Set");
0751: addActionListener(this );
0752: setEnabled(true);
0753: }
0754:
0755: void saveState(String vfsURL, List<Entry> pluginList) {
0756: StringBuffer sb = new StringBuffer("<pluginset>\n ");
0757:
0758: for (Entry entry : pluginList) {
0759: String jarName = entry.jar.substring(1 + entry.jar
0760: .lastIndexOf(File.separatorChar));
0761: sb.append(" <plugin name=\"" + entry.name
0762: + "\" jar=\"" + jarName + "\" />\n ");
0763: }
0764: sb.append("</pluginset>\n");
0765:
0766: VFS vfs = VFSManager.getVFSForPath(vfsURL);
0767: Object session = vfs.createVFSSession(vfsURL,
0768: ManagePanel.this );
0769: try {
0770: OutputStream os = vfs._createOutputStream(session,
0771: vfsURL, ManagePanel.this );
0772: OutputStreamWriter writer = new OutputStreamWriter(os);
0773: writer.write(sb.toString());
0774: writer.close();
0775: os.close();
0776: } catch (Exception e) {
0777: Log.log(Log.ERROR, this , "Saving State Error", e);
0778: }
0779:
0780: }
0781:
0782: public void actionPerformed(ActionEvent e) {
0783: String path = jEdit.getProperty(
0784: "plugin-manager.pluginset.path", jEdit
0785: .getSettingsDirectory()
0786: + File.separator);
0787: VFSFileChooserDialog fileChooser = new VFSFileChooserDialog(
0788: ManagePanel.this .window, jEdit.getActiveView(),
0789: path, VFSBrowser.SAVE_DIALOG, false, true);
0790: String[] fileselections = fileChooser.getSelectedFiles();
0791: ArrayList<Entry> pluginSelections = new ArrayList<Entry>();
0792: if (fileselections == null || fileselections.length != 1)
0793: return;
0794:
0795: PluginJAR[] jars = jEdit.getPluginJARs();
0796: for (PluginJAR jar : jars) {
0797: if (jar.getPlugin() != null) {
0798: Entry entry = new Entry(jar);
0799: pluginSelections.add(entry);
0800: }
0801: }
0802: saveState(fileselections[0], pluginSelections);
0803: jEdit.setProperty("plugin-manager.pluginset.path",
0804: fileselections[0]);
0805: EditBus.send(new PropertiesChanged(PluginManager
0806: .getInstance()));
0807: }
0808: }//}}}
0809:
0810: //{{{ RemoveButton class
0811: class RemoveButton extends JButton implements
0812: ListSelectionListener, ActionListener {
0813: RemoveButton() {
0814: super (jEdit.getProperty("manage-plugins.remove"));
0815: table.getSelectionModel().addListSelectionListener(this );
0816: addActionListener(this );
0817: setEnabled(false);
0818: }
0819:
0820: public void actionPerformed(ActionEvent evt) {
0821: int[] selected = table.getSelectedRows();
0822:
0823: List<String> listModel = new LinkedList<String>();
0824: Roster roster = new Roster();
0825: Set<String> jarsToRemove = new HashSet<String>();
0826: for (int i = 0; i < selected.length; i++) {
0827: Entry entry = pluginModel.getEntry(selected[i]);
0828: if (entry.status.equals(Entry.NOT_LOADED)) {
0829: if (entry.jar != null) {
0830: try {
0831: Collection<String> jarList = getDeclaredJars(entry.jar);
0832: jarsToRemove.addAll(jarList);
0833: } catch (IOException e) {
0834: Log.log(Log.ERROR, this , e);
0835: }
0836: }
0837: } else {
0838: jarsToRemove.addAll(entry.jars);
0839: }
0840: table.getSelectionModel().removeSelectionInterval(
0841: selected[i], selected[i]);
0842: }
0843:
0844: for (String jar : jarsToRemove) {
0845: listModel.add(jar);
0846: roster.addRemove(jar);
0847: }
0848:
0849: int button = GUIUtilities.listConfirm(window,
0850: "plugin-manager.remove-confirm", null, listModel
0851: .toArray());
0852: if (button == JOptionPane.YES_OPTION) {
0853: roster.performOperationsInAWTThread(window);
0854: pluginModel.update();
0855: if (table.getRowCount() != 0) {
0856: table.setRowSelectionInterval(0, 0);
0857: }
0858: table.setColumnSelectionInterval(0, 0);
0859: JScrollBar scrollbar = scrollpane
0860: .getVerticalScrollBar();
0861: scrollbar.setValue(scrollbar.getMinimum());
0862: }
0863: }
0864:
0865: public void valueChanged(ListSelectionEvent e) {
0866: if (table.getSelectedRowCount() == 0)
0867: setEnabled(false);
0868: else
0869: setEnabled(true);
0870: }
0871: } //}}}
0872:
0873: //{{{ FindOrphanActionListener class
0874: private class FindOrphan extends JButton implements ActionListener {
0875: private FindOrphan() {
0876: super (jEdit.getProperty("plugin-manager.findOrphan.label"));
0877: addActionListener(this );
0878: }
0879:
0880: public void actionPerformed(ActionEvent e) {
0881: PluginJAR[] pluginJARs = jEdit.getPluginJARs();
0882: Set<String> neededJars = new HashSet<String>();
0883:
0884: Map<String, String> jarlibs = new HashMap<String, String>();
0885: for (PluginJAR pluginJAR : pluginJARs) {
0886: EditPlugin plugin = pluginJAR.getPlugin();
0887: if (plugin == null) {
0888: jarlibs.put(
0889: new File(pluginJAR.getPath()).getName(),
0890: pluginJAR.getPath());
0891: } else {
0892: Set<String> strings = plugin.getPluginJAR()
0893: .getRequiredJars();
0894: for (String string : strings) {
0895: neededJars.add(new File(string).getName());
0896: }
0897: }
0898: }
0899:
0900: String[] notLoadedJars = jEdit.getNotLoadedPluginJARs();
0901: for (int i = 0; i < notLoadedJars.length; i++) {
0902: PluginJAR pluginJAR = new PluginJAR(new File(
0903: notLoadedJars[i]));
0904: PluginJAR.PluginCacheEntry pluginCacheEntry = PluginJAR
0905: .getPluginCache(pluginJAR);
0906: try {
0907: if (pluginCacheEntry == null) {
0908: pluginCacheEntry = pluginJAR.generateCache();
0909: }
0910: if (pluginCacheEntry.pluginClass == null) {
0911: // Not a plugin
0912: jarlibs.put(new File(notLoadedJars[i])
0913: .getName(), notLoadedJars[i]);
0914: continue;
0915: }
0916:
0917: Properties cachedProperties = pluginCacheEntry.cachedProperties;
0918:
0919: String jars = cachedProperties
0920: .getProperty("plugin."
0921: + pluginCacheEntry.pluginClass
0922: + ".jars");
0923:
0924: if (jars != null) {
0925: StringTokenizer st = new StringTokenizer(jars);
0926: while (st.hasMoreTokens()) {
0927: neededJars.add(st.nextToken());
0928: }
0929: }
0930: } catch (IOException e1) {
0931: Log.log(Log.ERROR, this , e);
0932: }
0933: }
0934:
0935: List<String> removingJars = new ArrayList<String>();
0936: Set<String> jarlibsKeys = jarlibs.keySet();
0937: for (String jar : jarlibsKeys) {
0938: if (!neededJars.contains(jar)) {
0939: removingJars.add(jar);
0940: Log.log(Log.MESSAGE, this ,
0941: "It seems that this jar do not belong to any plugin "
0942: + jar);
0943: }
0944: }
0945: if (removingJars.isEmpty()) {
0946: GUIUtilities.message(ManagePanel.this ,
0947: "plugin-manager.noOrphan", null);
0948: return;
0949: }
0950:
0951: String[] strings = removingJars
0952: .toArray(new String[removingJars.size()]);
0953: List<String> mustRemove = new ArrayList<String>();
0954: int ret = GUIUtilities.listConfirm(ManagePanel.this ,
0955: "plugin-manager.findOrphan", null, strings,
0956: mustRemove);
0957: if (ret != JOptionPane.OK_OPTION || mustRemove.isEmpty())
0958: return;
0959:
0960: Roster roster = new Roster();
0961: for (int i = 0; i < mustRemove.size(); i++) {
0962: String entry = mustRemove.get(i);
0963: roster.addRemove(jarlibs.get(entry));
0964: }
0965:
0966: roster.performOperationsInAWTThread(window);
0967: pluginModel.update();
0968: if (table.getRowCount() != 0) {
0969: table.setRowSelectionInterval(0, 0);
0970: }
0971: table.setColumnSelectionInterval(0, 0);
0972: JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
0973: scrollbar.setValue(scrollbar.getMinimum());
0974: table.repaint();
0975: }
0976: } //}}}
0977:
0978: //{{{ HelpButton class
0979: class HelpButton extends JButton implements ListSelectionListener,
0980: ActionListener {
0981: private URL docURL;
0982:
0983: HelpButton() {
0984: super (jEdit.getProperty("manage-plugins.help"));
0985: table.getSelectionModel().addListSelectionListener(this );
0986: addActionListener(this );
0987: setEnabled(false);
0988: }
0989:
0990: public void actionPerformed(ActionEvent evt) {
0991: new HelpViewer(docURL);
0992: }
0993:
0994: public void valueChanged(ListSelectionEvent e) {
0995: if (table.getSelectedRowCount() == 1) {
0996: try {
0997: Entry entry = pluginModel.getEntry(table
0998: .getSelectedRow());
0999: String label = entry.clazz;
1000: String docs = entry.docs;
1001: if (label != null) {
1002: EditPlugin plug = jEdit.getPlugin(label, false);
1003: PluginJAR jar = null;
1004: if (plug != null)
1005: jar = plug.getPluginJAR();
1006: if (jar != null && docs != null) {
1007: URL url = jar.getClassLoader().getResource(
1008: docs);
1009: if (url != null) {
1010: docURL = url;
1011: setEnabled(true);
1012: return;
1013: }
1014: }
1015: }
1016: } catch (Exception ex) {
1017: Log.log(Log.ERROR, this ,
1018: "ManagePanel HelpButton Update", ex);
1019: }
1020: }
1021: setEnabled(false);
1022: }
1023: } //}}}
1024:
1025: //{{{ EntryCompare class
1026: private static class EntryCompare implements
1027: Comparator<ManagePanel.Entry> {
1028: public static final int NAME = 1;
1029: public static final int STATUS = 2;
1030:
1031: private final int type;
1032:
1033: EntryCompare(int type) {
1034: this .type = type;
1035: }
1036:
1037: public int compare(ManagePanel.Entry e1, ManagePanel.Entry e2) {
1038: if (type == NAME)
1039: return compareNames(e1, e2);
1040: else {
1041: int result;
1042: if ((result = e1.status.compareToIgnoreCase(e2.status)) == 0)
1043: return compareNames(e1, e2);
1044: return result;
1045: }
1046: }
1047:
1048: private static int compareNames(ManagePanel.Entry e1,
1049: ManagePanel.Entry e2) {
1050: String s1;
1051: if (e1.name == null)
1052: s1 = MiscUtilities.getFileName(e1.jar);
1053: else
1054: s1 = e1.name;
1055: String s2;
1056: if (e2.name == null)
1057: s2 = MiscUtilities.getFileName(e2.jar);
1058: else
1059: s2 = e2.name;
1060:
1061: return s1.compareToIgnoreCase(s2);
1062: }
1063: } //}}}
1064:
1065: //{{{ HeaderMouseHandler class
1066: class HeaderMouseHandler extends MouseAdapter {
1067: public void mouseClicked(MouseEvent evt) {
1068: if (evt.getSource() == table.getTableHeader()) {
1069: switch (table.getTableHeader().columnAtPoint(
1070: evt.getPoint())) {
1071: case 1:
1072: pluginModel.setSortType(EntryCompare.NAME);
1073: break;
1074: case 3:
1075: pluginModel.setSortType(EntryCompare.STATUS);
1076: break;
1077: default:
1078: break;
1079: }
1080: } else {
1081: if (GUIUtilities.isPopupTrigger(evt)) {
1082: int row = table.rowAtPoint(evt.getPoint());
1083: if ((-1 != row) && (!table.isRowSelected(row))) {
1084: table.setRowSelectionInterval(row, row);
1085: }
1086: if (popup == null) {
1087: popup = new JPopupMenu();
1088: JMenuItem item = GUIUtilities
1089: .loadMenuItem("plugin-manager.cleanup");
1090: item
1091: .addActionListener(new CleanupActionListener());
1092: popup.add(item);
1093: }
1094: GUIUtilities.showPopupMenu(popup, table,
1095: evt.getX(), evt.getY());
1096: }
1097: }
1098: }
1099:
1100: //{{{ CleanupActionListener class
1101: private class CleanupActionListener implements ActionListener {
1102: public void actionPerformed(ActionEvent e) {
1103:
1104: int[] ints = table.getSelectedRows();
1105: List<String> list = new ArrayList<String>(ints.length);
1106: List<Entry> entries = new ArrayList<Entry>(ints.length);
1107: for (int i = 0; i < ints.length; i++) {
1108: Entry entry = pluginModel.getEntry(ints[i]);
1109: if (entry.plugin != null) {
1110: list.add(entry.name);
1111: entries.add(entry);
1112: }
1113: }
1114:
1115: String[] strings = list
1116: .toArray(new String[list.size()]);
1117: int ret = GUIUtilities.listConfirm(ManagePanel.this ,
1118: "plugin-manager.cleanup", null, strings);
1119: if (ret != JOptionPane.OK_OPTION)
1120: return;
1121:
1122: for (int i = 0; i < entries.size(); i++) {
1123: Entry entry = entries.get(i);
1124: File path = entry.plugin.getPluginHome();
1125: Log.log(Log.NOTICE, this ,
1126: "Removing data of plugin " + entry.name
1127: + " home=" + path);
1128: FileVFS.recursiveDelete(path);
1129: entry.dataSize = null;
1130: }
1131: table.repaint();
1132: }
1133: } //}}}
1134: } //}}}
1135:
1136: //{{{ KeyboardAction class
1137: class KeyboardAction extends AbstractAction {
1138: private KeyboardCommand command = KeyboardCommand.NONE;
1139:
1140: KeyboardAction(KeyboardCommand command) {
1141: this .command = command;
1142: }
1143:
1144: public void actionPerformed(ActionEvent evt) {
1145: switch (command) {
1146: case TAB_OUT_FORWARD:
1147: KeyboardFocusManager.getCurrentKeyboardFocusManager()
1148: .focusNextComponent();
1149: break;
1150: case TAB_OUT_BACK:
1151: KeyboardFocusManager.getCurrentKeyboardFocusManager()
1152: .focusPreviousComponent();
1153: break;
1154: case EDIT_PLUGIN:
1155: int[] rows = table.getSelectedRows();
1156: for (int i = 0; i < rows.length; i++) {
1157: Object st = pluginModel.getValueAt(rows[i], 0);
1158: pluginModel.setValueAt(st.equals(Boolean.FALSE),
1159: rows[i], 0);
1160: }
1161: break;
1162: case CLOSE_PLUGIN_MANAGER:
1163: window.ok();
1164: break;
1165: default:
1166: throw new InternalError();
1167: }
1168: }
1169: } //}}}
1170:
1171: //{{{ TableFocusHandler class
1172: class TableFocusHandler extends FocusAdapter {
1173: public void focusGained(FocusEvent fe) {
1174: if (-1 == table.getSelectedRow()) {
1175: table.setRowSelectionInterval(0, 0);
1176: JScrollBar scrollbar = scrollpane
1177: .getVerticalScrollBar();
1178: scrollbar.setValue(scrollbar.getMinimum());
1179: }
1180: if (-1 == table.getSelectedColumn()) {
1181: table.setColumnSelectionInterval(0, 0);
1182: }
1183: }
1184: } //}}}
1185:
1186: //}}}
1187: }
|