?? mainwindow.cpp
字號(hào):
/****************************************************************************
**
** Copyright (C) 2004-2006 Trolltech ASA. All rights reserved.
**
** This file is part of the example classes of the Qt Toolkit.
**
** Licensees holding a valid Qt License Agreement may use this file in
** accordance with the rights, responsibilities and obligations
** contained therein. Please consult your licensing agreement or
** contact sales@trolltech.com if any conditions of this licensing
** agreement are not clear to you.
**
** Further information about Qt licensing is available at:
** http://www.trolltech.com/products/qt/licensing.html or by
** contacting info@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include <QtGui>
#include "addtorrentdialog.h"
#include "mainwindow.h"
#include "ratecontroller.h"
#include "torrentclient.h"
// 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);
};
// 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;
}
// Set up a QStyleOptionProgressBar to precisely mimic the
// 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;
// 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);
// 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)
{
// Initialize some static strings
QStringList headers;
headers << tr("Torrent") << tr("Peers/Seeds") << tr("Progress")
<< tr("Down rate") << tr("Up rate") << tr("Status");
// 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);
// 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") + " ")));
// 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);
// 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()));
// Help menu
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, SLOT(about()));
helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
// 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"));
// 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()));
// 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()));
// Load settings and start
setWindowTitle(tr("Torrent Client"));
setActionsEnabled();
QMetaObject::invokeMethod(this, "loadSettings", Qt::QueuedConnection);
}
QSize MainWindow::sizeHint() const
{
const QHeaderView *header = torrentView->header();
// Add up the sizes of all header sections. The last section is
// stretched, so its size is relative to the size of the width;
// 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
{
// Return the client at the given row.
return jobs.at(row).client;
}
int MainWindow::rowOfClient(TorrentClient *client) const
{
// Return the row that displays this client's status, or -1 if the
// client is not known.
int row = 0;
foreach (Job job, jobs) {
if (job.client == client)
return row;
++row;
}
return -1;
}
void MainWindow::loadSettings()
{
// 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);
// 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()
{
// 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();
// Show the "Add Torrent" dialog.
AddTorrentDialog *addTorrentDialog = new AddTorrentDialog(this);
addTorrentDialog->setTorrent(fileName);
addTorrentDialog->deleteLater();
if (!addTorrentDialog->exec())
return false;
// 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()
{
// Find the row of the current item, and find the torrent client
// for that row.
int row = torrentView->indexOfTopLevelItem(torrentView->currentItem());
TorrentClient *client = jobs.at(row).client;
// Stop the client.
client->disconnect();
connect(client, SIGNAL(stopped()), this, SLOT(torrentStopped()));
client->stop();
// Remove the row from the view.
delete torrentView->takeTopLevelItem(row);
jobs.removeAt(row);
setActionsEnabled();
saveChanges = true;
saveSettings();
}
void MainWindow::torrentStopped()
{
// Schedule the client for deletion.
TorrentClient *client = qobject_cast<TorrentClient *>(sender());
client->deleteLater();
// If the quit dialog is shown, update its progress.
if (quitDialog) {
if (++jobsStopped == jobsToStop)
quitDialog->close();
}
}
void MainWindow::torrentError(TorrentClient::Error)
{
// Delete the client.
TorrentClient *client = qobject_cast<TorrentClient *>(sender());
int row = rowOfClient(client);
QString fileName = jobs.at(row).torrentFileName;
jobs.removeAt(row);
// 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)
{
// 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;
}
}
// 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);
// Setup the client connections.
connect(client, SIGNAL(stateChanged(TorrentClient::State)), this, SLOT(updateState(TorrentClient::State)));
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -