Fix silly error in bit fiddling
[qt-netbsd.git] / examples / network / torrent / mainwindow.cpp
blobf38682e1fddfede75e3ebdd7665ce247c6345c04
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the examples of the Qt Toolkit.
8 **
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
14 ** this package.
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.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include <QtGui>
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
52 Q_OBJECT
53 public:
54 TorrentView(QWidget *parent = 0);
56 signals:
57 void fileDropped(const QString &fileName);
59 protected:
60 void dragMoveEvent(QDragMoveEvent *event);
61 void dropEvent(QDropEvent *event);
64 // TorrentViewDelegate is used to draw the progress bars.
65 class TorrentViewDelegate : public QItemDelegate
67 Q_OBJECT
68 public:
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);
76 return;
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
105 QStringList headers;
106 headers << tr("Torrent") << tr("Peers/Seeds") << tr("Progress")
107 << tr("Down rate") << tr("Up rate") << tr("Status");
109 // Main torrent list
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);
133 // File menu
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()));
141 // Help menu
142 QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
143 helpMenu->addAction(tr("&About"), this, SLOT(about()));
144 helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
146 // Top toolbar
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"));
157 // Bottom toolbar
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"));
197 setActionsEnabled();
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.
226 int row = 0;
227 foreach (Job job, jobs) {
228 if (job.client == client)
229 return row;
230 ++row;
232 return -1;
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"),
267 lastDirectory,
268 tr("Torrents (*.torrent);;"
269 " All files (*.*)"));
270 if (fileName.isEmpty())
271 return false;
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())
279 return false;
281 // Add the torrent to our list of downloads
282 addTorrent(fileName, addTorrentDialog->destinationFolder());
283 if (!saveChanges) {
284 saveChanges = true;
285 QTimer::singleShot(1000, this, SLOT(saveSettings()));
287 return true;
290 void MainWindow::removeTorrent()
292 // Find the row of the current item, and find the torrent client
293 // for that row.
294 int row = torrentView->indexOfTopLevelItem(torrentView->currentItem());
295 TorrentClient *client = jobs.at(row).client;
297 // Stop the client.
298 client->disconnect();
299 connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped()));
300 client->stop();
302 // Remove the row from the view.
303 delete torrentView->takeTopLevelItem(row);
304 jobs.removeAt(row);
305 setActionsEnabled();
307 saveChanges = true;
308 saveSettings();
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.
318 if (quitDialog) {
319 if (++jobsStopped == jobsToStop)
320 quitDialog->close();
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;
330 jobs.removeAt(row);
332 // Display the warning.
333 QMessageBox::warning(this, tr("Error"),
334 tr("An error occurred while downloading %0: %1")
335 .arg(fileName)
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));
351 return false;
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));
360 delete client;
361 return false;
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.
376 Job job;
377 job.client = client;
378 job.torrentFileName = fileName;
379 job.destinationDirectory = destinationFolder;
380 jobs << job;
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);
400 if (!saveChanges) {
401 saveChanges = true;
402 QTimer::singleShot(5000, this, SLOT(saveSettings()));
404 client->start();
405 return true;
408 void MainWindow::saveSettings()
410 if (!saveChanges)
411 return;
412 saveChanges = false;
414 // Prepare and reset the settings
415 QSettings settings("Trolltech", "Torrent");
416 settings.clear();
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());
432 settings.endArray();
433 settings.sync();
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);
442 if (item) {
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());
450 setActionsEnabled();
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);
471 if (item)
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"));
492 } else {
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);
507 QString num;
508 num.sprintf("%.1f KB/s", bytesPerSecond / 1024.0);
509 torrentView->topLevelItem(row)->setText(3, num);
511 if (!saveChanges) {
512 saveChanges = true;
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);
522 QString num;
523 num.sprintf("%.1f KB/s", bytesPerSecond / 1024.0);
524 torrentView->topLevelItem(row)->setText(4, num);
526 if (!saveChanges) {
527 saveChanges = true;
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);
538 setActionsEnabled();
541 void MainWindow::moveTorrentUp()
543 QTreeWidgetItem *item = torrentView->currentItem();
544 int row = torrentView->indexOfTopLevelItem(item);
545 if (row == 0)
546 return;
548 Job tmp = jobs.at(row - 1);
549 jobs[row - 1] = jobs[row];
550 jobs[row] = tmp;
552 QTreeWidgetItem *itemAbove = torrentView->takeTopLevelItem(row - 1);
553 torrentView->insertTopLevelItem(row, itemAbove);
554 setActionsEnabled();
557 void MainWindow::moveTorrentDown()
559 QTreeWidgetItem *item = torrentView->currentItem();
560 int row = torrentView->indexOfTopLevelItem(item);
561 if (row == jobs.size() - 1)
562 return;
564 Job tmp = jobs.at(row + 1);
565 jobs[row + 1] = jobs[row];
566 jobs[row] = tmp;
568 QTreeWidgetItem *itemAbove = torrentView->takeTopLevelItem(row + 1);
569 torrentView->insertTopLevelItem(row, itemAbove);
570 setActionsEnabled();
573 static int rateFromValue(int value)
575 int rate = 0;
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);
582 } else {
583 rate = 512 + int((value - 750) * 6.1445);
585 return rate;
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);
634 QDialog about(this);
635 about.setModal(true);
636 about.setWindowTitle(tr("About Torrent Client"));
637 about.setLayout(mainLayout);
639 connect(quitButton, SIGNAL(clicked()), &about, SLOT(close()));
641 about.exec();
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())
652 return;
654 // Add the torrent to our list of downloads.
655 addTorrent(fileName, addTorrentDialog->destinationFolder());
656 saveSettings();
659 void MainWindow::closeEvent(QCloseEvent *)
661 if (jobs.isEmpty())
662 return;
664 // Save upload / download numbers.
665 saveSettings();
666 saveChanges = false;
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.
672 jobsToStop = 0;
673 jobsStopped = 0;
674 foreach (Job job, jobs) {
675 ++jobsToStop;
676 TorrentClient *client = job.client;
677 client->disconnect();
678 connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped()));
679 client->stop();
680 delete torrentView->takeTopLevelItem(0);
683 if (jobsToStop > jobsStopped)
684 quitDialog->exec();
685 quitDialog->deleteLater();
686 quitDialog = 0;
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
707 // exists.
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"