OpenTorrentWindow.java

Index Score
org.gudy.azureus2.ui.swt
Azureus

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
LOOPSNumber of loops
LOGICAL_LINESNumber of statements
CYCLOMATICCyclomatic complexity
COMPARISONSNumber of comparison operators
OPERATORSNumber of operators
PROGRAM_LENGTHHalstead program length
ELOCEffective lines of code
OPERANDSNumber of operands
JAVA0034JAVA0034 Missing braces in if statement
LOCLines of code
EXITSProcedure exits
SIZESize of the file in bytes
LINESNumber of lines in the source file
LINE_COMMENTNumber of line comments
EXEC_COMMENTSComments in executable code
BLOCKSNumber of blocks
UNIQUE_OPERANDSNumber of unique operands
JAVA0145JAVA0145 Tab character used in source file
PROGRAM_VOCABHalstead program vocabulary
RETURNSNumber of return points from functions
WHITESPACENumber of whitespace lines
INTERFACE_COMPLEXITYInterface complexity
FUNCTIONSNumber of function declarations
JAVA0270JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
PARAMSNumber of formal parameter declarations
JAVA0177JAVA0177 Variable declaration missing initializer
JAVA0068JAVA0068 Modifiers not declared in recommended order
DECL_COMMENTSComments in declarations
JAVA0166JAVA0166 Generic exception caught
JAVA0049JAVA0049 Nested block at depth N (maximum: M)
JAVA0117JAVA0117 Missing javadoc: method 'method'
COMMENTSComment lines
JAVA0076JAVA0076 Use of magic number
JAVA0035JAVA0035 Missing braces in for statement
JAVA0128JAVA0128 Public constructor in non-public class
JAVA0254JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0071JAVA0071 Strings compared with ==
JAVA0143JAVA0143 Synchronized method
JAVA0130JAVA0130 Non-static method does not use instance fields
JAVA0179JAVA0179 Local variable hides visible field
JAVA0265JAVA0265 Use of Throwable.printStackTrace()
JAVA0039JAVA0039 Break statement with label
JAVA0008JAVA0008 Empty catch block
UNIQUE_OPERATORSNumber of unique operators
JAVA0119JAVA0119 Control variable changed within body of for loop
JAVA0077JAVA0077 Private field not used in declaring class
NEST_DEPTHMaximum nesting depth
JAVA0081JAVA0081 Boolean literal in comparison
DOC_COMMENTNumber of javadoc comment lines
JAVA0100JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0096JAVA0096 Field in nested class hides outer field
PROGRAM_VOLUMEHalstead program volume
JAVA0136JAVA0136 N methods defined in class (maximum: M)
JAVA0126JAVA0126 Method declares unchecked exception in throws
JAVA0110JAVA0110 Incorrect javadoc: no @return tag
JAVA0043JAVA0043 Inner class does not use outer class
JAVA0030JAVA0030 Private field not used
JAVA0287JAVA0287 Unnecessary null check
/* * 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.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Rectangle; 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.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.MessageSlideShell; import com.aelitis.azureus.core.AzureusCore; import com.aelitis.azureus.core.AzureusCoreFactory; import com.aelitis.azureus.ui.UIFunctionsManager; import com.aelitis.azureus.ui.common.updater.UIUpdatable; /** * 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 = Constants.isWindows ? 24 : -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 downloaders = new ArrayList(); 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 static final AzureusCore core; private StringList dirList; private Label dataFileTableLabel; private Composite diskspaceComp; static { if (!AzureusCoreFactory.isCoreAvailable()) { // This should be only called in test mode AzureusCore core2 = AzureusCoreFactory.create(); core2.start(); } core = AzureusCoreFactory.getSingleton(); } /** * 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) { // 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) { 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(); File file = new File(sDestDir); if (!file.isDirectory()) { cmbDataDir.setBackground(Colors.colorErrorBG); } else { cmbDataDir.setBackground(null); } cmbDataDir.redraw(); cmbDataDir.update(); diskFreeInfoRefreshPending = true; } }); updateDataDirCombo(); if (sDestDir != null && sDestDir.length() > 0) { cmbDataDir.add(sDestDir); } 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 { UIFunctionsManager.getUIFunctions().getUIUpdater().addUpdater(this); } catch (Exception e) { Debug.out(e); } } 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()) { int doCreate = Utils.openMessageBox(shellForChildren, SWT.YES | SWT.NO | SWT.ICON_QUESTION, "OpenTorrentWindow.mb.askCreateDir", new String[] { file.toString() }); if (doCreate == SWT.YES) isPathInvalid = !FileUtil.mkdirs(file); else { cmbDataDir.setFocus(); return; } } if (isPathInvalid) { Utils.openMessageBox(shellForChildren, SWT.OK | SWT.ICON_ERROR, "OpenTorrentWindow.mb.noGlobalDestDir", new String[] { file.toString() }); 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)) { Utils.openMessageBox(shellForChildren, SWT.OK | SWT.ICON_ERROR, "OpenTorrentWindow.mb.noDestDir", new String[] { file.toString(), info.getTorrentName() }); return; } if (!info.isValid) { Utils.openMessageBox(shellForChildren, SWT.OK | SWT.ICON_ERROR, "OpenTorrentWindow.mb.notValid", new String[] { info.getTorrentName() }); 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"; } if (Utils.openMessageBox(shellForChildren, SWT.OK | SWT.CANCEL | SWT.ICON_WARNING, "OpenTorrentWindow.mb.existingFiles", new String[] { sExistingFiles }) != 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) { 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(core, 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 { UIFunctionsManager.getUIFunctions().getUIUpdater().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 (downloaders.size() > 0) { for (Iterator iter = downloaders.iterator(); iter.hasNext();) { TorrentDownloader element = (TorrentDownloader) iter.next(); element.cancel(); } downloaders.clear(); } if (bCancel) { 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); 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) { 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); Button torMoveUp = new Button(cTorrentListRight, SWT.PUSH); torMoveUp.setImage(ImageRepository.getImage("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); torMoveDown.setImage(ImageRepository.getImage("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")); torMoveRemove.setImage(ImageRepository.getImage("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 Utils.openMessageBox(shellForChildren, SWT.OK, "OpenTorrentWindow.mb.badSize", new String[] { file.getName(), fileInfo.orgFullName }); } 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(core, shellForChildren, sURL, null, null, this); } else { new OpenUrlWindow(core, 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 { 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", "", new String[] { sOriginatingLocation, "Not a File" }, -1 ); else Utils.openMessageBox(shell, SWT.OK, "OpenTorrentWindow.mb.openError", new String[] { sOriginatingLocation, "Not a File" }); } }); 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); } // 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 Utils.openMessageBox(shell, SWT.OK, "OpenTorrentWindow.mb.openError", new String[] { sOriginatingLocation, e.getMessage() }); } }); 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() { if (shell == null) 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 Utils.openMessageBox(shell, SWT.OK, MSG_ALREADY_EXISTS, new String[] { ":" + sOriginatingLocation, sfExistingName, MessageText.getString(MSG_ALREADY_EXISTS_NAME), }); } }); 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() { 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(); try { dm.getDownloadState().suppressStateSave(true); boolean[] toSkip = new boolean[fileInfos.length]; boolean[] toCompact = new boolean[fileInfos.length]; for (int iIndex = 0; iIndex < fileInfos.length; iIndex++) { DiskManagerFileInfo fileInfo = fileInfos[iIndex]; if (iIndex >= 0 && iIndex < files.length && files[iIndex].lSize == fileInfo.getLength()) { File fDest = files[iIndex].getDestFileFullName(); if (files[iIndex].isLinked()) { // 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()) toCompact[iIndex] = true; } } } dm.getDiskManagerFileInfoSet().setStorageTypes(toCompact, DiskManagerFileInfo.ST_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 Utils.openMessageBox(shell, SWT.OK, "OpenTorrentWindow.mb.openError", new String[] { info.sOriginatingLocation, e.getMessage() }); } } 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); 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); downloaders.add(inf); } else if (state == TorrentDownloader.STATE_FINISHED) { activeTorrentCount--; enableControl(ok, activeTorrentCount < 1); // This can be called more than once for each inf.. 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); 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() { if (torrent == null) return ""; try { LocaleUtilDecoder decoder = LocaleTorrentUtil.getTorrentEncodingIfAvailable(torrent); if (decoder != null) return decoder.decodeString(torrent.getName()); } catch (Exception e) { } try { return new String(torrent.getName()); } catch (Exception e) { return "TextDecodingError"; } } 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 { UIFunctionsManager.getUIFunctions().getUIUpdater().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) { Display display = Display.getDefault(); ImageRepository.loadImages(display); 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(); } }

The table below shows all metrics for OpenTorrentWindow.java.

MetricValueDescription
BLOCKS364.00Number of blocks
BLOCK_COMMENT59.00Number of block comment lines
COMMENTS309.00Comment lines
COMMENT_DENSITY 0.16Comment density
COMPARISONS361.00Number of comparison operators
CYCLOMATIC510.00Cyclomatic complexity
DECL_COMMENTS41.00Comments in declarations
DOC_COMMENT138.00Number of javadoc comment lines
ELOC1896.00Effective lines of code
EXEC_COMMENTS72.00Comments in executable code
EXITS309.00Procedure exits
FUNCTIONS105.00Number of function declarations
HALSTEAD_DIFFICULTY140.88Halstead difficulty
HALSTEAD_EFFORT 0.00Halstead effort
INTERFACE_COMPLEXITY260.00Interface complexity
JAVA0001 1.00JAVA0001 Package name does not contain only lower case letters
JAVA0002 0.00JAVA0002 Package name does not begin with a top level domain name or country code
JAVA0003 0.00JAVA0003 Minimize use of on-demand (.*) imports
JAVA0004 0.00JAVA0004 Unnecessary import from java.lang
JAVA0005 0.00JAVA0005 Imports not in specified order
JAVA0006 0.00JAVA0006 Empty finally block
JAVA0007 0.00JAVA0007 Should not declare public field
JAVA0008 4.00JAVA0008 Empty catch block
JAVA0009 0.00JAVA0009 Protected member in final class
JAVA0010 0.00JAVA0010 Non-instantiable class does not contain a non-private static member
JAVA0011 0.00JAVA0011 Abstract class does not contain an abstract method
JAVA0012 0.00JAVA0012 Non-constructor method with same name as declaring class
JAVA0013 0.00JAVA0013 Non-blank final field is not static
JAVA0014 0.00JAVA0014 Class with only static members has non-private constructor
JAVA0015 0.00JAVA0015 Package class contains public nested type
JAVA0016 0.00JAVA0016 Abstract class contains public constructor
JAVA0017 0.00JAVA0017 Class name does not have required form
JAVA0018 0.00JAVA0018 Method name does not have required form
JAVA0019 0.00JAVA0019 Interface name does not have required form
JAVA0020 0.00JAVA0020 Field name does not have required form
JAVA0021 0.00JAVA0021 Interface method name does not have required form
JAVA0022 0.00JAVA0022 Static final field name does not have required form
JAVA0023 0.00JAVA0023 Empty finalize method
JAVA0024 0.00JAVA0024 Empty class
JAVA0025 0.00JAVA0025 Method override is empty
JAVA0026 0.00JAVA0026 Finalize method with parameters
JAVA0029 0.00JAVA0029 Private method not used
JAVA0030 1.00JAVA0030 Private field not used
JAVA0031 0.00JAVA0031 Case statement not properly closed
JAVA0032 0.00JAVA0032 Switch statement missing default
JAVA0033 0.00JAVA0033 default: not last case in switch statement
JAVA0034107.00JAVA0034 Missing braces in if statement
JAVA0035 5.00JAVA0035 Missing braces in for statement
JAVA0036 0.00JAVA0036 Missing braces in while statement
JAVA0038 0.00JAVA0038 Non-case label in switch statement
JAVA0039 1.00JAVA0039 Break statement with label
JAVA0040 0.00JAVA0040 Switch statement contains N cases (maximum: M)
JAVA0041 0.00JAVA0041 Nested synchronized block
JAVA0042 0.00JAVA0042 Empty synchronized statement
JAVA0043 1.00JAVA0043 Inner class does not use outer class
JAVA0044 0.00JAVA0044 Serializable class with no instance variables
JAVA0045 0.00JAVA0045 Serializable class with only transient fields
JAVA0046 0.00JAVA0046 Name of class not derived from Exception ends with 'Exception'
JAVA0047 0.00JAVA0047 Serializable class derives from invalid base class
JAVA0048 0.00JAVA0048 Name of class derived from Exception does not end with 'Exception'
JAVA0049 9.00JAVA0049 Nested block at depth N (maximum: M)
JAVA0050 0.00JAVA0050 Class derives from java.lang.Error
JAVA0051 0.00JAVA0051 Class derives from java.lang.RuntimeException
JAVA0052 0.00JAVA0052 Class derives from java.lang.Throwable
JAVA0053 0.00JAVA0053 Unused label
JAVA0054 0.00JAVA0054 Inheritance depth N exceeds maximum M
JAVA0055 0.00JAVA0055 Class should be interface
JAVA0056 0.00JAVA0056 Unnecessary abstract modifier for interface or annotation
JAVA0057 0.00JAVA0057 Unnecessary default constructor
JAVA0058 0.00JAVA0058 Constructor calls super()
JAVA0059 0.00JAVA0059 Method override only calls super()
JAVA0061 0.00JAVA0061 Inaccessible member in anonymous class
JAVA0062 0.00JAVA0062 Public class missing public member or protected constructor
JAVA0063 0.00JAVA0063 Identifier name should not contain '$'
JAVA0064 0.00JAVA0064 N variations of identifier name (maximum: M)
JAVA0065