<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Qt 4.3: mainwindow.cpp Example File (network/torrent/mainwindow.cpp)</title> <link href="classic.css" rel="stylesheet" type="text/css" /> </head> <body> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr> <td align="left" valign="top" width="32"><a href="http://www.trolltech.com/products/qt"><img src="images/qt-logo.png" align="left" width="32" height="32" border="0" /></a></td> <td width="1"> </td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a> · <a href="classes.html"><font color="#004faf">All Classes</font></a> · <a href="mainclasses.html"><font color="#004faf">Main Classes</font></a> · <a href="groups.html"><font color="#004faf">Grouped Classes</font></a> · <a href="modules.html"><font color="#004faf">Modules</font></a> · <a href="functions.html"><font color="#004faf">Functions</font></a></td> <td align="right" valign="top" width="230"><a href="http://www.trolltech.com"><img src="images/trolltech-logo.png" align="right" width="203" height="32" border="0" /></a></td></tr></table><h1 align="center">mainwindow.cpp Example File<br /><sup><sup>network/torrent/mainwindow.cpp</sup></sup></h1> <pre><span class="comment"> /**************************************************************************** ** ** Copyright (C) 2004-2008 Trolltech ASA. All rights reserved. ** ** This file is part of the example classes of the Qt Toolkit. ** ** This file may be used under the terms of the GNU General Public ** License versions 2.0 or 3.0 as published by the Free Software ** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Alternatively you may (at ** your option) use any later version of the GNU General Public ** License if such license has been publicly approved by Trolltech ASA ** (or its successors, if any) and the KDE Free Qt Foundation. In ** addition, as a special exception, Trolltech gives you certain ** additional rights. These rights are described in the Trolltech GPL ** Exception version 1.1, which can be found at ** http://www.trolltech.com/products/qt/gplexception/ and in the file ** GPL_EXCEPTION.txt in this package. ** ** Please review the following information to ensure GNU General ** Public Licensing requirements will be met: ** http://trolltech.com/products/qt/licenses/licensing/opensource/. If ** you are unsure which license is appropriate for your use, please ** review the following information: ** http://trolltech.com/products/qt/licenses/licensing/licensingoverview ** or contact the sales department at sales@trolltech.com. ** ** In addition, as a special exception, Trolltech, as the sole ** copyright holder for Qt Designer, grants users of the Qt/Eclipse ** Integration plug-in the right for the Qt/Eclipse Integration to ** link to functionality provided by Qt Designer and its related ** libraries. ** ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly ** granted herein. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/</span> #include <QtGui> #include "addtorrentdialog.h" #include "mainwindow.h" #include "ratecontroller.h" #include "torrentclient.h" <span class="comment"> //</span> TorrentView extends QTreeWidget to allow drag and drop. class TorrentView : public QTreeWidget { Q_OBJECT public: TorrentView(QWidget *parent = 0); signals: void fileDropped(const QString &fileName); protected: void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); }; <span class="comment"> //</span> TorrentViewDelegate is used to draw the progress bars. class TorrentViewDelegate : public QItemDelegate { Q_OBJECT public: inline TorrentViewDelegate(MainWindow *mainWindow) : QItemDelegate(mainWindow) {} inline void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { if (index.column() != 2) { QItemDelegate::paint(painter, option, index); return; } <span class="comment">//</span> Set up a QStyleOptionProgressBar to precisely mimic the <span class="comment">//</span> environment of a progress bar. QStyleOptionProgressBar progressBarOption; progressBarOption.state = QStyle::State_Enabled; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = option.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = true; <span class="comment">//</span> Set the progress and text values of the style option. int progress = qobject_cast<MainWindow *>(parent())->clientForRow(index.row())->progress(); progressBarOption.progress = progress < 0 ? 0 : progress; progressBarOption.text = QString().sprintf("%d%%", progressBarOption.progress); <span class="comment">//</span> Draw the progress bar onto the view. QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); } }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), quitDialog(0), saveChanges(false) { <span class="comment">//</span> Initialize some static strings QStringList headers; headers << tr("Torrent") << tr("Peers/Seeds") << tr("Progress") << tr("Down rate") << tr("Up rate") << tr("Status"); <span class="comment">//</span> Main torrent list torrentView = new TorrentView(this); torrentView->setItemDelegate(new TorrentViewDelegate(this)); torrentView->setHeaderLabels(headers); torrentView->setSelectionBehavior(QAbstractItemView::SelectRows); torrentView->setAlternatingRowColors(true); torrentView->setRootIsDecorated(false); setCentralWidget(torrentView); <span class="comment">//</span> Set header resize modes and initial section sizes QFontMetrics fm = fontMetrics(); QHeaderView *header = torrentView->header(); header->resizeSection(0, fm.width("typical-name-for-a-torrent.torrent")); header->resizeSection(1, fm.width(headers.at(1) + " ")); header->resizeSection(2, fm.width(headers.at(2) + " ")); header->resizeSection(3, qMax(fm.width(headers.at(3) + " "), fm.width(" 1234.0 KB/s "))); header->resizeSection(4, qMax(fm.width(headers.at(4) + " "), fm.width(" 1234.0 KB/s "))); header->resizeSection(5, qMax(fm.width(headers.at(5) + " "), fm.width(tr("Downloading") + " "))); <span class="comment">//</span> Create common actions QAction *newTorrentAction = new QAction(QIcon(":/icons/bottom.png"), tr("Add &new torrent"), this); pauseTorrentAction = new QAction(QIcon(":/icons/player_pause.png"), tr("&Pause torrent"), this); removeTorrentAction = new QAction(QIcon(":/icons/player_stop.png"), tr("&Remove torrent"), this); <span class="comment">//</span> File menu QMenu *fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(newTorrentAction); fileMenu->addAction(pauseTorrentAction); fileMenu->addAction(removeTorrentAction); fileMenu->addSeparator(); fileMenu->addAction(QIcon(":/icons/exit.png"), tr("E&xit"), this, SLOT(close())); <span class="comment">//</span> Help menu QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(tr("&About"), this, SLOT(about())); helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt())); <span class="comment">//</span> Top toolbar QToolBar *topBar = new QToolBar(tr("Tools")); addToolBar(Qt::TopToolBarArea, topBar); topBar->setMovable(false); topBar->addAction(newTorrentAction); topBar->addAction(removeTorrentAction); topBar->addAction(pauseTorrentAction); topBar->addSeparator(); downActionTool = topBar->addAction(QIcon(tr(":/icons/1downarrow.png")), tr("Move down")); upActionTool = topBar->addAction(QIcon(tr(":/icons/1uparrow.png")), tr("Move up")); <span class="comment">//</span> Bottom toolbar QToolBar *bottomBar = new QToolBar(tr("Rate control")); addToolBar(Qt::BottomToolBarArea, bottomBar); bottomBar->setMovable(false); downloadLimitSlider = new QSlider(Qt::Horizontal); downloadLimitSlider->setRange(0, 1000); bottomBar->addWidget(new QLabel(tr("Max download:"))); bottomBar->addWidget(downloadLimitSlider); bottomBar->addWidget((downloadLimitLabel = new QLabel(tr("0 KB/s")))); downloadLimitLabel->setFixedSize(QSize(fm.width(tr("99999 KB/s")), fm.lineSpacing())); bottomBar->addSeparator(); uploadLimitSlider = new QSlider(Qt::Horizontal); uploadLimitSlider->setRange(0, 1000); bottomBar->addWidget(new QLabel(tr("Max upload:"))); bottomBar->addWidget(uploadLimitSlider); bottomBar->addWidget((uploadLimitLabel = new QLabel(tr("0 KB/s")))); uploadLimitLabel->setFixedSize(QSize(fm.width(tr("99999 KB/s")), fm.lineSpacing())); <span class="comment">//</span> Set up connections connect(torrentView, SIGNAL(itemSelectionChanged()), this, SLOT(setActionsEnabled())); connect(torrentView, SIGNAL(fileDropped(const QString &)), this, SLOT(acceptFileDrop(const QString &))); connect(uploadLimitSlider, SIGNAL(valueChanged(int)), this, SLOT(setUploadLimit(int))); connect(downloadLimitSlider, SIGNAL(valueChanged(int)), this, SLOT(setDownloadLimit(int))); connect(newTorrentAction, SIGNAL(triggered()), this, SLOT(addTorrent())); connect(pauseTorrentAction, SIGNAL(triggered()), this, SLOT(pauseTorrent())); connect(removeTorrentAction, SIGNAL(triggered()), this, SLOT(removeTorrent())); connect(upActionTool, SIGNAL(triggered(bool)), this, SLOT(moveTorrentUp())); connect(downActionTool, SIGNAL(triggered(bool)), this, SLOT(moveTorrentDown())); <span class="comment">//</span> Load settings and start setWindowTitle(tr("Torrent Client")); setActionsEnabled(); QMetaObject::invokeMethod(this, "loadSettings", Qt::QueuedConnection); } QSize MainWindow::sizeHint() const { const QHeaderView *header = torrentView->header(); <span class="comment">//</span> Add up the sizes of all header sections. The last section is <span class="comment">//</span> stretched, so its size is relative to the size of the width; <span class="comment">//</span> instead of counting it, we count the size of its largest value. int width = fontMetrics().width(tr("Downloading") + " "); for (int i = 0; i < header->count() - 1; ++i) width += header->sectionSize(i); return QSize(width, QMainWindow::sizeHint().height()) .expandedTo(QApplication::globalStrut()); } const TorrentClient *MainWindow::clientForRow(int row) const { <span class="comment">//</span> Return the client at the given row. return jobs.at(row).client; } int MainWindow::rowOfClient(TorrentClient *client) const { <span class="comment">//</span> Return the row that displays this client's status, or -1 if the <span class="comment">//</span> client is not known. int row = 0; foreach (Job job, jobs) { if (job.client == client) return row; ++row; } return -1; } void MainWindow::loadSettings() { <span class="comment">//</span> Load base settings (last working directory, upload/download limits). QSettings settings("Trolltech", "Torrent"); lastDirectory = settings.value("LastDirectory").toString(); if (lastDirectory.isEmpty()) lastDirectory = QDir::currentPath(); int up = settings.value("UploadLimit").toInt(); int down = settings.value("DownloadLimit").toInt(); uploadLimitSlider->setValue(up ? up : 170); downloadLimitSlider->setValue(down ? down : 550); <span class="comment">//</span> Resume all previous downloads. int size = settings.beginReadArray("Torrents"); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); QByteArray resumeState = settings.value("resumeState").toByteArray(); QString fileName = settings.value("sourceFileName").toString(); QString dest = settings.value("destinationFolder").toString(); if (addTorrent(fileName, dest, resumeState)) { TorrentClient *client = jobs.last().client; client->setDownloadedBytes(settings.value("downloadedBytes").toLongLong()); client->setUploadedBytes(settings.value("uploadedBytes").toLongLong()); } } } bool MainWindow::addTorrent() { <span class="comment">//</span> Show the file dialog, let the user select what torrent to start downloading. QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a torrent file"), lastDirectory, tr("Torrents (*.torrent);;" " All files (*.*)")); if (fileName.isEmpty()) return false; lastDirectory = QFileInfo(fileName).absolutePath(); <span class="comment">//</span> Show the "Add Torrent" dialog. AddTorrentDialog *addTorrentDialog = new AddTorrentDialog(this); addTorrentDialog->setTorrent(fileName); addTorrentDialog->deleteLater(); if (!addTorrentDialog->exec()) return false; <span class="comment">//</span> Add the torrent to our list of downloads addTorrent(fileName, addTorrentDialog->destinationFolder()); if (!saveChanges) { saveChanges = true; QTimer::singleShot(1000, this, SLOT(saveSettings())); } return true; } void MainWindow::removeTorrent() { <span class="comment">//</span> Find the row of the current item, and find the torrent client <span class="comment">//</span> for that row. int row = torrentView->indexOfTopLevelItem(torrentView->currentItem()); TorrentClient *client = jobs.at(row).client; <span class="comment">//</span> Stop the client. client->disconnect(); connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped())); client->stop(); <span class="comment">//</span> Remove the row from the view. delete torrentView->takeTopLevelItem(row); jobs.removeAt(row); setActionsEnabled(); saveChanges = true; saveSettings(); } void MainWindow::torrentStopped() { <span class="comment">//</span> Schedule the client for deletion. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); client->deleteLater(); <span class="comment">//</span> If the quit dialog is shown, update its progress. if (quitDialog) { if (++jobsStopped == jobsToStop) quitDialog->close(); } } void MainWindow::torrentError(TorrentClient::Error) { <span class="comment">//</span> Delete the client. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); QString fileName = jobs.at(row).torrentFileName; jobs.removeAt(row); <span class="comment">//</span> Display the warning. QMessageBox::warning(this, tr("Error"), tr("An error occurred while downloading %0: %1") .arg(fileName) .arg(client->errorString())); delete torrentView->takeTopLevelItem(row); client->deleteLater(); } bool MainWindow::addTorrent(const QString &fileName, const QString &destinationFolder, const QByteArray &resumeState) { <span class="comment">//</span> Check if the torrent is already being downloaded. foreach (Job job, jobs) { if (job.torrentFileName == fileName && job.destinationDirectory == destinationFolder) { QMessageBox::warning(this, tr("Already downloading"), tr("The torrent file you have selected is " "already being downloaded.")); return false; } } <span class="comment">//</span> Create a new torrent client and attempt to parse the torrent data. TorrentClient *client = new TorrentClient(this); if (!client->setTorrent(fileName)) { QMessageBox::warning(this, tr("Error"), tr("The torrent file you have selected can not be opened.")); delete client; return false; } client->setDestinationFolder(destinationFolder); client->setDumpedState(resumeState); <span class="comment">//</span> Setup the client connections. connect(client, SIGNAL(stateChanged(TorrentClient::State)), this, SLOT(updateState(TorrentClient::State))); connect(client, SIGNAL(peerInfoUpdated()), this, SLOT(updatePeerInfo())); connect(client, SIGNAL(progressUpdated(int)), this, SLOT(updateProgress(int))); connect(client, SIGNAL(downloadRateUpdated(int)), this, SLOT(updateDownloadRate(int))); connect(client, SIGNAL(uploadRateUpdated(int)), this, SLOT(updateUploadRate(int))); connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped())); connect(client, SIGNAL(error(TorrentClient::Error)), this, SLOT(torrentError(TorrentClient::Error))); <span class="comment">//</span> Add the client to the list of downloading jobs. Job job; job.client = client; job.torrentFileName = fileName; job.destinationDirectory = destinationFolder; jobs << job; <span class="comment">//</span> Create and add a row in the torrent view for this download. QTreeWidgetItem *item = new QTreeWidgetItem(torrentView); QString baseFileName = QFileInfo(fileName).fileName(); if (baseFileName.toLower().endsWith(".torrent")) baseFileName.remove(baseFileName.size() - 8); item->setText(0, baseFileName); item->setToolTip(0, tr("Torrent: %1<br>Destination: %2") .arg(baseFileName).arg(destinationFolder)); item->setText(1, tr("0/0")); item->setText(2, "0"); item->setText(3, "0.0 KB/s"); item->setText(4, "0.0 KB/s"); item->setText(5, tr("Idle")); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setTextAlignment(1, Qt::AlignHCenter); if (!saveChanges) { saveChanges = true; QTimer::singleShot(5000, this, SLOT(saveSettings())); } client->start(); return true; } void MainWindow::saveSettings() { if (!saveChanges) return; saveChanges = false; <span class="comment">//</span> Prepare and reset the settings QSettings settings("Trolltech", "Torrent"); settings.clear(); settings.setValue("LastDirectory", lastDirectory); settings.setValue("UploadLimit", uploadLimitSlider->value()); settings.setValue("DownloadLimit", downloadLimitSlider->value()); <span class="comment">//</span> Store data on all known torrents settings.beginWriteArray("Torrents"); for (int i = 0; i < jobs.size(); ++i) { settings.setArrayIndex(i); settings.setValue("sourceFileName", jobs.at(i).torrentFileName); settings.setValue("destinationFolder", jobs.at(i).destinationDirectory); settings.setValue("uploadedBytes", jobs.at(i).client->uploadedBytes()); settings.setValue("downloadedBytes", jobs.at(i).client->downloadedBytes()); settings.setValue("resumeState", jobs.at(i).client->dumpedState()); } settings.endArray(); settings.sync(); } void MainWindow::updateState(TorrentClient::State) { <span class="comment">//</span> Update the state string whenever the client's state changes. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); QTreeWidgetItem *item = torrentView->topLevelItem(row); if (item) { item->setToolTip(0, tr("Torrent: %1<br>Destination: %2<br>State: %3") .arg(jobs.at(row).torrentFileName) .arg(jobs.at(row).destinationDirectory) .arg(client->stateString())); item->setText(5, client->stateString()); } setActionsEnabled(); } void MainWindow::updatePeerInfo() { <span class="comment">//</span> Update the number of connected, visited, seed and leecher peers. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); QTreeWidgetItem *item = torrentView->topLevelItem(row); item->setText(1, tr("%1/%2").arg(client->connectedPeerCount()) .arg(client->seedCount())); } void MainWindow::updateProgress(int percent) { TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); <span class="comment">//</span> Update the progressbar. QTreeWidgetItem *item = torrentView->topLevelItem(row); if (item) item->setText(2, QString::number(percent)); } void MainWindow::setActionsEnabled() { <span class="comment">//</span> Find the view item and client for the current row, and update <span class="comment">//</span> the states of the actions. QTreeWidgetItem *item = 0; if (!torrentView->selectedItems().isEmpty()) item = torrentView->selectedItems().first(); TorrentClient *client = item ? jobs.at(torrentView->indexOfTopLevelItem(item)).client : 0; bool pauseEnabled = client && ((client->state() == TorrentClient::Paused) || (client->state() > TorrentClient::Preparing)); removeTorrentAction->setEnabled(item != 0); pauseTorrentAction->setEnabled(item != 0 && pauseEnabled); if (client && client->state() == TorrentClient::Paused) { pauseTorrentAction->setIcon(QIcon(":/icons/player_play.png")); pauseTorrentAction->setText(tr("Resume torrent")); } else { pauseTorrentAction->setIcon(QIcon(":/icons/player_pause.png")); pauseTorrentAction->setText(tr("Pause torrent")); } int row = torrentView->indexOfTopLevelItem(item); upActionTool->setEnabled(item && row != 0); downActionTool->setEnabled(item && row != jobs.size() - 1); } void MainWindow::updateDownloadRate(int bytesPerSecond) { <span class="comment">//</span> Update the download rate. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); QString num; num.sprintf("%.1f KB/s", bytesPerSecond / 1024.0); torrentView->topLevelItem(row)->setText(3, num); if (!saveChanges) { saveChanges = true; QTimer::singleShot(5000, this, SLOT(saveSettings())); } } void MainWindow::updateUploadRate(int bytesPerSecond) { <span class="comment">//</span> Update the upload rate. TorrentClient *client = qobject_cast<TorrentClient *>(sender()); int row = rowOfClient(client); QString num; num.sprintf("%.1f KB/s", bytesPerSecond / 1024.0); torrentView->topLevelItem(row)->setText(4, num); if (!saveChanges) { saveChanges = true; QTimer::singleShot(5000, this, SLOT(saveSettings())); } } void MainWindow::pauseTorrent() { <span class="comment">//</span> Pause or unpause the current torrent. int row = torrentView->indexOfTopLevelItem(torrentView->currentItem()); TorrentClient *client = jobs.at(row).client; client->setPaused(client->state() != TorrentClient::Paused); setActionsEnabled(); } void MainWindow::moveTorrentUp() { QTreeWidgetItem *item = torrentView->currentItem(); int row = torrentView->indexOfTopLevelItem(item); if (row == 0) return; Job tmp = jobs.at(row - 1); jobs[row - 1] = jobs[row]; jobs[row] = tmp; QTreeWidgetItem *itemAbove = torrentView->takeTopLevelItem(row - 1); torrentView->insertTopLevelItem(row, itemAbove); setActionsEnabled(); } void MainWindow::moveTorrentDown() { QTreeWidgetItem *item = torrentView->currentItem(); int row = torrentView->indexOfTopLevelItem(item); if (row == jobs.size() - 1) return; Job tmp = jobs.at(row + 1); jobs[row + 1] = jobs[row]; jobs[row] = tmp; QTreeWidgetItem *itemAbove = torrentView->takeTopLevelItem(row + 1); torrentView->insertTopLevelItem(row, itemAbove); setActionsEnabled(); } static int rateFromValue(int value) { int rate = 0; if (value >= 0 && value < 250) { rate = 1 + int(value * 0.124); } else if (value < 500) { rate = 32 + int((value - 250) * 0.384); } else if (value < 750) { rate = 128 + int((value - 500) * 1.536); } else { rate = 512 + int((value - 750) * 6.1445); } return rate; } void MainWindow::setUploadLimit(int value) { int rate = rateFromValue(value); uploadLimitLabel->setText(tr("%1 KB/s").arg(QString().sprintf("%4d", rate))); RateController::instance()->setUploadLimit(rate * 1024); } void MainWindow::setDownloadLimit(int value) { int rate = rateFromValue(value); downloadLimitLabel->setText(tr("%1 KB/s").arg(QString().sprintf("%4d", rate))); RateController::instance()->setDownloadLimit(rate * 1024); } void MainWindow::about() { QLabel *icon = new QLabel; icon->setPixmap(QPixmap(":/icons/peertopeer.png")); QLabel *text = new QLabel; text->setWordWrap(true); text->setText("<p>The <b>Torrent Client</b> example demonstrates how to" " write a complete peer-to-peer file sharing" " application using Qt's network and thread classes.</p>" "<p>This feature complete client implementation of" " the BitTorrent protocol can efficiently" " maintain several hundred network connections" " simultaneously.</p>"); QPushButton *quitButton = new QPushButton("OK"); QHBoxLayout *topLayout = new QHBoxLayout; topLayout->setMargin(10); topLayout->setSpacing(10); topLayout->addWidget(icon); topLayout->addWidget(text); QHBoxLayout *bottomLayout = new QHBoxLayout; bottomLayout->addStretch(); bottomLayout->addWidget(quitButton); bottomLayout->addStretch(); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(topLayout); mainLayout->addLayout(bottomLayout); QDialog about(this); about.setModal(true); about.setWindowTitle(tr("About Torrent Client")); about.setLayout(mainLayout); connect(quitButton, SIGNAL(clicked()), &about, SLOT(close())); about.exec(); } void MainWindow::acceptFileDrop(const QString &fileName) { <span class="comment">//</span> Create and show the "Add Torrent" dialog. AddTorrentDialog *addTorrentDialog = new AddTorrentDialog; lastDirectory = QFileInfo(fileName).absolutePath(); addTorrentDialog->setTorrent(fileName); addTorrentDialog->deleteLater(); if (!addTorrentDialog->exec()) return; <span class="comment">//</span> Add the torrent to our list of downloads. addTorrent(fileName, addTorrentDialog->destinationFolder()); saveSettings(); } void MainWindow::closeEvent(QCloseEvent *) { if (jobs.isEmpty()) return; <span class="comment">//</span> Save upload / download numbers. saveSettings(); saveChanges = false; quitDialog = new QProgressDialog(tr("Disconnecting from trackers"), tr("Abort"), 0, jobsToStop, this); <span class="comment">//</span> Stop all clients, remove the rows from the view and wait for <span class="comment">//</span> them to signal that they have stopped. jobsToStop = 0; jobsStopped = 0; foreach (Job job, jobs) { ++jobsToStop; TorrentClient *client = job.client; client->disconnect(); connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped())); client->stop(); delete torrentView->takeTopLevelItem(0); } if (jobsToStop > jobsStopped) quitDialog->exec(); quitDialog->deleteLater(); quitDialog = 0; } TorrentView::TorrentView(QWidget *parent) : QTreeWidget(parent) { setAcceptDrops(true); } void TorrentView::dragMoveEvent(QDragMoveEvent *event) { <span class="comment">//</span> Accept file actions with a '.torrent' extension. QUrl url(event->mimeData()->text()); if (url.isValid() && url.scheme().toLower() == "file" && url.path().toLower().endsWith(".torrent")) event->acceptProposedAction(); } void TorrentView::dropEvent(QDropEvent *event) { <span class="comment">//</span> Accept drops if the file has a '.torrent' extension and it <span class="comment">//</span> exists. QString fileName = QUrl(event->mimeData()->text()).path(); if (QFile::exists(fileName) && fileName.toLower().endsWith(".torrent")) emit fileDropped(fileName); } #include "mainwindow.moc"</pre> <p /><address><hr /><div align="center"> <table width="100%" cellspacing="0" border="0"><tr class="address"> <td width="30%">Copyright © 2008 <a href="trolltech.html">Trolltech</a></td> <td width="40%" align="center"><a href="trademarks.html">Trademarks</a></td> <td width="30%" align="right"><div align="right">Qt 4.3.4</div></td> </tr></table></div></address></body> </html>