Package org.gudy.azureus2.ui.swt

Source Code of org.gudy.azureus2.ui.swt.OpenTorrentWindow$Partition

/*
* OpenTorrentWindow.java
*
* Created on February 23, 2004, 4:09 PM
*
* Copyright (C) 2004, 2005, 2006 Aelitis SAS, All rights Reserved
*
* 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.
*
* 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 ( see the LICENSE file ).
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* AELITIS, SAS au capital de 46,603.30 euros,
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/

package org.gudy.azureus2.ui.swt;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.StringIterator;
import org.gudy.azureus2.core3.config.StringList;
import org.gudy.azureus2.core3.disk.DiskManagerFileInfo;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerInitialisationAdapter;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.internat.LocaleTorrentUtil;
import org.gudy.azureus2.core3.internat.LocaleUtilDecoder;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.LogAlert;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.torrentdownloader.TorrentDownloader;
import org.gudy.azureus2.core3.torrentdownloader.TorrentDownloaderCallBackInterface;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.ui.swt.components.shell.ShellFactory;
import org.gudy.azureus2.ui.swt.mainwindow.Colors;
import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener;
import org.gudy.azureus2.ui.swt.shells.MessageBoxShell;
import org.gudy.azureus2.ui.swt.shells.MessageSlideShell;

import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.vuzefile.VuzeFile;
import com.aelitis.azureus.core.vuzefile.VuzeFileComponent;
import com.aelitis.azureus.core.vuzefile.VuzeFileHandler;
import com.aelitis.azureus.ui.common.updater.UIUpdatable;
import com.aelitis.azureus.ui.swt.UIFunctionsManagerSWT;
import com.aelitis.azureus.ui.swt.imageloader.ImageLoader;
import com.aelitis.azureus.ui.swt.uiupdater.UIUpdaterSWT;

/**
* Torrent Opener Window.
*
* @author TuxPaper
*
* TODO Category Option
*/
public class OpenTorrentWindow
  implements TorrentDownloaderCallBackInterface, UIUpdatable
{

  /**
   * We prevent users from unselecting small files to prevent them missing
   * out "signature" files from trackers (.nfo file, readme file etc)
   *
   * We define two constants to control this - one defines what a small file
   * is, and the other defines whether we believe a torrent has signature
   * files or not - we do this by seeing how many small files the torrent has.
   *
   * If it has several small files, then it would be silly for us to assume
   * that the torrent consists of multiple signature files.
   *
   * Note: I (amc1) have disabled this now, because it can force users who may want
   * to only download one file to download those small files, which may not be in
   * an overlapping piece. Since I've now seen comments from people who've complained
   * about this, I'm disabling it.
   */
  //private final static int MIN_NODOWNLOAD_SIZE = 64 * 1024;
  //private final static int MAX_NODOWNLOAD_COUNT = 3;
  private final static int MIN_BUTTON_HEIGHT = -1;

  private final static String PARAM_DEFSAVEPATH = "Default save path";

  private final static String PARAM_MOVEWHENDONE = "Move Completed When Done";

  private static final String PARAM_VIEWMODE = "OpenTorrentWindow.viewMode";

  private final static String MSG_ALREADY_EXISTS = "OpenTorrentWindow.mb.alreadyExists";

  private final static String MSG_ALREADY_EXISTS_NAME = MSG_ALREADY_EXISTS
      + ".default.name";

  private final static int STARTMODE_QUEUED = 0;

  private final static int STARTMODE_STOPPED = 1;

  private final static int STARTMODE_FORCESTARTED = 2;

  private final static int STARTMODE_SEEDING = 3;

  private final static int QUEUELOCATION_TOP = 0;

  private final static int QUEUELOCATION_BOTTOM = 1;

  private final static String[] startModes = {
    "queued",
    "stopped",
    "forceStarted",
    "seeding"
  };

  private final static String[] queueLocations = {
    "first",
    "last"
  };

  /** Only one window, since it can handle multiple torrents */
  private static OpenTorrentWindow stOpenTorrentWindow = null;

  // SWT Stuff
  private Shell shell;

  private Table dataFileTable;
  private TableEditor dataFileTableEditor;

  private Table torrentTable;

  private Button ok;

  private Combo cmbDataDir;

  private Composite cSaveTo;

  private Combo cmbStartMode = null;

  private Combo cmbQueueLocation = null;

  // Link to the outside
  private GlobalManager gm;

  // Internal Stuff

  /** TorrentFileInfo list.  All dataFiles currently in table, same order */
  private ArrayList dataFiles = new ArrayList();

  /** TorrentInfo list.  All torrents to open, same order as table */
  private ArrayList torrentList = new ArrayList();

  /** List of torrents being downloaded.  Stored so we don't close window
   * until they are done/aborted.
   */
  private ArrayList<TorrentDownloader> downloaders = new ArrayList<TorrentDownloader>();

  private boolean bOverrideStartModeToStopped = false;

  private boolean bDefaultForSeeding;

  /** Things to be disposed of when window closes */
  private ArrayList disposeList = new ArrayList();

  private boolean bClosed = false;

  /** Shell to use to open children (FileDialog, etc) */
  private Shell shellForChildren;

  private String sDestDir;

  protected boolean bSkipDataDirModify = false;

  private StringList dirList;

  private Label dataFileTableLabel;

  private Composite diskspaceComp;

  /**
   * A counter to track torrent file downloads that are still active;
   * this is purely used to enable/disable the OK button
   */
  private int activeTorrentCount = 0;

  /**
   *
   * @param parent
   * @param gm
   * @param sPathOfFilesToOpen
   * @param sFilesToOpen
   * @param bDefaultStopped
   * @param bForSeeding
   * @param bPopupOpenURL
   */
  public synchronized static final void invoke(Shell parent, GlobalManager gm,
      String sPathOfFilesToOpen, String[] sFilesToOpen,
      boolean bDefaultStopped, boolean bForSeeding, boolean bPopupOpenURL) {

    String saveSilentlyDir = null;

    if (stOpenTorrentWindow == null) {
      boolean bMustOpen = (sPathOfFilesToOpen == null && sFilesToOpen == null)
          || bForSeeding;
      if (!bMustOpen) {
        saveSilentlyDir = getSaveSilentlyDir();
        bMustOpen = saveSilentlyDir == null;
      }

      stOpenTorrentWindow = new OpenTorrentWindow(parent, gm, bMustOpen);
    } else {
      if (stOpenTorrentWindow.shell != null)
        stOpenTorrentWindow.shell.forceActive();
    }

    if (stOpenTorrentWindow != null) {
      // local var because static may get set o null
      OpenTorrentWindow openTorrentWindow = stOpenTorrentWindow;
      openTorrentWindow.bOverrideStartModeToStopped = bDefaultStopped;
      openTorrentWindow.bDefaultForSeeding = bForSeeding;
      if (sFilesToOpen != null || sPathOfFilesToOpen != null) {
        // If none of the files sent to us were valid files, don't open the
        // window
        if (!bPopupOpenURL
            && openTorrentWindow.addTorrents(sPathOfFilesToOpen, sFilesToOpen) == 0
            && openTorrentWindow.torrentList.size() == 0
            && openTorrentWindow.downloaders.size() == 0) {
          openTorrentWindow.close(true, true);
          return;
        }
      }

      if (bPopupOpenURL)
        openTorrentWindow.browseURL();

      if (saveSilentlyDir != null) {
        openTorrentWindow.sDestDir = saveSilentlyDir;
        for (int i = 0; i < openTorrentWindow.torrentList.size(); i++) {
          final TorrentInfo info = (TorrentInfo) openTorrentWindow.torrentList.get(i);
          info.renameDuplicates();
        }

        openTorrentWindow.openTorrents();
        openTorrentWindow.close(true, false);
      }
    }
  }

  /**
   *
   * @param parent
   * @param gm
   */
  public synchronized static final void invoke(final Shell parent,
      GlobalManager gm) {
    invoke(parent, gm, null, null, false, false, false);
  }

  public synchronized static final void invokeURLPopup(final Shell parent,
      GlobalManager gm) {
    invoke(parent, gm, null, null, false, false, true);
  }

  /**
   *
   * @param parent
   * @param gm
   * @param bOpenWindow
   */
  private OpenTorrentWindow(final Shell parent, GlobalManager gm,
      boolean bOpenWindow) {
    this.gm = gm;

    sDestDir = COConfigurationManager.getStringParameter(PARAM_DEFSAVEPATH);

    if (bOpenWindow)
      openWindow(parent);
    else
      shellForChildren = parent;
  }

  private void openWindow(Shell parent) {
    boolean bTorrentInClipboard = false;
    GridData gridData;
    Label label;
    Composite cArea;

    shell = ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);

    shellForChildren = shell;

    shell.setText(MessageText.getString("OpenTorrentWindow.title"));
    Utils.setShellIcon(shell);

    GridLayout layout = FixupLayout(new GridLayout(), false);
    shell.setLayout(layout);
    shell.addListener(SWT.Resize, new Listener() {
      public void handleEvent(Event e) {
        resizeTables(3);
      }
    });

    Clipboard clipboard = new Clipboard(shell.getDisplay());

    String sClipText = (String) clipboard.getContents(TextTransfer.getInstance());
    if (sClipText != null)
      bTorrentInClipboard = addTorrentsFromTextList(sClipText, true) > 0;

    //    label = new Label(shell, SWT.BORDER | SWT.WRAP);
    //    Messages.setLanguageText(label, "OpenTorrentWindow.message");
    //    gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    //    label.setLayoutData(gridData);

    // Torrents
    // ========

    Composite cButtons = new Composite(shell, SWT.NONE);
    RowLayout rLayout = new RowLayout(SWT.HORIZONTAL);
    rLayout.marginBottom = 0;
    rLayout.marginLeft = 0;
    rLayout.marginRight = 0;
    rLayout.marginTop = 0;
    cButtons.setLayout(rLayout);

    // Buttons for tableTorrents

    Button browseTorrent = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(browseTorrent, "OpenTorrentWindow.addFiles");
    browseTorrent.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        FileDialog fDialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);
        fDialog.setFilterExtensions(new String[] {
          "*.torrent",
          "*.tor",
          Constants.FILE_WILDCARD
        });
        fDialog.setFilterNames(new String[] {
          "*.torrent",
          "*.tor",
          Constants.FILE_WILDCARD
        });
        fDialog.setFilterPath(TorrentOpener.getFilterPathTorrent());
        fDialog.setText(MessageText.getString("MainWindow.dialog.choose.file"));
        String fileName = TorrentOpener.setFilterPathTorrent(fDialog.open());
        if (fileName != null) {
          addTorrents(fDialog.getFilterPath(), fDialog.getFileNames());
        }
      }
    });

    Utils.setGridData(cButtons, GridData.FILL_HORIZONTAL, browseTorrent,
        MIN_BUTTON_HEIGHT);

    Button browseURL = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(browseURL, "OpenTorrentWindow.addFiles.URL");
    browseURL.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        browseURL();
      }
    });

    Button browseFolder = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(browseFolder, "OpenTorrentWindow.addFiles.Folder");
    browseFolder.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        DirectoryDialog fDialog = new DirectoryDialog(shell, SWT.NULL);
        fDialog.setFilterPath(TorrentOpener.getFilterPathTorrent());
        fDialog.setMessage(MessageText.getString("MainWindow.dialog.choose.folder"));
        String path = TorrentOpener.setFilterPathTorrent(fDialog.open());
        if (path != null) {
          addTorrents(path, null);
        }
      }
    });

    if (bTorrentInClipboard) {
      Button pasteOpen = new Button(cButtons, SWT.PUSH);
      Messages.setLanguageText(pasteOpen,
          "OpenTorrentWindow.addFiles.Clipboard");
      pasteOpen.setToolTipText(sClipText);
      pasteOpen.addListener(SWT.Selection, new Listener() {
        public void handleEvent(Event event) {
          Clipboard clipboard = new Clipboard(shell.getDisplay());

          String sClipText = (String) clipboard.getContents(TextTransfer.getInstance());
          if (sClipText != null) {
            addTorrentsFromTextList(sClipText.trim(), false);
          }
        }
      });
    }

    Group gTorrentsArea = new Group(shell, SWT.NONE);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    gTorrentsArea.setLayoutData(gridData);
    layout = FixupLayout(new GridLayout(), true);
    gTorrentsArea.setLayout(layout);
    Messages.setLanguageText(gTorrentsArea, "OpenTorrentWindow.torrentLocation");

    Composite cTorrentList = new Composite(gTorrentsArea, SWT.NONE);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    cTorrentList.setLayoutData(gridData);

    createTorrentListArea(cTorrentList);

    Composite cTorrentOptions = new Composite(gTorrentsArea, SWT.NONE);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    cTorrentOptions.setLayoutData(gridData);
    layout = FixupLayout(new GridLayout(), true);
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    cTorrentOptions.setLayout(layout);

    label = new Label(cTorrentOptions, SWT.NONE);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    label.setLayoutData(gridData);
    Messages.setLanguageText(label, "OpenTorrentWindow.torrent.options");

    int userMode = COConfigurationManager.getIntParameter("User Mode");
    if (userMode > 0) {
      Composite cTorrentModes = new Composite(cTorrentOptions, SWT.NONE);
      gridData = new GridData(GridData.FILL_HORIZONTAL);
      cTorrentModes.setLayoutData(gridData);
      layout = new GridLayout();
      layout.numColumns = 4;
      layout.marginWidth = 0;
      layout.marginHeight = 0;
      cTorrentModes.setLayout(layout);

      label = new Label(cTorrentModes, SWT.NONE);
      gridData = new GridData(GridData.VERTICAL_ALIGN_CENTER);
      label.setLayoutData(gridData);
      Messages.setLanguageText(label, "OpenTorrentWindow.startMode");

      cmbStartMode = new Combo(cTorrentModes, SWT.BORDER | SWT.READ_ONLY);
      gridData = new GridData(GridData.FILL_HORIZONTAL);
      cmbStartMode.setLayoutData(gridData);
      updateStartModeCombo();
      cmbStartMode.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          setSelectedStartMode(cmbStartMode.getSelectionIndex());
        }
      });

      label = new Label(cTorrentModes, SWT.NONE);
      gridData = new GridData(GridData.VERTICAL_ALIGN_CENTER);
      label.setLayoutData(gridData);
      Messages.setLanguageText(label, "OpenTorrentWindow.addPosition");

      cmbQueueLocation = new Combo(cTorrentModes, SWT.BORDER | SWT.READ_ONLY);
      gridData = new GridData(GridData.FILL_HORIZONTAL);
      cmbQueueLocation.setLayoutData(gridData);
      updateQueueLocationCombo();
      cmbQueueLocation.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          setSelectedQueueLocation(cmbQueueLocation.getSelectionIndex());
        }
      });
    }

    // Save To..
    // =========

    cSaveTo = new Composite(cTorrentOptions, SWT.NONE);
    layout = FixupLayout(new GridLayout(), false);
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    layout.verticalSpacing = 0;
    layout.numColumns = 2;
    cSaveTo.setLayout(layout);

    Label lblDataDir = new Label(cSaveTo, SWT.NONE);
    gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    gridData.horizontalSpan = 2;
    lblDataDir.setLayoutData(gridData);
    Messages.setLanguageText(lblDataDir, "OpenTorrentWindow.dataLocation");

    cmbDataDir = new Combo(cSaveTo, SWT.BORDER);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    cmbDataDir.setLayoutData(gridData);

    cmbDataDir.addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent e) {
        cmbDataDirChanged();
      }
    });
    cmbDataDir.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        cmbDataDirChanged();
      }
    });

    updateDataDirCombo();
    dirList = COConfigurationManager.getStringListParameter("saveTo_list");
    StringIterator iter = dirList.iterator();
    while (iter.hasNext()) {
      String s = iter.next();
      if (!s.equals(sDestDir)) {
        cmbDataDir.add(s);
      }
    }

    Button browseData = new Button(cSaveTo, SWT.PUSH);
    Messages.setLanguageText(browseData, "ConfigView.button.browse");

    browseData.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        String sSavePath;
        String sDefPath = cmbDataDir.getText();

        File f = new File(sDefPath);
        if (sDefPath.length() > 0) {
          while (!f.exists()) {
            f = f.getParentFile();
            if (f == null) {
              f = new File(sDefPath);
              break;
            }
          }
        }

        DirectoryDialog dDialog = new DirectoryDialog(shell, SWT.SYSTEM_MODAL);
        dDialog.setFilterPath(f.getAbsolutePath());
        dDialog.setMessage(MessageText.getString("MainWindow.dialog.choose.savepath_forallfiles"));
        sSavePath = dDialog.open();

        if (sSavePath != null) {
          cmbDataDir.setText(sSavePath);
        }
      }
    });

    gridData = new GridData(GridData.FILL_HORIZONTAL);
    cSaveTo.setLayoutData(gridData);

    // File List
    // =========

    Group gFilesArea = new Group(shell, SWT.NONE);
    gridData = new GridData(GridData.FILL_BOTH);
    gFilesArea.setLayoutData(gridData);
    layout = FixupLayout(new GridLayout(), true);
    gFilesArea.setLayout(layout);
    Messages.setLanguageText(gFilesArea, "OpenTorrentWindow.fileList");

    createTableDataFiles(gFilesArea);

    // Ok, cancel

    cArea = new Composite(shell, SWT.NULL);
    layout = new GridLayout();
    layout.marginHeight = 0;
    layout.numColumns = 2;
    cArea.setLayout(layout);

    ok = new Button(cArea, SWT.PUSH);
    Messages.setLanguageText(ok, "Button.ok");
    gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
    gridData.widthHint = 70;
    ok.setLayoutData(gridData);
    shell.setDefaultButton(ok);
    ok.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        okPressed();
      }
    });

    checkSeedingMode();

    Button cancel = new Button(cArea, SWT.PUSH);
    Messages.setLanguageText(cancel, "Button.cancel");
    gridData = new GridData();
    gridData.widthHint = 70;
    cancel.setLayoutData(gridData);
    cancel.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        close(true, true);
      }
    });

    Utils.setGridData(cArea, GridData.HORIZONTAL_ALIGN_END, ok,
        MIN_BUTTON_HEIGHT);

    shell.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        if (!bClosed)
          close(false, true);
      }
    });

    shell.addListener(SWT.Traverse, new Listener() {
      public void handleEvent(Event e) {
        if (e.detail == SWT.TRAVERSE_ESCAPE) {
          close(true, true);
        }
      }
    });

    KeyListener pasteKeyListener = new org.eclipse.swt.events.KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        int key = e.character;
        if ((e.stateMask & SWT.MOD1) != 0 && e.character <= 26
            && e.character > 0)
          key += 'a' - 1;

        if ((key == 'v' && (e.stateMask & SWT.MOD1) > 0)
            || (e.keyCode == SWT.INSERT && (e.stateMask & SWT.SHIFT) > 0)) {
          e.doit = false;

          // Paste
          Clipboard clipboard = new Clipboard(shell.getDisplay());

          String sClipText = (String) clipboard.getContents(TextTransfer.getInstance());
          if (sClipText != null) {
            addTorrentsFromTextList(sClipText, false);
          }
        }
      }
    };

    setPasteKeyListener(shell, pasteKeyListener);

    Utils.createTorrentDropTarget(shell, false);
    shell.pack();

    if (!Utils.linkShellMetricsToConfig(shell, "OpenTorrentWindow")) {
      Utils.centreWindow(shell);
    }
    resizeTables(3);
    shell.open();

    if (cSaveTo != null && !cSaveTo.isDisposed()) {
      cSaveTo.setFocus();
    }

    try {
      UIUpdaterSWT.getInstance().addUpdater(this);
    } catch (Exception e) {
      Debug.out(e);
    }
  }

  protected void cmbDataDirChanged() {
    if (bSkipDataDirModify) {
      return;
    }
    sDestDir = cmbDataDir.getText();

    int[] indexes = torrentTable.getSelectionIndices();
    for (int i = 0; i < indexes.length; i++) {
      TorrentInfo info = (TorrentInfo) torrentList.get(indexes[i]);
      //if (!info.allFilesMoving())
      info.sDestDir = sDestDir;
    }

    torrentTable.clearAll();

    checkSeedingMode();

    if (!Utils.isCocoa || SWT.getVersion() > 3600) { // See Eclipse Bug 292449
      File file = new File(sDestDir);
      if (!file.isDirectory()) {
        cmbDataDir.setBackground(Colors.colorErrorBG);
      } else {
        cmbDataDir.setBackground(null);
      }
      cmbDataDir.redraw();
      cmbDataDir.update();
    }
    diskFreeInfoRefreshPending = true;
  }

  protected void okPressed() {
    if (bClosed) {
      return;
    }

    if ((torrentList.size() == 0 && downloaders.size() == 0)) {
      close(true, false);
      return;
    }

    File file = new File(cmbDataDir.getText());

    File fileDefSavePath = new File(
        COConfigurationManager.getStringParameter(PARAM_DEFSAVEPATH));

    if (file.equals(fileDefSavePath) && !fileDefSavePath.isDirectory()) {
      FileUtil.mkdirs(fileDefSavePath);
    }

    boolean isPathInvalid = cmbDataDir.getText().length() == 0 || file.isFile();
    if (!isPathInvalid && !file.isDirectory()) {
      MessageBoxShell mb = new MessageBoxShell(SWT.YES | SWT.NO
          | SWT.ICON_QUESTION, "OpenTorrentWindow.mb.askCreateDir",
          new String[] {
            file.toString()
          });
      mb.open(null);
      int doCreate = mb.waitUntilClosed();

      if (doCreate == SWT.YES)
        isPathInvalid = !FileUtil.mkdirs(file);
      else {
        cmbDataDir.setFocus();
        return;
      }
    }

    if (isPathInvalid) {
      MessageBoxShell mb = new MessageBoxShell(SWT.OK | SWT.ICON_ERROR,
          "OpenTorrentWindow.mb.noGlobalDestDir", new String[] {
            file.toString()
          });
      mb.open(null);
      cmbDataDir.setFocus();
      return;
    }

    String sExistingFiles = "";
    int iNumExistingFiles = 0;
    for (int i = 0; i < torrentList.size(); i++) {
      TorrentInfo info = (TorrentInfo) torrentList.get(i);

      file = new File(info.getDataDir());
     
      // Need to make directory now, or single file torrent will take the
      // "dest dir" as their filename.  ie:
      // 1) Add single file torrent with named "hi.exe"
      // 2) type a non-existant directory c:\test\moo
      // 3) unselect the torrent
      // 4) change the global def directory to a real one
      // 5) click ok.  "hi.exe" will be written as moo in c:\test     
      if (!file.isDirectory() && !FileUtil.mkdirs(file)) {
        MessageBoxShell mb = new MessageBoxShell(SWT.OK | SWT.ICON_ERROR,
            "OpenTorrentWindow.mb.noDestDir", new String[] {
              file.toString(),
              info.getTorrentName()
            });
        mb.open(null);
        return;
      }

      if (!info.isValid) {
        MessageBoxShell mb = new MessageBoxShell(SWT.OK | SWT.ICON_ERROR,
            "OpenTorrentWindow.mb.notValid", new String[] {
              info.getTorrentName()
            });
        mb.open(null);
        return;
      }

      TorrentFileInfo[] files = info.getFiles();
      for (int j = 0; j < files.length; j++) {
        TorrentFileInfo fileInfo = files[j];
        if (fileInfo.getDestFileFullName().exists()) {
          sExistingFiles += fileInfo.orgFullName + " - " + info.getTorrentName()
              + "\n";
          iNumExistingFiles++;
          if (iNumExistingFiles > 5) {
            // this has the potential effect of adding 5 files from the first
            // torrent and then 1 file from each of the remaining torrents
            break;
          }
        }
      }
    }

    if (sExistingFiles.length() > 0) {
      if (iNumExistingFiles > 5) {
        sExistingFiles += MessageText.getString(
            "OpenTorrentWindow.mb.existingFiles.partialList", new String[] {
              "" + iNumExistingFiles
            })
            + "\n";
      }

      MessageBoxShell mb = new MessageBoxShell(SWT.OK | SWT.CANCEL
          | SWT.ICON_WARNING, "OpenTorrentWindow.mb.existingFiles",
          new String[] {
            sExistingFiles
          });
      mb.open(null);
      if (mb.waitUntilClosed() != SWT.OK) {
        return;
      }
    }

    String sDefaultPath = COConfigurationManager.getStringParameter(PARAM_DEFSAVEPATH);
    if (!sDestDir.equals(sDefaultPath)) {
      // Move sDestDir to top of list

      // First, check to see if sDestDir is already in the list
      File fDestDir = new File(sDestDir);
      int iDirPos = -1;
      for (int i = 0; i < dirList.size(); i++) {
        String sDirName = dirList.get(i);
        File dir = new File(sDirName);
        if (dir.equals(fDestDir)) {
          iDirPos = i;
          break;
        }
      }

      // If already in list, remove it
      if (iDirPos > 0 && iDirPos < dirList.size())
        dirList.remove(iDirPos);

      // and add it to the top
      dirList.add(0, sDestDir);

      // Limit
      if (dirList.size() > 15)
        dirList.remove(dirList.size() - 1);

      // Temporary list cleanup
      try {
        for (int j = 0; j < dirList.size(); j++) {
          File dirJ = new File(dirList.get(j));
          for (int i = 0; i < dirList.size(); i++) {
            try {
              if (i == j)
                continue;

              File dirI = new File(dirList.get(i));

              if (dirI.equals(dirJ)) {
                dirList.remove(i);
                // dirList shifted up, fix indexes
                if (j > i)
                  j--;
                i--;
              }
            } catch (Exception e) {
              // Ignore
            }
          }
        }
      } catch (Exception e) {
        // Ignore
      }

      COConfigurationManager.setParameter("saveTo_list", dirList);
      COConfigurationManager.save();
    }

    if (COConfigurationManager.getBooleanParameter("DefaultDir.AutoUpdate")
        && !COConfigurationManager.getBooleanParameter("Use default data dir"))
      COConfigurationManager.setParameter(PARAM_DEFSAVEPATH, sDestDir);

    openTorrents();
    close(true, false);
  }

  /**
   * @param layout
   * @return
   */
  private GridLayout FixupLayout(GridLayout layout, boolean bFixMargin) {
    if (Constants.isOSX) {
      layout.horizontalSpacing = 0;
      layout.verticalSpacing = 0;

      if (bFixMargin) {
        layout.marginHeight = 0;
        layout.marginWidth = 0;
      }
    }

    return layout;
  }

  private void updateDataDirCombo() {
    if (cmbDataDir == null) {
      return;
    }

    try {
      bSkipDataDirModify = true;

      int[] indexes = torrentTable.getSelectionIndices();

      if (indexes.length == 0) {
        if (cmbDataDir.getItemCount() == 0) {
          cmbDataDir.add(sDestDir);
        }
        cmbDataDir.setText(sDestDir);
        return;
      }

      boolean allSame = true;
      String lastDir = null;
      for (int i = 0; i < indexes.length; i++) {
        TorrentInfo info = (TorrentInfo) torrentList.get(indexes[i]);
        if (lastDir != null && !info.sDestDir.equals(lastDir)) {
          allSame = false;
          break;
        }
        lastDir = info.sDestDir;
      }

      if (allSame && lastDir != null) {
        cmbDataDir.setText(lastDir);
        sDestDir = lastDir;
      } else {
        cmbDataDir.setText("");
      }
    } finally {
      bSkipDataDirModify = false;
    }
  }

  private void updateStartModeCombo() {
    if (cmbStartMode == null)
      return;

    int[] indexes = torrentTable.getSelectionIndices();
    String[] sItemsText = new String[startModes.length];
    int iMaxMatches = 0;
    int iIndexToSelect = getDefaultStartMode();
    for (int i = 0; i < startModes.length; i++) {
      int iMatches = 0;
      for (int j = 0; j < indexes.length; j++) {
        TorrentInfo info = (TorrentInfo) torrentList.get(indexes[j]);
        if (info.iStartID == i)
          iMatches++;
      }

      if (iMatches > iMaxMatches) {
        iMaxMatches = iMatches;
        iIndexToSelect = i;
      }

      String sText = MessageText.getString("OpenTorrentWindow.startMode."
          + startModes[i]);
      if (iMatches > 0)
        sText += " "
            + MessageText.getString("OpenTorrentWindow.xOfTotal", new String[] {
              Integer.toString(iMatches),
              Integer.toString(indexes.length)
            });
      sItemsText[i] = sText;
    }
    cmbStartMode.setItems(sItemsText);
    cmbStartMode.select(iIndexToSelect);
    cmbStartMode.layout(true);
  }

  private void updateQueueLocationCombo() {
    if (cmbQueueLocation == null)
      return;

    int[] indexes = torrentTable.getSelectionIndices();
    String[] sItemsText = new String[queueLocations.length];
    int iMaxMatches = 0;
    int iIndexToSelect = QUEUELOCATION_BOTTOM;
    for (int i = 0; i < queueLocations.length; i++) {
      int iMatches = 0;
      for (int j = 0; j < indexes.length; j++) {
        TorrentInfo info = (TorrentInfo) torrentList.get(indexes[j]);
        if (info.iQueueLocation == i)
          iMatches++;
      }

      if (iMatches > iMaxMatches) {
        iMaxMatches = iMatches;
        iIndexToSelect = i;
      }

      String sText = MessageText.getString("OpenTorrentWindow.addPosition."
          + queueLocations[i]);
      if (iMatches > 0)
        sText += " "
            + MessageText.getString("OpenTorrentWindow.xOfTotal", new String[] {
              Integer.toString(iMatches),
              Integer.toString(indexes.length)
            });
      sItemsText[i] = sText;
    }
    cmbQueueLocation.setItems(sItemsText);
    cmbQueueLocation.select(iIndexToSelect);
  }

  /**
   * @param c
   * @param keyListener
   */
  private void setPasteKeyListener(Control c, KeyListener keyListener) {
    if (!(c instanceof Text) && !(c instanceof Combo)
        && !(c instanceof Composite) || (c instanceof Table)) {
      c.addKeyListener(keyListener);
    }
    if (c instanceof Composite) {
      Control[] controls = ((Composite) c).getChildren();
      for (int i = 0; i < controls.length; i++) {
        setPasteKeyListener(controls[i], keyListener);
      }
    }
  }

  private void browseURL() {
    new OpenUrlWindow(shellForChildren, null, null,
        OpenTorrentWindow.this);
  }

  private void close(boolean dispose, boolean bCancel) {
    stOpenTorrentWindow = null;
    // Can't rely on (stOpenTorrentWindow == null) to check if we are closed
    // since another thread may create another OpenTorrentWindow while
    // we are closing this one.
    bClosed = true;

    try {
      UIUpdaterSWT.getInstance().removeUpdater(this);
    } catch (Exception e) {
      Debug.out(e);
    }
   
    if (dispose && shell != null && !shell.isDisposed()) {
      // We won't be recalled by disposal hook because we set bClosed
      shell.dispose();
    }

    Utils.disposeSWTObjects(disposeList);

    if (bCancel) {
     
      List<TorrentDownloader> to_cancel;
     
      synchronized( downloaders ){
       
        to_cancel = new ArrayList<TorrentDownloader>( downloaders );
       
        downloaders.clear();
      }
     
      if (to_cancel.size() > 0){
        for (Iterator iter = to_cancel.iterator(); iter.hasNext();) {
          TorrentDownloader element = (TorrentDownloader) iter.next();
          element.cancel();
        }
      }

      for (Iterator iter = torrentList.iterator(); iter.hasNext();) {
        TorrentInfo info = (TorrentInfo) iter.next();
        if (info.bDeleteFileOnCancel) {
          File file = new File(info.sFileName);
          if (file.exists())
            file.delete();
        }
      }
      torrentList.clear();
    }
  }

  private void createTorrentListArea(Composite cArea) {
    GridData gridData;
    TableColumn tc;

    GridLayout layout = new GridLayout();
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    layout.numColumns = 2;
    cArea.setLayout(layout);

    torrentTable = new Table(cArea, SWT.MULTI | SWT.BORDER
        | SWT.FULL_SELECTION | SWT.VIRTUAL);
    gridData = new GridData(GridData.FILL_HORIZONTAL
        | GridData.VERTICAL_ALIGN_FILL);
    gridData.heightHint = 50;
    gridData.widthHint = 450;
    torrentTable.setLayoutData(gridData);

    tc = new TableColumn(torrentTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.torrentTable.name");
    tc.setWidth(150);
    tc = new TableColumn(torrentTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.torrentTable.saveLocation");
    tc.setWidth(150);
    tc = new TableColumn(torrentTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.startMode");
    tc.setWidth(70);
    tc = new TableColumn(torrentTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.addPosition");
    tc.setWidth(80);

    if (Utils.LAST_TABLECOLUMN_EXPANDS)
      tc.setData("Width", new Long(80));

    torrentTable.addListener(SWT.SetData, new Listener() {
      public void handleEvent(Event event) {
        if (bClosed)
          return;

        TableItem item = (TableItem) event.item;
        int index = torrentTable.indexOf(item);
        if (index < 0)
          return;

        TorrentInfo info = (TorrentInfo) torrentList.get(index);

        item.setText(new String[] {
          info.getTorrentName(),
          info.getDataDir(),
          MessageText.getString("OpenTorrentWindow.startMode."
              + startModes[info.iStartID]),
          MessageText.getString("OpenTorrentWindow.addPosition."
              + queueLocations[info.iQueueLocation])
        });
        if (!info.isValid) {
          item.setForeground(Colors.red);
          Font font = item.getFont();
          FontData[] fd = font.getFontData();
          for (int i = 0; i < fd.length; i++) {
            fd[i].setStyle(SWT.ITALIC);
          }
          font = new Font(item.getDisplay(), fd);
          disposeList.add(font);
          item.setFont(font);
        }
        Utils.alternateRowBackground(item);
      }
    });

    torrentTable.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        dataFiles.clear();
        int[] indexes = torrentTable.getSelectionIndices();
        for (int i = 0; i < indexes.length; i++) {
          TorrentInfo info = (TorrentInfo) torrentList.get(indexes[i]);
          TorrentFileInfo[] files = info.getFiles();
          dataFiles.addAll(Arrays.asList(files));
        }

        updateDataDirCombo();
        updateStartModeCombo();
        updateQueueLocationCombo();

        dataFileTable.setItemCount(dataFiles.size());
        dataFileTable.clearAll();
        editCell(-1);
        updateSize();
        resizeTables(2);
      }
    });

    torrentTable.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        if (e.character == SWT.DEL) {
          deleteSelected(torrentTable, torrentList);
          e.doit = false;
        }
      }
    });

    torrentTable.setHeaderVisible(true);

    // Menu for tableTorrents

    String sTitle;
    Menu menu = new Menu(torrentTable.getShell());
    MenuItem item;
    sTitle = MessageText.getString("OpenTorrentWindow.startMode");

    int userMode = COConfigurationManager.getIntParameter("User Mode");
    for (int i = 0; i < startModes.length; i++) {
      if (i == STARTMODE_FORCESTARTED && userMode == 0)
        continue;

      item = new MenuItem(menu, SWT.PUSH);
      item.setData("Value", new Long(i));
      item.setText(sTitle
          + ": "
          + MessageText.getString("OpenTorrentWindow.startMode."
              + startModes[i]));

      item.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          Long l = (Long) e.widget.getData("Value");
          if (l != null) {
            setSelectedStartMode(l.intValue());
            checkSeedingMode();
          }
        }
      });
    }

    item = new MenuItem(menu, SWT.SEPARATOR);
    sTitle = MessageText.getString("OpenTorrentWindow.addPosition");

    for (int i = 0; i < queueLocations.length; i++) {
      item = new MenuItem(menu, SWT.PUSH);
      item.setData("Value", new Long(i));
      item.setText(sTitle
          + ": "
          + MessageText.getString("OpenTorrentWindow.addPosition."
              + queueLocations[i]));

      item.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          Long l = (Long) e.widget.getData("Value");
          if (l != null) {
            setSelectedQueueLocation(l.intValue());
          }
        }
      });
    }

    item = new MenuItem(menu, SWT.SEPARATOR);

    item = new MenuItem(menu, SWT.PUSH);
    // steal text
    Messages.setLanguageText(item, "MyTorrentsView.menu.remove");
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        deleteSelected(torrentTable, torrentList);
      }
    });

    item = new MenuItem(menu, SWT.PUSH);
    Messages.setLanguageText(item,
        "OpenTorrentWindow.fileList.changeDestination");
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        int[] indexes = torrentTable.getSelectionIndices();
        String sDefPath = sDestDir;

        for (int i = 0; i < indexes.length; i++) {
          TorrentInfo info = (TorrentInfo) torrentList.get(indexes[i]);

          TorrentFileInfo[] files = info.getFiles();
          if (files.length == 1 && info.torrent.isSimpleTorrent()) {
            changeFileDestination(new int[] {
              0
            });
          } else {
            DirectoryDialog dDialog = new DirectoryDialog(shellForChildren,
                SWT.SYSTEM_MODAL);

            dDialog.setFilterPath(sDefPath);
            dDialog.setMessage(MessageText.getString("MainWindow.dialog.choose.savepath")
                + " (" + info.getTorrentName() + ")");
            String sNewDir = dDialog.open();

            if (sNewDir == null)
              return;

            File newDir = new File(sNewDir).getAbsoluteFile();
           
            if(newDir.isDirectory())
              sDefPath = sNewDir;

            info.sDestDir = newDir.getParent();
            if (info.sDestDir == null)
              info.sDestDir = newDir.getPath();
            info.sDestSubDir = newDir.getName();

            for (int j = 0; j < files.length; j++) {
              TorrentFileInfo fileInfo = files[j];
              fileInfo.setDestFileName(null);
            }
          }

        } // for i

        checkSeedingMode();
        updateDataDirCombo();
        diskFreeInfoRefreshPending = true;
      }
    });

    torrentTable.setMenu(menu);

    Composite cTorrentListRight = new Composite(cArea, SWT.NONE);
    gridData = new GridData();
    cTorrentListRight.setLayoutData(gridData);
    RowLayout rLayout = new RowLayout(SWT.VERTICAL);
    rLayout.marginBottom = 0;
    rLayout.marginLeft = 0;
    rLayout.marginRight = 0;
    rLayout.marginTop = 0;
    if (!Constants.isOSX)
      rLayout.spacing = 0;
    rLayout.fill = true;
    cTorrentListRight.setLayout(rLayout);

    ImageLoader imageLoader = ImageLoader.getInstance();

    Button torMoveUp = new Button(cTorrentListRight, SWT.PUSH);
    imageLoader.setButtonImage(torMoveUp, "up");
    torMoveUp.setToolTipText(MessageText.getString("Button.moveUp"));
    torMoveUp.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        int[] indices = torrentTable.getSelectionIndices();
        if (indices.length == 0)
          return;

        Arrays.sort(indices);
        if (indices[0] == 0)
          return;

        for (int i = 0; i < indices.length; i++) {
          int pos = indices[i];
          Object save = torrentList.get(pos - 1);
          torrentList.set(pos - 1, torrentList.get(pos));
          torrentList.set(pos, save);

          indices[i]--;
        }
        torrentTable.setSelection(indices);
        torrentTable.clearAll();
      }
    });

    Button torMoveDown = new Button(cTorrentListRight, SWT.PUSH);
    imageLoader.setButtonImage(torMoveDown, "down");
    torMoveDown.setToolTipText(MessageText.getString("Button.moveDown"));
    torMoveDown.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        int[] indices = torrentTable.getSelectionIndices();
        if (indices.length == 0)
          return;

        Arrays.sort(indices);
        int max = indices.length - 1;
        if (indices[max] == torrentList.size() - 1)
          return;

        for (int i = max; i >= 0; i--) {
          int pos = indices[i];
          Object save = torrentList.get(pos + 1);
          torrentList.set(pos + 1, torrentList.get(pos));
          torrentList.set(pos, save);

          indices[i]++;
        }
        torrentTable.setSelection(indices);
        torrentTable.clearAll();
      }
    });

    Button torMoveRemove = new Button(cTorrentListRight, SWT.PUSH);
    torMoveRemove.setToolTipText(MessageText.getString("OpenTorrentWindow.torrent.remove"));
    imageLoader.setButtonImage(torMoveRemove, "delete");
    torMoveRemove.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        deleteSelected(torrentTable, torrentList);
      }
    });

  }

  /**
   * @param iLocation
   */
  protected void setSelectedQueueLocation(int iLocation) {
    int[] indices = torrentTable.getSelectionIndices();
    for (int i = 0; i < indices.length; i++) {
      TorrentInfo info = (TorrentInfo) torrentList.get(indices[i]);
      info.iQueueLocation = iLocation;
    }
    updateQueueLocationCombo();
    torrentTable.clear(indices);
  }

  /**
   * @param iStartID
   */
  protected void setSelectedStartMode(int iStartID) {
    int[] indices = torrentTable.getSelectionIndices();
    for (int i = 0; i < indices.length; i++) {
      TorrentInfo info = (TorrentInfo) torrentList.get(indices[i]);
      info.iStartID = iStartID;
    }

    checkSeedingMode();
    updateStartModeCombo();
    torrentTable.clear(indices);
  }

  private void checkSeedingMode() {
    // Check for seeding
    for (int i = 0; i < torrentList.size(); i++) {
      boolean bTorrentValid = true;
      TorrentInfo info = (TorrentInfo) torrentList.get(i);

      if (info.iStartID == STARTMODE_SEEDING) {
        // check if all selected files exist
        TorrentFileInfo[] files = info.getFiles();
        for (int j = 0; j < files.length; j++) {
          TorrentFileInfo fileInfo = files[j];
          if (!fileInfo.bDownload)
            continue;


          File file = fileInfo.getDestFileFullName();
          if (!file.exists()) {
            fileInfo.isValid = false;
            bTorrentValid = false;
          } else if (!fileInfo.isValid) {
            fileInfo.isValid = true;
          }
        }
      }

      info.isValid = bTorrentValid;
    }

    Utils.execSWTThread(new AERunnable() {
      public void runSupport() {
        if (torrentTable != null && !torrentTable.isDisposed()) {
          torrentTable.clearAll();
        }
        if (dataFileTable != null && !dataFileTable.isDisposed()) {
          dataFileTable.clearAll();
          editCell(-1);
        }
      }
    });
  }

  private void deleteSelected(Table table, ArrayList list) {
    int[] indexes = table.getSelectionIndices();
    Arrays.sort(indexes);
    for (int i = indexes.length - 1; i >= 0; i--) {
      if (list.get(indexes[i]) instanceof TorrentInfo) {
        TorrentInfo info = (TorrentInfo) list.get(indexes[i]);
        if (info.bDeleteFileOnCancel) {
          File file = new File(info.sFileName);
          if (file.exists())
            file.delete();
        }
      }
      list.remove(indexes[i]);
    }
    table.setItemCount(list.size());
    table.clearAll();
    table.notifyListeners(SWT.Selection, new Event());
  }
 
 
  private void editCell(final int row)
  {
    Text oldEditor = (Text)dataFileTableEditor.getEditor();
    if(row < 0 || row >= dataFileTable.getItemCount())
    {
      if(oldEditor != null && !oldEditor.isDisposed())
        oldEditor.dispose();
      return;
    }
   
   
    final Text newEditor = oldEditor == null || oldEditor.isDisposed() ? new Text(dataFileTable,SWT.BORDER) : oldEditor;
    final TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(row);
    final String uneditedName = file.getDestFileName();
    TableItem item = dataFileTable.getItem(row);
    TableColumn column = dataFileTable.getColumn(EDIT_COLUMN_INDEX);

    newEditor.setText(uneditedName);
    newEditor.selectAll();
    newEditor.forceFocus();
    Rectangle leftAlignedBounds = item.getBounds(EDIT_COLUMN_INDEX);
    leftAlignedBounds.width = dataFileTableEditor.minimumWidth = newEditor.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
    if(leftAlignedBounds.intersection(dataFileTable.getClientArea()).equals(leftAlignedBounds))
      dataFileTableEditor.horizontalAlignment = SWT.LEFT;
    else
      dataFileTableEditor.horizontalAlignment = SWT.RIGHT;
   
    dataFileTable.deselectAll();
    dataFileTable.select(row);
    dataFileTable.showItem(item);
    dataFileTable.showColumn(column);
   
    class QuickEditListener implements ModifyListener, SelectionListener, KeyListener, TraverseListener {
      public void modifyText(ModifyEvent e) {
        file.setDestFileName(newEditor.getText());
        try
        {
          file.getDestFileFullName().getCanonicalFile();
          newEditor.setBackground(null);
        } catch (IOException e1)
        {
          newEditor.setBackground(Colors.colorErrorBG);
        }
      }
     
      public void widgetDefaultSelected(SelectionEvent e) {
        try
        {
          file.getDestFileFullName().getCanonicalFile();
        } catch (IOException e1)
        {
          file.setDestFileName(uneditedName);
        }
        move(row,1,(Text)e.widget);
      }
     
      public void widgetSelected(SelectionEvent e) {}
      public void keyReleased(KeyEvent e) {}
     
      public void keyPressed(KeyEvent e) {
        if(e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.ARROW_UP)
        {
          e.doit = false;
          move(row,e.keyCode == SWT.ARROW_DOWN ? 1 : -1,(Text)e.widget);
        }
      }
     
      public void keyTraversed(TraverseEvent e) {
        if(e.detail == SWT.TRAVERSE_ESCAPE || e.detail == SWT.TRAVERSE_RETURN)
          e.doit = false;
        if(e.detail == SWT.TRAVERSE_ESCAPE)
          editCell(-1);
      }
     
      private void move(int oldRow, int offset, Text current)
      {
        current.removeModifyListener(QuickEditListener.this);
        current.removeSelectionListener(QuickEditListener.this);
        current.removeKeyListener(QuickEditListener.this);
        current.removeTraverseListener(QuickEditListener.this);
        editCell(oldRow+offset);
        dataFileTable.clear(oldRow);
      }
     
    }
   
    QuickEditListener listener = new QuickEditListener();
   
    newEditor.addModifyListener(listener);
    newEditor.addSelectionListener(listener);
    newEditor.addKeyListener(listener);
    newEditor.addTraverseListener(listener);
   
    dataFileTableEditor.setEditor(newEditor, dataFileTable.getItem(row), EDIT_COLUMN_INDEX);
  }

  private static final int EDIT_COLUMN_INDEX = 1;
 
 
  private void createTableDataFiles(Composite cArea) {
    GridData gridData;
    TableColumn tc;

    dataFileTable = new Table(cArea, SWT.BORDER | SWT.CHECK
        | SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.MULTI);
    dataFileTableEditor = new TableEditor(dataFileTable);
    dataFileTableEditor.grabHorizontal = true;
    dataFileTableEditor.minimumWidth = 50;
   
    gridData = new GridData(GridData.FILL_BOTH);
    gridData.heightHint = 80;
    gridData.widthHint = 100;
    dataFileTable.setLayoutData(gridData);
   
   

    tc = new TableColumn(dataFileTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.fileTable.fileName");
    tc.setWidth(150);
    tc = new TableColumn(dataFileTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.fileTable.destinationName");
    tc.setWidth(140);
    tc = new TableColumn(dataFileTable, SWT.NULL);
    Messages.setLanguageText(tc, "OpenTorrentWindow.fileTable.size");
    tc.setAlignment(SWT.TRAIL);
    tc.setWidth(90);

    if (Utils.LAST_TABLECOLUMN_EXPANDS)
      tc.setData("Width", new Long(90));

    dataFileTable.addListener(SWT.SetData, new Listener() {
      public void handleEvent(Event event) {
        if (bClosed)
          return;
       
        final TableItem item = (TableItem) event.item;
       
        int index = dataFileTable.indexOf(item);
        final TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(index);

        item.setText(new String[] {
          file.orgFullName,
          file.isLinked() ? file.getDestFileFullName().toString() : file.getDestFileName(),
          DisplayFormatters.formatByteCountToKiBEtc(file.lSize)
        });
        if (!file.isValid) {
          item.setForeground(Colors.red);
          Font font = item.getFont();
          FontData[] fd = font.getFontData();
          for (int i = 0; i < fd.length; i++) {
            fd[i].setStyle(SWT.ITALIC);
          }
          font = new Font(item.getDisplay(), fd);
          disposeList.add(font);
          item.setFont(font);
        }
        Utils.alternateRowBackground(item);
        Utils.setCheckedInSetData(item, file.bDownload);

        item.setGrayed(!file.okToDisable());
      }
    });

    dataFileTable.addSelectionListener(new SelectionAdapter() {

      public void widgetSelected(SelectionEvent event) {
        if (event.detail == SWT.CHECK) {
          TableItem item = (TableItem) event.item;
          int index = dataFileTable.indexOf(item);
          TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(index);
          // don't allow disabling of small files
          // XXX Maybe warning prompt instead?
          if (!item.getChecked() && !file.okToDisable())
            item.setChecked(true);
          else
            file.bDownload = item.getChecked();

          updateSize();
        }
      }

    });
   
    dataFileTable.addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {
        editCell(-1); // cleanup
        if(e.button != 1)
          return;

        TableItem[] items = dataFileTable.getItems();
        boolean found = false;
        int i;
        outer: for (i = 0; i < items.length; i++)
        {
          TableItem item = items[i];
          Rectangle rect = item.getBounds();
          if (e.y < rect.y || (rect.y + rect.height) < e.y)
            continue;
          for (int j = 0; j < dataFileTable.getColumnCount(); j++)
          {
            if (!item.getBounds(j).contains(e.x, e.y))
              continue;
            found = j == EDIT_COLUMN_INDEX;
            break outer;
          }
        }
        if(found)
          editCell(i);
      }
    });
   
   

    dataFileTable.setHeaderVisible(true);

    Menu menu = new Menu(dataFileTable);
    dataFileTable.setMenu(menu);

    MenuItem item;

    item = new MenuItem(menu, SWT.PUSH);
    Messages.setLanguageText(item,
        "OpenTorrentWindow.fileList.changeDestination");
    item.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        int[] indexes = dataFileTable.getSelectionIndices();
        changeFileDestination(indexes);
      }
    });

    Composite cBottomArea = new Composite(cArea, SWT.NONE);
    GridLayout gLayout = new GridLayout();
    gLayout.marginHeight = 0;
    gLayout.marginWidth = 0;
    gLayout.numColumns = 2;
    gLayout.verticalSpacing = 0;
    cBottomArea.setLayout(gLayout);
    gridData = new GridData(GridData.FILL_HORIZONTAL);
    cBottomArea.setLayoutData(gridData);

    Composite cButtons = new Composite(cBottomArea, SWT.NONE);
    RowLayout rLayout = new RowLayout(SWT.HORIZONTAL);
    rLayout.wrap = false;
    rLayout.marginBottom = 0;
    rLayout.marginLeft = 0;
    rLayout.marginRight = 0;
    rLayout.marginTop = 0;
    cButtons.setLayout(rLayout);
    gridData = new GridData(SWT.END, SWT.BEGINNING, false, false);
    gridData.verticalSpan = 2;
    cButtons.setLayoutData(gridData);

    Button btnSelectAll = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(btnSelectAll, "Button.selectAll");
    btnSelectAll.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        dataFileTable.selectAll();
      }
    });

    Button btnMarkSelected = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(btnMarkSelected, "Button.markSelected");
    btnMarkSelected.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        int[] indexes = dataFileTable.getSelectionIndices();
        for (int i = 0; i < indexes.length; i++) {
          TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(indexes[i]);
          file.bDownload = true;
        }
        dataFileTable.clearAll();
        updateSize();
      }
    });

    Button btnUnmarkSelected = new Button(cButtons, SWT.PUSH);
    Messages.setLanguageText(btnUnmarkSelected, "Button.unmarkSelected");
    btnUnmarkSelected.addListener(SWT.Selection, new Listener() {
      public void handleEvent(Event event) {
        int[] indexes = dataFileTable.getSelectionIndices();
        for (int i = 0; i < indexes.length; i++) {
          TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(indexes[i]);
          if (file.okToDisable())
            file.bDownload = false;
        }
        dataFileTable.clearAll();
        updateSize();
      }
    });

    dataFileTableLabel = new Label(cBottomArea, SWT.WRAP);
    dataFileTableLabel.setAlignment(SWT.RIGHT);
    gridData = new GridData(SWT.END, SWT.BEGINNING, true, false);
    dataFileTableLabel.setLayoutData(gridData);

    diskspaceComp = new Composite(cBottomArea, SWT.NONE);
    gLayout = new GridLayout(2, false);
    gLayout.marginHeight = gLayout.marginWidth = 1;
    gLayout.verticalSpacing = 0;
    gLayout.horizontalSpacing = 15;
    diskspaceComp.setLayout(gLayout);
    gridData = new GridData(SWT.END, SWT.BEGINNING, true, false);
    diskspaceComp.setLayoutData(gridData);

  }

  /**
   * @param indexes
   */
  protected void changeFileDestination(int[] indexes) {
    for (int i = 0; i < indexes.length; i++) {
      TorrentFileInfo fileInfo = (TorrentFileInfo) dataFiles.get(indexes[i]);
      int style = (fileInfo.parent.iStartID == STARTMODE_SEEDING) ? SWT.OPEN
          : SWT.SAVE;
      FileDialog fDialog = new FileDialog(shellForChildren, SWT.SYSTEM_MODAL
          | style);

      String sFilterPath = fileInfo.getDestPathName();
      String sFileName = fileInfo.orgFileName;

      File f = new File(sFilterPath);
      if (!f.isDirectory()) {
        // Move up the tree until we have an existing path
        while (sFilterPath != null) {
          String parentPath = f.getParent();
          if (parentPath == null)
            break;

          sFilterPath = parentPath;
          f = new File(sFilterPath);
          if (f.isDirectory())
            break;
        }
      }

      if (sFilterPath != null)
        fDialog.setFilterPath(sFilterPath);
      fDialog.setFileName(sFileName);
      fDialog.setText(MessageText.getString("MainWindow.dialog.choose.savepath")
          + " (" + fileInfo.orgFullName + ")");
      String sNewName = fDialog.open();

      if (sNewName == null)
        return;

      if (fileInfo.parent.iStartID == STARTMODE_SEEDING) {
        File file = new File(sNewName);
        if (file.length() == fileInfo.lSize)
          fileInfo.setFullDestName(sNewName);
        else {
          MessageBoxShell mb = new MessageBoxShell(SWT.OK,
              "OpenTorrentWindow.mb.badSize", new String[] {
                file.getName(),
                fileInfo.orgFullName
              });
          mb.open(null);
        }
      } else
        fileInfo.setFullDestName(sNewName);

    } // for i

    checkSeedingMode();
    updateDataDirCombo();
    diskFreeInfoRefreshPending = true;
  }

  /**
   * Add Torrent(s) to Window using a text list of files/urls/torrents
   *
   * @param sClipText Text to parse
   * @param bVerifyOnly Only check if there's potential torrents in the text,
   *                     do not try to add the torrents.
   *
   * @return Number of torrents added or found.  When bVerifyOnly, this number
   *          may not be exact.
   */
  private int addTorrentsFromTextList(String sClipText, boolean bVerifyOnly) {
    String[] lines = null;
    int iNumFound = 0;
    // # of consecutive non torrent lines
    int iNoTorrentLines = 0;
    // no use checking the whole clipboard (which may be megabytes)
    final int MAX_CONSECUTIVE_NONTORRENT_LINES = 100;

    final String[] splitters = {
      "\r\n",
      "\n",
      "\r",
      "\t"
    };

    for (int i = 0; i < splitters.length; i++)
      if (sClipText.indexOf(splitters[i]) >= 0) {
        lines = sClipText.split(splitters[i]);
        break;
      }

    if (lines == null)
      lines = new String[] {
        sClipText
      };

    // Check if URL, 20 byte hash, Dir, or file
    for (int i = 0; i < lines.length; i++) {
      String line = lines[i].trim();
      if (line.startsWith("\"") && line.endsWith("\"")) {
        if (line.length() < 3) {
          line = "";
        } else {
          line = line.substring(1, line.length() - 2);
        }
      }

      boolean ok;

      if (line == "") {
        ok = false;
      } else if (UrlUtils.isURL(line)) {
        ok = true;
      } else {
        File file = new File(line);

        if (!file.exists()) {
          ok = false;
        } else if (file.isDirectory()) {
          if (bVerifyOnly) {
            // XXX Could do a file count here, but the number found is not
            //     expected to be an exact number anyway, since we aren't
            //     event verifying if they are torrents.
            ok = true;
          } else {
            iNumFound += addTorrents(lines[i], null);
            ok = false;
          }
        } else {
          ok = true;
        }
      }

      if (!ok) {
        iNoTorrentLines++;
        lines[i] = null;
        if (iNoTorrentLines > MAX_CONSECUTIVE_NONTORRENT_LINES)
          break;
      } else {
        iNumFound++;
        iNoTorrentLines = 0;
      }
    }

    if (bVerifyOnly) {
      return iNumFound;
    }

    return addTorrents(null, lines);
  }

  /**
   * Add Torrent(s) to window
   *
   * @param sTorrentFilePath
   * @param sTorrentFilenames
   * @return # torrents actually added to list (or downloading)
   */
  private int addTorrents(String sTorrentFilePath, String[] sTorrentFilenames) {
    sTorrentFilePath = ensureTrailingSeparator(sTorrentFilePath);

    // Process Directory
    if (sTorrentFilePath != null && sTorrentFilenames == null) {
      File dir = new File(sTorrentFilePath);
      if (!dir.isDirectory())
        return 0;

      final File[] files = dir.listFiles(new FileFilter() {
        public boolean accept(File arg0) {
          if (FileUtil.getCanonicalFileName(arg0.getName()).endsWith(".torrent"))
            return true;
          if (FileUtil.getCanonicalFileName(arg0.getName()).endsWith(".tor"))
            return true;
          return false;
        }
      });

      if (files.length == 0)
        return 0;

      sTorrentFilenames = new String[files.length];
      for (int i = 0; i < files.length; i++)
        sTorrentFilenames[i] = files[i].getName();
    }

    int numAdded = 0;
    for (int i = 0; i < sTorrentFilenames.length; i++) {
      if (sTorrentFilenames[i] == null || sTorrentFilenames[i] == "")
        continue;

      // Process File
      String sFileName = ((sTorrentFilePath == null) ? "" : sTorrentFilePath)
          + sTorrentFilenames[i];

      if (!new File(sFileName).exists()) {
        // Process URL
        String sURL = UrlUtils.parseTextForURL(sTorrentFilenames[i], true);
        if (sURL != null) {
          if (COConfigurationManager.getBooleanParameter("Add URL Silently")) {
            new FileDownloadWindow(shellForChildren, sURL, null, null, this);
          } else {
            new OpenUrlWindow(shellForChildren, sURL, null, this);
          }
          numAdded++;
          continue;
        }
      }

      if (addTorrent(sFileName, sFileName) != null)
        numAdded++;
    }

    if (numAdded > 0 && shell != null && torrentTable != null
        && !shell.isDisposed()) {
      int iTotal = torrentList.size();
      torrentTable.setItemCount(iTotal);
      // select the ones we just added
      torrentTable.select(iTotal - numAdded, iTotal - 1);
      torrentTable.clearAll();
      // select doesn't notify listeners? Do it manually.
      torrentTable.notifyListeners(SWT.Selection, new Event());

      resizeTables(1);
      checkSeedingMode();
    }
    return numAdded;
  }

  private TorrentInfo addTorrent(String sFileName,
      final String sOriginatingLocation) {
    TorrentInfo info = null;
    TOTorrent torrent = null;
    File torrentFile;
    boolean bDeleteFileOnCancel = false;

    // Make a copy if user wants that.  We'll delete it when we cancel, if we
    // actually made a copy.
    try {
      if (sFileName.startsWith("file://localhost/")) {
        sFileName = UrlUtils.decode(sFileName.substring(16));
      }

      final File fOriginal = new File(sFileName);

      if (!fOriginal.isFile() || !fOriginal.exists()) {
        Utils.execSWTThread(new AERunnable() {
          public void runSupport() {
            if (shell == null)
              new MessageSlideShell(Display.getCurrent(), SWT.ICON_ERROR,
                  "OpenTorrentWindow.mb.openError", fOriginal.toString(), new String[] {
                    UrlUtils.decode(sOriginatingLocation),
                    "Not a File"
                  }, -1 );
            else {
              MessageBoxShell mb = new MessageBoxShell(SWT.OK,
                  "OpenTorrentWindow.mb.openError", new String[] {
                    sOriginatingLocation,
                    "Not a File"
                  });
              mb.open(null);
            }
          }
        });
        return null;
      }

      if (fOriginal.length() > 20*1024*1024) {
        Utils.execSWTThread(new AERunnable() {
          public void runSupport() {
            if (shell == null)
              new MessageSlideShell(Display.getCurrent(), SWT.ICON_ERROR,
                  "OpenTorrentWindow.mb.openError", fOriginal.toString(), new String[] {
                    UrlUtils.decode(sOriginatingLocation),
                    "Too large to be a torrent"
                  }, -1 );
            else {
              MessageBoxShell mb = new MessageBoxShell(SWT.OK,
                  "OpenTorrentWindow.mb.openError", new String[] {
                    sOriginatingLocation,
                    "Too large to be a torrent"
                  });
              mb.open(null);
            }
          }
        });
        return null;
      }

      torrentFile = TorrentUtils.copyTorrentFileToSaveDir(fOriginal, true);
      bDeleteFileOnCancel = !fOriginal.equals(torrentFile);
      // TODO if the files are still equal, and it isn't in the save
      //       dir, we should copy it to a temp file in case something
      //       re-writes it.  No need to copy a torrent coming from the
      //       downloader though..
    } catch (IOException e1) {
      // Use torrent in wherever it is and hope for the best
      // XXX Should error instead?
      torrentFile = new File(sFileName);
    }

    VuzeFileHandler vfh = VuzeFileHandler.getSingleton();
   
    VuzeFile vf = vfh.loadVuzeFile( torrentFile );
   
    if ( vf != null ){
     
        vfh.handleFiles( new VuzeFile[]{ vf }, VuzeFileComponent.COMP_TYPE_NONE );

        return null;
    }
   
    // Do a quick check to see if it's a torrent
    if (!TorrentUtil.isFileTorrent(torrentFile, shellForChildren,
        torrentFile.getName())) {
      if (bDeleteFileOnCancel) {
        torrentFile.delete();
      }
      return null;
    }

    // Load up the torrent, see it it's real
    try {
      torrent = TorrentUtils.readFromFile(torrentFile, false);
    } catch (final TOTorrentException e) {
     
      Utils.execSWTThread(new AERunnable() {
        public void runSupport() {
          if (shell == null)
            new MessageSlideShell(Display.getCurrent(), SWT.ICON_ERROR,
                "OpenTorrentWindow.mb.openError", Debug.getStackTrace(e),
                new String[] {
                  sOriginatingLocation,
                  e.getMessage()
                }, -1 );
          else {
            MessageBoxShell mb = new MessageBoxShell(SWT.OK,
                "OpenTorrentWindow.mb.openError", new String[] {
                  sOriginatingLocation,
                  e.getMessage()
                });
            mb.open(null);
          }
        }
      });

      if (bDeleteFileOnCancel)
        torrentFile.delete();

      return null;
    }

    String sExistingName = null;
    try {
      HashWrapper hash = torrent.getHashWrapper();
      if (hash != null) {
        for (int i = 0; i < torrentList.size(); i++) {
          try {
            TorrentInfo existing = (TorrentInfo) torrentList.get(i);
            if (existing.torrent.getHashWrapper().equals(hash)) {
              //sExistingName = existing.sOriginatingLocation;

              // Exit without warning when it already exists in list
              if (bDeleteFileOnCancel)
                torrentFile.delete();

              return null;
            }
          } catch (Exception e) {
          }
        }
      }
    } catch (Exception e) {
    }

    DownloadManager existingDownload = null;
    if (sExistingName == null) {
      // Check if torrent already exists in gm, and add if not
      existingDownload = (gm == null) ? null : gm.getDownloadManager(torrent);
      if (existingDownload != null) {
        sExistingName = existingDownload.getDisplayName();
      }
    }

    if (sExistingName == null) {
      info = new TorrentInfo(torrentFile.getAbsolutePath(), torrent,
          bDeleteFileOnCancel);
      info.sOriginatingLocation = sOriginatingLocation;
      torrentList.add(info);

    } else {

      final String sfExistingName = sExistingName;
      final DownloadManager fExistingDownload = existingDownload;
      Utils.execSWTThread(new AERunnable() {
        public void runSupport() {
          Shell mainShell = UIFunctionsManagerSWT.getUIFunctionsSWT().getMainShell();
          if (Display.getDefault().getActiveShell() == null || !mainShell.isVisible() || mainShell.getMinimized() ) {
            new MessageSlideShell(Display.getCurrent(), SWT.ICON_INFORMATION,
                MSG_ALREADY_EXISTS, null, new String[] {
                  ":" + sOriginatingLocation,
                  sfExistingName,
                  MessageText.getString(MSG_ALREADY_EXISTS_NAME),
                }, new Object[] {
                  fExistingDownload
                }, -1 );
          } else {
            MessageBoxShell mb = new MessageBoxShell(SWT.OK, MSG_ALREADY_EXISTS,
                new String[] {
                  ":" + sOriginatingLocation,
                  sfExistingName,
                  MessageText.getString(MSG_ALREADY_EXISTS_NAME),
                });
            mb.open(null);
          }
        }
      });

      if (bDeleteFileOnCancel)
        torrentFile.delete();
    }

    return info;
  }

  /**
   * Resize the columns of the tables to fit without horizontal scrollbar
   *
   * @param which bitwise field of which table to recalc
   *         Bit 0: torrents table
   *         Bit 1: Data Files Table
   */
  private void resizeTables(int which) {
    try {
      TableColumn[] tcs;
      if ((which & 1) > 0 && torrentTable != null
          && !torrentTable.isDisposed()) {
        tcs = torrentTable.getColumns();
        int newSize = torrentTable.getClientArea().width - 20;
        int iLength = tcs.length;
        if (Utils.LAST_TABLECOLUMN_EXPANDS) {
          iLength--;
          newSize -= ((Long) tcs[iLength].getData("Width")).intValue();
        }

        final int columnToExpand = 1;

        for (int i = 0; i < iLength; i++)
          if (i != columnToExpand)
            newSize -= tcs[i].getWidth();

        if (newSize > 10)
          tcs[columnToExpand].setWidth(newSize);
      }

      // Adjust only first column
      if ((which & 2) > 0 && dataFileTable != null
          && !dataFileTable.isDisposed()) {
        tcs = dataFileTable.getColumns();
        int newSize = dataFileTable.getClientArea().width - 20;
        int iLength = tcs.length;
        if (Utils.LAST_TABLECOLUMN_EXPANDS) {
          iLength--;
          newSize -= ((Long) tcs[iLength].getData("Width")).intValue();
        }

        final int columnToExpand = 0;

        for (int i = 0; i < iLength; i++)
          if (i != columnToExpand)
            newSize -= tcs[i].getWidth();

        if (newSize > 10)
          tcs[columnToExpand].setWidth(newSize);
      }
    } catch (Exception e) {
      // ignore
      e.printStackTrace();
    }
  }

  /**
   * Open the torrents already added based on user choices
   *
   * @param sDataDir
   */
  private void openTorrents() {
    Utils.getOffOfSWTThread(new AERunnable() {
      public void runSupport() {
        _openTorrents();
      }
    });
  }

  private void _openTorrents() {
    ArrayList addedTorrentsTop = new ArrayList();

    for (int i = 0; i < torrentList.size(); i++) {
      final TorrentInfo info = (TorrentInfo) torrentList.get(i);
      try {
        if (info.torrent == null)
          continue;

        int iStartState = (info.iStartID == STARTMODE_STOPPED)
            ? DownloadManager.STATE_STOPPED : DownloadManager.STATE_QUEUED;

        final TorrentFileInfo[] files = info.getFiles();

        byte[] hash = null;
        try {
          hash = info.torrent.getHash();
        } catch (TOTorrentException e1) {
        }

        DownloadManager dm = gm.addDownloadManager(info.sFileName, hash, info.sDestDir, info.sDestSubDir, iStartState, true, info.iStartID == STARTMODE_SEEDING, new DownloadManagerInitialisationAdapter()
        {
          public void initialised(DownloadManager dm) {
            DiskManagerFileInfo[] fileInfos = dm.getDiskManagerFileInfo();
           
            boolean  reorder_mode     = COConfigurationManager.getBooleanParameter( "Enable reorder storage mode" );
            int    reorder_mode_min_mb = COConfigurationManager.getIntParameter( "Reorder storage mode min MB" );
           
            try
            {
              dm.getDownloadState().suppressStateSave(true);
             
              boolean[] toSkip       = new boolean[fileInfos.length];
              boolean[] toCompact     = new boolean[fileInfos.length];
              boolean[] toReorderCompact   = new boolean[fileInfos.length];
             
              int  comp_num       = 0;
              int reorder_comp_num  = 0;
             
              for (int iIndex = 0; iIndex < fileInfos.length; iIndex++)
              {
                DiskManagerFileInfo fileInfo = fileInfos[iIndex];
                if (iIndex >= 0 && iIndex < files.length && files[iIndex].lSize == fileInfo.getLength())
                {
                  // Always pull destination file from fileInfo and not from
                  // TorrentFileInfo because the destination may have changed
                  // by magic code elsewhere
                  File fDest = fileInfo.getFile(true);
                  if (files[iIndex].isLinked()){
                 
                    fDest = files[iIndex].getDestFileFullName();
                   
                      // Can't use fileInfo.setLink(fDest) as it renames
                      // the existing file if there is one
                   
                    dm.getDownloadState().setFileLink( fileInfo.getFile(false), fDest);
                  }
                 
                  if (!files[iIndex].bDownload){
                 
                    toSkip[iIndex] = true;
                   
                    if (!fDest.exists()){
                     
                      if ( reorder_mode && ( fileInfo.getLength()/(1024*1024)) >= reorder_mode_min_mb ){
                       
                        toReorderCompact[iIndex] = true;
                       
                        reorder_comp_num++;
                       
                      }else{
                       
                        toCompact[iIndex] = true;
                       
                        comp_num++;
                      }
                    }
                  }
                }
              }
             
              if ( comp_num > 0 ){
               
                dm.getDiskManagerFileInfoSet().setStorageTypes(toCompact, DiskManagerFileInfo.ST_COMPACT);
              }
             
              if ( reorder_comp_num > 0 ){
               
                dm.getDiskManagerFileInfoSet().setStorageTypes(toReorderCompact, DiskManagerFileInfo.ST_REORDER_COMPACT );
              }
             
              dm.getDiskManagerFileInfoSet().setSkipped(toSkip, true);
             
            }finally{
           
              dm.getDownloadState().suppressStateSave(false);
            }
          }
        });

        // If dm is null, most likely there was an error printed.. let's hope
        // the user was notified and skip the error quietly.
        // We don't have to worry about deleting the file (info.bDelete..)
        // since gm.addDown.. will handle it.
        if (dm == null)
          continue;

        if (info.iQueueLocation == QUEUELOCATION_TOP)
          addedTorrentsTop.add(dm);

        if (info.iStartID == STARTMODE_FORCESTARTED) {
          dm.setForceStart(true);
        }

      } catch (Exception e) {
        if (shell == null)
          new MessageSlideShell(Display.getCurrent(), SWT.ICON_ERROR,
              "OpenTorrentWindow.mb.openError", Debug.getStackTrace(e),
              new String[] {
                info.sOriginatingLocation,
                e.getMessage()
              }, -1 );
        else {
          MessageBoxShell mb = new MessageBoxShell(SWT.OK, "OpenTorrentWindow.mb.openError",
              new String[] {
                info.sOriginatingLocation,
                e.getMessage()
              });
          mb.open(null);
        }
      }
    }

    if (addedTorrentsTop.size() > 0) {
      DownloadManager[] dms = (DownloadManager[]) addedTorrentsTop.toArray(new DownloadManager[0]);
      gm.moveTop(dms);
    }

    torrentList.clear();
  }

  private int getDefaultStartMode() {
    if (bDefaultForSeeding)
      return STARTMODE_SEEDING;
    return (bOverrideStartModeToStopped || COConfigurationManager.getBooleanParameter("Default Start Torrents Stopped"))
        ? STARTMODE_STOPPED : STARTMODE_QUEUED;
  }

  // TorrentDownloaderCallBackInterface
  public void TorrentDownloaderEvent(int state, final TorrentDownloader inf) {
    // This method is run even if the window is closed.

    // The default is to delete file on cancel
    // We set this flag to false if we detected the file was not a torrent
    if (!inf.getDeleteFileOnCancel()
        && (state == TorrentDownloader.STATE_CANCELLED
            || state == TorrentDownloader.STATE_ERROR
            || state == TorrentDownloader.STATE_DUPLICATE || state == TorrentDownloader.STATE_FINISHED)) {

      activeTorrentCount--;
      enableControl(ok, activeTorrentCount < 1);
     
        // PARG - yes, this code sucks, added some sync here to prvent some errors but obviously
        // it needs a complete rewrite
     
      synchronized( downloaders ){
        if (!downloaders.contains(inf))
          return;
        downloaders.remove(inf);
      }
     
      File file = inf.getFile();
      // we already know it isn't a torrent.. we are just using the call
      // to popup the message
      TorrentUtil.isFileTorrent(file, shellForChildren, inf.getURL());
      if (file.exists()) {
        file.delete();
      }
      return;
    }

    if (state == TorrentDownloader.STATE_INIT) {
      activeTorrentCount++;
      enableControl(ok, activeTorrentCount < 1);
      synchronized( downloaders ){
        downloaders.add(inf);
      }
    } else if (state == TorrentDownloader.STATE_FINISHED) {
      activeTorrentCount--;
      enableControl(ok, activeTorrentCount < 1);

      // This can be called more than once for each inf..
      synchronized( downloaders ){
        if (!downloaders.contains(inf))
          return;
        downloaders.remove(inf);
      }
     
      File file = inf.getFile();
      if (addTorrent(file.getAbsolutePath(), inf.getURL()) == null) {
        // addTorrent may not delete it on error if the downloader saved it
        // to the place where user wants to store torrents (which is most
        // likely)
        if (file.exists())
          file.delete();

      } else {
        if (shell != null && !shell.isDisposed()) {
          Utils.execSWTThread(new AERunnable() {
            public void runSupport() {
              torrentTable.setItemCount(torrentList.size());
              torrentTable.clearAll();

              // select the one we just added
              torrentTable.select(torrentList.size() - 1);
              // select doesn't notify listeners? Do it manually.
              torrentTable.notifyListeners(SWT.Selection, new Event());

              resizeTables(1);
            }
          });
        } else {
          String saveSilentlyDir = getSaveSilentlyDir();
          if (saveSilentlyDir != null) {
            sDestDir = saveSilentlyDir;
            for (int i = 0; i < torrentList.size(); i++) {
              final TorrentInfo info = (TorrentInfo) torrentList.get(i);
              info.renameDuplicates();
            }

            openTorrents();
          }
        }
      }

      checkSeedingMode();
    } else if (state == TorrentDownloader.STATE_CANCELLED
        || state == TorrentDownloader.STATE_ERROR
        || state == TorrentDownloader.STATE_DUPLICATE) {
      activeTorrentCount--;
      enableControl(ok, activeTorrentCount < 1);
      synchronized( downloaders ){
        downloaders.remove(inf);
      }
    } else if (state == TorrentDownloader.STATE_DOWNLOADING) {
      int count = inf.getLastReadCount();
      int numRead = inf.getTotalRead();

      if (!inf.getDeleteFileOnCancel() && numRead >= 16384) {
        inf.cancel();
      } else if (numRead == count && count > 0) {
        final byte[] bytes = inf.getLastReadBytes();
        if (bytes[0] != 'd') {
          inf.setDeleteFileOnCancel(false);
        }
      }
    } else {
      return;
    }
  }

  /**
   * Class to store one Torrent file's info.  Used to populate table and store
   * user's choices.
   */
  private class TorrentInfo
  {
    /** Where the torrent came from.  Could be a file, URL, or some other text */
    String sOriginatingLocation;

    /** Filename the .torrent is saved to */
    String sFileName;

    String sDestDir;

    /** for multifiletorrents and change location */
    String sDestSubDir;

    TOTorrent torrent;

    int iStartID;

    int iQueueLocation;

    boolean isValid;

    boolean bDeleteFileOnCancel;

    private TorrentFileInfo[] files = null;

    /**
     * Init
     *
     * @param sFileName
     * @param torrent
     * @param bDeleteFileOnCancel
     */
    public TorrentInfo(String sFileName, TOTorrent torrent,
        boolean bDeleteFileOnCancel) {
      this.bDeleteFileOnCancel = bDeleteFileOnCancel;
      this.sFileName = sFileName;
      this.sOriginatingLocation = sFileName;
      this.torrent = torrent;
      this.sDestDir = OpenTorrentWindow.this.sDestDir;

      iStartID = getDefaultStartMode();
      iQueueLocation = QUEUELOCATION_BOTTOM;
      isValid = true;

      // Force a check on the encoding, will prompt user if we dunno
      try {
        LocaleTorrentUtil.getTorrentEncoding(TorrentInfo.this.torrent);
      } catch (Exception e) {
        e.printStackTrace();
      }

      if (getSaveSilentlyDir() == null
          && COConfigurationManager.getBooleanParameter("DefaultDir.BestGuess")
          && !COConfigurationManager.getBooleanParameter(PARAM_MOVEWHENDONE)) {
        this.sDestDir = getSmartDestDir();
      }
    }

    public String getParentDir() {
      return sDestDir;
    }
   
    public void setParentDir(String parentDir)
    {
      sDestDir = parentDir;
    }

    public String getDataDir() {
      if (torrent.isSimpleTorrent())
        return sDestDir;
      return new File(sDestDir, sDestSubDir == null ? FileUtil.convertOSSpecificChars(getTorrentName(), true)
          : sDestSubDir).getPath();
    }

    public String getSmartDestDir() {
      String sSmartDir = sDestDir;
      try {
        String name = getTorrentName();
        String torrentFileName = new File(sFileName).getName().replaceFirst(
            "\\.torrent$", "");
        int totalSegmentsLengths = 0;

        String[][] segments = {
          name.split("[^a-zA-Z]+"),
          torrentFileName.split("[^a-zA-Z]+")
        };
        List downloadManagers = gm.getDownloadManagers();

        for (int x = 0; x < segments.length; x++) {
          String[] segmentArray = segments[x];
          for (int i = 0; i < segmentArray.length; i++) {
            int l = segmentArray[i].length();
            if (l <= 1) {
              continue;
            }
            segmentArray[i] = segmentArray[i].toLowerCase();
            totalSegmentsLengths += l;
          }
        }

        int maxMatches = 0;
        DownloadManager match = null;
        for (Iterator iter = downloadManagers.iterator(); iter.hasNext();) {
          DownloadManager dm = (DownloadManager) iter.next();

          if (dm.getState() == DownloadManager.STATE_ERROR) {
            continue;
          }

          int numMatches = 0;

          String dmName = dm.getDisplayName().toLowerCase();

          for (int x = 0; x < segments.length; x++) {
            String[] segmentArray = segments[x];
            for (int i = 0; i < segmentArray.length; i++) {
              int l = segmentArray[i].length();
              if (l <= 1) {
                continue;
              }

              String segment = segmentArray[i];

              if (dmName.indexOf(segment) >= 0) {
                numMatches += l;
              }
            }
          }

          if (numMatches > maxMatches) {
            maxMatches = numMatches;
            match = dm;
          }
        }
        if (match != null) {
          //System.out.println(match + ": " + (maxMatches * 100 / totalSegmentsLengths) + "%\n");
          int iMatchLevel = (maxMatches * 100 / totalSegmentsLengths);
          if (iMatchLevel >= 30) {
            File f = match.getSaveLocation();
            if (!f.isDirectory() || match.getDiskManagerFileInfo().length > 1) {
              // don't place data within another torrent's data dir
              f = f.getParentFile();
            }

            if (f != null && f.isDirectory()) {
              sSmartDir = f.getAbsolutePath();
            }
          }
        }

      } catch (Exception e) {
        e.printStackTrace();
      }
      return sSmartDir;
    }

    public TorrentFileInfo[] getFiles() {
      if (files == null && torrent != null) {
        TOTorrentFile[] tfiles = torrent.getFiles();
        files = new TorrentFileInfo[tfiles.length];
        for (int i = 0; i < files.length; i++) {
          files[i] = new TorrentFileInfo(this, tfiles[i], i);
        }
      }

      return files;
    }

    public String getTorrentName() {
      return TorrentUtils.getLocalisedName(torrent);
    }

    public boolean allFilesMoving() {
      TorrentFileInfo[] files = getFiles();
      for (int j = 0; j < files.length; j++) {
        if (files[j].isLinked()) {
          return false;
        }
      }
      return true;
    }

    public boolean allFilesExist() {
      // check if all selected files exist
      TorrentFileInfo[] files = getFiles();
      for (int i = 0; i < files.length; i++) {
        TorrentFileInfo fileInfo = files[i];
        if (!fileInfo.bDownload)
          continue;

        File file = fileInfo.getDestFileFullName();
        if (!file.exists() || file.length() != fileInfo.lSize) {
          return false;
        }
      }
      return true;
    }

    public void renameDuplicates() {
      if (iStartID == STARTMODE_SEEDING
          || !COConfigurationManager.getBooleanParameter("DefaultDir.AutoSave.AutoRename")
          || allFilesExist()) {
        return;
      }

      if (!torrent.isSimpleTorrent()) {
        if (new File(getDataDir()).isDirectory()) {
          File f;
          int idx = 0;
          do {
            idx++;
            f = new File(getDataDir() + "-" + idx);
          } while (f.isDirectory());

          sDestSubDir = f.getName();
        }
      } else {
        // should only be one file
        TorrentFileInfo[] fileInfos = getFiles();
        for (int i = 0; i < fileInfos.length; i++) {
          TorrentFileInfo info = fileInfos[i];

          File file = info.getDestFileFullName();
          int idx = 0;
          while (file.exists()) {
            idx++;
            file = new File(info.getDestPathName(), idx + "-" + info.getDestFileName());
          }

          info.setDestFileName(file.getName());
        }
      }
    }

    /*
    private Boolean has_multiple_small_files = null;
    private boolean hasMultipleSmallFiles() {
      TorrentFileInfo[] tfi_files = getFiles();
      if (tfi_files.length <= MAX_NODOWNLOAD_COUNT)
        return false;
     
      int small_files_counted = 0;
      for (int i=0; i<tfi_files.length; i++) {
        if (tfi_files[i].lSize < MIN_NODOWNLOAD_SIZE) {
          small_files_counted++;
          if (small_files_counted > MAX_NODOWNLOAD_COUNT) {
            return true;
          }
        }
      }
     
      return false;
    }
    */

    // Indicates whether all files in this torrent can be deselected
    // (if not, then it occurs on a per-file basis).
    public boolean okToDisableAll() {
      return true;

      /*
      if (iStartID == STARTMODE_SEEDING)
        return true;
     
      // Do we have multiple small files? We'll allow all of them to
      // be disabled if we do.
      if (has_multiple_small_files == null) {
        has_multiple_small_files = new Boolean(hasMultipleSmallFiles());
      }
     
      // You can disable all files if there are lots of small files.
      return has_multiple_small_files.booleanValue();
      */
    }

  }

  /**
   * Class to store the file list of a Torrent.  Used to populate table and
   * store user's choices
   */
  private class TorrentFileInfo
  {
    /** relative path + full file name as specified by the torrent */
    final String orgFullName;
   
    final String orgFileName;

    long lSize;

    boolean bDownload;

    private String destFileName;
    private String destPathName;

    long iIndex;

    boolean isValid;

    final TorrentInfo parent;

    /**
     * Init
     *
     * @param parent
     * @param torrentFile
     * @param iIndex
     */
    public TorrentFileInfo(TorrentInfo parent, TOTorrentFile torrentFile,
        int iIndex) {
      this.parent = parent;
      lSize = torrentFile.getLength();
      this.iIndex = iIndex;
      bDownload = true;
      isValid = true;

      orgFullName = torrentFile.getRelativePath(); // translated to locale
      orgFileName = new File(orgFullName).getName();
    }
   
    public void setFullDestName(String newFullName)
    {
      if(newFullName == null)
      {
        setDestPathName(null);
        setDestFileName(null);
        return;
      }
       
      File newPath = new File(newFullName);
      setDestPathName(newPath.getParent());
      setDestFileName(newPath.getName());
    }
   
    public void setDestPathName(String newPath)
    {
      if(parent.torrent.isSimpleTorrent())
        parent.setParentDir(newPath);
      else
        destPathName = newPath;
    }
   
    public void setDestFileName (String newFileName)
    {
      if(orgFileName.equals(newFileName))
        destFileName = null;
      else
        destFileName = newFileName;     
    }

    public String getDestPathName() {
      if (destPathName != null)
        return destPathName;

      if (parent.torrent.isSimpleTorrent())
        return parent.getParentDir();

      return new File(parent.getDataDir(), orgFullName).getParent();
    }
   
    public String getDestFileName() {
      return destFileName == null ? orgFileName : destFileName;
    }

    public File getDestFileFullName() {
      String path = getDestPathName();
      String file = getDestFileName();
      return new File(path,file);
    }

    public boolean okToDisable() {
      return /* lSize >= MIN_NODOWNLOAD_SIZE  || */parent.okToDisableAll();
    }
   
    public boolean isLinked()
    {
      return destFileName != null || destPathName != null;
    }
  }

  private String ensureTrailingSeparator(String sPath) {
    if (sPath == null || sPath.length() == 0 || sPath.endsWith(File.separator))
      return sPath;
    return sPath + File.separator;
  }

  /**
   *
   * @return Null if user doesn't want to save silently, or if no path set
   */
  private static String getSaveSilentlyDir() {
    boolean bUseDefault = COConfigurationManager.getBooleanParameter("Use default data dir");
    if (!bUseDefault)
      return null;

    String sDefDir = "";
    try {
      sDefDir = COConfigurationManager.getDirectoryParameter(PARAM_DEFSAVEPATH);
    } catch (IOException e) {
      return null;
    }

    return (sDefDir == "") ? null : sDefDir;
  }

  private final static class Partition
  {
    public Partition(File root) {
      this.root = root;
    }

    long bytesToConsume = 0;

    long freeSpace = 0;

    final File root;
  }

  private final static class FileStatsCacheItem
  {
    public FileStatsCacheItem(final File f) {
      exists = f.exists();
      if (exists)
        freeSpace = FileUtil.getUsableSpace(f);
      else
        freeSpace = -1;
    }

    boolean exists;

    long freeSpace;
  }

  private long getCachedDirFreeSpace(File directory) {
    FileStatsCacheItem item = (FileStatsCacheItem) fileStatCache.get(directory);
    if (item == null)
      fileStatCache.put(directory, item = new FileStatsCacheItem(directory));
    return item.freeSpace;
  }

  private boolean getCachedExistsStat(File directory) {
    FileStatsCacheItem item = (FileStatsCacheItem) fileStatCache.get(directory);
    if (item == null)
      fileStatCache.put(directory, item = new FileStatsCacheItem(directory));
    return item.exists;
  }

  private final Map fileStatCache = new WeakHashMap(20);

  private final Map parentToRootCache = new WeakHashMap(20);

  private volatile boolean diskFreeInfoRefreshPending = false;

  private volatile boolean diskFreeInfoRefreshRunning = false;

  // @see com.aelitis.azureus.ui.swt.uiupdater.UIUpdatable#getUpdateUIName()
  public String getUpdateUIName() {
    return "OpenTorrentWindow";
  }

  // @see com.aelitis.azureus.ui.swt.uiupdater.UIUpdatable#updateUI()
  public void updateUI() {
    if (bClosed) {
      try {
        UIUpdaterSWT.getInstance().removeUpdater(this);
      } catch (Exception e) {
        Debug.out(e);
      }
      return;
    }

    if (diskFreeInfoRefreshPending && !diskFreeInfoRefreshRunning
        && FileUtil.getUsableSpaceSupported()) {
      diskFreeInfoRefreshRunning = true;
      diskFreeInfoRefreshPending = false;

      final HashSet FSroots = new HashSet(Arrays.asList(File.listRoots()));
      final HashMap partitions = new HashMap();

      for (int i = 0; i < torrentList.size(); i++) {
        TorrentInfo tor = (TorrentInfo) torrentList.get(i);
        TorrentFileInfo[] files = tor.getFiles();
        for (int j = 0; j < files.length; j++) {
          TorrentFileInfo file = files[j];
          if (!file.bDownload)
            continue;

          // reduce each file to its partition root
          File root = file.getDestFileFullName().getAbsoluteFile();

          Partition part = (Partition) partitions.get((File) parentToRootCache.get(root.getParentFile()));

          if (part == null) {
            File next;
            while (true) {
              root = root.getParentFile();
              next = root.getParentFile();
              if (next == null)
                break;

              // bubble up until we hit an existing directory
              if (!getCachedExistsStat(root) || !root.isDirectory())
                continue;

              // check for mount points (different free space) or simple loops in the directory structure
              if (FSroots.contains(root) || root.equals(next)
                  || getCachedDirFreeSpace(next) != getCachedDirFreeSpace(root))
                break;
            }

            parentToRootCache.put(
                file.getDestFileFullName().getAbsoluteFile().getParentFile(), root);

            part = (Partition) partitions.get(root);

            if (part == null) {
              part = new Partition(root);
              part.freeSpace = getCachedDirFreeSpace(root);
              partitions.put(root, part);
            }
          }

          part.bytesToConsume += file.lSize;
        }
      }
      // clear child objects
      Control[] labels = diskspaceComp.getChildren();
      for (int i = 0; i < labels.length; i++)
        labels[i].dispose();

      // build labels
      Iterator it = partitions.values().iterator();
      while (it.hasNext()) {
        Partition part = (Partition) it.next();

        boolean filesTooBig = part.bytesToConsume > part.freeSpace;

        Label l;
        l = new Label(diskspaceComp, SWT.NONE);
        l.setForeground(filesTooBig ? Colors.colorError : null);
        l.setText(part.root.getPath());
        l.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
        l = new Label(diskspaceComp, SWT.NONE);
        l.setForeground(filesTooBig ? Colors.colorError : null);
        l.setText(MessageText.getString("OpenTorrentWindow.diskUsage",
            new String[] {
              DisplayFormatters.formatByteCountToKiBEtc(part.bytesToConsume),
              DisplayFormatters.formatByteCountToKiBEtc(part.freeSpace)
            }));
        l.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
      }

      diskspaceComp.update();
      diskspaceComp.getParent().getParent().getParent().layout(true, true);

      diskFreeInfoRefreshRunning = false;
    }

  }

  private void updateSize() {

    /*
     * determine info for selected torrents only
     */
    long totalSize = 0;
    long checkedSize = 0;

    for (int i = 0; i < dataFiles.size(); i++) {
      TorrentFileInfo file = (TorrentFileInfo) dataFiles.get(i);

      totalSize += file.lSize;

      if (file.bDownload) {
        checkedSize += file.lSize;
      }
    }

    // build string and set label
    if (totalSize == 0) {
      dataFileTableLabel.setText("");
    } else {
      dataFileTableLabel.setText(MessageText.getString(
          "OpenTorrentWindow.filesInfo", new String[] {
            DisplayFormatters.formatByteCountToKiBEtc(checkedSize),
            DisplayFormatters.formatByteCountToKiBEtc(totalSize)
          }));
    }
    dataFileTableLabel.update();
    dataFileTableLabel.getParent().getParent().layout(true, true);

    diskFreeInfoRefreshPending = true;

  }

  /**
   * Convenience method for setting the enabled state of a control
   * <P>This method may be called from any thread</p>
   * @param control
   * @param enabledState
   */
  private void enableControl(final Control control, final boolean enabledState) {
    Utils.execSWTThread(new AERunnable() {
      public void runSupport() {
        if (control != null && false == control.isDisposed()) {
          control.setEnabled(enabledState);
        }
      }
    });
  }

  public static void main(String[] args) {
    AzureusCore core = AzureusCoreFactory.create();
    core.start();
    Display display = Display.getDefault();

    Colors.getInstance();

    invoke(null, core.getGlobalManager());
    //OpenTorrentWindow window = new OpenTorrentWindow(null, null, true);
    while (stOpenTorrentWindow != null && !stOpenTorrentWindow.bClosed) {
      if (!display.readAndDispatch())
        display.sleep();
    }

    core.stop();
  }
}
TOP

Related Classes of org.gudy.azureus2.ui.swt.OpenTorrentWindow$Partition

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.
reate', 'UA-20639858-1', 'auto'); ga('send', 'pageview');