Package nixonftp

Source Code of nixonftp.NixonFTP$TraverseMenuListener

/* nixonFTP
* FTP client version 0.1
* Copyright (C) 2010 NIXON Development Corporation.
* All rights reserved.
* http://members.shaw.ca/nixon.com
*/
package nixonftp;

import nixonftp.ui.*;
import nixonftp.list.*;
import java.awt.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager.*;
import javax.swing.*;
import javax.swing.event.MenuEvent;
import javax.swing.event.PopupMenuEvent;
import sun.net.ftp.FtpLoginException;
import sun.net.ftp.FtpProtocolException;
import javax.swing.event.MenuListener;
import javax.swing.event.PopupMenuListener;
import nixonftp.list.NXDefaultListModel;
import nixonftp.ui.NXLogPanel;
import nixonftp.ui.NXMenu;

public class NixonFTP extends java.applet.Applet implements ActionListener {

  static NXFtpClient ftpClient;
  static JFrame frame;
  static NXSubFrame previewFrame;
  static NXLog ftpLog;
  private NXToolbar toolBar;
  private NXFtpBrowserPanel remotePanel;
  private NXFtpBrowserPanel localPanel;
  private JButton btnLog;
  private JProgressBar progressBar;
  private NXSplitPane splitBrowser;
  private NXSplitPane splitOverall;
  private NXSidebar sideBar;
  private javax.swing.Timer splitBrowserAnimator;
  private boolean splitBrowserReverse;
  private NXQueue queue;
  private JProgressBar overallProgressBar;
  private JPanel bottomPanel;
  private NXObjectIndex drives;
  private NXDragFeedbackLabel dragFeedbackLabel;
  private int proxyType = -1;
  private int PROXY_TYPE_HTTP = 0;
  private int PROXY_TYPE_SOCKS = 1;
  private NXQueuePanel queuePanel;
  private NXLogPanel logPanel;
  private JMenu menu;
  private NXListAdapter dragItem;

  public NixonFTP() {
    frame = new JFrame("nixonFTP");
    try {
      frame.setIconImages(NXIcon.iconList);
    } catch (NoSuchMethodError ex) {
      frame.setIconImage((Image) NXIcon.iconList.get(0));
    }

    frame.getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE);
    Container contentPane = frame.getContentPane();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setPreferredSize(new Dimension(816, 580));
    frame.setGlassPane(new NXDragFeedbackLabel());
    construct(contentPane);
    frame.pack();
    frame.setVisible(true);
  }

  private void construct(Container contentPane) {
    ftpLog = new NXLog();

    toolBar = new NXToolbar(this);

    SpringLayout frameLayout = new SpringLayout();
    contentPane.setLayout(frameLayout);


    remotePanel = new NXFtpBrowserPanel(true, false);
    //NXScrollPane remoteScroll = new NXScrollPane(remotePanel);
    remotePanel.btnConnect.addActionListener(this);
    remotePanel.txtHost.addActionListener(this);
    remotePanel.txtUser.addActionListener(this);
    remotePanel.txtPassword.addActionListener(this);
    //addRemoteList("", 0);

    localPanel = new NXFtpBrowserPanel(false, true);
    //NXScrollPane localScroll = new NXScrollPane(localPanel);
    splitBrowser = new NXSplitPane(JSplitPane.VERTICAL_SPLIT,
        remotePanel, null);
    splitBrowser.setSecondComponent(localPanel);

    sideBar = new NXSidebar();
    splitOverall = new NXSplitPane(JSplitPane.HORIZONTAL_SPLIT,
        null, splitBrowser);
    splitOverall.setFirstComponent(sideBar);

    bottomPanel = new JPanel();
    bottomPanel.setLayout(new GridLayout(0, 2));
    bottomPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY));

    progressBar = new JProgressBar(0, 100);
    progressBar.setVisible(false);
    progressBar.setStringPainted(true);
    bottomPanel.add(progressBar);

    overallProgressBar = new JProgressBar(0, 100);
    overallProgressBar.setVisible(false);
    overallProgressBar.setStringPainted(true);
    overallProgressBar.setString("All");
    bottomPanel.add(overallProgressBar);

    contentPane.add(toolBar);
    contentPane.add(splitOverall);
    contentPane.add(bottomPanel);

    // Make object expand to window.
    frameLayout.putConstraint(SpringLayout.EAST, toolBar, 0,
        SpringLayout.EAST, contentPane);
    frameLayout.putConstraint(SpringLayout.WEST, toolBar, 0,
        SpringLayout.WEST, contentPane);

    frameLayout.putConstraint(SpringLayout.EAST, splitOverall, 0,
        SpringLayout.EAST, contentPane);
    frameLayout.putConstraint(SpringLayout.WEST, splitOverall, 0,
        SpringLayout.WEST, contentPane);
    frameLayout.putConstraint(SpringLayout.SOUTH, splitOverall, 0,
        SpringLayout.NORTH, bottomPanel);
    frameLayout.putConstraint(SpringLayout.SOUTH, bottomPanel, 0,
        SpringLayout.SOUTH, contentPane);
    frameLayout.putConstraint(SpringLayout.EAST, bottomPanel, 0,
        SpringLayout.EAST, contentPane);
    frameLayout.putConstraint(SpringLayout.WEST, bottomPanel, 0,
        SpringLayout.WEST, contentPane);
    frameLayout.putConstraint(SpringLayout.NORTH, splitOverall, 0,
        SpringLayout.SOUTH, toolBar);

    queue = new NXQueue();

    addLocalList("", 0);
    //if (File.listRoots()[0].getPath().equals("/")) {
    //  (new ListingWorker("/", true)).execute();
    //} else {
    (new DriveWorker()).execute();
    //}
    splitBrowser.setDividerLocation(0.6);
    doTable(remotePanel.table);
    doTable(localPanel.table);

    queuePanel = new NXQueuePanel();
    sideBar.addImpl("Queue", queuePanel);

    logPanel = new NXLogPanel();
    ftpLog.setArea(logPanel);
    sideBar.addImpl("Log", logPanel);
  }

  private void makeMenu() {
    JMenuBar bar = new JMenuBar();
    menu = new JMenu();

    menu.add(new JMenuItem("Filters..."));
    //menu.addMenuListener(this);
  }

  public NixonFTP(Container contentPane, NXDragFeedbackLabel lbl) {
    construct(contentPane);
    dragFeedbackLabel = lbl;
  }

  public void setProxyType(String type) {
    if (type.equals("0")) {
      proxyType = PROXY_TYPE_HTTP;
    } else if (type.equals("1")) {
      proxyType = PROXY_TYPE_SOCKS;
    }
  }

  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();

    boolean accountPanel = source.equals(remotePanel.btnConnect)
        || source.equals(remotePanel.txtHost)
        || source.equals(remotePanel.txtUser)
        || source.equals(remotePanel.txtPassword);
    if (accountPanel) { //from account interface inside browser
      String[] s = remotePanel.getValues();
      connect(s[0], s[1], s[2]);
    } else if (source.equals(toolBar.btnConnect)) {
      if (!remotePanel.init) {
        switchAccountPanel();
      }
    } else if (source.equals(toolBar.btnListing)) {
      if (!remotePanel.accountPanel.isVisible()) {
        doListing(false, !remotePanel.listing);
      }
    } else if (source.equals(toolBar.btnListingLocal)) {
      doListing(true, !localPanel.listing);
    } else if (source.equals(toolBar.btnFilters)) {
      doFilters();
    } else if (source.equals(toolBar.btnLocal)) {
      toolBar.btnLocal.setSelected(splitBrowser.toggle(false));
    } else if (source.equals(toolBar.btnQueue)) {
      //queuePanel.setVisible(toolBar.btnQueue.isSelected());
      toolBar.btnQueue.setSelected(splitOverall.toggle(true));
    }
  }

  private void doListing(boolean local, boolean b) {
    NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
    panel.listing = b;
    panel.listingPanel.setVisible(b);
    panel.browserScroll.setVisible(!b);

    ImageIcon i = null;

    if (b) {
      NXList list = panel.getListBoxes(-1);
      String dir = list.getDirectory();
      String getDir = (dir.equals("")) ? "/" : dir;
      if (local) {
        (new ListingWorker(dir, true)).execute();
      } else {
        updateList(panel.table, (NXObjectIndex) ftpClient.getObjectIndex().get(getDir), local);
      }
      doCrumbs(dir, local);
      panel.browserScroll.getViewport().setViewPosition(new Point(0, 0));
      i = NXIcon.columns;
    } else {
      traversePath(local, panel.table.getDirectory());
      i = NXIcon.detail;
    }

    if (!local) {
      /*JButton btn = (local) ? toolBar.btnListingLocal : toolBar.btnListing;
      btn.setIcon(i);*/
      toolBar.btnListing.setIcon(i);
    }
  }

  private void switchAccountPanel() {
    boolean b = remotePanel.toggleAccountPanel();
    if (b) {
      String[] s = ftpClient.getCredentials();
      remotePanel.txtHost.setText(s[0]);
      remotePanel.txtUser.setText(s[1]);
      remotePanel.txtPassword.setText(s[2]);
    }
    remotePanel.validateAccountPanel();
    toolBar.btnConnect.setText((b) ? "Return" : "");
    if (!remotePanel.init) {
      toolBar.btnListing.setVisible(!b);
      //toolBar.btnFilters.setVisible(!b);
    }
  }

  private void traversePath(boolean local, String dir) {
    NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
    String[] dirs = dir.split("/");
    panel.removeList(1);

    NXList list;
    String initialPath = "";
    String newDir;
    NXObjectIndex oi;

    for (int x = 1; x < dirs.length; x++) {
      newDir = initialPath + "/" + dirs[x];
      if (local) {
        addLocalList(newDir, x);
      } else {
        addRemoteList(newDir, x);
      }

      list = panel.getListBoxes(-1);

      if (local) {
        (new ListingWorker(newDir, true, list)).execute();
      } else {
        oi = (NXObjectIndex) ftpClient.getObjectIndex().get(newDir);
        if (oi != null) {
          updateList(list, oi, false);
        }
      }

      initialPath = newDir;
    }
  }

  private Proxy getProxy() {
    if (proxyType == -1) {
      return null;
    }
    Proxy proxy = null;

    String proxyHost = System.getProperty("ftp.proxyHost");
    if (proxyHost != null) {
      System.out.println("Using proxy server");
      int proxyPort = 1080;
      String portProperty = System.getProperty("ftp.proxyPort");
      if (portProperty != null) {
        try {
          proxyPort = Integer.parseInt(portProperty);
        } catch (NumberFormatException e) {
        }
      }
      SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort);
      Proxy.Type type = (proxyType == 0) ? Proxy.Type.HTTP : Proxy.Type.SOCKS;
      proxy = new Proxy(type, addr);
    }
    return proxy;
  }

  private void connect(String host, String user, String password) {
    ftpClient = new NXFtpClient(ftpLog, getProxy());
    ftpClient.setCredentials(
        new String[]{host,
          user,
          password,
          ""});
    remotePanel.setInit(false);
    switchAccountPanel();
    (new ConnectWorker()).execute();
  }

  private void updateList(NXListAdapter list, NXObjectIndex oi, boolean local) {
    Object model = null;
    Object[] data = null;
    NXDefaultListModel listModel = null;
    NXTableModel tableModel = null;
    NXList nixonList = null;
    NXTable table = null;
    NXFilter[] filters = null;
    boolean blFilter = false;
    NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;

    if (!panel.listing) {
      listModel = new NXDefaultListModel();
      nixonList = (NXList) list;
      filters = nixonList.getFilters();
      blFilter = filters != null;
    } else {
      tableModel = new NXTableModel();
      table = panel.table;
    }

    boolean showOnly = false;
    boolean hide = false;
    boolean add = false;

    for (Object obj : oi.objects.values()) {
      NXObjectIndex oioi = (NXObjectIndex) obj;
      if (blFilter) {
        add = false;
        hide = false;
        NXFilter[] filter = nixonList.filter(filters, oioi);
        for (int x = 0; x < filter.length; x++) {
          if (filter[x] != null) {
            hide = filter[x].action == NXFilter.HIDE;
            showOnly = filter[x].action == NXFilter.SHOW;
            add = filter[x].action == NXFilter.SHOW || filter[x].action == NXFilter.COLOR;
          } else {
            if (!showOnly) {
              add = true;
            }
          }
        }
        if (!add && hide) {
          continue;
        }
      }
      if (panel.listing) {
        tableModel.addRow(oioi);
      } else {
        listModel.addElement(oioi);
      }
    }

    if (!panel.listing) {
      model = new NXSortedListModel(listModel, NXSortedListModel.SortOrder.DESCENDING, new NXObjectComparator());
      nixonList.setModel((ListModel) model);
    } else {
      table.setModel(tableModel);
      table.getColumnModel().getColumn(0).setHeaderValue("Name");
      table.getColumnModel().getColumn(1).setHeaderValue("Size");
      table.getColumnModel().getColumn(2).setHeaderValue("Modified");
      table.dirty = false;
    }
  }

  class NXObjectComparator implements Comparator {

    public int compare(Object o1, Object o2) {
      NXObjectIndex oi1 = (NXObjectIndex) o1;
      NXObjectIndex oi2 = (NXObjectIndex) o2;
      String name1 = oi1.name;
      String name2 = oi2.name;

      if (oi1.type == oi2.type) {
        return name2.compareToIgnoreCase(name1);
      } else if (oi1.type > oi2.type) { //folders/links take precedence
        return 1;
      } else {
        return -1;
      }
    }
  }

  class ConnectWorker extends SwingWorker {

    String[] credentials;

    public ConnectWorker() {
      super();
      credentials = ftpClient.getCredentials();
      setStatus("Connecting to \"" + credentials[0] + "\"...", true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      NXMessageLabel lbl = new NXMessageLabel();
      String[] sError = new String[2];

      try {
        ftpClient.connect();
      } catch (FtpLoginException e) {
        sError[0] = "Could not log in to the server \"" + credentials[0] + "\".";
        sError[1] = "Make sure that you entered your username and password correctly.";
      } catch (FtpProtocolException e) {
        sError[0] = "Could not connect to the server \"" + credentials[0] + "\".";
        sError[1] = "Make sure that the server is an RFC 959-compliant FTP server.";
      } catch (UnknownHostException e) {
        sError[0] = "Could not find the server \"" + credentials[0] + "\".";
        sError[1] = "Make sure you entered the address correctly. The server could be down at the moment. ";
      } catch (IOException e) {
        sError[0] = "Could not connect to the server \"" + credentials[0] + "\".";
        sError[1] = "The error was: " + e.getMessage();
      }

      if (sError[0] != null) {
        lbl.setInfo(sError[0], sError[1]);
        JOptionPane.showMessageDialog(frame, lbl,
            "", JOptionPane.ERROR_MESSAGE);
        switchAccountPanel();
      }
      return new Object();
    }

    @Override
    public void done() {
      NXListAdapter obj = null;
      if (!remotePanel.listing) {
        addRemoteList("", 0);
        obj = remotePanel.getListBoxes(-1);
      } else {
        remotePanel.table.setDirectory("");
      }
      updateList(obj, (NXObjectIndex) ftpClient.getObjectIndex().get("/"), false);
      progressBar.setVisible(false);
    }
  };

  class DriveWorker extends SwingWorker {

    File[] roots;

    @Override
    protected Object doInBackground() throws Exception {
      roots = File.listRoots();
      return new Object();
    }

    @Override
    public void done() {
      JList list = null;
      NXDefaultListModel listModel = new NXDefaultListModel();
      ;
      NXTable table = null;
      NXTableModel tableModel = null;
      NXSortedListModel sortedModel = null;

      if (localPanel.listing) {
        table = localPanel.table;
        tableModel = new NXTableModel();
      } else {
        list = localPanel.getListBoxes(-1);
      }

      String drivePath;
      drives = new NXObjectIndex('z', "");
      for (Object obj : roots) {
        File drive = (File) obj;
        drivePath = drive.getPath();
        if (drivePath.length() >= 3) {
          drivePath = drivePath.substring(0, 2);
        }
        NXObjectIndex driveIndex = new NXObjectIndex('z', drivePath);
        if (localPanel.listing) {
          tableModel.addRow(driveIndex);
        } else {
          listModel.addElement(driveIndex);
        }
        drives.objects.put(drivePath, driveIndex);
      }
      NXObjectIndex homeItem = new NXObjectIndex('h', "Home");
      if (localPanel.listing) {
        tableModel.addRow(homeItem);
        table.setModel(tableModel);
      } else {
        listModel.addElement(homeItem);
        sortedModel = new NXSortedListModel(listModel, NXSortedListModel.SortOrder.DESCENDING, new NXObjectComparator());
        list.setModel(sortedModel);
      }
      drives.objects.put("Home", homeItem);
    }
  };

  class ListingWorker extends SwingWorker {

    private String directory;
    private boolean local = false;
    private File[] files;
    private NXListAdapter list = null;
    private boolean blDrives = false;
    private int listingSize;
    private String fake;

    protected ListingWorker(String directory, boolean local, Object list) {
      this.local = local;
      if (list != null) {
        this.list = (NXListAdapter) list;
      }
      setUp(directory);
    }

    protected ListingWorker(String directory, boolean local) {
      this.local = true;
      setUp(directory);
    }

    protected ListingWorker(String directory) {
      setUp(directory);
      toolBar.btnListing.setEnabled(false);
    }

    public void setFakeDirectory(String dir) {
      fake = dir;
    }

    @Override
    protected Object doInBackground() throws Exception {
      if (local) {
        if (directory.equals("")) {
          blDrives = true;
        } else {
          if (directory.equals("/")) {
            directory = "";
          }
          File f = new File(directory + "/");
          files = f.listFiles(new HiddenFileFilter());
        }
      } else {
        listingSize = ftpClient.indexDirectory(directory);
      }
      return new Object();
    }

    private void doLocal() {
      String name;
      char type;
      char[] perms = new char[3];
      String strPerms;
      long size;
      Date date;
      boolean exe = false;

      NXObjectIndex root = new NXObjectIndex('d', directory, "rwxrwxrwx", "", "", 0, 0, new Date());

      File testFile = new File("");
      try {
        exe = testFile.canExecute();
        exe = true;
      } catch (NoSuchMethodError e) { //Java 5
        exe = false;
      }

      if (files != null) {
        for (int x = 0; x < files.length; x++) {
          name = files[x].getName();
          type = (files[x].isDirectory()) ? ('d') : ('-');
          perms[0] = (files[x].canRead()) ? ('w') : ('-');
          perms[1] = (files[x].canWrite()) ? ('r') : ('-');

          if (exe) { //Java 6
            perms[2] = (files[x].canExecute()) ? ('x') : ('-');
          } else {
            perms[2] = '-';
          }

          strPerms = new String(perms);
          size = files[x].length();
          date = new Date(files[x].lastModified());
          NXObjectIndex oi = new NXObjectIndex(type, name, strPerms, "", "", size, 0, date);
          root.objects.put(oi.name, oi);
        }
      }
      if (list == null) {
        list = localPanel.getListBoxes(-1);
      }
      updateList(list, root, true);
      resetBars();
    }

    private void resetBars() {
      if (queue.queue.isEmpty()) {
        progressBar.setVisible(false);
        overallProgressBar.setVisible(false);
      }
    }

    @Override
    public void done() {
      if (blDrives) {
        (new DriveWorker()).execute();
        resetBars();
      } else if (local) {
        doLocal();
      } else {
        progressBar.setVisible(false);
        toolBar.btnListing.setEnabled(true);

        NXObjectIndex dirObj = (NXObjectIndex) ftpClient.getObjectIndex().get(directory);
        if (fake != null) {
          ftpClient.fakeDirectory(dirObj, fake);
        }
        if (remotePanel.listing) {
          updateList(null, dirObj, false);
        } else {
          boolean listDefined = (list != null);
          if (!listDefined) {
            list = remotePanel.getListBoxes(-1);
          }
          if (list.getDirectory().equals(directory) || listDefined) { //user didn't move to another directory
            updateList(list, dirObj, false);
          }
        }
        queue.totalSize += listingSize;
        queue.totalTransferred += listingSize;
        queue.process();
      }
    }

    private void setUp(String directory) {
      this.directory = directory;
      setStatus("Getting contents of \"" + directory + "\"...", true);
    }
  };

  private void uploadFromFileList(String dir, java.util.List files) {
    File file;
    for (int x = 0; x < files.size(); x++) {
      file = (File) files.get(x);
      if (file.isDirectory()) {
        String name = file.getPath();
        String basePath = dir + '/' + NXFormat.getNameFromPath(name, false);
        recursiveUpload(file.listFiles(), basePath);
      } else {
        queue.add(new NXQueueItem("upload", file.getAbsolutePath(), dir + '/' + file.getName(), ""), false);
      }
    }
  }

  private void recursiveUpload(File[] files, String basePath) {
    createDirectoryIf(basePath);
    for (int x = 0; x < files.length; x++) {
      if (files[x].isDirectory()) {
        String name = files[x].getPath();
        String newPath = basePath + '/' + NXFormat.getNameFromPath(name, false);
        recursiveUpload(files[x].listFiles(), newPath);
      } else {
        queue.add(new NXQueueItem("upload", files[x].getAbsolutePath(), basePath + '/' + files[x].getName(), ""), false);
      }
    }
  }

  class NXListTransferHandler extends TransferHandler {

    DataFlavor localObjectFlavor;
    String localArrayListType = DataFlavor.javaJVMLocalObjectMimeType;
    private final boolean local;
    private final boolean listing;

    public NXListTransferHandler(boolean local, boolean listing) {
      this.local = local;
      this.listing = listing;
      try {
        localObjectFlavor = new DataFlavor(localArrayListType);
      } catch (ClassNotFoundException ex) {
      }
    }

    @Override
    public int getSourceActions(JComponent c) {
      if (dragItem != null) {
        if (((NXListAdapter) c).getLocal() == dragItem.getLocal()) return MOVE;
        else return COPY;
      } else {
        return COPY_OR_MOVE;
      }
      //return NONE;
    }

    @Override
    public Transferable createTransferable(JComponent c) {
      NXObjectIndex[] objs = null;
      String dir = "";
      boolean blLocal = false;
      if (listing) {
        NXTable table = (NXTable) c;
        int[] rows = table.getSelectedRows();
        NXTableModel model = (NXTableModel) table.getModel();
        objs = new NXObjectIndex[rows.length];
        for (int x = 0; x < rows.length; x++) {
          objs[x] = model.getValueAt(rows[x]);
        }
        dir = table.getDirectory();
        blLocal = table.getLocal();
      } else {
        NXList list = (NXList) c;
        objs = list.getSelectedObjects();
        dir = list.getDirectory();
        blLocal = list.getLocal();
      }
      dragItem = (NXListAdapter) c;
      return new NXObjectTransferable(objs, dir, blLocal);
    }

    @Override
    public void exportDone(JComponent c, Transferable t, int action) {
    }

    @Override
    public boolean importData(JComponent comp, Transferable t) {
      NXObjectIndex[] oi = null;
      NXListAdapter list = (NXListAdapter) comp;

      DataFlavor unix = null;
      try {
        DataFlavor[] flavors = t.getTransferDataFlavors();

        try {
          unix = new DataFlavor("text/uri-list;class=java.io.Reader");
        } catch (ClassNotFoundException ex) {
          Logger.getLogger(NixonFTP.class.getName()).log(Level.SEVERE, null, ex);
        }

        String dir = list.getDirectory();
        NXObjectIndex val = list.getSelectedValue();

        if (val != null && (val.type == 2 || val.realType == 2) && list.dropLeft()) {
          dir += '/' + val.name;
        }

        for (int x = 0; x < flavors.length; x++) {
          if (flavors[x].isFlavorJavaFileListType()) {
            java.util.List fileList = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);
            uploadFromFileList(dir, fileList);
            break;
          } else if (flavors[x].equals(unix)) {
            uploadFromFileList(dir, doUnix(flavors[x], t));
          } else if (flavors[x].equals(localObjectFlavor)) {
            Object[] data = (Object[]) t.getTransferData(flavors[x]);
            NXObjectIndex[] o = (NXObjectIndex[]) data[0];
            String dir2 = (String) data[1];
            boolean importFromLocal = data[2].equals(true);

            if (dir2.equals(dir)) return false;

            if (importFromLocal == list.getLocal()) { //move operation
              if (importFromLocal) { localMoveFromIndex(dir2, dir, o);
              } else { remoteMoveFromIndex(dir2, dir, o); }
            } else if (importFromLocal) {
              uploadFromIndex(dir, dir2, o, list);
            } else {
              downloadFromIndex(dir2, dir, o, list);
              return true;
            }
            break;
          }
        }

      } catch (UnsupportedFlavorException ex) {
      } catch (IOException ex) {
      }
      return true;
    }

    private ArrayList doUnix(DataFlavor f, Transferable t) throws UnsupportedFlavorException, IOException {
      BufferedReader read = new BufferedReader(f.getReaderForText(t));
      // Delete "file://" protocol from filename
      String fileName;
      ArrayList fileList = new ArrayList();
      while ((fileName = read.readLine()) != null) {
        fileName = fileName.substring(7).replace("%20", " ");
        String test = fileName.substring(0, 9);
        if (test.equals("localhost")) {
          fileName = fileName.substring(9);
        }
        fileList.add(new File(fileName));
      }
      // Delete "localhost" from Mac filenames
      read.close();
      return fileList;
    }

    @Override
    public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
      if (dragItem != null) {
        if (comp.equals(dragItem) && !dragItem.dropLeft()) return false;
        return true;
      }
      return false;
    }

    class NXObjectTransferable implements Transferable {

      private NXObjectIndex[] objects;
      public boolean local;
      public String dir;

      public NXObjectTransferable(NXObjectIndex[] files, String dir, boolean local) {
        objects = files;
        this.dir = dir;
        this.local = local;
      }

      public synchronized Object getTransferData(DataFlavor flavor) {
        return new Object[]{objects, dir, local};
      }

      public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[]{localObjectFlavor};
      }

      public boolean isDataFlavorSupported(DataFlavor flavor) {
        return flavor.equals(localObjectFlavor);
      }
    }
  }

  class UploadWorker extends SwingWorker {

    private String localFile;
    private String remoteFile;
    private Object list;
    private File file;

    protected UploadWorker(String localFile, String remoteFile, Object list) {
      this.localFile = localFile;
      this.remoteFile = remoteFile;
      this.list = list;
      setStatus("Uploading " + NXFormat.getNameFromPath(localFile, false), false);
    }

    protected Object doInBackground() throws IOException {
      int i = 0;
      long uploaded = 0;
      byte[] bytesIn = new byte[1024];
      if (!ftpClient.getBinary()) {
        ftpClient.binary();
      }
      file = new File(localFile);
      long size = file.length();
      FileInputStream in = new FileInputStream(localFile);
      BufferedOutputStream out = null;
      double progress = 0.0;

      try {
        out = new BufferedOutputStream(ftpClient.put(remoteFile));
        while ((i = in.read(bytesIn)) >= 0) {
          uploaded += i;
          //frame.setTitle(Long.toString(uploaded));
          progress = (double) uploaded / (double) size * (double) 100;
          queue.updateTransferred(i);
          progressBar.setValue((int) progress);
          if (progressBar.isIndeterminate()) {
            progressBar.setIndeterminate(false);
          }
          out.write(bytesIn, 0, i);
        }
        in.close();
        out.close();
        addToList();
      } catch (Exception e) {
        String message = e.getMessage();
        if (message.contains("550")) {
          NXQueueItem curr = (NXQueueItem) queue.get(0);
          curr.setError("You do not have permission to upload the file " + NXFormat.getNameFromPath(curr.localFile, false));
          queue.addError(curr);
        }
      }
      return new Object();
    }

    private void addToList() {
      addItem(false, remoteFile, new Date(file.lastModified()), file.length());
    }

    @Override
    public void done() {
      progressBar.setVisible(false);
      queue.process();
    }
  };

  private void addItem(boolean local, String file, Date modified, long size) {
    NXObjectIndex oi;
    String[] elements = NXFormat.getNameFromPath(file);
    NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
    NXListAdapter l = panel.getListIfShown(elements[0]);
    NXObjectIndex dirIndex = (NXObjectIndex) ftpClient.getObjectIndex().get(elements[0]);
    if (l != null) {
      oi = new NXObjectIndex('-', elements[1], "wrxwrxwrx", "", "", size, 0, modified);
      l.addElement(oi);
      if (dirIndex != null) {
        dirIndex.objects.put(elements[1], oi);
      }
    }
  }

  private void setStatus(String s, boolean indeterminate) {
    progressBar.setVisible(true);
    progressBar.setString(s);
    queue.currentString = s;
    progressBar.setIndeterminate(indeterminate);
  }

  private void updateOverall() {
    float progress = (float) queue.totalTransferred / (float) queue.totalSize * 100;
    overallProgressBar.setValue((int) progress);
    overallProgressBar.setVisible(true);
  }

  class DownloadWorker extends SwingWorker {

    private String localFile;
    private String remoteFile;
    private boolean preview;
    private Object list = null;
    private NXObjectIndex obj;
    byte[] bytesIn;
    byte[] bytesOut;
    boolean error = false;
    long size;
    private boolean temp;
    File tempFile;

    protected DownloadWorker(String localFile, String remoteFile, Object list) {
      this.list = list;
      setUp(localFile, remoteFile);
    }

    protected DownloadWorker(String localFile, String remoteFile, boolean preview, boolean temp) {
      this.preview = preview;
      this.temp = temp;
      setUp(localFile, remoteFile);
    }

    protected void setUp(String localFile, String remoteFile) {
      if (temp) {
        try {
          tempFile = File.createTempFile("nixonftp", NXFormat.getNameFromPath(remoteFile, false));
          this.localFile = tempFile.getAbsolutePath();
          tempFile.deleteOnExit();
        } catch (IOException ex) {
          System.out.println("DownloadWorker: IOException creating local temp file");
        }
      } else { this.localFile = localFile; }
      this.remoteFile = remoteFile;
      setStatus("Downloading " + NXFormat.getNameFromPath(this.remoteFile, false), false);
    }

    protected Object doInBackground() throws IOException {
      int i = 0;
      int downloaded = 0;
      FileOutputStream out = null;
      if (!ftpClient.getBinary()) {
        ftpClient.binary();
      }
      if (!preview) {
        out = new FileOutputStream(localFile);
      }
      String[] parts = NXFormat.getNameFromPath(remoteFile); //get parent directory, filename only
      String fileName = parts[1];
      String pathName = parts[0];
      NXObjectIndex oi = (NXObjectIndex) ftpClient.getObjectIndex().get(pathName);
      obj = (NXObjectIndex) oi.objects.get(fileName);
      size = obj.size;
      BufferedInputStream in = null;
      bytesIn = new byte[4096];
      if (preview) {
        bytesOut = new byte[(int) size];
      }
      double progress;

      try {
        in = new BufferedInputStream(ftpClient.get(remoteFile));
        if (preview) {
          while (downloaded < size
              && (i = in.read(bytesOut, downloaded, bytesOut.length - downloaded)) >= 0) {
            downloaded += i;
          }
        } else {
          while ((i = in.read(bytesIn)) >= 0) {
            downloaded += i;
            out.write(bytesIn, 0, i);
            progress = (double) downloaded / (double) size * (double) 100;
            progressBar.setValue((int) progress);
            queue.updateTransferred(i);
          }
        }
      } catch (Exception e) {
        error = true;
        String message = e.getMessage();
        System.out.println("Error in DownloadWorker: " + message);
        if (message.contains("550")) {
          NXQueueItem curr = (NXQueueItem) queue.get(0);
          curr.setError("You do not have permission to download the file " + NXFormat.getNameFromPath(curr.localFile, false));
          queue.addError(curr);
        } else {
        }
      } finally {
        in.close();
        out.close();
      }
      return new Object();
    }

    @Override
    public void done() {
      progressBar.setVisible(false);
      queue.process();
      if (!error) {
        addItem(true, localFile, new Date(), size);
      }

      if (temp) {
        openFile(localFile);
        java.util.Timer t = new java.util.Timer();
        t.schedule(new FileWatcher(tempFile, remoteFile), 3000, 3000);
      }
      if (preview) {
        (new PreviewWorker(remoteFile, bytesOut)).execute();
      }
    }
  };

  class FileWatcher extends TimerTask {
    File f;
    long lastModified;
    String origFile;
    boolean pending;
   
    public FileWatcher(File f, String origFile) {
      this.f = f;
      this.origFile = origFile;
      lastModified = f.lastModified();
    }

    @Override
    public void run() {
      long currentModified = f.lastModified();
      if (currentModified != lastModified) {
        int result = uploadTempFile(f, origFile);
        if (result == 0) { //upload it nao!
          queue.add(new NXQueueItem("upload", f.getAbsolutePath(), origFile, "", null, f.length()), true);
          cancel();
        } else if (result == 1) {
          lastModified = currentModified;
        } else {
          f.delete();
          cancel();
        }
      }
    }

  }

  int uploadTempFile(File temp, String remoteFile) {

    int result = NXFormat.alertBox(this,
      "The local file representing " + NXFormat.getNameFromPath(remoteFile, false) + " has changed. Do you want to upload these changes?",
      "<b>Full remote file path: </b>" + remoteFile +
      "<br /><b>Modified: </b>" + NXFormat.parseDate(new Date(temp.lastModified())),
      JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
      new String[] {"Upload","Don't Upload Yet","Never Upload"}, 0);

    return result;
  }

  class PreviewWorker extends SwingWorker {

    private File file;
    private String data;
    boolean image = false;
    String title;
    private byte[] bytes;

    protected PreviewWorker(String remoteFile, byte[] bytes) {
      this.bytes = bytes;
      setUp(remoteFile);
    }

    protected PreviewWorker(String remoteFile, File file) {
      this.file = file;
      setUp(remoteFile);
    }

    private void setUp(String remoteFile) {
      image = NXFormat.isImage(remoteFile);
      title = NXFormat.getNameFromPath(remoteFile, false);
      ImageIcon img = null;

      if (image) {
        if (file != null) {
          img = new ImageIcon(file.getAbsolutePath());
        } else if (bytes != null) {
          img = new ImageIcon(bytes);
        }
      }
      if (!(previewFrame instanceof NXSubFrame)) {
        previewFrame = new NXSubFrame(frame, title, image, img);
      } else {
        //previewFrame already created
        previewFrame.setTitle(title);
        //previewFrame.setUp(image, img);
        if (img != null) {
          previewFrame.setImage(img);
        }
      }
      previewFrame.setVisible(true);

      if (!image) {
        previewFrame.displayPlainText("");
      }
    }

    private boolean verifyLoad(long size) {
      Object[] options = {"Load",
        "Cancel"};
      int n = JOptionPane.showOptionDialog(frame,
          "<html><table width='360'><tr><td><strong>The file " + title + " may take a long time to preview. Would you still like to load it?</strong>"
          + "</td></tr><tr><td>" + title + " is " + NXFormat.fileSize(size) + ". Text files larger than 128 KB need a lot of time to load.</td></tr></table></html>",
          null,
          JOptionPane.OK_CANCEL_OPTION,
          JOptionPane.WARNING_MESSAGE,
          null,
          options,
          options[1]);
      return (n == JOptionPane.OK_OPTION);
    }

    @Override
    protected Object doInBackground() throws Exception {
      if (!image && file != null) {
        if (file.length() > 131072) {
          if (!verifyLoad(file.length())) {
            return new Object();
          }
        }
        FileInputStream in = null;
        BufferedInputStream bis;
        DataInputStream dis = null;
        BufferedReader br = null;
        try {
          in = new FileInputStream(file);
          // Get the object of DataInputStream
          dis = new DataInputStream(in);
          br = new BufferedReader(new InputStreamReader(in));
          String strLine;
          //Read File Line By Line
          while ((strLine = br.readLine()) != null) {
            // Print the content on the console
            data += strLine + "\n";
          }
          //Close the input stream

        } finally {
          dis.close();
          in.close();
          br.close();
        }
      }
      return new Object();
    }

    @Override
    public void done() {
      if (data == null && bytes != null) {
        data = new String(bytes);
      }
      if (data != null && image == false) {
        if (bytes.length > 131072) {
          if (!verifyLoad(bytes.length)) {
            return;
          }
        }
        previewFrame.displayPlainText(data);
      }
    }
  };

  class CommandWorker extends SwingWorker {

    private String cmd;
    private final boolean explicit;
    private String error;

    protected CommandWorker(String cmd, String message, boolean explicit) {
      this.cmd = cmd;
      this.explicit = explicit;
      setStatus(message, true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      String[] sError = new String[2];

      try {
        ftpClient.cd("/");
        ftpClient.sendCommand(cmd);
      } catch (Exception e) {
        String msg = e.getMessage();
        NXQueueItem curr = (NXQueueItem) queue.get(0);
        if (cmd.contains("MKD") && !explicit) {
          error = "You do not have permission to create a folder here.";
          if (explicit) {
            if (msg.contains("550")) {
              sError[0] = "Could not create new folder.";
              sError[1] = error;
            }
          }
        } else if (cmd.contains("RMD")) {
          error = "You do not have permission to delete the folder.";
          if (explicit) {
            if (msg.contains("550")) {
              sError[0] = "Could not delete the folder.";
              sError[1] = error;
            }
          }
        }
        if (!explicit && error != null) {
          curr.setError(error);
          queue.addError(curr);
        }
        if (sError[0] != null) {
          showError(sError);
        }
      }
      return new Object();
    }

    @Override
    public void done() {
      progressBar.setVisible(false);
      overallProgressBar.setVisible(false);
      if (error == null && cmd.startsWith("MKD")) {
        String base = cmd.substring(4);
        String[] pathElements = NXFormat.getNameFromPath(base);
        NXListAdapter list = remotePanel.getListIfShown(pathElements[0]);
        if (list != null) {
          list.addElement(new NXObjectIndex('d', pathElements[1]));
        }
      }
      queue.process();
    }
  };

  class RenameWorker extends SwingWorker {

    private String oldFile;
    private String newFile;

    protected RenameWorker(String oldFile, String newFile) {
      this.oldFile = oldFile;
      this.newFile = newFile;
      setStatus("Renaming \"" + NXFormat.getNameFromPath(oldFile, false) + "\"", true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      String[] sError = new String[2];

      try {
        ftpClient.rename(oldFile, newFile);
      } catch (Exception e) {
        String msg = e.getMessage();
        if (msg.contains("550")) {
          String[] parts = NXFormat.getNameFromPath(oldFile);

          sError[0] = "Could not rename the file \""
              + parts[1] + "\" to \""
              + NXFormat.getNameFromPath(newFile, false) + "\".";
          sError[1] = "You do not have permission to rename files in \""
              + parts[0] + "\".";
        }
        if (sError[0] != null) {
          showError(sError);
        }
      }
      return new Object();
    }

    @Override
    public void done() {
      queue.process();
    }
  };

  class DeleteWorker extends SwingWorker {

    private String file;

    protected DeleteWorker(String file) {
      this.file = file;
      setStatus("Deleting \"" + NXFormat.getNameFromPath(file, false) + "\".", true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      deleteRemoteFile(file);
      return new Object();
    }

    @Override
    public void done() {
      queue.process();
    }
  };

  void deleteRemoteFile(String file) {
    String[] sError = new String[2];

    try {
      ftpClient.sendCommand("DELE " + file);
    } catch (Exception e) {
      String msg = e.getMessage();
      if (msg.contains("550")) {
        NXQueueItem curr = new NXQueueItem("delete", "", file, "");
        curr.setError("You do not have permission to delete the file " + NXFormat.getNameFromPath(file, false));
        queue.addError(curr);
      }
    }
  }

  class LocalDeleteWorker extends SwingWorker {

    private String initialPath;
    private NXListAdapter list;
    private char type = '-';
    private boolean success;

    protected LocalDeleteWorker(String initialPath, NXListAdapter list) {
      super();
      this.initialPath = initialPath;
      this.list = list;
      setStatus("Deleting \"" + NXFormat.getNameFromPath(initialPath, false) + "\".", true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      deleteRecursively(initialPath);
      return new Object();
    }

    private void deleteRecursively(String path) {
      File f = new File(path);
      if (f.isDirectory()) {
        type = 'd';
        File[] files = f.listFiles();
        for (int x = 0; x < files.length; x++) {
          if (files[x].isDirectory()) {
            deleteRecursively(files[x].getPath());
          } else {
            files[x].delete();
          }
        }
      }
      boolean b = f.delete();
      if (path.equals(initialPath)) {
        success = b;
      }
    }

    @Override
    public void done() {
      if (success) {
        NXObjectIndex[] items = new NXObjectIndex[1];
        items[0] = new NXObjectIndex(type, NXFormat.getNameFromPath(initialPath, false));
        localPanel.remoteItemsFromList(list, items);
        if (type == 'd') {
          localPanel.removeList(list.getIndex() + 1);
        }
      }
      progressBar.setVisible(false);
    }
  };

  private void showError(String[] s) {
    NXMessageLabel lbl = new NXMessageLabel();
    lbl.setInfo(s[0], s[1]);
    JOptionPane.showMessageDialog(frame, lbl,
        "", JOptionPane.ERROR_MESSAGE);
  }

  private void doTable(NXTable t) {
    t.addMouseListener(new ListListener(t.getLocal()));
    setMenu(t, t.getLocal());
    t.setTransferHandler(new NXListTransferHandler(t.getLocal(), true));
    try {
      t.getDropTarget().addDropTargetListener(new NXDropListener(t));
    } catch (TooManyListenersException ex) {
    }
  }

  private void doCrumbs(String dir, boolean local) {
    NXFtpBrowserPanel panel = null;
    panel = (local) ? localPanel : remotePanel;
    if (local) {
      dir = dir.replace("\\", "/");
    }
    panel.crumbPanel.removeAll();
    String[] dirs = dir.split("/");
    String lastDir = "";
    String currDir;
    NXCrumb crumb;
    boolean first;
    for (int x = 0; x < dirs.length; x++) {
      first = dirs[x].equals("");
      if (first) {
        currDir = (local) ? "" : "/";
      } else {
        currDir = dirs[x];
      }
      crumb = new NXCrumb(currDir, lastDir + currDir);
      crumb.first = first;
      if (first && local) {
        crumb.setText("Computer");
      }
      crumb.addMouseListener(new CrumbListener(local));
      panel.crumbPanel.add(crumb);
      lastDir += dirs[x] + "/";
    }
    panel.crumbPanel.updateUI();
    panel.table.setDirectory(dir);
  }

  class CrumbListener implements MouseListener {

    private boolean local;

    public CrumbListener(boolean local) {
      this.local = local;
    }

    public void mouseClicked(MouseEvent e) {
      if (e.getButton() == MouseEvent.BUTTON3) {
        return;
      }
      NXCrumb crumb = (NXCrumb) e.getComponent();
      NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
      String dir = (crumb.dir.equals("/") || crumb.first) ? "" : crumb.dir;
      panel.table.setDirectory(dir);

      if (local) {
        (new ListingWorker(dir, true)).execute();
      } else {
        HashMap map = ftpClient.getObjectIndex();
        if (map.containsKey(crumb.dir)) {
          updateList(null,
              (NXObjectIndex) ftpClient.getObjectIndex().get(crumb.dir), local);
        } else {
          queue.add(new NXQueueItem("list", "", crumb.dir, ""), true);
        }
      }

      doCrumbs(dir, local);
    }

    public void mousePressed(MouseEvent e) {
      if (e.getButton() == MouseEvent.BUTTON3) {
        JPopupMenu menu = new JPopupMenu();
        HashMap map = ftpClient.getObjectIndex();
        NXCrumb lbl = (NXCrumb) e.getComponent();
        if (!local) {
          NXObjectIndex oi = (NXObjectIndex) ftpClient.getObjectIndex().get(lbl.dir);
          NXObjectIndex obj;
          NXTraverseMenu m;
          String dir = (lbl.dir.equals("/")) ? "" : lbl.dir;
          Object[] objects = oi.objects.values().toArray();
          for (int x = 0; x < objects.length; x++) {
            obj = (NXObjectIndex) objects[x];
            if (obj.type == 2 || obj.realType == 2) {
              m = new NXTraverseMenu(obj.name, dir + "/" + obj.name, false);
              m.setIcon(NXIcon.small[2]);
              m.addMenuListener(new ListTraverseMenuListener(true, null));
              menu.add(m);
            }
          }
        }
        menu.show(lbl, 0, lbl.getHeight());
      }
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
  }

  private void addRemoteList(String dir, int index) {
    if (remotePanel.listing) {
      return;
    }
    remotePanel.removeList(index);
    remotePanel.addList();
    final NXList list = remotePanel.getListBoxes(-1);
    list.setDirectory(dir);
    list.addMouseListener(new ListListener(false));
    list.addKeyListener(new ListListener(false));
    list.setTransferHandler(new NXListTransferHandler(false, false));
    try {
      list.getDropTarget().addDropTargetListener(new NXDropListener(list));
    } catch (TooManyListenersException ex) {
    }
    //list.setTransferHandler(new ListTransferHandler());
    setMenu(list, false);

    NXMenu menu = (NXMenu) list.getMenu();
    JMenu transferTo = (JMenu) menu.getIndex().get("TransferTo");

    transferTo.addMenuListener(new ListTraverseMenuListener(list.getLocal(), new TransferToActionListener(list)));

  }

  private void addUniqueLocation(NXTraverseMenu menu, boolean local) {
    boolean conflict = false;
    NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
    String dir;
    for (int x = 0; x < panel.locations.size(); x++) {
      dir = panel.locations.get(x).getDir();
      if (menu.getDir().contains(dir)) {
        conflict = true; //already added in subfolder!
      }
    }
    if (!conflict) {
      panel.locations.add(menu);
    }
  }

  class TransferToActionListener implements ActionListener {

    private final NXListAdapter list;

    public TransferToActionListener(NXList list) {
      this.list = list;
    }

    public void actionPerformed(ActionEvent e) {
      NXTraverseMenu menu;
      if (e.getSource() instanceof NXMenuItem) {
        NXMenuItem item = (NXMenuItem) e.getSource();
        menu = (NXTraverseMenu) item.parent;
      } else {
        menu = (NXTraverseMenu) e.getSource();
      }

      addUniqueLocation(menu, list.getLocal());
      NXListAdapter otherList;
      NXFtpBrowserPanel panel = (list.getLocal()) ? remotePanel : localPanel;
      otherList = panel.getListIfShown(menu.getDir());
      if (list.getLocal()) {
        uploadFromIndex(menu.getDir(), list.getDirectory(), list.getSelectedValues(), otherList);
      } else {
        downloadFromIndex(list.getDirectory(), menu.getDir(), list.getSelectedValues(), otherList);
      }
      NXMenu popUpMenu = (NXMenu) list.getMenu();
      popUpMenu.setVisible(false);
      popUpMenu.updateUI();
    }
  }

  class TraverseMenuListener implements MenuListener {

    boolean local;
    ActionListener listener;

    public TraverseMenuListener(boolean local, ActionListener listener) {
    }

    void showLocalMenu(String root, NXTraverseMenu topMenu) {
      topMenu.removeAll();
      if (ftpClient == null) {
        return;
      }
      NXObjectIndex rootIndex = (NXObjectIndex) ftpClient.getObjectIndex().get(root);
      if (rootIndex != null) {
        Object[] folderContents = rootIndex.objects.values().toArray();
        String name;
        String path;
        for (int x = 0; x < rootIndex.objects.size(); x++) {
          NXObjectIndex oi = (NXObjectIndex) folderContents[x];
          path = (root.equals("/")) ? '/' + oi.name : root + '/' + oi.name;
          name = NXFormat.getNameFromPath(path, false);
          if (oi.type == 2 || oi.realType == 2) {
            NXTraverseMenu newMenu = new NXTraverseMenu(name, path, false);
            newMenu.addMenuListener(this);
            topMenu.add(newMenu);
          }
        }
      }
      addAction(topMenu);
    }

    public void showMenu(String root, NXTraverseMenu topMenu) {
      topMenu.removeAll();

      NXMenuItem here = new NXMenuItem("Here", "Here");
      topMenu.add(here);
      here.parent = topMenu;
      here.addActionListener(listener);

      File f = new File(root);
      File[] files = f.listFiles(new HiddenFileFilter());
      if (files == null) {
        return;
      }
      String name;
      String path;
      for (int x = 0; x < files.length; x++) {
        path = files[x].getPath();
        name = NXFormat.getNameFromPath(path, false);
        if (files[x].isDirectory()) {
          NXTraverseMenu newMenu = new NXTraverseMenu(name, path, false);
          newMenu.addMenuListener(this);
          topMenu.add(newMenu);
        }
      }
      addAction(topMenu);
    }

    private void addAction(NXTraverseMenu menu) {
      menu.addActionListener(listener);
    }

    public void doMenu(EventObject e) {
      NXTraverseMenu m = (NXTraverseMenu) e.getSource();
      String dir = m.getDir();
      if (!local) {
        if (dir.equals("")) { //initial
          Object[] roots = drives.objects.values().toArray();
          m.removeAll();
          String path;
          boolean home;
          NXFtpBrowserPanel panel = (local) ? localPanel : remotePanel;
          int size = panel.locations.size();
          for (int x = 0; x < size; x++) {
            m.add(panel.locations.get(x));
          }
          if (size > 0) {
            m.addSeparator();
          }
          for (int x = 0; x < roots.length; x++) {
            NXObjectIndex oi = (NXObjectIndex) roots[x];
            home = oi.type == 4;
            path = home ? System.getProperty("user.home") : oi.name + '/';
            NXTraverseMenu newMenu = new NXTraverseMenu(oi.name, path, true);
            newMenu.setIcon((home) ? NXIcon.small[4] : NXIcon.small[3]);
            newMenu.addMenuListener(this);
            m.add(newMenu);
          }
        } else {
          showMenu(m.getDir(), m);
        }
      } else {
        if (dir.equals("")) { //inital
          showLocalMenu("/", m);
        } else {
          showLocalMenu(dir, m);
        }
      }
    }

    public void menuSelected(MenuEvent e) {
      throw new UnsupportedOperationException("Not supported yet.");
    }

    public void menuDeselected(MenuEvent e) {
      throw new UnsupportedOperationException("Not supported yet.");
    }

    public void menuCanceled(MenuEvent e) {
      throw new UnsupportedOperationException("Not supported yet.");
    }
  }

  class ListTraverseMenuListener extends TraverseMenuListener implements MenuListener {

    public ListTraverseMenuListener(boolean local, ActionListener listener) {
      super(local, listener);
      this.local = local;
      this.listener = listener;
    }

    @Override
    public void menuCanceled(MenuEvent evt) {
    }

    @Override
    public void menuDeselected(MenuEvent evt) {
    }

    public void menuSelected(MenuEvent evt) {
      doMenu(evt);
    }
  }

  class CrumbMenuListener extends TraverseMenuListener implements PopupMenuListener {

    public CrumbMenuListener(boolean local, ActionListener listener) {
      super(local, listener);
      this.local = local;
      this.listener = listener;
    }

    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
      doMenu(e);
    }

    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    }

    public void popupMenuCanceled(PopupMenuEvent e) {
    }
  }

  class HiddenFileFilter implements FilenameFilter {

    public boolean accept(File f, String name) {
      return !new File(f.getPath() + '/' + name).isHidden();
    }
  }

  private void addLocalList(String dir, int index) {
    if (localPanel.listing) {
      return;
    }
    localPanel.removeList(index);
    localPanel.addList();
    NXList list = localPanel.getListBoxes(-1);
    list.setDirectory(dir);
    list.setTransferHandler(new NXListTransferHandler(true, false));
    try {
      list.getDropTarget().addDropTargetListener(new NXDropListener(list));
    } catch (TooManyListenersException ex) {
    }
    list.addMouseListener(new ListListener(true));
    list.addKeyListener(new ListListener(true));
    setMenu(list, true);
    NXContextMenu m = (NXContextMenu) list.getMenu();
    JMenu transferTo = (JMenu) m.getIndex().get("TransferTo");
    transferTo.addMenuListener(new ListTraverseMenuListener(list.getLocal(), new TransferToActionListener(list)));
    localPanel.originalMenu = transferTo;
  }

  private void setMenu(NXListAdapter list, boolean local) {
    MouseListener popupListener = new PopupListener();
    list.addMouseListener(popupListener);
    NXMenu m = (NXMenu) list.getMenu();
    Object[] menuItems = (Object[]) m.getIndex().values().toArray();
    for (int x = 0; x < menuItems.length; x++) {
      try {
        ((JMenuItem) menuItems[x]).addActionListener(new ListPopupListener(list, local));
      } catch (Exception e) {
        continue;
      } //separator
    }
  }

  class ListListener implements MouseListener, KeyListener {

    private boolean local;
    private NXFtpBrowserPanel panel;

    public ListListener(boolean local) {
      super();
      this.local = local;
      if (local) {
        this.panel = localPanel;
      } else {
        this.panel = remotePanel;
      }
    }

    public void mouseClicked(MouseEvent e) {
      NXListAdapter adapter = (NXListAdapter) e.getComponent();
      if (e.getButton() != MouseEvent.BUTTON3) {
        listAction(adapter, e.getClickCount() - 1);
      }
    }

    private void listAction(NXListAdapter adapter, int eventType) { // type 0 for single-click; 1 for double
      NXObjectIndex selectedObject = (NXObjectIndex) adapter.getSelectedValue();

      boolean quit = panel.table.dirty && panel.listing;
      if (selectedObject == null || quit) {
        return;
      }
      NXListAdapter list = (panel.listing) ? null : adapter;
      String dir = null;

      if (adapter.getSelectedItemCount() == 1) {
        String pre = "";
        pre += (adapter.getDirectory().equals("")) ? "/" : adapter.getDirectory() + "/";
        boolean home = selectedObject.type == 4;
        dir = home ? //home directory?
            System.getProperty("user.home") : pre + selectedObject.name;
        int type = getType(pre, selectedObject);
        if (eventType == 0) {
          if (type >= 1) { //directory
            if (local) {
              if (!panel.listing) {
                addLocalList(dir, list.getIndex() + 1);
              }
              (new ListingWorker(dir, true)).execute();
            } else { //remote
              NXList update = null;
              if (!panel.listing) {
                addRemoteList(dir, list.getIndex() + 1);
                update = remotePanel.getListBoxes(-1);
              } else {
                panel.table.setDirectory(dir);
              }
              HashMap map = ftpClient.getObjectIndex();
              if (map.containsKey(dir)) {
                updateList(update,
                    (NXObjectIndex) ftpClient.getObjectIndex().get(dir), local);
              } else {
                NXQueueItem qi = new NXQueueItem("list", "", dir, "");
                if (selectedObject.type == 1) { //link, must update real location too!
                  qi.fakePath = pre + selectedObject.realLoc;
                  System.out.println(qi.fakePath);
                }
                queue.add(qi, true);
                if (panel.listing) {
                  panel.table.dirty = true;
                }
              }
            }
            if (panel.listing) {
              if (home) {
                dir = "/" + dir;
              }
              doCrumbs(dir, local);
            }
          } else if (type == 0) {
            //check if image
            if (previewFrame != null && previewFrame.isVisible()) {
              previewImage(dir, local);
            }
            if (!panel.listing) {
              panel.removeList(list.getIndex() + 1);
            }
          }
        } else if (eventType == 1 && type == 0) { //double-click on file
          if (local) { openFile(dir);
          } else {
            //previewImage(dir, local);
            queue.add(new NXQueueItem("open", "", dir, ""), true);
          }
        }
      }
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
    }

    public void keyReleased(KeyEvent e) {
      NXListAdapter list = (NXListAdapter) e.getComponent();
      switch (e.getKeyCode()) {
        case KeyEvent.VK_DELETE:
          deleteFromList(list, local);
          break;
        case KeyEvent.VK_CONTEXT_MENU:
        case KeyEvent.VK_F10:
          showPopup(list, 0, list.getRealBounds().height);
          break;
        case KeyEvent.VK_LEFT:
          NXList l = panel.getListBoxes(list.getIndex() - 1);
          l.requestFocusInWindow();
          panel.browserScroll.getViewport().scrollRectToVisible(l.getRealBounds());
          break;
        case KeyEvent.VK_ENTER:
        case KeyEvent.VK_RIGHT:
          int type = (e.isControlDown()) ? 1 : 0;
          listAction(list, type);
          break;
      }
    }
  }

  class PopupListener extends MouseAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
      maybeShowPopup(e);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
      maybeShowPopup(e);
    }

    private void maybeShowPopup(MouseEvent e) {
      if (e.getButton() == 3) {
        NXListAdapter c = (NXListAdapter) e.getComponent();
        showPopup(c, e.getX(), e.getY());
      }
    }
  }

  void showPopup(NXListAdapter c, int posX, int posY) {
    NXContextMenu m = (NXContextMenu) c.getMenu();

    int selDiff = c.getSelectedItemCount();

    HashMap idx = m.getIndex();

    NXObjectIndex selectedObject = (NXObjectIndex) c.getSelectedValue();
    NXMenuItem newFolder = (NXMenuItem) m.getIndex().get("NewFolder");
    NXMenuItem newFolderInItem = (NXMenuItem) m.getIndex().get("NewFolderIn");
    NXMenuItem preview = (NXMenuItem) idx.get("Preview");
    NXMenuItem transfer = (NXMenuItem) idx.get("Transfer");
    NXMenuItem switchView = (NXMenuItem) idx.get("SwitchView");
    NXTraverseMenu transferTo = (NXTraverseMenu) idx.get("TransferTo");

    NXMenuItem rename = (NXMenuItem) idx.get("Rename");
    JMenu deleteMenu = m.getDeleteMenu();

    newFolderInItem.setVisible(false);
    preview.setVisible(false);

    m.switchView(c.getLocal() ? localPanel.listing : remotePanel.listing);

    String appe;
    boolean selection = selectedObject != null;

    if (selection) {
      if (selDiff == 1) { // 1 item selected
        if (selectedObject.type == 2 || selectedObject.realType == 2) {
          newFolderInItem.setText("New Folder in " + selectedObject.name);
          newFolderInItem.setVisible(true);
        } else if (selectedObject.type == 0 || selectedObject.realType == 0) {
          if (selectedObject.size <= 524288) {
            preview.setVisible(true);
          }
        }
        appe = " \"" + selectedObject.name + "\"";
      } else { // more than 1 item selected
        appe = " these " + selDiff + " items";
      }
      deleteMenu.setText("Delete" + appe);
      String strTransfer = (m.local) ? "Upload" : "Download";
      transfer.setText(strTransfer + appe);
      transferTo.setText(strTransfer + " To");
      rename.setText("Rename" + appe);
    }
    transfer.setVisible(selection);
    transferTo.setVisible(selection);

    HashMap separators = m.getSeparators();
    //((JSeparator) separators.get("bottom")).setVisible(selection);
    ((JSeparator) separators.get("middle")).setVisible(selection);
    deleteMenu.setVisible(selection);
    rename.setVisible(selection);

    m.show((Component) c, posX, posY);
  }

  class ListPopupListener implements ActionListener {

    private final NXListAdapter list;
    private String id;
    private NXObjectIndex selectedObject;
    private final boolean local;

    public ListPopupListener(NXListAdapter list, boolean local) {
      this.list = list;
      this.local = local;
    }

    public void actionPerformed(ActionEvent e) {
      NXMenuItem menuItem = (NXMenuItem) e.getSource();

      selectedObject = (NXObjectIndex) list.getSelectedValue();

      id = menuItem.getId();
      if (id.contains("NewFolder")) {
        newFolder();
        /*} else if (id.equals("ShowLog")) {
        showLog();
        } else if (id.equals("ShowQueue")) {
        showQueue();
        } else if (id.equals("Filters")) {
        doFilters();*/
      } else if (id.equals("Preview")) {
        preview();
      } else if (id.equals("Open")) {
        open();
      } else if (id.equals("Rename")) {
        rename();
      } else if (id.equals("Delete")) {
        deleteFromList(list, local);
      } else if (id.equals("Transfer")) {
        transfer();
      } else if (id.equals("Reload")) {
        reload();
      } else if (id.equals("SwitchView")) {
        NXFtpBrowserPanel panel = list.getLocal() ? localPanel : remotePanel;
        doListing(list.getLocal(), !panel.listing);
      }
    }

    private void rename() {
      String currFile = list.getDirectory() + '/' + selectedObject.name;

      String newName = (String) JOptionPane.showInputDialog(
          frame,
          "Enter the new name of the file \"" + selectedObject.name + "\".",
          "Rename",
          JOptionPane.QUESTION_MESSAGE,
          null,
          null,
          selectedObject.name);

      String fullPath = list.getDirectory() + '/' + newName;
      if (newName != null && !newName.equals(selectedObject.name)) {
        if (!local) {
          queue.add(new NXQueueItem("rename", currFile, fullPath, ""), true);
        } else {
          File f = new File(currFile);
          boolean success = f.renameTo(new File(fullPath));
          if (success) {
            selectedObject.name = newName;
            list.updateUI();
          } else { //could not rename
            NXMessageLabel lbl = new NXMessageLabel();
            lbl.setInfo("Could not rename \"" + selectedObject.name + "\" to \"" + newName + "\".",
                "Make sure there is not already a file or folder with the same name in \"" + list.getDirectory() + "\".");
            JOptionPane.showMessageDialog(frame, lbl,
                "", JOptionPane.ERROR_MESSAGE);
          }
        }
      }
    }

    private void newFolder() {
      String shortDir;
      String initialDir = list.getDirectory();
      boolean in;

      in = id.equals("NewFolderIn");
      if (in) {
        initialDir += '/' + selectedObject.name;
        shortDir = selectedObject.name;
      } else {
        if (list.getDirectory().equals("")) {
          shortDir = "/";
        } else {
          shortDir = NXFormat.getNameFromPath(list.getDirectory(), false);
        }
      }

      String newDir = (String) JOptionPane.showInputDialog(
          frame,
          "Enter the name of the folder that will be created in: \n"
          + "<html><font face='Helvetica' size='+1'>" + shortDir + "</font><br>"
          + "<font color='#336699' size='-2'>" + initialDir + "</font></html>\n",
          "Create New Folder",
          JOptionPane.QUESTION_MESSAGE,
          NXIcon.folder,
          null,
          "");
      if (newDir != null) {
        String newPath = initialDir + '/' + newDir;
        NXObjectIndex dir = new NXObjectIndex('d', newDir, "rwxrwxrwx", "", "", 0, 0, new Date());
        NXListAdapter updateList;

        if (!local) {
          queue.add(new NXQueueItem("mkdir-explicit", "", newPath, "", list), true);
        } else {
          File f = new File(newPath);
          f.mkdir();
          if (in) {
            updateList = localPanel.getListBoxes(-1);
          } else {
            updateList = list;
          }
          NXObjectIndex[] dirs = new NXObjectIndex[1];
          dirs[0] = dir;
          localPanel.addItemsToList(updateList, dirs);
        }
      }
    } //newFolder

    private void preview() {
      previewImage(list.getDirectory() + '/' + selectedObject.name, local);
    }

    private void open() {
      openFile(list.getDirectory() + '/' + selectedObject.name);
    }

    private void transfer() {
      String toBase;
      NXListAdapter dest;
      NXFtpBrowserPanel panel;

      panel = (local) ? remotePanel : localPanel;
      dest = (panel.listing) ? panel.table : panel.getListBoxes(-1);

      if (!local) {
        toBase = dest.getDirectory();
        downloadFromIndex(list.getDirectory(), toBase, list.getSelectedValues(), dest);
      } else {
        toBase = remotePanel.getListBoxes(-1).getDirectory();
        uploadFromIndex(toBase, list.getDirectory(), list.getSelectedValues(), dest);
      }
    }

    private void reload() {
      reloadList(list);
    }

    private void showQueue() {
      if (!queuePanel.isVisible()) {
        queuePanel.setVisible(true);
      }
    }
  }

  private void openFile(String file) {
    try {
      Desktop.getDesktop().open(new File(file));
    } catch (IOException ex) {
    }
  }

  private void deleteFromList(NXListAdapter list, boolean local) {
    Object[] values = list.getSelectedValues();
    if (!local) {
      NXQueueItem i = new NXQueueItem("deletefromindex", "", list.getDirectory(), "", values);
      i.setDisplay(list);
      queue.add(i, false);
    } else {
      for (int x = 0; x < values.length; x++) {
        (new LocalDeleteWorker(list.getDirectory() + '/' + ((NXObjectIndex) values[x]).name, list)).execute();
      }
    }
  }

  private void reloadList(NXListAdapter list) {
    if (list.getLocal()) {
      (new ListingWorker(list.getDirectory(), true, list)).execute();
    } else {
      String dir = list.getDirectory();
      if (dir.equals("")) {
        dir = "/";
      }
      queue.add(new NXQueueItem("list", "", dir, "", list), false);
    }
  }

  private void doFilters() {
    NXFilterDialog dlg = new NXFilterDialog(frame);
    dlg.setFilters(remotePanel.getFilters());
    dlg.setModal(true);
    dlg.setVisible(true);
    NXFilter[] filters = dlg.getFilters();
    remotePanel.setFilters(filters);
    localPanel.setFilters(filters);
  }

  private void previewImage(String path, boolean local) {
    try {
      if (!local) {
        queue.add(new NXQueueItem("preview", "", path, ""), true);
      } else {
        (new PreviewWorker(path, new File(path))).execute();
      }
    } catch (Exception ex) {
      System.out.println("OH SHIT");
    }
  }

  private void downloadFromIndex(String base, String localBase, Object[] index, NXListAdapter list) {
    NXObjectIndex oi;
    String pwf;
    String localFile;
    File f = new File(localBase);
    if (!f.exists()) {
      f.mkdir();
    }
    int type;
    for (int x = 0; x < index.length; x++) {
      oi = (NXObjectIndex) index[x];
      pwf = base + '/' + oi.name;
      localFile = localBase + '/' + oi.name;
      type = getType(base, oi);
      if (type > 0) {
        if (list != null) {
          list.addElement(new NXObjectIndex('d', oi.name));
        }
        NXQueueItem item = new NXQueueItem("index", localFile, pwf, "");
        if (oi.type == 1) { //link
          item.fakePath = oi.realLoc;
        }
        queue.add(item, false);
      } else {
        queue.add(new NXQueueItem("download", localFile, pwf, "", list, oi.size), false);
      }
    }
  }

  private void createDirectoryIf(String base) {
    String indexBase;
    String[] pathElements = NXFormat.getNameFromPath(base);
    if (pathElements[1] == null) {
      return;
    }
    indexBase = base.equals("") ? "/" : pathElements[0];
    NXObjectIndex check = (NXObjectIndex) ftpClient.getObjectIndex().get(indexBase);
    if (check == null || !check.objects.containsKey(pathElements[1])) {
      queue.add(new NXQueueItem("mkdir", "", base, ""), true);
    }
  }

  private void uploadFromIndex(String base, String localBase, Object[] index, Object list) {
    NXObjectIndex oi;
    String pwf;
    String localFile;
    File file;
    String folderFileName;

    char type;
    int inType;
    createDirectoryIf(base);
    for (int x = 0; x < index.length; x++) {
      oi = (NXObjectIndex) index[x];
      pwf = base + '/' + oi.name;
      localFile = localBase + '/' + oi.name;
      inType = getType(base, oi);
      if (inType > 0) {
        File folder = new File(localBase + '/' + oi.name);
        File[] files = folder.listFiles();
        NXObjectIndex[] folderIndex = new NXObjectIndex[files.length];
        for (int y = 0; y < files.length; y++) {
          folderFileName = NXFormat.getNameFromPath(files[y].getPath(), false);
          File folderFile = new File(files[y].getPath());
          type = (folderFile.isDirectory()) ? 'd' : '-';
          folderIndex[y] = new NXObjectIndex(type, folderFileName);
        }
        uploadFromIndex(pwf, localFile, folderIndex, list);
      } else {
        file = new File(localFile);
        queue.add(new NXQueueItem("upload", localFile, pwf, "", remotePanel.getListIfShown(pwf), file.length()), false);
      }
    }
  }

  private void localMoveFromIndex(String base, String destBase, Object[] index) {
    NXObjectIndex oi;
    String strDestFile;
    String strSrcFile;
    File file;

    NXListAdapter srcList = localPanel.getListIfShown(base);
    NXListAdapter destList = localPanel.getListIfShown(destBase);

    for (int x = 0; x < index.length; x++) {
      oi = (NXObjectIndex) index[x];
      strDestFile = destBase + '/' + oi.name;
      strSrcFile = base + '/' + oi.name;
      file = new File(strSrcFile);
      File destFile = new File(strDestFile);
      if (file.renameTo(destFile)) {
        if (destList != null) destList.addElement(oi);
      }
    }

    reloadList(srcList);
    if (destList != null) localPanel.removeList(destList.getIndex() + 1);
  }

  private void remoteMoveFromIndex(String base, String destBase, Object[] index) {
    NXObjectIndex oi;
    String strDestFile;
    String strSrcFile;

    NXListAdapter srcList = remotePanel.getListIfShown(base);
    NXListAdapter destList = remotePanel.getListIfShown(destBase);

    for (int x = 0; x < index.length; x++) {
      oi = (NXObjectIndex) index[x];
      strDestFile = destBase + '/' + oi.name;
      strSrcFile = base + '/' + oi.name;
      File destFile = new File(strDestFile);
      queue.add(new NXQueueItem("rename", strSrcFile, strDestFile, ""), true);
    }

    reloadList(srcList);
    if (destList != null) {
      reloadList(destList);
      remotePanel.removeList(destList.getIndex() + 1);
    } else {
      ftpClient.getObjectIndex().remove(destBase);
    }
  }

  private int getType(String base, NXObjectIndex oi) {
    int type;
    if (oi.type == 1) { //link
      if (oi.realType == -1) { //don't know type yet
        type = (ftpClient.isDirectory(base + "/" + oi.name)) ? 2 : 0;
        oi.setRealType(type);
      } else { //already know type
        type = oi.realType;
      }
    } else {
      type = oi.type;
    }
    return type;
  }

  class DeleteIndexWorker extends SwingWorker {

    private final String folder;
    private final Object[] index;
    private final NXListAdapter display;

    protected DeleteIndexWorker(String folder, Object[] index, NXListAdapter display) {
      this.folder = folder;
      this.index = index;
      this.display = display;
    }

    @Override
    protected Object doInBackground() throws Exception {
      deleteFromIndex(folder, index, true);
      reloadList(display);
      remotePanel.removeList(display.getIndex() + 1);
      return new Object();
    }

    private void deleteFromIndex(String base, Object[] index, boolean start) {
      NXObjectIndex oi;
      String pwf;
      setStatus("Deleting \"" + NXFormat.getNameFromPath(base, false) + "\".", true);
      int type;
      for (int x = 0; x < index.length; x++) {
        oi = (NXObjectIndex) index[x];
        pwf = base + '/' + oi.name;
        type = getType(base, oi);
        if (type > 0) {
          ftpClient.indexDirectory(pwf);
          NXObjectIndex folderIndex = (NXObjectIndex) ftpClient.getObjectIndex().get(pwf);
          deleteFromIndex(pwf, folderIndex.objects.values().toArray(), false);
        } else {
          queue.add(new NXQueueItem("delete", "", pwf, ""), false);
        }
      }

      if (!start) {
        queue.add(new NXQueueItem("command", "Removing directory " + NXFormat.getNameFromPath(base, false), "RMD " + base, ""), false);
      }
    }

    @Override
    public void done() {
      queue.process();
    }
  };

  class IndexWorker extends SwingWorker {

    private final String folder;
    private final String localFolder;
    private final boolean download;
    private int listingSize;

    protected IndexWorker(String localFolder, String folder, boolean download) {
      this.folder = folder;
      this.localFolder = localFolder;
      this.download = download;
      setStatus("Indexing \"" + NXFormat.getNameFromPath(folder, false) + "\".", true);
    }

    @Override
    protected Object doInBackground() throws Exception {
      listingSize = ftpClient.indexDirectory(folder);
      return new Object();
    }

    @Override
    public void done() {
      NXObjectIndex folderIndex = (NXObjectIndex) ftpClient.getObjectIndex().get(folder);
      Object[] arrObjects = folderIndex.objects.values().toArray();
      queue.totalSize += listingSize;
      queue.totalTransferred += listingSize;
      queue.process();
      if (download) {
        downloadFromIndex(folder, localFolder, arrObjects, null);
      }
    }
  };

  public class NXQueue implements ActionListener {

    public ArrayList queue = new ArrayList();
    public ArrayList errorQueue = new ArrayList();
    int done = 0;
    int totalTransferred = 0;
    long totalSize = 0;
    int seconds = 0;
    int currentSeconds = 0;
    String currentString = "";
    private final javax.swing.Timer timer = new javax.swing.Timer(1000, this);
    private int currentTransferred;

    public void add(NXQueueItem q, boolean priority) {
      int size = queue.size();
      int pos = (priority && size != 0) ? 1 : size;
      queue.add(pos, q);
      queuePanel.addItem(q, pos);
      totalSize += q.totalSize;
      if (size + 1 == 1) {
        doItem(queue.get(0));
        update();
        timer.start();
      }
    }

    public void addError(NXQueueItem q) {
      errorQueue.add(q);
    }

    public Object get(int item) {
      return queue.get(item);
    }

    public int getDone() {
      return done;
    }

    public int getLength() {
      return queue.size();
    }

    public void process() {
      currentTransferred = 0;
      currentSeconds = 0;
      if (queue.size() > 0) {
        queuePanel.removeItem((NXQueueItem) queue.get(0));
        queue.remove(0);
      }
      if (queue.size() > 0) {
        doItem(queue.get(0));
        done++;
      } else { //end of queue
        done = 0;
        seconds = 0;
        totalTransferred = 0;
        timer.stop();
        totalSize = 0;

        overallProgressBar.setVisible(false);
        progressBar.setVisible(false);
        if (errorQueue.size() > 0) {
          NXTransferDialog m = new NXTransferDialog(frame, errorQueue);
          m.setVisible(true);
          errorQueue.clear();
        }
      }
    }

    public void updateTransferred(int add) {
      currentTransferred += add;
      totalTransferred += add;
    }

    private void doItem(Object i) {
      NXQueueItem qi = (NXQueueItem) i;
      boolean explicit = qi.activity.contains("-explicit");

      queuePanel.updateActivity(qi);

      if (qi.activity.equals("list")) {
        ListingWorker lw = new ListingWorker(qi.remoteFile, false, qi.list);
        if (qi.fakePath != null) { //used for directory links so that real path is updated
          lw.fake = qi.fakePath;
        }
        lw.execute();
      }
      if (qi.activity.contains("mkdir")) {
        (new CommandWorker("MKD " + qi.remoteFile, "Creating remote directory "
            + NXFormat.getNameFromPath(qi.remoteFile, false) + "...", explicit)).execute();
      }
      if (qi.activity.contains("command")) {
        (new CommandWorker(qi.remoteFile, qi.localFile, explicit)).execute();
      }
      if (qi.activity.equals("upload")) {
        (new UploadWorker(qi.localFile, qi.remoteFile, qi.list)).execute();
      }
      if (qi.activity.equals("download")) {
        (new DownloadWorker(qi.localFile, qi.remoteFile, qi.list)).execute();
      }
      if (qi.activity.equals("preview")) {
        (new DownloadWorker(qi.localFile, qi.remoteFile, true, false)).execute();
      }
      if (qi.activity.equals("open")) {
        (new DownloadWorker(qi.localFile, qi.remoteFile, false, true)).execute();
      }
      if (qi.activity.equals("index")) {
        (new IndexWorker(qi.localFile, qi.remoteFile, true)).execute();
      }
      if (qi.activity.equals("delete")) {
        (new DeleteWorker(qi.remoteFile)).execute();
      }
      if (qi.activity.equals("deletefromindex")) {
        (new DeleteIndexWorker(qi.remoteFile, (Object[]) qi.list, (NXListAdapter) qi.display)).execute();
      }
      if (qi.activity.equals("rename")) {
        (new RenameWorker(qi.localFile, qi.remoteFile)).execute();
      }
    }

    private void update() {
      seconds++;
      currentSeconds++;
      queuePanel.updateProgress(currentTransferred, currentSeconds, totalTransferred, seconds, totalSize);
      updateOverall();
      updateSpeed();
    }

    private void updateSpeed() {
      int bps = 0;
      if (currentSeconds != 0) {
        bps = (int) (currentTransferred / currentSeconds);
        progressBar.setString(currentString + " at " + NXFormat.fileSize(bps, true) + "/s");
      }

      if (seconds != 0) {
        bps = (int) (totalTransferred / seconds);
      } else {
        bps = 0;
      }
      int eta = NXFormat.getEta(totalSize, totalTransferred, bps);
      if (seconds != 0) {
        overallProgressBar.setString("All Actions" + eta(eta));
      }
    }

    private String eta(int eta) {
      String strEta = NXFormat.parseTime(eta);
      if (!strEta.equals("")) {
        strEta = " (" + strEta + " remaining)";
      }
      return strEta;
    }

    public void actionPerformed(ActionEvent e) { //timer to update queue data
      update();
    }
  }

  private class NXDropListener implements DropTargetListener {

    private JToolTip label;
    private NXDragFeedbackLabel glassPane;
    private NXListAdapter source;
    private boolean reject;
    private String initial;
    private String dir;

    public NXDropListener(NXListAdapter source) {
      this.source = source;

      dir = (source.getDirectory().equals("")) ? "/" : NXFormat.getNameFromPath(source.getDirectory(), false);
      label = new JToolTip();
      label.setTipText(initial + dir);
      label.setOpaque(true);
      label.setSize(label.getPreferredSize());
      if (frame != null) {
        glassPane = (NXDragFeedbackLabel) frame.getGlassPane();
      } else {
        glassPane = dragFeedbackLabel;
      }
    }

    public void dragEnter(DropTargetDragEvent dtde) {
      if (source.equals(dragItem)) {
        dtde.rejectDrag();
      }
    }

    public void dragOver(DropTargetDragEvent dtde) {
      if (reject) {
        return;
      }
      Component c = label;
      BufferedImage image = new BufferedImage(c.getWidth(),
          c.getHeight(),
          BufferedImage.TYPE_INT_ARGB);
      Graphics g = image.getGraphics();
      c.paint(g);

      int top = 0;
      int listLeft = 0;
      boolean leftSide = false;
      top = (source.getLocal()) ? splitBrowser.getDividerLocation() : 0;

      NXFtpBrowserPanel panel = (!source.getLocal()) ? remotePanel : localPanel;

      if (source.getType() == false) {
        //list
        NXList l = (NXList) source;
        NXScrollPane sp = (NXScrollPane) l.getParent().getParent();
        listLeft = sp.getX();
        listLeft += splitOverall.getDividerLocation() + splitOverall.getDividerSize();
        top -= ((JViewport) l.getParent()).getViewPosition().y;
        leftSide = dtde.getLocation().x < l.getWidth() / 2;
      }

      NXListAdapter a = (NXListAdapter) source;
      a.setDropLeft(leftSide);
      Object[] obj = a.getSelectedValues();

      if (source.getLocal() != dragItem.getLocal()) {
        initial = source.getLocal() ? "Download" : "Upload";
      } else {
        initial = "Move";
      }
      initial += " to ";

      if (obj.length > 0 && leftSide) {
        NXObjectIndex oi = (NXObjectIndex) obj[0];
        label.setTipText((oi.type == 2 || oi.realType == 2) ? initial + oi.name : initial + dir);
      } else {
        label.setTipText(initial + dir);
      }

      label.setSize(label.getPreferredSize());

      glassPane.setVisible(true);

      Point p = (Point) dtde.getLocation().clone();

      int left = 0;
      JViewport scrollBrowser = (JViewport) panel.browserScroll.getViewport();
      int start = scrollBrowser.getViewPosition().x;
      int end = scrollBrowser.getViewSize().width;
      System.out.println(end);

      int diff = listLeft - start + p.x;

      if (diff + label.getSize().width + 24 > end) {
        left = end - label.getSize().width - 24;
      } else {
        left = diff;
      }

      p.x = left;
      p.y += top;
      glassPane.setPoint(p);
      glassPane.setImage(image);
      glassPane.repaint();
    }

    public void dropActionChanged(DropTargetDragEvent dtde) {
    }

    public void dragExit(DropTargetEvent dte) {
      glassPane.setVisible(false);
    }

    public void drop(DropTargetDropEvent dtde) {
      dtde.getLocation();
      glassPane.setVisible(false);
    }
  }
}

class NXDragFeedbackLabel extends JLabel {

  private AlphaComposite composite;
  private BufferedImage dragged = null;
  private Point location = new Point(0, 0);

  public NXDragFeedbackLabel() {
    super();
    setOpaque(false);
    composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);
  }

  public void setImage(BufferedImage dragged) {
    this.dragged = dragged;
  }

  public void setPoint(Point location) {
    this.location = location;
  }

  public void paintComponent(Graphics g) {
    if (dragged == null) {
      return;
    }

    Graphics2D g2 = (Graphics2D) g;
    g2.setComposite(composite);
    g2.drawImage(dragged,
        (int) (location.getX() + 24),
        (int) (location.getY() + 64),
        null);
  }
}
TOP

Related Classes of nixonftp.NixonFTP$TraverseMenuListener

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.