1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the examples of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
44 #include "addtorrentdialog.h"
45 #include "mainwindow.h"
46 #include "ratecontroller.h"
47 #include "torrentclient.h"
49 // TorrentView extends QTreeWidget to allow drag and drop.
50 class TorrentView
: public QTreeWidget
54 TorrentView(QWidget
*parent
= 0);
57 void fileDropped(const QString
&fileName
);
60 void dragMoveEvent(QDragMoveEvent
*event
);
61 void dropEvent(QDropEvent
*event
);
64 // TorrentViewDelegate is used to draw the progress bars.
65 class TorrentViewDelegate
: public QItemDelegate
69 inline TorrentViewDelegate(MainWindow
*mainWindow
) : QItemDelegate(mainWindow
) {}
71 inline void paint(QPainter
*painter
, const QStyleOptionViewItem
&option
,
72 const QModelIndex
&index
) const
74 if (index
.column() != 2) {
75 QItemDelegate::paint(painter
, option
, index
);
79 // Set up a QStyleOptionProgressBar to precisely mimic the
80 // environment of a progress bar.
81 QStyleOptionProgressBar progressBarOption
;
82 progressBarOption
.state
= QStyle::State_Enabled
;
83 progressBarOption
.direction
= QApplication::layoutDirection();
84 progressBarOption
.rect
= option
.rect
;
85 progressBarOption
.fontMetrics
= QApplication::fontMetrics();
86 progressBarOption
.minimum
= 0;
87 progressBarOption
.maximum
= 100;
88 progressBarOption
.textAlignment
= Qt::AlignCenter
;
89 progressBarOption
.textVisible
= true;
91 // Set the progress and text values of the style option.
92 int progress
= qobject_cast
<MainWindow
*>(parent())->clientForRow(index
.row())->progress();
93 progressBarOption
.progress
= progress
< 0 ? 0 : progress
;
94 progressBarOption
.text
= QString().sprintf("%d%%", progressBarOption
.progress
);
96 // Draw the progress bar onto the view.
97 QApplication::style()->drawControl(QStyle::CE_ProgressBar
, &progressBarOption
, painter
);
101 MainWindow::MainWindow(QWidget
*parent
)
102 : QMainWindow(parent
), quitDialog(0), saveChanges(false)
104 // Initialize some static strings
106 headers
<< tr("Torrent") << tr("Peers/Seeds") << tr("Progress")
107 << tr("Down rate") << tr("Up rate") << tr("Status");
110 torrentView
= new TorrentView(this);
111 torrentView
->setItemDelegate(new TorrentViewDelegate(this));
112 torrentView
->setHeaderLabels(headers
);
113 torrentView
->setSelectionBehavior(QAbstractItemView::SelectRows
);
114 torrentView
->setAlternatingRowColors(true);
115 torrentView
->setRootIsDecorated(false);
116 setCentralWidget(torrentView
);
118 // Set header resize modes and initial section sizes
119 QFontMetrics fm
= fontMetrics();
120 QHeaderView
*header
= torrentView
->header();
121 header
->resizeSection(0, fm
.width("typical-name-for-a-torrent.torrent"));
122 header
->resizeSection(1, fm
.width(headers
.at(1) + " "));
123 header
->resizeSection(2, fm
.width(headers
.at(2) + " "));
124 header
->resizeSection(3, qMax(fm
.width(headers
.at(3) + " "), fm
.width(" 1234.0 KB/s ")));
125 header
->resizeSection(4, qMax(fm
.width(headers
.at(4) + " "), fm
.width(" 1234.0 KB/s ")));
126 header
->resizeSection(5, qMax(fm
.width(headers
.at(5) + " "), fm
.width(tr("Downloading") + " ")));
128 // Create common actions
129 QAction
*newTorrentAction
= new QAction(QIcon(":/icons/bottom.png"), tr("Add &new torrent"), this);
130 pauseTorrentAction
= new QAction(QIcon(":/icons/player_pause.png"), tr("&Pause torrent"), this);
131 removeTorrentAction
= new QAction(QIcon(":/icons/player_stop.png"), tr("&Remove torrent"), this);
134 QMenu
*fileMenu
= menuBar()->addMenu(tr("&File"));
135 fileMenu
->addAction(newTorrentAction
);
136 fileMenu
->addAction(pauseTorrentAction
);
137 fileMenu
->addAction(removeTorrentAction
);
138 fileMenu
->addSeparator();
139 fileMenu
->addAction(QIcon(":/icons/exit.png"), tr("E&xit"), this, SLOT(close()));
142 QMenu
*helpMenu
= menuBar()->addMenu(tr("&Help"));
143 helpMenu
->addAction(tr("&About"), this, SLOT(about()));
144 helpMenu
->addAction(tr("About &Qt"), qApp
, SLOT(aboutQt()));
147 QToolBar
*topBar
= new QToolBar(tr("Tools"));
148 addToolBar(Qt::TopToolBarArea
, topBar
);
149 topBar
->setMovable(false);
150 topBar
->addAction(newTorrentAction
);
151 topBar
->addAction(removeTorrentAction
);
152 topBar
->addAction(pauseTorrentAction
);
153 topBar
->addSeparator();
154 downActionTool
= topBar
->addAction(QIcon(tr(":/icons/1downarrow.png")), tr("Move down"));
155 upActionTool
= topBar
->addAction(QIcon(tr(":/icons/1uparrow.png")), tr("Move up"));
158 QToolBar
*bottomBar
= new QToolBar(tr("Rate control"));
159 addToolBar(Qt::BottomToolBarArea
, bottomBar
);
160 bottomBar
->setMovable(false);
161 downloadLimitSlider
= new QSlider(Qt::Horizontal
);
162 downloadLimitSlider
->setRange(0, 1000);
163 bottomBar
->addWidget(new QLabel(tr("Max download:")));
164 bottomBar
->addWidget(downloadLimitSlider
);
165 bottomBar
->addWidget((downloadLimitLabel
= new QLabel(tr("0 KB/s"))));
166 downloadLimitLabel
->setFixedSize(QSize(fm
.width(tr("99999 KB/s")), fm
.lineSpacing()));
167 bottomBar
->addSeparator();
168 uploadLimitSlider
= new QSlider(Qt::Horizontal
);
169 uploadLimitSlider
->setRange(0, 1000);
170 bottomBar
->addWidget(new QLabel(tr("Max upload:")));
171 bottomBar
->addWidget(uploadLimitSlider
);
172 bottomBar
->addWidget((uploadLimitLabel
= new QLabel(tr("0 KB/s"))));
173 uploadLimitLabel
->setFixedSize(QSize(fm
.width(tr("99999 KB/s")), fm
.lineSpacing()));
175 // Set up connections
176 connect(torrentView
, SIGNAL(itemSelectionChanged()),
177 this, SLOT(setActionsEnabled()));
178 connect(torrentView
, SIGNAL(fileDropped(const QString
&)),
179 this, SLOT(acceptFileDrop(const QString
&)));
180 connect(uploadLimitSlider
, SIGNAL(valueChanged(int)),
181 this, SLOT(setUploadLimit(int)));
182 connect(downloadLimitSlider
, SIGNAL(valueChanged(int)),
183 this, SLOT(setDownloadLimit(int)));
184 connect(newTorrentAction
, SIGNAL(triggered()),
185 this, SLOT(addTorrent()));
186 connect(pauseTorrentAction
, SIGNAL(triggered()),
187 this, SLOT(pauseTorrent()));
188 connect(removeTorrentAction
, SIGNAL(triggered()),
189 this, SLOT(removeTorrent()));
190 connect(upActionTool
, SIGNAL(triggered(bool)),
191 this, SLOT(moveTorrentUp()));
192 connect(downActionTool
, SIGNAL(triggered(bool)),
193 this, SLOT(moveTorrentDown()));
195 // Load settings and start
196 setWindowTitle(tr("Torrent Client"));
198 QMetaObject::invokeMethod(this, "loadSettings", Qt::QueuedConnection
);
201 QSize
MainWindow::sizeHint() const
203 const QHeaderView
*header
= torrentView
->header();
205 // Add up the sizes of all header sections. The last section is
206 // stretched, so its size is relative to the size of the width;
207 // instead of counting it, we count the size of its largest value.
208 int width
= fontMetrics().width(tr("Downloading") + " ");
209 for (int i
= 0; i
< header
->count() - 1; ++i
)
210 width
+= header
->sectionSize(i
);
212 return QSize(width
, QMainWindow::sizeHint().height())
213 .expandedTo(QApplication::globalStrut());
216 const TorrentClient
*MainWindow::clientForRow(int row
) const
218 // Return the client at the given row.
219 return jobs
.at(row
).client
;
222 int MainWindow::rowOfClient(TorrentClient
*client
) const
224 // Return the row that displays this client's status, or -1 if the
225 // client is not known.
227 foreach (Job job
, jobs
) {
228 if (job
.client
== client
)
235 void MainWindow::loadSettings()
237 // Load base settings (last working directory, upload/download limits).
238 QSettings
settings("Trolltech", "Torrent");
239 lastDirectory
= settings
.value("LastDirectory").toString();
240 if (lastDirectory
.isEmpty())
241 lastDirectory
= QDir::currentPath();
242 int up
= settings
.value("UploadLimit").toInt();
243 int down
= settings
.value("DownloadLimit").toInt();
244 uploadLimitSlider
->setValue(up
? up
: 170);
245 downloadLimitSlider
->setValue(down
? down
: 550);
247 // Resume all previous downloads.
248 int size
= settings
.beginReadArray("Torrents");
249 for (int i
= 0; i
< size
; ++i
) {
250 settings
.setArrayIndex(i
);
251 QByteArray resumeState
= settings
.value("resumeState").toByteArray();
252 QString fileName
= settings
.value("sourceFileName").toString();
253 QString dest
= settings
.value("destinationFolder").toString();
255 if (addTorrent(fileName
, dest
, resumeState
)) {
256 TorrentClient
*client
= jobs
.last().client
;
257 client
->setDownloadedBytes(settings
.value("downloadedBytes").toLongLong());
258 client
->setUploadedBytes(settings
.value("uploadedBytes").toLongLong());
263 bool MainWindow::addTorrent()
265 // Show the file dialog, let the user select what torrent to start downloading.
266 QString fileName
= QFileDialog::getOpenFileName(this, tr("Choose a torrent file"),
268 tr("Torrents (*.torrent);;"
269 " All files (*.*)"));
270 if (fileName
.isEmpty())
272 lastDirectory
= QFileInfo(fileName
).absolutePath();
274 // Show the "Add Torrent" dialog.
275 AddTorrentDialog
*addTorrentDialog
= new AddTorrentDialog(this);
276 addTorrentDialog
->setTorrent(fileName
);
277 addTorrentDialog
->deleteLater();
278 if (!addTorrentDialog
->exec())
281 // Add the torrent to our list of downloads
282 addTorrent(fileName
, addTorrentDialog
->destinationFolder());
285 QTimer::singleShot(1000, this, SLOT(saveSettings()));
290 void MainWindow::removeTorrent()
292 // Find the row of the current item, and find the torrent client
294 int row
= torrentView
->indexOfTopLevelItem(torrentView
->currentItem());
295 TorrentClient
*client
= jobs
.at(row
).client
;
298 client
->disconnect();
299 connect(client
, SIGNAL(stopped()), this, SLOT(torrentStopped()));
302 // Remove the row from the view.
303 delete torrentView
->takeTopLevelItem(row
);
311 void MainWindow::torrentStopped()
313 // Schedule the client for deletion.
314 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
315 client
->deleteLater();
317 // If the quit dialog is shown, update its progress.
319 if (++jobsStopped
== jobsToStop
)
324 void MainWindow::torrentError(TorrentClient::Error
)
326 // Delete the client.
327 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
328 int row
= rowOfClient(client
);
329 QString fileName
= jobs
.at(row
).torrentFileName
;
332 // Display the warning.
333 QMessageBox::warning(this, tr("Error"),
334 tr("An error occurred while downloading %0: %1")
336 .arg(client
->errorString()));
338 delete torrentView
->takeTopLevelItem(row
);
339 client
->deleteLater();
342 bool MainWindow::addTorrent(const QString
&fileName
, const QString
&destinationFolder
,
343 const QByteArray
&resumeState
)
345 // Check if the torrent is already being downloaded.
346 foreach (Job job
, jobs
) {
347 if (job
.torrentFileName
== fileName
&& job
.destinationDirectory
== destinationFolder
) {
348 QMessageBox::warning(this, tr("Already downloading"),
349 tr("The torrent file %1 is "
350 "already being downloaded.").arg(fileName
));
355 // Create a new torrent client and attempt to parse the torrent data.
356 TorrentClient
*client
= new TorrentClient(this);
357 if (!client
->setTorrent(fileName
)) {
358 QMessageBox::warning(this, tr("Error"),
359 tr("The torrent file %1 cannot not be opened/resumed.").arg(fileName
));
363 client
->setDestinationFolder(destinationFolder
);
364 client
->setDumpedState(resumeState
);
366 // Setup the client connections.
367 connect(client
, SIGNAL(stateChanged(TorrentClient::State
)), this, SLOT(updateState(TorrentClient::State
)));
368 connect(client
, SIGNAL(peerInfoUpdated()), this, SLOT(updatePeerInfo()));
369 connect(client
, SIGNAL(progressUpdated(int)), this, SLOT(updateProgress(int)));
370 connect(client
, SIGNAL(downloadRateUpdated(int)), this, SLOT(updateDownloadRate(int)));
371 connect(client
, SIGNAL(uploadRateUpdated(int)), this, SLOT(updateUploadRate(int)));
372 connect(client
, SIGNAL(stopped()), this, SLOT(torrentStopped()));
373 connect(client
, SIGNAL(error(TorrentClient::Error
)), this, SLOT(torrentError(TorrentClient::Error
)));
375 // Add the client to the list of downloading jobs.
378 job
.torrentFileName
= fileName
;
379 job
.destinationDirectory
= destinationFolder
;
382 // Create and add a row in the torrent view for this download.
383 QTreeWidgetItem
*item
= new QTreeWidgetItem(torrentView
);
385 QString baseFileName
= QFileInfo(fileName
).fileName();
386 if (baseFileName
.toLower().endsWith(".torrent"))
387 baseFileName
.remove(baseFileName
.size() - 8);
389 item
->setText(0, baseFileName
);
390 item
->setToolTip(0, tr("Torrent: %1<br>Destination: %2")
391 .arg(baseFileName
).arg(destinationFolder
));
392 item
->setText(1, tr("0/0"));
393 item
->setText(2, "0");
394 item
->setText(3, "0.0 KB/s");
395 item
->setText(4, "0.0 KB/s");
396 item
->setText(5, tr("Idle"));
397 item
->setFlags(item
->flags() & ~Qt::ItemIsEditable
);
398 item
->setTextAlignment(1, Qt::AlignHCenter
);
402 QTimer::singleShot(5000, this, SLOT(saveSettings()));
408 void MainWindow::saveSettings()
414 // Prepare and reset the settings
415 QSettings
settings("Trolltech", "Torrent");
418 settings
.setValue("LastDirectory", lastDirectory
);
419 settings
.setValue("UploadLimit", uploadLimitSlider
->value());
420 settings
.setValue("DownloadLimit", downloadLimitSlider
->value());
422 // Store data on all known torrents
423 settings
.beginWriteArray("Torrents");
424 for (int i
= 0; i
< jobs
.size(); ++i
) {
425 settings
.setArrayIndex(i
);
426 settings
.setValue("sourceFileName", jobs
.at(i
).torrentFileName
);
427 settings
.setValue("destinationFolder", jobs
.at(i
).destinationDirectory
);
428 settings
.setValue("uploadedBytes", jobs
.at(i
).client
->uploadedBytes());
429 settings
.setValue("downloadedBytes", jobs
.at(i
).client
->downloadedBytes());
430 settings
.setValue("resumeState", jobs
.at(i
).client
->dumpedState());
436 void MainWindow::updateState(TorrentClient::State
)
438 // Update the state string whenever the client's state changes.
439 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
440 int row
= rowOfClient(client
);
441 QTreeWidgetItem
*item
= torrentView
->topLevelItem(row
);
443 item
->setToolTip(0, tr("Torrent: %1<br>Destination: %2<br>State: %3")
444 .arg(jobs
.at(row
).torrentFileName
)
445 .arg(jobs
.at(row
).destinationDirectory
)
446 .arg(client
->stateString()));
448 item
->setText(5, client
->stateString());
453 void MainWindow::updatePeerInfo()
455 // Update the number of connected, visited, seed and leecher peers.
456 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
457 int row
= rowOfClient(client
);
459 QTreeWidgetItem
*item
= torrentView
->topLevelItem(row
);
460 item
->setText(1, tr("%1/%2").arg(client
->connectedPeerCount())
461 .arg(client
->seedCount()));
464 void MainWindow::updateProgress(int percent
)
466 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
467 int row
= rowOfClient(client
);
469 // Update the progressbar.
470 QTreeWidgetItem
*item
= torrentView
->topLevelItem(row
);
472 item
->setText(2, QString::number(percent
));
475 void MainWindow::setActionsEnabled()
477 // Find the view item and client for the current row, and update
478 // the states of the actions.
479 QTreeWidgetItem
*item
= 0;
480 if (!torrentView
->selectedItems().isEmpty())
481 item
= torrentView
->selectedItems().first();
482 TorrentClient
*client
= item
? jobs
.at(torrentView
->indexOfTopLevelItem(item
)).client
: 0;
483 bool pauseEnabled
= client
&& ((client
->state() == TorrentClient::Paused
)
484 || (client
->state() > TorrentClient::Preparing
));
486 removeTorrentAction
->setEnabled(item
!= 0);
487 pauseTorrentAction
->setEnabled(item
!= 0 && pauseEnabled
);
489 if (client
&& client
->state() == TorrentClient::Paused
) {
490 pauseTorrentAction
->setIcon(QIcon(":/icons/player_play.png"));
491 pauseTorrentAction
->setText(tr("Resume torrent"));
493 pauseTorrentAction
->setIcon(QIcon(":/icons/player_pause.png"));
494 pauseTorrentAction
->setText(tr("Pause torrent"));
497 int row
= torrentView
->indexOfTopLevelItem(item
);
498 upActionTool
->setEnabled(item
&& row
!= 0);
499 downActionTool
->setEnabled(item
&& row
!= jobs
.size() - 1);
502 void MainWindow::updateDownloadRate(int bytesPerSecond
)
504 // Update the download rate.
505 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
506 int row
= rowOfClient(client
);
508 num
.sprintf("%.1f KB/s", bytesPerSecond
/ 1024.0);
509 torrentView
->topLevelItem(row
)->setText(3, num
);
513 QTimer::singleShot(5000, this, SLOT(saveSettings()));
517 void MainWindow::updateUploadRate(int bytesPerSecond
)
519 // Update the upload rate.
520 TorrentClient
*client
= qobject_cast
<TorrentClient
*>(sender());
521 int row
= rowOfClient(client
);
523 num
.sprintf("%.1f KB/s", bytesPerSecond
/ 1024.0);
524 torrentView
->topLevelItem(row
)->setText(4, num
);
528 QTimer::singleShot(5000, this, SLOT(saveSettings()));
532 void MainWindow::pauseTorrent()
534 // Pause or unpause the current torrent.
535 int row
= torrentView
->indexOfTopLevelItem(torrentView
->currentItem());
536 TorrentClient
*client
= jobs
.at(row
).client
;
537 client
->setPaused(client
->state() != TorrentClient::Paused
);
541 void MainWindow::moveTorrentUp()
543 QTreeWidgetItem
*item
= torrentView
->currentItem();
544 int row
= torrentView
->indexOfTopLevelItem(item
);
548 Job tmp
= jobs
.at(row
- 1);
549 jobs
[row
- 1] = jobs
[row
];
552 QTreeWidgetItem
*itemAbove
= torrentView
->takeTopLevelItem(row
- 1);
553 torrentView
->insertTopLevelItem(row
, itemAbove
);
557 void MainWindow::moveTorrentDown()
559 QTreeWidgetItem
*item
= torrentView
->currentItem();
560 int row
= torrentView
->indexOfTopLevelItem(item
);
561 if (row
== jobs
.size() - 1)
564 Job tmp
= jobs
.at(row
+ 1);
565 jobs
[row
+ 1] = jobs
[row
];
568 QTreeWidgetItem
*itemAbove
= torrentView
->takeTopLevelItem(row
+ 1);
569 torrentView
->insertTopLevelItem(row
, itemAbove
);
573 static int rateFromValue(int value
)
576 if (value
>= 0 && value
< 250) {
577 rate
= 1 + int(value
* 0.124);
578 } else if (value
< 500) {
579 rate
= 32 + int((value
- 250) * 0.384);
580 } else if (value
< 750) {
581 rate
= 128 + int((value
- 500) * 1.536);
583 rate
= 512 + int((value
- 750) * 6.1445);
588 void MainWindow::setUploadLimit(int value
)
590 int rate
= rateFromValue(value
);
591 uploadLimitLabel
->setText(tr("%1 KB/s").arg(QString().sprintf("%4d", rate
)));
592 RateController::instance()->setUploadLimit(rate
* 1024);
595 void MainWindow::setDownloadLimit(int value
)
597 int rate
= rateFromValue(value
);
598 downloadLimitLabel
->setText(tr("%1 KB/s").arg(QString().sprintf("%4d", rate
)));
599 RateController::instance()->setDownloadLimit(rate
* 1024);
602 void MainWindow::about()
604 QLabel
*icon
= new QLabel
;
605 icon
->setPixmap(QPixmap(":/icons/peertopeer.png"));
607 QLabel
*text
= new QLabel
;
608 text
->setWordWrap(true);
609 text
->setText("<p>The <b>Torrent Client</b> example demonstrates how to"
610 " write a complete peer-to-peer file sharing"
611 " application using Qt's network and thread classes.</p>"
612 "<p>This feature complete client implementation of"
613 " the BitTorrent protocol can efficiently"
614 " maintain several hundred network connections"
615 " simultaneously.</p>");
617 QPushButton
*quitButton
= new QPushButton("OK");
619 QHBoxLayout
*topLayout
= new QHBoxLayout
;
620 topLayout
->setMargin(10);
621 topLayout
->setSpacing(10);
622 topLayout
->addWidget(icon
);
623 topLayout
->addWidget(text
);
625 QHBoxLayout
*bottomLayout
= new QHBoxLayout
;
626 bottomLayout
->addStretch();
627 bottomLayout
->addWidget(quitButton
);
628 bottomLayout
->addStretch();
630 QVBoxLayout
*mainLayout
= new QVBoxLayout
;
631 mainLayout
->addLayout(topLayout
);
632 mainLayout
->addLayout(bottomLayout
);
635 about
.setModal(true);
636 about
.setWindowTitle(tr("About Torrent Client"));
637 about
.setLayout(mainLayout
);
639 connect(quitButton
, SIGNAL(clicked()), &about
, SLOT(close()));
644 void MainWindow::acceptFileDrop(const QString
&fileName
)
646 // Create and show the "Add Torrent" dialog.
647 AddTorrentDialog
*addTorrentDialog
= new AddTorrentDialog
;
648 lastDirectory
= QFileInfo(fileName
).absolutePath();
649 addTorrentDialog
->setTorrent(fileName
);
650 addTorrentDialog
->deleteLater();
651 if (!addTorrentDialog
->exec())
654 // Add the torrent to our list of downloads.
655 addTorrent(fileName
, addTorrentDialog
->destinationFolder());
659 void MainWindow::closeEvent(QCloseEvent
*)
664 // Save upload / download numbers.
668 quitDialog
= new QProgressDialog(tr("Disconnecting from trackers"), tr("Abort"), 0, jobsToStop
, this);
670 // Stop all clients, remove the rows from the view and wait for
671 // them to signal that they have stopped.
674 foreach (Job job
, jobs
) {
676 TorrentClient
*client
= job
.client
;
677 client
->disconnect();
678 connect(client
, SIGNAL(stopped()), this, SLOT(torrentStopped()));
680 delete torrentView
->takeTopLevelItem(0);
683 if (jobsToStop
> jobsStopped
)
685 quitDialog
->deleteLater();
689 TorrentView::TorrentView(QWidget
*parent
)
690 : QTreeWidget(parent
)
692 setAcceptDrops(true);
695 void TorrentView::dragMoveEvent(QDragMoveEvent
*event
)
697 // Accept file actions with a '.torrent' extension.
698 QUrl
url(event
->mimeData()->text());
699 if (url
.isValid() && url
.scheme().toLower() == "file"
700 && url
.path().toLower().endsWith(".torrent"))
701 event
->acceptProposedAction();
704 void TorrentView::dropEvent(QDropEvent
*event
)
706 // Accept drops if the file has a '.torrent' extension and it
708 QString fileName
= QUrl(event
->mimeData()->text()).path();
709 if (QFile::exists(fileName
) && fileName
.toLower().endsWith(".torrent"))
710 emit
fileDropped(fileName
);
713 #include "mainwindow.moc"