Package weka.gui

Source Code of weka.gui.PackageManager$ComboBoxEditor

/*
*    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();
  }
 
}
TOP

Related Classes of weka.gui.PackageManager$ComboBoxEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.