/* * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * PackageManager.java * Copyright (C) 2009 University of Waikato, Hamilton, New Zealand */ package weka.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultCellEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.SwingWorker; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumnModel; import org.pentaho.packageManagement.Dependency; import org.pentaho.packageManagement.Package; import org.pentaho.packageManagement.PackageConstraint; import weka.core.Environment; import weka.core.Utils; import weka.core.WekaPackageManager; import weka.gui.beans.FileEnvironmentField; /** * A GUI interface the the package management system. * * @author Mark Hall (mhall{[at]}pentaho{[dot]}com) * @version $Revision: 7080 $ */ public class PackageManager extends JPanel { /** For serialization */ private static final long serialVersionUID = -7463821313750352385L; protected static final String PACKAGE_COLUMN = "Package"; protected static final String CATEGORY_COLUMN = "Category"; protected static final String INSTALLED_COLUMN = "Installed version"; protected static final String REPOSITORY_COLUMN = "Repository version"; protected static final String LOADED_COLUMN = "Loaded"; /** The JTable for displaying the package names and version numbers */ protected JTable m_table = new ETable(); protected JSplitPane m_splitP; // protected JTextArea m_packageDescription; /** An editor pane to display package information */ protected JEditorPane m_infoPane; /** Installed radio button */ protected JRadioButton m_installedBut = new JRadioButton("Installed"); /** Available radio button */ protected JRadioButton m_availableBut = new JRadioButton("Available"); /** All radio button */ protected JRadioButton m_allBut = new JRadioButton("All"); /** Button for installing the selected package */ protected JButton m_installBut = new JButton("Install"); protected JCheckBox m_forceBut = new JCheckBox("Ignore dependencies/conflicts"); /** Button for uninstalling the selected package */ protected JButton m_uninstallBut = new JButton("Uninstall"); protected JButton m_refreshCacheBut = new JButton("Refresh repository cache"); protected JProgressBar m_progress = new JProgressBar(0, 100); protected JLabel m_detailLabel = new JLabel(); protected JButton m_backB; protected LinkedList<URL> m_browserHistory = new LinkedList<URL>(); protected static final String BROWSER_HOME = "http://www.cs.waikato.ac.nz/ml/weka/index_home_pm.html"; protected JButton m_homeB; protected JToolBar m_browserTools; protected JLabel m_newPackagesAvailableL; protected DefaultTableModel m_model; protected Map<String, List<Object>> m_packageLookupInfo; protected List<Package> m_allPackages; protected List<Package> m_installedPackages; protected List<Package> m_availablePackages; /** The column in the table to sort the entries by */ protected int m_sortColumn = 0; /** Reverse the sort order if the user clicks the same column header twice */ protected boolean m_reverseSort = false; /** Button to pop up the file environment field widget */ protected JButton m_unofficialBut = new JButton("File/URL"); /** Widget for specifying a URL or path to an unofficial package to install */ protected FileEnvironmentField m_unofficialChooser = new FileEnvironmentField("File/URL", Environment.getSystemWide()); protected JFrame m_unofficialFrame = null; protected Comparator<Package> m_packageComparator = new Comparator<Package>() { @Override public int compare(Package o1, Package o2) { String meta1 = ""; String meta2 = ""; if (m_sortColumn == 0) { meta1 = o1.getName(); meta2 = o2.getName(); } else { if (o1.getPackageMetaDataElement("Category") != null) { meta1 = o1.getPackageMetaDataElement("Category").toString(); } if (o2.getPackageMetaDataElement("Category") != null) { meta2 = o2.getPackageMetaDataElement("Category").toString(); } } int result = meta1.compareTo(meta2); if (m_reverseSort) { result = -result; } return result; } }; protected boolean m_installing = false; class ProgressPrintStream extends PrintStream { private Progressable m_listener; public ProgressPrintStream(Progressable listener) { // have to invoke a super class constructor super(System.out); m_listener = listener; } public void println(String string) { boolean messageOnly = false; if (string.startsWith("%%")) { string = string.substring(2); messageOnly = true; } if (!messageOnly) { System.out.println(string); // make sure the log picks it up m_listener.makeProgress(string); } else { m_listener.makeProgressMessageOnly(string); } } public void println(Object obj) { println(obj.toString()); } public void print(String string) { boolean messageOnly = false; if (string.startsWith("%%")) { string = string.substring(2); messageOnly = true; } if (!messageOnly) { System.out.print(string); // make sure the log picks it up m_listener.makeProgress(string); } else { m_listener.makeProgressMessageOnly(string); } } public void print(Object obj) { print (obj.toString()); } } interface Progressable { void makeProgress(String progressMessage); void makeProgressMessageOnly(String progressMessage); } class EstablishCache extends SwingWorker<Void, Void> implements Progressable { private int m_progressCount = 0; private Exception m_error = null; private javax.swing.ProgressMonitor m_progress; public void makeProgress(String progressMessage) { m_progress.setNote(progressMessage); m_progressCount++; m_progress.setProgress(m_progressCount); } public void makeProgressMessageOnly(String progressMessage) { m_progress.setNote(progressMessage); } public Void doInBackground() { int numPackages = WekaPackageManager.numRepositoryPackages(); if (numPackages < 0) { // there was some problem getting the file that holds this // information from the repository server - try to continue // anyway with a max value of 100 for the number of packages // (since all we use this for is setting the upper bound on // the progress bar). numPackages = 100; } m_progress = new javax.swing.ProgressMonitor(PackageManager.this, "Establising cache...", "", 0, numPackages); ProgressPrintStream pps = new ProgressPrintStream(this); m_error = WekaPackageManager.establishCacheIfNeeded(pps); m_cacheEstablished = true; return null; } public void done() { m_progress.close(); if (m_error != null) { displayErrorDialog("There was a problem establishing the package\n" + "meta data cache. We'll try to use the repository" + "directly.", m_error); } } } class CheckForNewPackages extends SwingWorker<Void, Void> { public Void doInBackground() { Map<String, String> localPackageNameList = WekaPackageManager.getPackageList(true); if (localPackageNameList == null) { // quietly return and see if we can continue anyway return null; } Map<String, String> repositoryPackageNameList = WekaPackageManager.getPackageList(false); if (repositoryPackageNameList == null) { // quietly return and see if we can continue anyway return null; } if (repositoryPackageNameList.keySet().size() < localPackageNameList.keySet().size()) { // package(s) have disappeared from the repository. // Force a cache refresh... RefreshCache r = new RefreshCache(); r.execute(); return null; } StringBuffer newPackagesBuff = new StringBuffer(); for (String s : repositoryPackageNameList.keySet()) { if (!localPackageNameList.containsKey(s)) { newPackagesBuff.append(s + "<br>"); } } if (newPackagesBuff.length() > 0) { String information = "<html><font size=-2>There are new packages available " + "on the server (do a cache refresh for more " + "information):<br><br>" + newPackagesBuff.toString() + "</font></html>"; m_newPackagesAvailableL.setToolTipText(information); m_browserTools.add(m_newPackagesAvailableL); m_browserTools.revalidate(); } return null; } } class RefreshCache extends SwingWorker<Void, Void> implements Progressable { private int m_progressCount = 0; private Exception m_error = null; public void makeProgress(String progressMessage) { m_detailLabel.setText(progressMessage); m_progressCount++; m_progress.setValue(m_progressCount); } public void makeProgressMessageOnly(String progressMessage) { m_detailLabel.setText(progressMessage); } public Void doInBackground() { m_cacheRefreshInProgress = true; int numPackages = WekaPackageManager.numRepositoryPackages(); if (numPackages < 0) { // there was some problem getting the file that holds this // information from the repository server - try to continue // anyway with a max value of 100 for the number of packages // (since all we use this for is setting the upper bound on // the progress bar). numPackages = 100; } m_progress.setMaximum(numPackages); m_refreshCacheBut.setEnabled(false); m_installBut.setEnabled(false); m_unofficialBut.setEnabled(false); m_installedBut.setEnabled(false); m_availableBut.setEnabled(false); m_allBut.setEnabled(false); ProgressPrintStream pps = new ProgressPrintStream(this); m_error = WekaPackageManager.refreshCache(pps); getAllPackages(); return null; } public void done() { m_progress.setValue(m_progress.getMinimum()); if (m_error != null) { displayErrorDialog("There was a problem refreshing the package\n" + "meta data cache. We'll try to use the repository" + "directly.", m_error); m_detailLabel.setText(""); } else { m_detailLabel.setText("Cache refresh completed"); } m_installBut.setEnabled(true); m_unofficialBut.setEnabled(true); m_refreshCacheBut.setEnabled(true); m_installedBut.setEnabled(true); m_availableBut.setEnabled(true); m_allBut.setEnabled(true); updateTable(); try { m_browserTools.remove(m_newPackagesAvailableL); m_browserTools.revalidate(); } catch (Exception ex) { } m_cacheRefreshInProgress = false; } } private void pleaseCloseAppWindowsPopUp() { if (!Utils.getDontShowDialog("weka.gui.PackageManager.PleaseCloseApplicationWindows")) { JCheckBox dontShow = new JCheckBox("Do not show this message again"); Object[] stuff = new Object[2]; stuff[0] = "Please close any open Weka application windows\n" + "(Explorer, Experimenter, KnowledgeFlow, SimpleCLI)\n" + "before proceeding.\n"; stuff[1] = dontShow; JOptionPane.showMessageDialog(PackageManager.this, stuff, "Weka Package Manager", JOptionPane.OK_OPTION); if (dontShow.isSelected()) { try { Utils.setDontShowDialog("weka.gui.PackageManager.PleaseCloseApplicationWindows"); } catch (Exception ex) { // quietly ignore } } } } class UninstallTask extends SwingWorker<Void, Void> implements Progressable { private List<String> m_packageNamesToUninstall; // private String m_packageName; // private boolean m_successfulUninstall = false; private List<String> m_unsuccessfulUninstalls = new ArrayList<String>(); private int m_progressCount = 0; public void setPackages(List<String> packageNames) { m_packageNamesToUninstall = packageNames; } public void makeProgress(String progressMessage) { m_detailLabel.setText(progressMessage); m_progressCount++; m_progress.setValue(m_progressCount); if (m_progressCount == m_progress.getMaximum()) { m_progress.setMaximum(m_progressCount + 5); } } public void makeProgressMessageOnly(String progressMessage) { m_detailLabel.setText(progressMessage); } public Void doInBackground() { m_installing = true; m_installBut.setEnabled(false); m_unofficialBut.setEnabled(false); m_uninstallBut.setEnabled(false); m_refreshCacheBut.setEnabled(false); m_availableBut.setEnabled(false); m_allBut.setEnabled(false); m_installedBut.setEnabled(false); ProgressPrintStream pps = new ProgressPrintStream(this); m_progress.setMaximum(m_packageNamesToUninstall.size() * 5); for (int zz = 0; zz < m_packageNamesToUninstall.size(); zz++) { String packageName = m_packageNamesToUninstall.get(zz); boolean explorerPropertiesExist = WekaPackageManager.installedPackageResourceExists(packageName, "Explorer.props"); if (!m_forceBut.isSelected()) { List<Package> compromised = new ArrayList<Package>(); // Now check to see which other installed packages depend on this one List<Package> installedPackages; try { installedPackages = WekaPackageManager.getInstalledPackages(); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Can't determine which packages are installed!", e); // return null; // can't proceed m_unsuccessfulUninstalls.add(packageName); continue; } for (Package p : installedPackages) { List<Dependency> tempDeps; try { tempDeps = p.getDependencies(); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem determining dependencies for package : " + p.getName(), e); //return null; // can't proceed m_unsuccessfulUninstalls.add(packageName); continue; } for (Dependency d : tempDeps) { if (d.getTarget().getPackage().getName().equals(packageName)) { // add this installed package to the list compromised.add(p); break; } } } if (compromised.size() > 0) { StringBuffer message = new StringBuffer(); message.append("The following installed packages depend on " + packageName + " :\n\n"); for (Package p : compromised) { message.append("\t" + p.getName() + "\n"); } message.append("\nDo you wish to proceed?"); int result = JOptionPane.showConfirmDialog(PackageManager.this, message.toString(), "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { // bail out here //return null; continue; } } } // m_progress.setMaximum(10); try { if (explorerPropertiesExist) { // need to remove any set Explorer properties first WekaPackageManager.removeExplorerProps(packageName); } WekaPackageManager.uninstallPackage(packageName, true, pps); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Unable to uninstall package: " + packageName, e); //return null; m_unsuccessfulUninstalls.add(packageName); continue; } } WekaPackageManager.refreshGOEProperties(); // m_successfulUninstall = true; return null; } public void done() { m_progress.setValue(m_progress.getMinimum()); if (m_unsuccessfulUninstalls.size() == 0) { m_detailLabel.setText("Packages removed successfully."); if (!Utils.getDontShowDialog("weka.gui.PackageManager.RestartAfterUninstall")) { JCheckBox dontShow = new JCheckBox("Do not show this message again"); Object[] stuff = new Object[2]; stuff[0] = "Weka might need to be restarted for\n" + "the changes to come into effect.\n"; stuff[1] = dontShow; JOptionPane.showMessageDialog(PackageManager.this, stuff, "Weka Package Manager", JOptionPane.OK_OPTION); if (dontShow.isSelected()) { try { Utils.setDontShowDialog("weka.gui.PackageManager.RestartAfterUninstall"); } catch (Exception ex) { // quietly ignore } } } } else { StringBuffer failedPackageNames = new StringBuffer(); for (String p : m_unsuccessfulUninstalls) { failedPackageNames.append(p + "\n"); } displayErrorDialog("The following package(s) could not be uninstalled\n" + "for some reason (check the log)\n" + failedPackageNames.toString() , ""); m_detailLabel.setText("Finished uninstalling."); } m_unofficialBut.setEnabled(true); m_refreshCacheBut.setEnabled(true); m_availableBut.setEnabled(true); m_allBut.setEnabled(true); m_installedBut.setEnabled(true); // force refresh of installed and available packages m_installedPackages = null; m_availablePackages = null; // m_installBut.setEnabled(true); m_installing = false; updateTable(); if (m_table.getSelectedRow() >= 0) { // mainly to update the install/uninstall button status //displayPackageInfo(m_table.getSelectedRow()); updateInstallUninstallButtonEnablement(); } } } class UnofficialInstallTask extends SwingWorker<Void, Void> implements Progressable { private String m_target; private int m_progressCount = 0; private boolean m_errorOccurred = false; public void setTargetToInstall(String target) { m_target = target; } public void makeProgress(String progressMessage) { m_detailLabel.setText(progressMessage); m_progressCount++; m_progress.setValue(m_progressCount); if (m_progressCount == m_progress.getMaximum()) { m_progress.setMaximum(m_progressCount + 5); } } public void makeProgressMessageOnly(String progressMessage) { m_detailLabel.setText(progressMessage); } public Void doInBackground() { m_installing = true; m_installBut.setEnabled(false); m_uninstallBut.setEnabled(false); m_refreshCacheBut.setEnabled(false); m_unofficialBut.setEnabled(false); m_availableBut.setEnabled(false); m_allBut.setEnabled(false); m_installedBut.setEnabled(false); ProgressPrintStream pps = new ProgressPrintStream(this); m_progress.setMaximum(30); Package installedPackage = null; String toInstall = m_target; try { toInstall = Environment.getSystemWide().substitute(m_target); } catch (Exception ex) {} try { if (toInstall.toLowerCase().startsWith("http://") || toInstall.toLowerCase().startsWith("https://")) { String packageName = WekaPackageManager.installPackageFromURL(new URL(toInstall), pps); installedPackage = WekaPackageManager.getInstalledPackageInfo(packageName); } else if (toInstall.toLowerCase().endsWith(".zip")){ String packageName = WekaPackageManager.installPackageFromArchive(toInstall, pps); installedPackage = WekaPackageManager.getInstalledPackageInfo(packageName); } else { displayErrorDialog("Unable to install package " + "\nfrom " + toInstall + ". Unrecognized as a URL or zip archive.", (String)null); m_errorOccurred = true; return null; } } catch (Exception ex) { displayErrorDialog("Unable to install package " + "\nfrom " + m_target + ". Check the log for error messages.", ex); m_errorOccurred = true; return null; } if (installedPackage != null) { try { File packageRoot = new File(WekaPackageManager.getPackageHome() + File.separator + installedPackage.getName()); boolean loadCheck = WekaPackageManager.loadCheck(installedPackage, packageRoot, pps); if (!loadCheck) { displayErrorDialog("Package was installed correctly but could not " + "be loaded. Check log for details", (String)null); } } catch (Exception ex) { displayErrorDialog("Unable to install package " + "\nfrom " + m_target + ".", ex); m_errorOccurred = true; } WekaPackageManager.refreshGOEProperties(); } return null; } public void done() { m_progress.setValue(m_progress.getMinimum()); if (m_errorOccurred) { m_detailLabel.setText("Problem installing - check log."); } else { m_detailLabel.setText("Package installed successfully."); } m_unofficialBut.setEnabled(true); m_refreshCacheBut.setEnabled(true); m_availableBut.setEnabled(true); m_allBut.setEnabled(true); m_installedBut.setEnabled(true); // force refresh of installed and available packages m_installedPackages = null; m_availablePackages = null; // m_installBut.setEnabled(true); m_installing = false; updateTable(); if (m_table.getSelectedRow() >= 0) { // mainly to update the install/uninstall button status //displayPackageInfo(m_table.getSelectedRow()); updateInstallUninstallButtonEnablement(); } } } class InstallTask extends SwingWorker<Void, Void> implements Progressable { private List<String> m_packageNamesToInstall; private List<Object> m_versionsToInstall; // private boolean m_successfulInstall = false; private List<Package> m_unsuccessfulInstalls = new ArrayList<Package>(); private int m_progressCount = 0; public void setPackages(List<String> packagesToInstall) { m_packageNamesToInstall = packagesToInstall; } public void setVersions(List<Object> versionsToInstall) { m_versionsToInstall = versionsToInstall; } public void makeProgress(String progressMessage) { m_detailLabel.setText(progressMessage); m_progressCount++; m_progress.setValue(m_progressCount); if (m_progressCount == m_progress.getMaximum()) { m_progress.setMaximum(m_progressCount + 5); } } public void makeProgressMessageOnly(String progressMessage) { m_detailLabel.setText(progressMessage); } /* * Main task. Executed in background thread. */ @Override public Void doInBackground() { m_installing = true; m_installBut.setEnabled(false); m_unofficialBut.setEnabled(true); m_uninstallBut.setEnabled(false); m_refreshCacheBut.setEnabled(false); m_availableBut.setEnabled(false); m_allBut.setEnabled(false); m_installedBut.setEnabled(false); ProgressPrintStream pps = new ProgressPrintStream(this); m_progress.setMaximum(m_packageNamesToInstall.size() * 30); for (int zz = 0; zz < m_packageNamesToInstall.size(); zz++) { Package packageToInstall = null; String packageName = m_packageNamesToInstall.get(zz); Object versionToInstall = m_versionsToInstall.get(zz); try { packageToInstall = WekaPackageManager.getRepositoryPackageInfo(packageName, versionToInstall.toString()); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Unable to obtain package info for package: " + packageName, e); // return null; // bail out here m_unsuccessfulInstalls.add(packageToInstall); continue; } // check for any special installation instructions Object specialInstallMessage = packageToInstall.getPackageMetaDataElement("MessageToDisplayOnInstallation"); if (specialInstallMessage != null && specialInstallMessage.toString().length() > 0) { String siM = specialInstallMessage.toString(); try { siM = Environment.getSystemWide().substitute(siM); } catch (Exception ex) { // quietly ignore } JOptionPane.showMessageDialog(PackageManager.this, packageToInstall + "\n\n" + siM, "Weka Package Manager", JOptionPane.OK_OPTION); } if (!m_forceBut.isSelected()) { try { if (!packageToInstall.isCompatibleBaseSystem()) { List<Dependency> baseSysDep = packageToInstall.getBaseSystemDependency(); StringBuffer depList = new StringBuffer(); for (Dependency bd : baseSysDep) { depList.append(bd.getTarget().toString() + " "); } JOptionPane.showMessageDialog(PackageManager.this, "Unable to install package " + "\n" + packageName + " because it requires" + "\n" + depList.toString(), "Weka Package Manager", JOptionPane.ERROR_MESSAGE); // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem determining dependency on base system" + " for package: " + packageName, e); //return null; // can't proceed m_unsuccessfulInstalls.add(packageToInstall); continue; } // check to see if package is already installed boolean upOrDowngrading = false; if (packageToInstall.isInstalled()) { Package installedVersion = null; try { installedVersion = WekaPackageManager.getInstalledPackageInfo(packageName); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem obtaining package info for package: " + packageName, e); //return null; // can't proceed m_unsuccessfulInstalls.add(packageToInstall); continue; } if (!packageToInstall.equals(installedVersion)) { int result = JOptionPane.showConfirmDialog(PackageManager.this, "Package " + installedVersion + " is already installed. Replace with " + packageToInstall + "?", "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } if (!Utils.getDontShowDialog("weka.gui.PackageManager.RestartAfterUpgrade")) { JCheckBox dontShow = new JCheckBox("Do not show this message again"); Object[] stuff = new Object[2]; stuff[0] = "Weka will need to be restared after installation for\n" + "the changes to come into effect.\n"; stuff[1] = dontShow; JOptionPane.showMessageDialog(PackageManager.this, stuff, "Weka Package Manager", JOptionPane.OK_OPTION); if (dontShow.isSelected()) { try { Utils.setDontShowDialog("weka.gui.PackageManager.RestartAfterUpgrade"); } catch (Exception ex) { // quietly ignore } } } } else { int result = JOptionPane.showConfirmDialog(PackageManager.this, "Package " + installedVersion + " is already installed. Install again?", "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } } } // Now get a full list of dependencies for this package and // check for any conflicts Map<String, List<Dependency>> conflicts = new HashMap<String, List<Dependency>>(); List<Dependency> dependencies = null; try { dependencies = WekaPackageManager.getAllDependenciesForPackage(packageToInstall, conflicts); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem determinining dependencies for package: " + packageToInstall.getName(), e); //return null; // can't proceed m_unsuccessfulInstalls.add(packageToInstall); continue; } if (conflicts.size() > 0) { StringBuffer message = new StringBuffer(); message.append("Package " + packageName + " requires the following packages:\n\n"); Iterator<Dependency> depI = dependencies.iterator(); while (depI.hasNext()) { Dependency d = depI.next(); message.append("\t" + d +"\n"); } message.append("\nThere are conflicting dependencies:\n\n"); Set<String> pNames = conflicts.keySet(); Iterator<String> pNameI = pNames.iterator(); while (pNameI.hasNext()) { String pName = pNameI.next(); message.append("Conflicts for " + pName + "\n"); List<Dependency> confsForPackage = conflicts.get(pName); Iterator<Dependency> confs = confsForPackage.iterator(); while (confs.hasNext()) { Dependency problem = confs.next(); message.append("\t" + problem + "\n"); } } JOptionPane.showConfirmDialog(PackageManager.this, message.toString(), "Weka Package Manager", JOptionPane.OK_OPTION); // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } // Next check all dependencies against what is installed and // inform the user about which installed packages will be altered. Also // build the list of only those packages that need to be installed or // upgraded (excluding those that are already installed and are OK). List<PackageConstraint> needsUpgrade = new ArrayList<PackageConstraint>(); List<Package> finalListToInstall = new ArrayList<Package>(); Iterator<Dependency> depI = dependencies.iterator(); boolean depsOk = true; while (depI.hasNext()) { Dependency toCheck = depI.next(); if (toCheck.getTarget().getPackage().isInstalled()) { String toCheckName = toCheck.getTarget().getPackage(). getPackageMetaDataElement("PackageName").toString(); try { Package installedVersion = WekaPackageManager.getInstalledPackageInfo(toCheckName); if (!toCheck.getTarget().checkConstraint(installedVersion)) { needsUpgrade.add(toCheck.getTarget()); Package mostRecent = toCheck.getTarget().getPackage(); if (toCheck.getTarget() instanceof org.pentaho.packageManagement.VersionPackageConstraint) { mostRecent = WekaPackageManager.mostRecentVersionWithRespectToConstraint(toCheck.getTarget()); } finalListToInstall.add(mostRecent); } } catch (Exception ex) { ex.printStackTrace(); displayErrorDialog("An error has occurred while checking " + "package dependencies", ex); // bail out here //return null; depsOk = false; break; } } else { try { Package mostRecent = toCheck.getTarget().getPackage(); if (toCheck.getTarget() instanceof org.pentaho.packageManagement.VersionPackageConstraint) { mostRecent = WekaPackageManager.mostRecentVersionWithRespectToConstraint(toCheck.getTarget()); } finalListToInstall.add(mostRecent); } catch (Exception ex) { ex.printStackTrace(); displayErrorDialog("An error has occurred while checking " + "package dependencies", ex); // bail out here //return null; depsOk = false; break; } } } if (!depsOk) { // bail out on this package m_unsuccessfulInstalls.add(packageToInstall); continue; } if (needsUpgrade.size() > 0) { StringBuffer temp = new StringBuffer(); for (PackageConstraint pc : needsUpgrade) { temp.append(pc + "\n"); } int result = JOptionPane.showConfirmDialog(PackageManager.this, "The following packages will be upgraded in order to install:\n\n" + temp.toString(), "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } // now take a look at the other installed packages and see if // any would have a problem when these ones are upgraded boolean conflictsAfterUpgrade = false; List<Package> installed = null; try { installed = WekaPackageManager.getInstalledPackages(); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Unable to determine what packages are installed!", e); //return null; // can't proceed m_unsuccessfulInstalls.add(packageToInstall); continue; } List<Package> toUpgrade = new ArrayList<Package>(); for (PackageConstraint pc : needsUpgrade) { toUpgrade.add(pc.getPackage()); } // add the actual package the user is wanting to install if it // is going to be an up/downgrade rather than a first install since // other installed packages may depend on the currently installed version // and thus could be affected after the up/downgrade toUpgrade.add(packageToInstall); StringBuffer tempM = new StringBuffer(); depsOk = true; for (int i = 0; i < installed.size(); i++) { Package tempP = installed.get(i); String tempPName = tempP.getName(); boolean checkIt = true; for (int j = 0; j < needsUpgrade.size(); j++) { if (tempPName.equals(needsUpgrade.get(j).getPackage().getName())) { checkIt = false; break; } } if (checkIt) { List<Dependency> problem = null; try { problem = tempP.getIncompatibleDependencies(toUpgrade); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("An error has occurred while checking " + "package dependencies", e); // return null; // can't continue depsOk = false; break; } if (problem.size() > 0) { conflictsAfterUpgrade = true; tempM.append("Package " + tempP.getName() + " will have a compatibility" + "problem with the following packages after upgrading them:\n"); Iterator<Dependency> dI = problem.iterator(); while (dI.hasNext()) { tempM.append("\t" + dI.next().getTarget().getPackage() + "\n"); } } } } if (!depsOk) { m_unsuccessfulInstalls.add(packageToInstall); continue; } if (conflictsAfterUpgrade) { JOptionPane.showConfirmDialog(PackageManager.this, tempM.toString() + "\n" + "Unable to continue with installation.", "Weka Package Manager", JOptionPane.OK_OPTION); // return null; //bail out here m_unsuccessfulInstalls.add(packageToInstall); continue; } } if (finalListToInstall.size() > 0) { StringBuffer message = new StringBuffer(); message.append("To install " + packageName + " the following packages will" + " be installed/upgraded:\n\n"); for (Package p : finalListToInstall) { message.append("\t" + p + "\n"); } int result = JOptionPane.showConfirmDialog(PackageManager.this, message.toString(), "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { // bail out here //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } m_progress.setMaximum(m_progress.getMaximum() + (finalListToInstall.size() * 30)); } // OK, now we can download and install everything // first install the final list of dependencies try { WekaPackageManager.installPackages(finalListToInstall, pps); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("An error has occurred while installing " + "dependent packages", e); //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } // Now install the package itself //m_progress.setMaximum(finalListToInstall.size() * 10 + 10); try { WekaPackageManager.installPackageFromRepository(packageName, versionToInstall.toString(), pps); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem installing package: " + packageName, e); // return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } } else { //m_progress.setMaximum(10); // just install this package without checking/downloading dependencies etc. try { WekaPackageManager.installPackageFromRepository(packageName, versionToInstall.toString(), pps); } catch (Exception e) { e.printStackTrace(); displayErrorDialog("Problem installing package: " + packageName, e); //return null; m_unsuccessfulInstalls.add(packageToInstall); continue; } } } // m_successfulInstall = true; // Make sure that the new stuff is available to all GUIs WekaPackageManager.refreshGOEProperties(); return null; } public void done() { m_progress.setValue(m_progress.getMinimum()); if (m_unsuccessfulInstalls.size() == 0) { // if (m_successfulInstall) { m_detailLabel.setText("Package(s) installed successfully."); } else { StringBuffer failedPackageNames = new StringBuffer(); for (Package p : m_unsuccessfulInstalls) { failedPackageNames.append(p.getName() + "\n"); } displayErrorDialog("The following package(s) could not be installed\n" + "for some reason (check the log)\n" + failedPackageNames.toString() , ""); m_detailLabel.setText("Install complete."); } m_unofficialBut.setEnabled(true); m_refreshCacheBut.setEnabled(true); m_availableBut.setEnabled(true); m_allBut.setEnabled(true); m_installedBut.setEnabled(true); // force refresh of installed and available packages m_installedPackages = null; m_availablePackages = null; // m_installBut.setEnabled(true); m_installing = false; updateTable(); if (m_table.getSelectedRow() >= 0) { // mainly to update the install/uninstall button status //displayPackageInfo(m_table.getSelectedRow()); updateInstallUninstallButtonEnablement(); } } } /*public class ComboBoxRenderer extends JComboBox implements TableCellRenderer { public ComboBoxRenderer(String[] items) { super(items); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { setForeground(table.getSelectionForeground()); super.setBackground(table.getSelectionBackground()); } else { setForeground(table.getForeground()); setBackground(table.getBackground()); } // Select the current value setSelectedItem(value); return this; } }*/ protected class ComboBoxEditor extends DefaultCellEditor { public ComboBoxEditor() { super(new JComboBox(new String[] {"one", "two"})); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { String packageName = m_table.getValueAt(row, getColumnIndex(PACKAGE_COLUMN)).toString(); List<Object> catAndVers = m_packageLookupInfo.get(packageName); List<Object> repVersions = (List<Object>)catAndVers.get(1); String[] versions = repVersions.toArray(new String[1]); Component combo = getComponent(); if (combo instanceof JComboBox) { ((JComboBox)combo).setModel(new DefaultComboBoxModel(versions)); ((JComboBox)combo).setSelectedItem(value); } else { System.err.println("Uh oh!!!!!"); } return combo; } } protected boolean m_cacheEstablished = false; protected boolean m_cacheRefreshInProgress = false; public static String PAGE_HEADER = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n" + "<html>\n<head>\n<title>Waikato Environment for Knowledge Analysis (WEKA)</title>\n" + "<!-- CSS Stylesheet -->\n<style>body\n{\nbackground: #ededed;\ncolor: #666666;\n" + "font: 14px Tahoma, Helvetica, sans-serif;;\nmargin: 5px 10px 5px 10px;\npadding: 0px;\n" + "}\n</style>\n\n</head>\n<body bgcolor=\"#ededed\" text=\"#666666\">\n"; private static String initialPage() { StringBuffer initialPage = new StringBuffer(); initialPage.append(PAGE_HEADER); initialPage.append("<h1>WEKA Package Manager</h1>\n\n</body></html>\n"); return initialPage.toString(); } protected class HomePageThread extends Thread { public void run() { try { m_homeB.setEnabled(false); m_backB.setEnabled(false); URLConnection conn = null; URL homeURL = new URL(BROWSER_HOME); org.pentaho.packageManagement.PackageManager pm = WekaPackageManager.getUnderlyingPackageManager(); if (pm.setProxyAuthentication()) { conn = homeURL.openConnection(pm.getProxy()); } else { conn = homeURL.openConnection(); } // read the html for the home page - all we want to do here is make // sure that the web server is responding, so that we don't tie // up the JEditorPane indefinitely, since there seems to be no // way to set a timeout in JEditorPane conn.setConnectTimeout(10000); // 10 seconds BufferedReader bi = new BufferedReader(new InputStreamReader(conn.getInputStream())); while (bi.readLine() != null) { // } m_infoPane.setPage(BROWSER_HOME); } catch (Exception ex) { // don't make a fuss } finally { m_homeB.setEnabled(true); m_backB.setEnabled(true); } } } private int getColumnIndex(String columnName) { return m_table.getColumn(columnName).getModelIndex(); } public PackageManager() { EstablishCache ec = new EstablishCache(); ec.execute(); while (!m_cacheEstablished) { try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } } // first try and get the full list of packages getAllPackages(); setLayout(new BorderLayout()); ButtonGroup bGroup = new ButtonGroup(); bGroup.add(m_installedBut); bGroup.add(m_availableBut); bGroup.add(m_allBut); JPanel butPanel = new JPanel(); butPanel.setLayout(new BorderLayout()); JPanel packageDisplayP = new JPanel(); packageDisplayP.setLayout(new BorderLayout()); JPanel packageDHolder = new JPanel(); packageDHolder.setLayout(new FlowLayout()); packageDHolder.add(m_installedBut); packageDHolder.add(m_availableBut); packageDHolder.add(m_allBut); packageDisplayP.add(packageDHolder, BorderLayout.SOUTH); packageDisplayP.add(m_refreshCacheBut, BorderLayout.NORTH); JPanel officialHolder = new JPanel(); officialHolder.setLayout(new BorderLayout()); officialHolder.setBorder(BorderFactory.createTitledBorder("Official")); officialHolder.add(packageDisplayP, BorderLayout.WEST); butPanel.add(officialHolder, BorderLayout.WEST); m_refreshCacheBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { RefreshCache r = new RefreshCache(); r.execute(); } }); JPanel unofficialHolder = new JPanel(); unofficialHolder.setLayout(new BorderLayout()); unofficialHolder.setBorder(BorderFactory.createTitledBorder("Unofficial")); unofficialHolder.add(m_unofficialBut, BorderLayout.NORTH); butPanel.add(unofficialHolder, BorderLayout.EAST); JPanel installP = new JPanel(); JPanel buttP = new JPanel(); buttP.setLayout(new GridLayout(1,2)); installP.setLayout(new BorderLayout()); buttP.add(m_installBut); buttP.add(m_uninstallBut); m_installBut.setEnabled(false); m_uninstallBut.setEnabled(false); installP.add(buttP, BorderLayout.NORTH); installP.add(m_forceBut, BorderLayout.SOUTH); m_forceBut.setEnabled(false); // butPanel.add(installP, BorderLayout.EAST); officialHolder.add(installP, BorderLayout.EAST); m_installBut.setToolTipText("Install the selected official package(s) " + "from the list"); m_uninstallBut.setToolTipText("Uninstall the selected package(s) from the list"); m_unofficialBut.setToolTipText("Install an unofficial package from a file or URL"); m_unofficialChooser.resetFileFilters(); m_unofficialChooser. addFileFilter(new ExtensionFileFilter(".zip", "Package archive file")); m_unofficialBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_unofficialFrame == null) { final JFrame jf = new JFrame("Unofficial package install"); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { jf.dispose(); m_unofficialBut.setEnabled(true); m_unofficialFrame = null; } }); jf.setLayout(new BorderLayout()); JButton okBut = new JButton("OK"); JButton cancelBut = new JButton("Cancel"); JPanel butHolder = new JPanel(); butHolder.setLayout(new GridLayout(1,2)); butHolder.add(okBut); butHolder.add(cancelBut); jf.add(m_unofficialChooser, BorderLayout.CENTER); jf.add(butHolder, BorderLayout.SOUTH); jf.pack(); jf.setVisible(true); m_unofficialFrame = jf; m_unofficialBut.setEnabled(false); cancelBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_unofficialFrame != null) { jf.dispose(); m_unofficialBut.setEnabled(true); m_unofficialFrame = null; } } }); okBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String target = m_unofficialChooser.getText(); UnofficialInstallTask t = new UnofficialInstallTask(); t.setTargetToInstall(target); t.execute(); if (m_unofficialFrame != null) { jf.dispose(); m_unofficialBut.setEnabled(true); m_unofficialFrame = null; } } }); } } }); m_installBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int[] selectedRows = m_table.getSelectedRows(); if (selectedRows.length > 0) { //int selected = m_table.getSelectedRow(); //if (selected != -1) { List<String> packageNames = new ArrayList<String>(); List<Object> versions = new ArrayList<Object>(); StringBuffer confirmList = new StringBuffer(); for (int i = 0; i < selectedRows.length; i++) { String packageName = m_table.getValueAt(selectedRows[i], getColumnIndex(PACKAGE_COLUMN)).toString(); packageNames.add(packageName); Object packageVersion = m_table.getValueAt(selectedRows[i], getColumnIndex(REPOSITORY_COLUMN)); versions.add(packageVersion); confirmList.append(packageName + " " + packageVersion.toString() + "\n"); } JTextArea jt = new JTextArea("The following packages will be " + "installed/upgraded:\n\n" + confirmList.toString(), 10, 40); int result = JOptionPane.showConfirmDialog(PackageManager.this, new JScrollPane(jt), "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { pleaseCloseAppWindowsPopUp(); InstallTask task = new InstallTask(); task.setPackages(packageNames); task.setVersions(versions); task.execute(); } } } }); m_uninstallBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // int selected = m_table.getSelectedRow(); int[] selectedRows = m_table.getSelectedRows(); if (selectedRows.length > 0) { List<String> packageNames = new ArrayList<String>(); StringBuffer confirmList = new StringBuffer(); for (int i = 0; i < selectedRows.length; i++) { String packageName = m_table.getValueAt(selectedRows[i], getColumnIndex(PACKAGE_COLUMN)).toString(); Package p = null; try { p = WekaPackageManager.getRepositoryPackageInfo(packageName); } catch (Exception e1) { // e1.printStackTrace(); // continue; // see if we can get installed package info try { p = WekaPackageManager.getInstalledPackageInfo(packageName); } catch (Exception e2) { e2.printStackTrace(); continue; } } if (p.isInstalled()) { packageNames.add(packageName); confirmList.append(packageName + "\n"); } } if (packageNames.size() > 0) { JTextArea jt = new JTextArea("The following packages will be " + "uninstalled:\n" + confirmList.toString(), 10, 40); int result = JOptionPane.showConfirmDialog(PackageManager.this, new JScrollPane(jt), "Weka Package Manager", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { pleaseCloseAppWindowsPopUp(); UninstallTask task = new UninstallTask(); task.setPackages(packageNames); task.execute(); } } } /* if (selected != -1) { String packageName = m_table.getValueAt(selected, getColumnIndex(PACKAGE_COLUMN)).toString(); pleaseCloseAppWindowsPopUp(); UninstallTask task = new UninstallTask(); task.setPackage(packageName); task.execute(); } */ } }); JPanel progressP = new JPanel(); progressP.setLayout(new BorderLayout()); progressP.setBorder(BorderFactory. createTitledBorder("Install/Uninstall/Refresh progress")); progressP.add(m_progress, BorderLayout.NORTH); progressP.add(m_detailLabel, BorderLayout.CENTER); butPanel.add(progressP, BorderLayout.CENTER); JPanel topPanel = new JPanel(); topPanel.setLayout(new BorderLayout()); // topPanel.setBorder(BorderFactory.createTitledBorder("Packages")); topPanel.add(butPanel, BorderLayout.NORTH); m_allBut.setSelected(true); m_allBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_table.clearSelection(); updateTable(); updateInstallUninstallButtonEnablement(); } }); m_availableBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_table.clearSelection(); updateTable(); updateInstallUninstallButtonEnablement(); } }); m_installedBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_table.clearSelection(); updateTable(); updateInstallUninstallButtonEnablement(); } }); m_model = new DefaultTableModel(new String[] {PACKAGE_COLUMN, CATEGORY_COLUMN, INSTALLED_COLUMN, REPOSITORY_COLUMN, LOADED_COLUMN}, 15) { private static final long serialVersionUID = -2886328542412471039L; public boolean isCellEditable(int row, int col) { if (col != 3) { return false; } else { return true; } } }; m_table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); m_table.setColumnSelectionAllowed(false); m_table.setPreferredScrollableViewportSize(new Dimension(550, 200)); m_table.setModel(m_model); if (System.getProperty("os.name").contains("Mac")) { m_table.setShowVerticalLines(true); } else { m_table.setShowVerticalLines(false); } m_table.setShowHorizontalLines(false); m_table.getColumn("Repository version").setCellEditor(new ComboBoxEditor()); m_table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting() && !m_cacheRefreshInProgress) { ListSelectionModel lm = (ListSelectionModel) e.getSource(); boolean infoDisplayed = false; for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) { if (lm.isSelectedIndex(i)) { if (!infoDisplayed) { // display package info for the first one in the list displayPackageInfo(i); infoDisplayed = true; break; } } } updateInstallUninstallButtonEnablement(); } } }); JTableHeader header = m_table.getTableHeader(); header.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { TableColumnModel colModel = m_table.getColumnModel(); // The index of the column whose header was clicked int vColIndex = colModel.getColumnIndexAtX(evt.getX()); // Return if not clicked on any column header or // clicked on the version number cols if (vColIndex == -1 || vColIndex > 1) { return; } if (vColIndex == m_sortColumn) { // toggle the sort order m_reverseSort = !m_reverseSort; } else { m_reverseSort = false; } m_sortColumn = vColIndex; updateTable(); } }); topPanel.add(new JScrollPane(m_table), BorderLayout.CENTER); // add(topPanel, BorderLayout.NORTH); /* m_packageDescription = new JTextArea(10,10); m_packageDescription.setLineWrap(true); */ try { //m_infoPane = new JEditorPane(BROWSER_HOME); String initialPage = initialPage(); m_infoPane = new JEditorPane("text/html", initialPage); } catch (Exception ex) { m_infoPane = new JEditorPane(); } m_infoPane.setEditable(false); m_infoPane.addHyperlinkListener(new HyperlinkListener() { public void hyperlinkUpdate(HyperlinkEvent event) { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { if (event.getURL().toExternalForm().endsWith(".zip") || event.getURL().toExternalForm().endsWith(".jar")) { // don't render archives! } else { if (m_browserHistory.size() == 0) { m_backB.setEnabled(true); } m_browserHistory.add(m_infoPane.getPage()); m_infoPane.setPage(event.getURL()); } } catch(IOException ioe) { } } } }); //JScrollPane sp = new JScrollPane(m_packageDescription); //JScrollPane sp = new JScrollPane(m_infoPane); //sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); //sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); JPanel browserP = new JPanel(); browserP.setLayout(new BorderLayout()); m_backB = new JButton(new ImageIcon(loadImage("weka/gui/images/back.gif"))); m_backB.setToolTipText("Back"); m_backB.setEnabled(false); m_backB.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); m_homeB = new JButton(new ImageIcon(loadImage("weka/gui/images/home.gif"))); m_homeB.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); m_homeB.setToolTipText("Home"); m_browserTools = new JToolBar(); m_browserTools.add(m_backB); m_browserTools.add(m_homeB); m_browserTools.setFloatable(false); // create the new packages available icon m_newPackagesAvailableL = new JLabel(new ImageIcon(loadImage("weka/gui/images/information.gif"))); // Start loading the home page Thread homePageThread = new HomePageThread(); homePageThread.setPriority(Thread.MIN_PRIORITY); homePageThread.start(); m_backB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { URL previous = m_browserHistory.removeLast(); try { m_infoPane.setPage(previous); if (m_browserHistory.size() == 0) { m_backB.setEnabled(false); } } catch (IOException ex) { // } } }); m_homeB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { URL back = m_infoPane.getPage(); if (back != null) { m_browserHistory.add(back); } String initialPage = initialPage(); m_infoPane.setContentType("text/html"); m_infoPane.setText(initialPage); HomePageThread hp = new HomePageThread(); hp.setPriority(Thread.MIN_PRIORITY); hp.start(); } catch (Exception ex) { // don't make a fuss } } }); browserP.add(m_browserTools, BorderLayout.NORTH); browserP.add(new JScrollPane(m_infoPane), BorderLayout.CENTER); // add(browserP, BorderLayout.CENTER); m_splitP = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topPanel, browserP); m_splitP.setOneTouchExpandable(true); add(m_splitP, BorderLayout.CENTER); updateTable(); // check for any new packages on the server (if possible) CheckForNewPackages cp = new CheckForNewPackages(); cp.execute(); } private void updateInstallUninstallButtonEnablement() { boolean enableInstall = false; boolean enableUninstall = false; m_unofficialBut.setEnabled(true); if (!m_installing) { int[] selectedRows = m_table.getSelectedRows(); // check the package to see whether we should enable the // install button or uninstall button. Once we've determined // that the list contains at least one package to be installed // and uninstalled we don't have to check any further for (int i = 0; i < selectedRows.length; i++) { if (!enableInstall || !enableUninstall) { enableInstall = true; // we should always be able to install an already installed package String packageName = m_table.getValueAt(selectedRows[i], getColumnIndex(PACKAGE_COLUMN)).toString(); try { Package p = WekaPackageManager.getRepositoryPackageInfo(packageName); if (!enableUninstall) { enableUninstall = p.isInstalled(); } /*if (!enableInstall) { enableInstall = !p.isInstalled(); } */ } catch (Exception e1) { // not a repository package - just enable the uninstall button enableUninstall = true; enableInstall = false; } } } } else { m_unofficialBut.setEnabled(false); } // now set the button enablement m_installBut.setEnabled(enableInstall); m_forceBut.setEnabled(enableInstall); m_uninstallBut.setEnabled(enableUninstall); } private Image loadImage(String path) { Image pic = null; URL imageURL = this.getClass().getClassLoader().getResource(path); if (imageURL == null) { // ignore } else { pic = Toolkit.getDefaultToolkit().getImage(imageURL); } return pic; } /*private String getRepVersions(String packageName, String packageVersion) { List<Object> repVersions = m_packageVersionsLookup.get(packageName); StringBuffer repString = new StringBuffer(); if (repVersions.size() > 1) { repString.append("("); for (int i = 0; i < repVersions.size(); i++) { if (!repVersions.get(i).equals(packageVersion)) { repString.append(repVersions.get(i).toString()); if (i < repVersions.size() - 1) { repString.append(", "); } } } repString.append(")"); } else { return ""; } return repString.toString(); } */ private void updateTable() { if (m_installedPackages == null || m_availablePackages == null) { // update the loaded status for (Package p : m_allPackages) { String loadStatus = ""; if (p.isInstalled()) { File packageRoot = new File(WekaPackageManager.getPackageHome().toString() + File.separator + p.getName()); boolean loaded = WekaPackageManager.loadCheck(p, packageRoot); loadStatus = (loaded) ? "Yes" : "No - check log"; } List<Object> catAndVers = m_packageLookupInfo.get(p.getName()); catAndVers.set(2, loadStatus); } } if (m_allBut.isSelected()) { m_model.setRowCount(m_allPackages.size()); Collections.sort(m_allPackages, m_packageComparator); int row = 0; for (Package p : m_allPackages) { m_model.setValueAt(p.getName(), row, getColumnIndex(PACKAGE_COLUMN)); String category = ""; if (p.getPackageMetaDataElement("Category") != null) { category = (String)p.getPackageMetaDataElement("Category"); } m_model.setValueAt(category, row, getColumnIndex(CATEGORY_COLUMN)); String installedV = ""; Object repositoryV = p.getPackageMetaDataElement("Version"); // String repString = getRepVersions(p.getName(), repositoryV); // String[] repVersions = getRepVersions2(p.getName(), repositoryV); // repositoryV = repositoryV + " " + repString; if (p.isInstalled()) { try { Package installed = WekaPackageManager.getInstalledPackageInfo(p.getName()); installedV = installed.getPackageMetaDataElement("Version").toString(); } catch (Exception ex) { ex.printStackTrace(); displayErrorDialog("An error has occurred while trying to obtain" + " installed package info", ex); } } m_model.setValueAt(installedV, row, getColumnIndex(INSTALLED_COLUMN)); m_model.setValueAt(repositoryV, row, getColumnIndex(REPOSITORY_COLUMN)); List<Object> catAndVers = m_packageLookupInfo.get(p.getName()); String loadStatus = (String)catAndVers.get(2); m_model.setValueAt(loadStatus, row, getColumnIndex(LOADED_COLUMN)); row++; } m_table.revalidate(); m_table.repaint(); } else if (m_installedBut.isSelected()) { try { if (m_installedPackages == null) { m_installedPackages = WekaPackageManager.getInstalledPackages(); } m_model.setRowCount(m_installedPackages.size()); int row = 0; for (Package p : m_installedPackages) { m_model.setValueAt(p.getName(), row, getColumnIndex(PACKAGE_COLUMN)); String installedV = p.getPackageMetaDataElement("Version").toString(); String category = ""; if (p.getPackageMetaDataElement("Category") != null) { category = p.getPackageMetaDataElement("Category").toString(); } List<Object> catAndVers = m_packageLookupInfo.get(p.getName()); Object repositoryV = "-----"; if (catAndVers != null) { // handle non-repository packages List<Object> repVersions = (List<Object>) catAndVers.get(1); repositoryV = repVersions.get(0); } // String repString = getRepVersions(p.getName(), repositoryV); // repositoryV = repositoryV + " " + repString; m_model.setValueAt(category, row, getColumnIndex(CATEGORY_COLUMN)); m_model.setValueAt(installedV, row, getColumnIndex(INSTALLED_COLUMN)); m_model.setValueAt(repositoryV, row, getColumnIndex(REPOSITORY_COLUMN)); if (catAndVers != null) { String loadStatus = (String)catAndVers.get(2); m_model.setValueAt(loadStatus, row, getColumnIndex(LOADED_COLUMN)); } else { // handle non-repository packages File packageRoot = new File(WekaPackageManager.getPackageHome().toString() + File.separator + p.getName()); boolean loaded = WekaPackageManager.loadCheck(p, packageRoot); String loadStatus = (loaded) ? "Yes" : "No - check log"; m_model.setValueAt(loadStatus, row, getColumnIndex(LOADED_COLUMN)); } row++; } } catch (Exception ex) { ex.printStackTrace(); } } else { try { if (m_availablePackages == null) { m_availablePackages = WekaPackageManager.getAvailablePackages(); } m_model.setRowCount(m_availablePackages.size()); int row = 0; for (Package p : m_availablePackages) { m_model.setValueAt(p.getName(), row, getColumnIndex(PACKAGE_COLUMN)); String category = ""; if (p.getPackageMetaDataElement("Category") != null) { category = p.getPackageMetaDataElement("Category").toString(); } String installedV = ""; List<Object> catAndVers = m_packageLookupInfo.get(p.getName()); List<Object> repVersions = (List<Object>) catAndVers.get(1); Object repositoryV = repVersions.get(0); // String repString = getRepVersions(p.getName(), repositoryV); // repositoryV = repositoryV + " " + repString; m_model.setValueAt(category, row, getColumnIndex(CATEGORY_COLUMN)); m_model.setValueAt(installedV, row, getColumnIndex(INSTALLED_COLUMN)); m_model.setValueAt(repositoryV, row, getColumnIndex(REPOSITORY_COLUMN)); String loadStatus = (String)catAndVers.get(2); m_model.setValueAt(loadStatus, row, getColumnIndex(LOADED_COLUMN)); row++; } } catch (Exception ex) { ex.printStackTrace(); } } } private void displayPackageInfo(int i) { String packageName = m_table.getValueAt(i, getColumnIndex(PACKAGE_COLUMN)).toString(); boolean repositoryPackage = true; try { Package repP = WekaPackageManager.getRepositoryPackageInfo(packageName); } catch (Exception ex) { repositoryPackage = false; } String versionURL = WekaPackageManager.getPackageRepositoryURL().toString() + "/" + packageName + "/index.html"; try { URL back = m_infoPane.getPage(); if (m_browserHistory.size() == 0 && back != null) { m_backB.setEnabled(true); } if (back != null) { m_browserHistory.add(back); } if (repositoryPackage) { m_infoPane.setPage(new URL(versionURL)); } else { // try and display something on this non-official package try { Package p = WekaPackageManager.getInstalledPackageInfo(packageName); Map<?, ?> meta = p.getPackageMetaData(); Set<?> keys = meta.keySet(); StringBuffer sb = new StringBuffer(); sb.append(weka.core.RepositoryIndexGenerator.HEADER); sb.append("<H1>" + packageName + " (Unofficial) </H1>"); for (Object k : keys) { if (!k.toString().equals("PackageName")) { Object value = meta.get(k); sb.append(k + " : " + value + "<p>"); } } sb.append("</html>\n"); m_infoPane.setText(sb.toString()); } catch (Exception e) { // ignore } } } catch (Exception ex) { ex.printStackTrace(); } updateInstallUninstallButtonEnablement(); if (m_availableBut.isSelected()) { m_uninstallBut.setEnabled(false); } /* if (m_installing) { m_installBut.setEnabled(false); m_uninstallBut.setEnabled(false); } else { m_installBut.setEnabled(true); if (m_availableBut.isSelected()) { m_uninstallBut.setEnabled(false); } else { try { Package p = WekaPackageManager.getRepositoryPackageInfo(packageName); m_uninstallBut.setEnabled(p.isInstalled()); } catch (Exception ex) { m_uninstallBut.setEnabled(false); } } } */ } private void getPackagesAndEstablishLookup() throws Exception { m_allPackages = WekaPackageManager.getAllPackages(); // now fill the lookup map m_packageLookupInfo = new TreeMap<String, List<Object>>(); //Iterator<Package> i = allP.iterator(); for (Package p : m_allPackages) { // Package p = i.next(); String packageName = p.getName(); String category = ""; if (p.getPackageMetaDataElement("Category") != null) { category = p.getPackageMetaDataElement("Category").toString(); } // check the load status of this package (if installed) String loadStatus = ""; if (p.isInstalled()) { File packageRoot = new File(WekaPackageManager.getPackageHome().toString()); boolean loaded = WekaPackageManager.loadCheck(p, packageRoot); loadStatus = (loaded) ? "Yes" : "No - check log"; } List<Object> versions = WekaPackageManager.getRepositoryPackageVersions(packageName); List<Object> catAndVers = new ArrayList<Object>(); catAndVers.add(category); catAndVers.add(versions); catAndVers.add(loadStatus); m_packageLookupInfo.put(packageName, catAndVers); } } private void getAllPackages() { try { getPackagesAndEstablishLookup(); } catch (Exception ex) { // warn the user that we were unable to get the list of packages // from the repository ex.printStackTrace(); System.err.println("A problem has occurred whilst trying to get all " + "package information. Trying a cache refresh..."); WekaPackageManager.refreshCache(System.out); try { // try again getPackagesAndEstablishLookup(); } catch (Exception e) { e.printStackTrace(); } } } private void displayErrorDialog(String message, Exception e) { java.io.StringWriter sw = new java.io.StringWriter(); e.printStackTrace(new java.io.PrintWriter(sw)); String result = sw.toString(); displayErrorDialog(message, result); } private void displayErrorDialog(String message, String stackTrace) { Object[] options = null; if (stackTrace != null && stackTrace.length() > 0) { options = new Object[2]; options[0] = "OK"; options[1] = "Show error"; } else { options = new Object[1]; options[0] = "OK"; } int result = JOptionPane.showOptionDialog(this, message, "Weka Package Manager", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]); if (result == 1) { JTextArea jt = new JTextArea(stackTrace, 10, 40); JOptionPane.showMessageDialog(PackageManager.this, new JScrollPane(jt), "Weka Package Manager", JOptionPane.OK_OPTION); } } /** * Setting the initial placement of the divider line on a JSplitPane * is problematic. Most of the time it positions itself just fine based * on the preferred and minimum sizes of the two things it divides. However, * sometimes it seems to set itself such that the top component is not visible * without manually setting the position. This method can be called (after * the containing frame is visible) to set the divider location to 40% of the * way down the window. */ public void setInitialSplitPaneDividerLocation() { m_splitP.setDividerLocation(0.4); } public static void main(String[] args) { weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO, "Logging started"); LookAndFeel.setLookAndFeel(); PackageManager pm = new PackageManager(); final javax.swing.JFrame jf = new javax.swing.JFrame("Weka Package Manager"); jf.getContentPane().setLayout(new BorderLayout()); jf.getContentPane().add(pm, BorderLayout.CENTER); jf.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { jf.dispose(); System.exit(0); } }); Dimension screenSize = jf.getToolkit().getScreenSize(); int width = screenSize.width * 8 / 10; int height = screenSize.height * 8 / 10; jf.setBounds(width/8, height/8, width, height); jf.setVisible(true); pm.setInitialSplitPaneDividerLocation(); } }