// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// 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 (at your option) 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
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: ManagerDialog.java,v 1.12 2007/04/06 10:23:26 spyromus Exp $
//
package com.salas.bb.plugins.gui;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.uif.AbstractDialog;
import com.jgoodies.uif.component.UIFButton;
import com.jgoodies.uif.util.Resizer;
import com.salas.bb.plugins.Manager;
import com.salas.bb.plugins.domain.IPlugin;
import com.salas.bb.plugins.domain.Package;
import com.salas.bb.utils.Constants;
import com.salas.bb.utils.StringUtils;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.uif.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.prefs.Preferences;
/**
* Packages / plug-ins manager dialog box.
*/
public class ManagerDialog extends AbstractDialog
{
private PluginsTable tblPackages;
private JButton btnUninstall;
private JButton btnRescan;
private JButton btnInstall;
private UIFButton btnClose;
private JTextArea taDescription;
/**
* Creates the dialog.
*
* @param frame parent frame.
*/
public ManagerDialog(Frame frame)
{
super(frame, Strings.message("plugin.manager.dialog.title"));
}
@Override
protected JComponent buildHeader()
{
return new HeaderPanelExt(
Strings.message("plugin.manager.dialog.title"),
Strings.message("plugin.manager.dialog.header"),
getIcon());
}
/**
* Returns the icon.
*
* @return icon.
*/
public static ImageIcon getIcon()
{
return IconSource.getIcon("plugin.manager.icon");
}
/**
* Builds main content area.
*
* @return the panel.
*/
protected JComponent buildContent()
{
JPanel panel = new JPanel(new BorderLayout());
panel.add(buildMainPanel(), BorderLayout.CENTER);
panel.add(buildButonsBar(), BorderLayout.SOUTH);
// Finally, select the first plug-in
if (!highlightFirstIfPresent())
{
onSelectionChange();
}
return panel;
}
/**
* Highlights the first package if present.
*
* @return <code>TRUE</code> if highlighted.
*/
private boolean highlightFirstIfPresent()
{
boolean present = tblPackages.getModel().getSize() > 0;
if (present) tblPackages.setSelectedIndex(0);
return present;
}
/**
* Returns buttons bar.
*
* @return bar.
*/
private Component buildButonsBar()
{
btnRescan = new JButton(new RescanAction());
btnInstall = new JButton(new InstallAction());
btnUninstall = new JButton(new UninstallAction());
btnClose = createCloseButton(false);
BBFormBuilder b = new BBFormBuilder("0:grow, p, 7dlu, p, 2dlu, p, 7dlu, p");
b.nextColumn();
b.append(btnRescan);
b.append(btnInstall);
b.append(btnUninstall);
b.append(btnClose);
JPanel p = b.getPanel();
p.setBorder(Constants.DIALOG_BUTTON_BAR_BORDER);
return p;
}
/**
* Returns main panel.
*
* @return panel.
*/
private Component buildMainPanel()
{
tblPackages = new PluginsTable();
tblPackages.setInstalledPackages(Manager.getInstalledPackages());
tblPackages.setSelectedPackages(Manager.getEnabledPackages());
tblPackages.addListSelectionListener(new PluginTableListener());
taDescription = new JTextArea();
Color bg = taDescription.getBackground();
taDescription.setEditable(false);
taDescription.setBackground(bg);
UifUtilities.smallerFont(taDescription);
BBFormBuilder b = new BBFormBuilder("p:grow");
b.setDefaultDialogBorder();
b.append(Strings.message("plugin.manager.plugins"), 1);
b.appendRelatedComponentsGapRow(2);
b.appendRow("100dlu:grow");
b.append(new JScrollPane(tblPackages), 1, CellConstraints.FILL, CellConstraints.FILL);
b.appendUnrelatedComponentsGapRow(2);
b.append(Strings.message("plugin.manager.details"), 1);
b.appendRelatedComponentsGapRow(2);
b.appendRow("50dlu");
b.append(new JScrollPane(taDescription), 1, CellConstraints.FILL, CellConstraints.FILL);
JTextArea lbNote = ComponentsFactory.createWrappedMultilineLabel(Strings.message("plugin.manager.warning"));
UifUtilities.smallerFont(lbNote);
b.append(lbNote);
b.appendRelatedComponentsGapRow();
return b.getPanel();
}
@Override
protected void resizeHook(JComponent component)
{
Resizer.ONE2ONE.resizeDialogContent(component);
}
/**
* Shows the dialog with the list of enabled packages provided.
*
* @return <code>TRUE</code> if something has changed.
*/
public boolean openDialog()
{
java.util.List<Package> before = Manager.getEnabledPackages();
super.open();
java.util.List<Package> after = tblPackages.getSelectedPackages();
boolean changed = isChanged(before, after);
if (changed) Manager.setEnabledPackages(after);
return changed;
}
/**
* Returns <code>TRUE</code> if the list of packages has changed.
*
* @param before before the action.
* @param after after the action.
*
* @return <code>TRUE</code> if the list of packages has changed.
*/
private static boolean isChanged(java.util.List<Package> before, java.util.List<Package> after)
{
if (after == null) return false;
if (before == null) return true;
boolean changed = true;
if (before.size() == after.size())
{
changed = false;
for (Package pack : after)
{
if (!before.contains(pack))
{
changed = true;
break;
}
}
}
return changed;
}
/**
* Enables / disables components.
*
* @param en <code>TRUE</code> to enable.
*/
private void enableComponents(boolean en)
{
btnClose.setEnabled(en);
btnInstall.setEnabled(en);
btnRescan.setEnabled(en);
btnUninstall.setEnabled(en && (tblPackages.getSelectedIndex() != -1));
tblPackages.setEnabled(en);
taDescription.setEnabled(en);
}
/**
* Calls the {@link #enableComponents(boolean)} from EDT.
*
* @param en <code>TRUE</code> to enable.
*/
private void enableComponentsEDT(final boolean en)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
enableComponents(en);
}
});
}
// ------------------------------------------------------------------------
// Listeners & Actions
// ------------------------------------------------------------------------
/**
* Creates executor service if necessary and submits a task.
*
* @param task task to start.
*/
private synchronized void backgroundTask(Runnable task)
{
Thread th = new Thread(task, task.getClass().getName());
th.setDaemon(true);
th.start();
}
/**
* Invoked when the selection state of the plug-in table changes.
*/
private void onSelectionChange()
{
Package pckg = tblPackages.getHighlightedPackage();
btnUninstall.setEnabled(pckg != null);
String descr = null;
if (pckg != null)
{
// Collect plug-in stats
Map<String, Integer> cnts = new HashMap<String, Integer>();
for (IPlugin plugin : pckg)
{
String typeName = plugin.getTypeName();
Integer cnt = cnts.get(typeName);
if (cnt == null) cnt = 0;
cnts.put(typeName, cnt + 1);
}
// Build the list
int i = 0;
String[] contents = new String[cnts.size()];
for (Map.Entry<String, Integer> entry : cnts.entrySet())
{
String type = entry.getKey();
int cnt = entry.getValue();
contents[i++] = type + (cnt > 1 ? " (" + cnt + ")" : "");
}
// Create the description text
descr = MessageFormat.format("{0}\n\nAuthor: {1} {2}\nContents: {3}",
pckg.getDescription(), pckg.getAuthor(), pckg.getEmail(), StringUtils.join(contents, ", "));
}
taDescription.setText(descr);
}
/** Reloads the list of packages. */
private void reloadPackagesList()
{
final java.util.List<Package> packages = Manager.reloadInstalledPackages();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
tblPackages.setInstalledPackages(packages);
}
});
}
/**
* Listener of the list selection.
*/
private class PluginTableListener implements ListSelectionListener
{
/**
* Called whenever the value of the selection changes.
*
* @param e the event that characterizes the change.
*/
public void valueChanged(ListSelectionEvent e)
{
onSelectionChange();
}
}
/**
* Rescans the directory of plug-ins.
*/
private class RescanAction extends AbstractAction
{
/**
* Creates action.
*/
public RescanAction()
{
super(Strings.message("plugin.manager.rescan"));
}
/**
* Invoked when an action occurs.
*
* @param e event object.
*/
public void actionPerformed(ActionEvent e)
{
backgroundTask(new RescanTask());
}
/** The task itself. */
private class RescanTask implements Runnable
{
/**
* Called when the task is staring.
*/
public void run()
{
enableComponentsEDT(false);
try
{
reloadPackagesList();
} finally
{
enableComponentsEDT(true);
}
}
}
}
/** Install action shows the file picker and then installs the selected file. */
private class InstallAction extends AbstractAction
{
/**
* Creates the action.
*/
public InstallAction()
{
super(Strings.message("plugin.manager.install"));
}
/**
* Invoked when the action is performed.
*
* @param e event object.
*/
public void actionPerformed(ActionEvent e)
{
Preferences prefs = Preferences.userNodeForPackage(ManagerDialog.class);
String lastPath = prefs.get("last.path", null);
JFileChooser chooser = new JFileChooser();
if (lastPath != null) chooser.setCurrentDirectory(new File(lastPath));
chooser.setFileFilter(new FileFilter()
{
public boolean accept(File f)
{
return f != null && (f.isDirectory() || (f.isFile() && f.getName().matches(".*\\.(jar|zip)\\s*$")));
}
public String getDescription()
{
return "Plug-in Packages";
}
});
int res = chooser.showOpenDialog(ManagerDialog.this);
if (res == JFileChooser.APPROVE_OPTION)
{
prefs.put("last.path", chooser.getCurrentDirectory().getAbsolutePath());
backgroundTask(new InstallTask(chooser.getSelectedFile()));
}
}
/** Installation task. */
private class InstallTask implements Runnable
{
private final File file;
/**
* Creates the task.
*
* @param file file to install.
*/
public InstallTask(File file)
{
this.file = file;
}
/** Invoked when the task runs. */
public void run()
{
enableComponentsEDT(false);
try
{
final String error = Manager.install(file);
if (error != null)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JOptionPane.showMessageDialog(ManagerDialog.this, error,
(String)InstallAction.this.getValue(Action.NAME),
JOptionPane.ERROR_MESSAGE);
}
});
} else
{
reloadPackagesList();
// Select package
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
tblPackages.selectPackage(file);
}
});
}
} finally
{
enableComponentsEDT(true);
}
}
}
}
/** Uninstall action that uninstalls the highlighted packages. */
private class UninstallAction extends AbstractAction
{
/**
* Creates the action.
*/
public UninstallAction()
{
super(Strings.message("plugin.manager.uninstall"));
}
/**
* Invoked when action occurs.
*
* @param e event object.
*/
public void actionPerformed(ActionEvent e)
{
Package pkg = tblPackages.getHighlightedPackage();
if (pkg != null)
{
Manager.uninstall(pkg);
reloadPackagesList();
highlightFirstIfPresent();
}
}
}
}