1
mirror of https://github.com/qbittorrent/qBittorrent synced 2025-10-12 03:12:18 +02:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Christophe Dumez
a4f62b4e18 Tagged v2.2.1 release 2010-03-20 17:43:18 +00:00
Christophe Dumez
2f291daefa Fix Ctrl+A in Web UI 2010-03-20 15:48:48 +00:00
Christophe Dumez
722f2aeb5d BUGFIX: Ask for user confirmation for recursive torrent download
BUGFIX: Fix "add file" dialog in torrent creation tool
2010-03-20 11:33:09 +00:00
Christophe Dumez
d5b9598b5b BUGFIX: Fix file filtering in complex torrents 2010-03-19 11:14:35 +00:00
Christophe Dumez
cc7d74b67c BUGFIX: Fix progress display with cleanlook style 2010-03-19 08:06:56 +00:00
Christophe Dumez
e853b0b736 Code optimization 2010-03-18 23:25:17 +00:00
Christophe Dumez
5e395b24a9 Code optimization 2010-03-18 23:13:41 +00:00
Christophe Dumez
9c3789f83f FEATURE: Display pieces that are being downloaded 2010-03-18 23:03:56 +00:00
Christophe Dumez
758595dc8c BUGFIX: Added back file prioritizing in Web UI 2010-03-18 20:07:10 +00:00
Christophe Dumez
01f9e989ef Bump to v2.2.1 2010-03-18 19:32:43 +00:00
Christophe Dumez
eb9f0cb559 Added back folder watching to Web UI 2010-03-18 19:27:23 +00:00
Christophe Dumez
2592948182 Fix Web UI compatiblity with Safari 2010-03-16 00:24:39 +00:00
Christophe Dumez
6f6ab1c439 Qt 4.4 compilation fix 2010-03-15 18:12:55 +00:00
Christophe Dumez
b10e606dda Branched v2.2.x 2010-03-14 20:44:17 +00:00
26 changed files with 562 additions and 96 deletions

View File

@@ -1,3 +1,15 @@
* Sat Mar 20 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.1
- FEATURE: Display pieces that are being downloaded
- FEATURE: Added back folder watching in Web UI
- FEATURE: Added back file prioritizing in Web UI
- BUGFIX: Fix compilation with Qt 4.4
- BUGFIX: Fix Web UI compatibility with Safari
- BUGFIX: Fix progress display with cleanlook style
- BUGFIX: Fix file filtering in complex torrents
- BUGFIX: Ask for user confirmation for recursive torrent download
- BUGFIX: Fix "add file" dialog in torrent creation tool
- BUGFIX: Fix "Ctrl+A" in Web UI
* Sun Mar 14 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.0
- FEATURE: User can set alternative speed limits for fast toggling
- FEATURE: Bandwidth scheduler (automatically use alternative speed limits for a given period)

View File

@@ -117,6 +117,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
connect(BTSession, SIGNAL(newDownloadedTorrent(QString, QString)), this, SLOT(processDownloadedFiles(QString, QString)));
connect(BTSession, SIGNAL(downloadFromUrlFailure(QString, QString)), this, SLOT(handleDownloadFromUrlFailure(QString, QString)));
connect(BTSession, SIGNAL(alternativeSpeedsModeChanged(bool)), this, SLOT(updateAltSpeedsBtn(bool)));
connect(BTSession, SIGNAL(recursiveTorrentDownloadPossible(QTorrentHandle&)), this, SLOT(askRecursiveTorrentDownloadConfirmation(QTorrentHandle&)));
qDebug("create tabWidget");
tabs = new QTabWidget();
@@ -413,6 +414,12 @@ void GUI::readParamsOnSocket() {
}
}
void GUI::askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h) {
if(QMessageBox::question(this, tr("Recursive download confirmation"), tr("The torrent %1 contains torrent files, do you want to proceed with their download?").arg(h.name()), QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes) {
BTSession->recursiveTorrentDownload(h);
}
}
void GUI::handleDownloadFromUrlFailure(QString url, QString reason) const{
// Display a message box
QMessageBox::critical(0, tr("Url download error"), tr("Couldn't download file at url: %1, reason: %2.").arg(url).arg(reason));

View File

@@ -116,6 +116,7 @@ protected slots:
void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker);
void processDownloadedFiles(QString path, QString url);
void finishedTorrent(QTorrentHandle& h) const;
void askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h);
// Options slots
void on_actionOptions_triggered();
void optionsSaved();

View File

@@ -1,6 +1,6 @@
[Desktop Entry]
Categories=Qt;Network;P2P;
Comment=V2.2.0
Comment=V2.2.1
Exec=qbittorrent %f
GenericName=Bittorrent client
GenericName[bg]=Торент клиент

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -70,13 +70,13 @@ enum VersionType { NORMAL,ALPHA,BETA,RELEASE_CANDIDATE,DEVEL };
// Main constructor
Bittorrent::Bittorrent()
: m_scanFolders(ScanFoldersModel::instance(this)),
preAllocateAll(false), addInPause(false), ratio_limit(-1),
UPnPEnabled(false), NATPMPEnabled(false), LSDEnabled(false),
DHTEnabled(false), current_dht_port(0), queueingEnabled(false),
torrentExport(false), exiting(false)
: m_scanFolders(ScanFoldersModel::instance(this)),
preAllocateAll(false), addInPause(false), ratio_limit(-1),
UPnPEnabled(false), NATPMPEnabled(false), LSDEnabled(false),
DHTEnabled(false), current_dht_port(0), queueingEnabled(false),
torrentExport(false), exiting(false)
#ifndef DISABLE_GUI
, geoipDBLoaded(false), resolve_countries(false)
, geoipDBLoaded(false), resolve_countries(false)
#endif
{
// To avoid some exceptions
@@ -197,6 +197,10 @@ void Bittorrent::preAllocateAllFiles(bool b) {
}
}
ScanFoldersModel* Bittorrent::getScanFoldersModel() const {
return m_scanFolders;
}
void Bittorrent::deleteBigRatios() {
if(ratio_limit == -1) return;
std::vector<torrent_handle> torrents = getTorrents();
@@ -1810,6 +1814,26 @@ void Bittorrent::addConsoleMessage(QString msg, QString) {
#endif
}
void Bittorrent::recursiveTorrentDownload(const QTorrentHandle &h) {
for(int i=0; i<h.get_torrent_info().num_files(); ++i) {
const QString &torrent_relpath = misc::toQString(h.get_torrent_info().file_at(i).path.string());
if(torrent_relpath.endsWith(".torrent")) {
addConsoleMessage(tr("Recursive download of file %1 embedded in torrent %2", "Recursive download of test.torrent embedded in torrent test2").arg(torrent_relpath).arg(h.name()));
const QString &torrent_fullpath = h.save_path()+QDir::separator()+torrent_relpath;
try {
boost::intrusive_ptr<torrent_info> t = new torrent_info(torrent_fullpath.toLocal8Bit().constData());
const QString &sub_hash = misc::toQString(t->info_hash());
// Passing the save path along to the sub torrent file
TorrentTempData::setSavePath(sub_hash, h.save_path());
addTorrent(torrent_fullpath);
} catch(std::exception&) {
qDebug("Caught error loading torrent");
addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(torrent_fullpath), QString::fromUtf8("red"));
}
}
}
}
// Read alerts sent by the Bittorrent session
void Bittorrent::readAlerts() {
// look at session alerts and display some infos
@@ -1837,18 +1861,21 @@ void Bittorrent::addConsoleMessage(QString msg, QString) {
const bool was_already_seeded = TorrentPersistentData::isSeed(hash);
if(!was_already_seeded) {
h.save_resume_data();
qDebug("Checking if the torrent contains torrent files to download");
// Check if there are torrent files inside
for(int i=0; i<h.get_torrent_info().num_files(); ++i) {
const QString &torrent_relpath = misc::toQString(h.get_torrent_info().file_at(i).path.string());
if(torrent_relpath.endsWith(".torrent")) {
addConsoleMessage(tr("Recursive download of file %1 embedded in torrent %2", "Recursive download of test.torrent embedded in torrent test2").arg(torrent_relpath).arg(h.name()));
qDebug("Found possible recursive torrent download.");
const QString &torrent_fullpath = h.save_path()+QDir::separator()+torrent_relpath;
qDebug("Full subtorrent path is %s", qPrintable(torrent_fullpath));
try {
boost::intrusive_ptr<torrent_info> t = new torrent_info(torrent_fullpath.toLocal8Bit().constData());
const QString &sub_hash = misc::toQString(t->info_hash());
// Passing the save path along to the sub torrent file
TorrentTempData::setSavePath(sub_hash, h.save_path());
addTorrent(torrent_fullpath);
if(t->is_valid()) {
qDebug("emitting recursiveTorrentDownloadPossible()");
emit recursiveTorrentDownloadPossible(h);
break;
}
} catch(std::exception&) {
qDebug("Caught error loading torrent");
addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(torrent_fullpath), QString::fromUtf8("red"));
@@ -2274,10 +2301,7 @@ void Bittorrent::addConsoleMessage(QString msg, QString) {
torrent_queue.push(qMakePair(prio, hash));
}
// Resume downloads
int prio = -1;
while(!torrent_queue.empty()) {
int new_prio = torrent_queue.top().first;
Q_ASSERT(new_prio >= prio);
const QString &hash = torrent_queue.top().second;
torrent_queue.pop();
qDebug("Starting up torrent %s", qPrintable(hash));

View File

@@ -115,6 +115,7 @@ public:
qlonglong getETA(QString hash);
bool useTemporaryFolder() const;
QString getDefaultSavePath() const;
ScanFoldersModel* getScanFoldersModel() const;
public slots:
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
@@ -181,6 +182,7 @@ public slots:
void downloadFromURLList(const QStringList& urls);
void configureSession();
void banIP(QString ip);
void recursiveTorrentDownload(const QTorrentHandle &h);
protected:
QString getSavePath(QString hash, bool fromScanDir = false, QString filePath = QString());
@@ -210,6 +212,7 @@ signals:
void savePathChanged(QTorrentHandle &h);
void newConsoleMessage(QString msg);
void alternativeSpeedsModeChanged(bool alternative);
void recursiveTorrentDownloadPossible(QTorrentHandle &h);
private:
// Bittorrent

View File

@@ -85,7 +85,7 @@ void createtorrent::on_addFolder_button_clicked(){
}
void createtorrent::on_addFile_button_clicked(){
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath(), QString(), 0, QFileDialog::ShowDirsOnly);
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath());
if(!file.isEmpty())
textInputPath->setText(file);
}

View File

@@ -53,34 +53,49 @@ public:
setFixedHeight(BAR_HEIGHT);
}
void setProgress(bitfield pieces) {
void setProgress(const bitfield &pieces, const bitfield &downloading_pieces) {
if(pieces.empty()) {
// Empty bar
QPixmap pix = QPixmap(1, 1);
pix.fill();
pixmap = pix;
} else {
int nb_pieces = pieces.size();
const int nb_pieces = pieces.size();
// Reduce the number of pieces before creating the pixmap
// otherwise it can crash when there are too many pieces
if(nb_pieces > width()) {
int ratio = floor(nb_pieces/(double)width());
QVector<bool> scaled_pieces;
const int ratio = floor(nb_pieces/(double)width());
std::vector<bool> scaled_pieces;
std::vector<bool> scaled_downloading;
for(int i=0; i<nb_pieces; i+= ratio) {
bool have = true;
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
if(!pieces[i]) { have = false; break; }
}
scaled_pieces << have;
scaled_pieces.push_back(have);
if(have) {
scaled_downloading.push_back(false);
} else {
bool downloading = false;
for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) {
if(downloading_pieces[i]) { downloading = true; break; }
}
scaled_downloading.push_back(downloading);
}
}
QPixmap pix = QPixmap(scaled_pieces.size(), 1);
pix.fill();
QPainter painter(&pix);
for(int i=0; i<scaled_pieces.size(); ++i) {
if(scaled_pieces[i])
for(uint i=0; i<scaled_pieces.size(); ++i) {
if(scaled_pieces[i]) {
painter.setPen(Qt::blue);
else
painter.setPen(Qt::white);
} else {
if(scaled_downloading[i]) {
painter.setPen(Qt::yellow);
} else {
painter.setPen(Qt::white);
}
}
painter.drawPoint(i,0);
}
pixmap = pix;
@@ -89,10 +104,15 @@ public:
pix.fill();
QPainter painter(&pix);
for(uint i=0; i<pieces.size(); ++i) {
if(pieces[i])
if(pieces[i]) {
painter.setPen(Qt::blue);
else
painter.setPen(Qt::white);
} else {
if(downloading_pieces[i]) {
painter.setPen(Qt::yellow);
} else {
painter.setPen(Qt::white);
}
}
painter.drawPoint(i,0);
}
pixmap = pix;

View File

@@ -31,6 +31,7 @@
#include "eventmanager.h"
#include "bittorrent.h"
#include "scannedfoldersmodel.h"
#include "misc.h"
#include "preferences.h"
//#include "proplistdelegate.h"
@@ -129,8 +130,23 @@ void EventManager::setGlobalPreferences(QVariantMap m) const {
Preferences::setTempPathEnabled(m["temp_path_enabled"].toBool());
if(m.contains("temp_path"))
Preferences::setTempPath(m["temp_path"].toString());
if(m.contains("scan_dirs"))
Preferences::setScanDirs(m["scan_dirs"].toStringList());
if(m.contains("scan_dirs")) {
QStringList old_folders = Preferences::getScanDirs();
QStringList new_folders = m["scan_dirs"].toStringList();
foreach(const QString &old_folder, old_folders) {
// Update deleted folders
if(!new_folders.contains(old_folder)) {
BTSession->getScanFoldersModel()->removePath(old_folder);
}
}
foreach(const QString &new_folder, new_folders) {
// Update new folders
if(!old_folders.contains(new_folder)) {
BTSession->getScanFoldersModel()->addPath(new_folder);
}
}
Preferences::setScanDirs(new_folders);
}
if(m.contains("download_in_scan_dirs"))
Preferences::setDownloadInScanDirs(m["download_in_scan_dirs"].toList());
if(m.contains("export_dir"))

View File

@@ -104,7 +104,7 @@ void HttpConnection::write()
}
QString HttpConnection::translateDocument(QString data) {
std::string contexts[] = {"TransferListFiltersWidget", "TransferListWidget", "PropertiesWidget", "GUI", "MainWindow", "HttpServer", "confirmDeletionDlg", "TrackerList", "TorrentFilesModel", "options_imp", "Preferences", "TrackersAdditionDlg"};
std::string contexts[] = {"TransferListFiltersWidget", "TransferListWidget", "PropertiesWidget", "GUI", "MainWindow", "HttpServer", "confirmDeletionDlg", "TrackerList", "TorrentFilesModel", "options_imp", "Preferences", "TrackersAdditionDlg", "ScanFoldersModel"};
int i=0;
bool found = false;
do {
@@ -119,7 +119,7 @@ QString HttpConnection::translateDocument(QString data) {
do {
translation = qApp->translate(contexts[context_index].c_str(), word.toLocal8Bit().constData(), 0, QCoreApplication::UnicodeUTF8, 1);
++context_index;
}while(translation == word && context_index < 12);
}while(translation == word && context_index < 13);
//qDebug("Translation is %s", translation.toUtf8().data());
data = data.replace(i, regex.matchedLength(), translation);
i += translation.length();
@@ -140,6 +140,14 @@ void HttpConnection::respond() {
return;
}
QString auth = parser.value("Authorization");
if(auth.isEmpty()) {
// Return unauthorized header
qDebug("Auth is Empty...");
generator.setStatusLine(401, "Unauthorized");
generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+parent->generateNonce()+"\", opaque=\""+parent->generateNonce()+"\", stale=\"false\", algorithm=\"MD5\", qop=\"auth\"");
write();
return;
}
qDebug("Auth: %s", qPrintable(auth.split(" ").first()));
if (QString::compare(auth.split(" ").first(), "Digest", Qt::CaseInsensitive) != 0 || !parent->isAuthorized(auth.toLocal8Bit(), parser.method())) {
// Update failed attempt counter

View File

@@ -259,7 +259,7 @@ bool HttpServer::isAuthorized(QByteArray auth, QString method) const {
md5_ha.addData(password_ha1+":"+prop_nonce+":"+ha2);
response = md5_ha.result().toHex();
}
qDebug("AUTH: comparing reponses");
qDebug("AUTH: comparing reponses: (%d)", static_cast<int>(prop_response == response));
return prop_response == response;
}

View File

@@ -113,7 +113,24 @@ namespace json {
if(json.startsWith("{") && json.endsWith("}")) {
json.chop(1);
json = json.replace(0, 1, "");
QStringList couples = json.split(",");
QStringList couples;
QString tmp = "";
bool in_list = false;
foreach(QChar c, json) {
if(c == ',' && !in_list) {
couples << tmp;
tmp = "";
} else {
if(c == '[') {
in_list = true;
} else {
if(c == ']') {
in_list = false;
}
}
tmp += c;
}
}
foreach(QString couple, couples) {
QStringList parts = couple.split(":");
if(parts.size() != 2) continue;
@@ -124,12 +141,29 @@ namespace json {
}
QString value_str = parts.last();
QVariant value;
if(value_str.startsWith("\"") && value_str.endsWith("\"")) {
if(value_str.startsWith("[") && value_str.endsWith("]")) {
value_str.chop(1);
value_str = value_str.replace(0, 1, "");
value = value_str;
value_str.replace(0, 1, "");
QStringList list_elems = value_str.split(",");
QVariantList varlist;
foreach(QString list_val, list_elems) {
if(list_val.startsWith("\"") && list_val.endsWith("\"")) {
list_val.chop(1);
list_val = list_val.replace(0, 1, "");
varlist << list_val;
} else {
varlist << list_val.toInt();
}
}
value = varlist;
} else {
value = value_str.toInt();
if(value_str.startsWith("\"") && value_str.endsWith("\"")) {
value_str.chop(1);
value_str = value_str.replace(0, 1, "");
value = value_str;
} else {
value = value_str.toInt();
}
}
m.insert(key,value);
qDebug("%s:%s", key.toLocal8Bit().data(), value_str.toLocal8Bit().data());

View File

@@ -36,8 +36,10 @@
#include <QApplication>
#include <QMessageBox>
#include <QStyleFactory>
#include <QStyle>
#include <QSplashScreen>
#include <QPushButton>
#include "qgnomelook.h"
#include "GUI.h"
#include "ico.h"
#else
@@ -158,6 +160,11 @@ void useStyle(QApplication *app, QString style){
if(!style.isEmpty()) {
QApplication::setStyle(QStyleFactory::create(style));
}
if(app->style()->objectName() == "cleanlooks") {
// Force our own cleanlooks style
qDebug("Forcing our own cleanlooks style");
app->setStyle(new QGnomeLookStyle());
}
Preferences::setStyle(app->style()->objectName());
}
#endif

View File

@@ -34,6 +34,7 @@
#include <QSystemTrayIcon>
#include <QApplication>
#include <QSettings>
#include "qgnomelook.h"
#include <QDialogButtonBox>
#include <QCloseEvent>
#include <QDesktopWidget>
@@ -307,6 +308,11 @@ void options_imp::changePage(QListWidgetItem *current, QListWidgetItem *previous
void options_imp::useStyle() {
QApplication::setStyle(QStyleFactory::create(comboStyle->itemText(comboStyle->currentIndex())));
if(QApplication::style()->objectName() == "cleanlooks") {
// Force our own cleanlooks style
qDebug("Forcing our own cleanlooks style");
QApplication::setStyle(new QGnomeLookStyle());
}
}
void options_imp::loadWindowState() {

View File

@@ -51,7 +51,7 @@ public:
setFixedHeight(BAR_HEIGHT);
}
double setAvailability(std::vector<int>& avail) {
double setAvailability(const std::vector<int>& avail) {
double average = 0;
if(avail.empty()) {
// Empty bar
@@ -60,12 +60,12 @@ public:
pixmap = pix;
} else {
// Look for maximum value
int nb_pieces = avail.size();
const int nb_pieces = avail.size();
average = std::accumulate(avail.begin(), avail.end(), 0)/(double)nb_pieces;
// Reduce the number of pieces before creating the pixmap
// otherwise it can crash when there are too many pieces
if(nb_pieces > width()) {
int ratio = floor(nb_pieces/(double)width());
const int ratio = floor(nb_pieces/(double)width());
std::vector<int> scaled_avail;
for(int i=0; i<nb_pieces; i+= ratio) {
int j = i;
@@ -113,7 +113,7 @@ protected:
QColor getPieceColor(int avail, double average) {
if(!avail) return Qt::white;
//qDebug("avail: %d/%d", avail, max_avail);
QColor color = Qt::blue; // average avail
const QColor color = Qt::blue; // average avail
double fraction = 100.*average/avail;
if(fraction < 100)
fraction *= 0.9;

View File

@@ -338,7 +338,9 @@ void PropertiesWidget::loadDynamicData() {
if(!h.is_seed()) {
showPiecesDownloaded(true);
// Downloaded pieces
downloaded_pieces->setProgress(h.pieces());
bitfield bf(h.get_torrent_info().num_pieces(), 0);
h.downloading_pieces(bf);
downloaded_pieces->setProgress(h.pieces(), bf);
// Pieces availability
if(h.has_metadata() && !h.is_paused() && !h.is_queued() && !h.is_checking()) {
showPiecesAvailability(true);

96
src/qgnomelook.h Normal file
View File

@@ -0,0 +1,96 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* 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, or (at your option) any later version.
*
* 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef QGNOMELOOK
#define QGNOMELOOK
#include <QCleanlooksStyle>
#include <QStyleOption>
#include <QStyleOptionProgressBar>
#include <QStyleOptionProgressBarV2>
#include <QPen>
#include <QPainter>
class QGnomeLookStyle : public QCleanlooksStyle {
public:
QGnomeLookStyle() : QCleanlooksStyle() {}
void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const {
switch(element) {
case CE_ProgressBarLabel:
if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
bool vertical = false;
if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) {
vertical = (pb2->orientation == Qt::Vertical);
}
if (!vertical) {
QPalette::ColorRole textRole = QPalette::WindowText;/*
if ((pb->textAlignment & Qt::AlignCenter) && pb->textVisible
&& ((qint64(pb->progress) - qint64(pb->minimum)) * 2 >= (qint64(pb->maximum) - qint64(pb->minimum)))) {
textRole = QPalette::HighlightedText;
//Draw text shadow, This will increase readability when the background of same color
QRect shadowRect(pb->rect);
shadowRect.translate(1,1);
QColor shadowColor = (pb->palette.color(textRole).value() <= 128) ? QColor(255,255,255,160) : QColor(0,0,0,160);
QPalette shadowPalette = pb->palette;
shadowPalette.setColor(textRole, shadowColor);
drawItemText(painter, shadowRect, Qt::AlignCenter | Qt::TextSingleLine, shadowPalette, pb->state, pb->text, textRole);
}
QPalette shadowPalette = pb->palette;
shadowPalette.setColor(textRole, QColor(0,0,0,160));*/
drawItemText(painter, pb->rect, Qt::AlignCenter | Qt::TextSingleLine, pb->palette, pb->state, pb->text, textRole);
}
}
break;
default:
QCleanlooksStyle::drawControl(element, option, painter, widget);
}
}
QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget=0) const
{
QRect rect;
switch (element) {
#ifndef QT_NO_PROGRESSBAR
case SE_ProgressBarLabel:
case SE_ProgressBarContents:
case SE_ProgressBarGroove:
return option->rect;
#endif // QT_NO_PROGRESSBAR
default:
return QCleanlooksStyle::subElementRect(element, option, widget);
}
return visualRect(option->direction, option->rect, rect);
}
};
#endif

View File

@@ -451,6 +451,16 @@ bool QTorrentHandle::has_error() const {
return h.status().error.empty();
}
void QTorrentHandle::downloading_pieces(bitfield &bf) const {
Q_ASSERT(h.is_valid());
std::vector<partial_piece_info> queue;
h.get_download_queue(queue);
for(std::vector<partial_piece_info>::iterator it=queue.begin(); it!= queue.end(); it++) {
bf.set_bit(it->piece_index);
}
return;
}
//
// Setters
//

View File

@@ -129,6 +129,7 @@ class QTorrentHandle {
bool first_last_piece_first() const;
QString root_path() const;
bool has_error() const;
void downloading_pieces(bitfield &bf) const;
//
// Setters

View File

@@ -11,10 +11,10 @@ CONFIG += qt \
thread
# Update this VERSION for each release
DEFINES += VERSION=\\\"v2.2.0\\\"
DEFINES += VERSION=\\\"v2.2.1\\\"
DEFINES += VERSION_MAJOR=2
DEFINES += VERSION_MINOR=2
DEFINES += VERSION_BUGFIX=0
DEFINES += VERSION_BUGFIX=1
# NORMAL,ALPHA,BETA,RELEASE_CANDIDATE,DEVEL
DEFINES += VERSION_TYPE=NORMAL
@@ -227,6 +227,7 @@ else:HEADERS += GUI.h \
ico.h \
engineselectdlg.h \
pluginsource.h \
qgnomelook.h \
searchEngine.h \
rss.h \
rss_imp.h \

View File

@@ -97,6 +97,7 @@ public:
TreeItem(QList<QVariant> data) {
parentItem = 0;
type = ROOT;
Q_ASSERT(data.size() == 4);
itemData = data;
total_done = 0;
}
@@ -201,12 +202,13 @@ public:
return itemData.value(3).toInt();
}
void setPriority(int new_prio, bool update_children=true) {
void setPriority(int new_prio, bool update_children=true, bool update_parent=true) {
int old_prio = getPriority();
if(old_prio != new_prio) {
qDebug("setPriority(%s, %d)", qPrintable(getName()), new_prio);
itemData.replace(3, new_prio);
// Update parent
if(parentItem) {
if(update_parent && parentItem) {
parentItem->updateSize();
parentItem->updateProgress();
parentItem->updatePriority();
@@ -215,9 +217,13 @@ public:
// Update children
if(update_children) {
foreach(TreeItem* child, childItems) {
child->setPriority(new_prio);
child->setPriority(new_prio, true, false);
}
}
if(type==FOLDER) {
updateSize();
updateProgress();
}
}
void updatePriority() {

View File

@@ -100,12 +100,17 @@
<tr>
<td style="vertical-align: bottom; text-align: right;"></td><td><input type="text" id="temppath_text"/></td>
</tr>
<!-- <tr>
<td style="vertical-align: bottom; text-align: right;"><input type="checkbox" id="scandir_checkbox" onclick="updateScanDirEnabled();"/></td><td>_(Automatically load .torrent files from:)</td>
</tr>
<tr><td colspan="2">_(Check Folders for .torrent Files:)</td></tr>
<tr>
<td style="vertical-align: bottom; text-align: right;"></td><td><input type="text" id="scandir_text"/></td>
</tr> -->
<td></td>
<td>
<table style="border: 1px solid black; text-align: center" id="watched_folders_tab">
<thead><tr style="border: 1px solid black;"><th>_(Watched Folder)</th><th>_(Download here)</th></tr></thead>
<tbody></tbody>
<tfoot><tr style="border: 1px solid black;"><td style="padding-top:4px;"><input type="text" id="new_watch_folder_txt"/></td><td style="padding-top:4px;"><input type="checkbox" id="new_watch_folder_dl" style="padding-left:18px;"/><img src="images/oxygen/list-add.png" alt="Add" style="padding-left:2px;width:16px;cursor:pointer;margin-right:-18px;" onclick="javascript:addWatchFolder();"/></td></tr></tfoot>
</table>
</td>
</tr>
<tr>
<td style="vertical-align: bottom; text-align: right;"><input type="checkbox" id="exportdir_checkbox" onclick="updateExportDirEnabled();"/></td><td>_(Copy .torrent files to:)</td>
</tr>
@@ -229,7 +234,7 @@
<option value="ja_JP" title="Icons/flags/japan.png">日本語</option>
<option value="zh_CN" title="Icons/flags/china.png">中文 (简体)</option>
<option value="zh_TW" title="Icons/flags/taiwan.png">中文 (繁體)</option>
<option value="ko_KR" title="Icons/flags/south_korea.png">한글"</option>
<option value="ko_KR" title="Icons/flags/south_korea.png">한글</option>
</select>
</td>
</tr>
@@ -266,6 +271,8 @@
<center><input type="button" value="_(Apply)" onclick="applyPreferences();"/></center>
<script type="text/javascript">
var WatchedFoldersTable = new HtmlTable($("watched_folders_tab"));
applyPreferences = function() {
// Validate form data
// Connection
@@ -340,12 +347,7 @@
if($defined($('temppath_checkbox').get('checked')) && $('temppath_checkbox').get('checked'))
temp_path_enabled = 1;
var temp_path = $('temppath_text').get('value');
/*var scandir_enabled = 0;
if($defined($('scandir_checkbox').get('checked')) && $('scandir_checkbox').get('checked'))
scandir_enabled = 1;
var scandir_path = '';
if(scandir_enabled)
scandir_path = $('scandir_text').get('value');*/
var watched_folders = getWatchedFolders();
var exportdir_enabled = 0;
if($defined($('exportdir_checkbox').get('checked')) && $('exportdir_checkbox').get('checked'))
exportdir_enabled = 1;
@@ -467,7 +469,8 @@
dict.set('save_path', save_path);
dict.set('temp_path_enabled', temp_path_enabled);
dict.set('temp_path', temp_path);
//dict.set('scan_dir', scandir_path);
dict.set('scan_dirs', watched_folders[0]);
dict.set('download_in_scan_dirs', watched_folders[1]);
dict.set('export_dir', exportdir_path);
dict.set('preallocate_all', preallocate_all);
if(!$('appendexttr').hasClass('invisible')) {
@@ -686,6 +689,47 @@ updatePeerProxyAuthSettings = function() {
}
}
getWatchedFolders = function() {
var nb_folders = $("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length;
var folders = Array();
var download_in_place = Array();
for(var i=0; i<nb_folders; i+=1) {
var folder_path = $('text_watch_'+i).get('value').trim();
if(folder_path.length > 0) {
folders[folders.length] = folder_path;
if($defined($("cb_watch_"+i).get('checked')) && $("cb_watch_"+i).get('checked')) {
download_in_place[download_in_place.length] = 1;
} else {
download_in_place[download_in_place.length] = 0;
}
}
}
return [folders, download_in_place];
}
addWatchFolder = function() {
var new_folder = $("new_watch_folder_txt").get('value').trim();
if(new_folder.length <= 0) return;
var download_here = ($defined($("new_watch_folder_dl").get('checked')) && $("new_watch_folder_dl").get('checked'));
var myinput = new Element("input");
var i = $("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length;
myinput.set('id', 'text_watch_'+i);
myinput.set('type', 'text');
myinput.set('value', new_folder);
var mycb = new Element("input");
mycb.set("type", "checkbox");
mycb.set("id", "cb_watch_"+i);
if(download_here) {
mycb.set("checked", "checked");
} else {
mycb.removeProperty('checked');
}
WatchedFoldersTable.push([myinput, mycb]);
// Clear fields
$("new_watch_folder_txt").set('value', '');
$("new_watch_folder_dl").removeProperty('checked');
}
loadPreferences = function() {
var url = 'json/preferences';
var request = new Request.JSON({
@@ -793,15 +837,23 @@ loadPreferences = function() {
var temp_path = pref.temp_path;
$('temppath_text').set('value', temp_path);
updateTempDirEnabled();
/*var scan_dir_enabled = pref.scan_dir_enabled;
if(scan_dir_enabled) {
$('scandir_text').set('value', pref.scan_dir);
$('scandir_checkbox').set('checked', 'checked');
} else {
$('scandir_text').set('value', '');
$('scandir_checkbox').removeProperty('checked');
var i = 0;
for(i=0; i<pref.scan_dirs.length; i+=1) {
var myinput = new Element("input");
myinput.set('id', 'text_watch_'+i);
myinput.set('type', 'text');
myinput.set('value', pref.scan_dirs[i]);
var mycb = new Element("input");
mycb.set("type", "checkbox");
mycb.set("id", "cb_watch_"+i);
if(pref.download_in_scan_dirs[i] == "true" || pref.download_in_scan_dirs[i] == 1) {
mycb.set("checked", "checked");
} else {
mycb.removeProperty('checked');
}
WatchedFoldersTable.push([myinput, mycb]);
}
updateScanDirEnabled();*/
var export_dir_enabled = pref.export_dir_enabled;
if(export_dir_enabled) {
$('exportdir_text').set('value', pref.export_dir);
@@ -905,4 +957,4 @@ loadPreferences = function() {
}
loadPreferences();
</script>
</script>

View File

@@ -2,10 +2,11 @@
<table class="torrentTable" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>_(Downloaded)</th>
<th>_(Name)</th>
<th>_(Size)</th>
<th style="width: 90px;">_(Progress)</th>
<th>_(Downloaded)</th>
<th>_(Priority)</th>
</tr>
</thead>
<tbody id="filesTable"></tbody>
@@ -32,10 +33,50 @@ var createDownloadedCB = function(id, downloaded) {
if($defined($('cbPrio'+id).get('checked')) && $('cbPrio'+id).get('checked'))
checked = 1;
setFilePriority(id, checked);
// Display or add combobox
if(checked) {
$('comboPrio'+id).set("value", 1);
$('comboPrio'+id).removeClass("invisible");
} else {
$('comboPrio'+id).addClass("invisible");
}
});
return CB;
}
var createPriorityCombo = function(id, selected_prio) {
var select = new Element('select');
select.set('id', 'comboPrio'+id);
select.addEvent('change', function(e){
var new_prio = $('comboPrio'+id).get('value');
setFilePriority(id, new_prio);
});
var opt = new Element("option");
opt.set('value', '1')
opt.set('html', "_(Normal)");
if(selected_prio <= 1)
opt.setAttribute('selected', '');
opt.injectInside(select);
opt = new Element("option");
opt.set('value', '2')
opt.set('html', "_(High)");
if(selected_prio == 2)
opt.setAttribute('selected', '');
opt.injectInside(select);
opt = new Element("option");
opt.set('value', '7')
opt.set('html', "_(Maximum)");
if(selected_prio == 7)
opt.setAttribute('selected', '');
opt.injectInside(select);
if(selected_prio < 1) {
select.addClass("invisible");
} else {
select.removeClass("invisible");
}
return select;
}
var filesDynTable = new Class ({
initialize: function(){
@@ -65,16 +106,26 @@ var createDownloadedCB = function(id, downloaded) {
updateRow: function(tr, row, id){
var tds = tr.getElements('td');
for(var i=0; i<row.length; i++) {
if(i==2) {
if(i==3) {
$('pbf_'+id).setValue(row[i].toFloat());
} else {
if(i==3) {
} else {
if(i==0) {
if(row[i] > 0)
tds[i].getChildren('input')[0].set('checked', 'checked');
else
tds[i].removeProperty('checked')
} else {
tds[i].set('html', row[i]);
if(i == 4) {
if(row[i] > 0) {
tds[i].getChildren('select').set('value', row[i]);
$('comboPrio'+id).removeClass("invisible");
} else {
if(!$('comboPrio'+id).hasClass("invisible"))
$('comboPrio'+id).addClass("invisible");
}
} else {
tds[i].set('html', row[i]);
}
}
}
}
@@ -93,13 +144,17 @@ var createDownloadedCB = function(id, downloaded) {
for(var i=0; i<row.length; i++)
{
var td = new Element('td');
if(i==2) {
td.adopt(new ProgressBar(row[i].toFloat(), {'id': 'pbf_'+id, 'width':80}));
} else {
if(i == 3) {
if(i==3) {
td.adopt(new ProgressBar(row[i].toFloat(), {'id': 'pbf_'+id, 'width':80}));
} else {
if(i == 0) {
td.adopt(createDownloadedCB(id,row[i]));
} else {
td.set('html', row[i]);
if(i == 4) {
td.adopt(createPriorityCombo(id,row[i]));
} else {
td.set('html', row[i]);
}
}
}
td.injectInside(tr);
@@ -143,10 +198,11 @@ var createDownloadedCB = function(id, downloaded) {
files.each(function(file){
var row = new Array();
row.length = 4;
row[0] = file.name;
row[1] = file.size;
row[2] = (file.progress*100).round(1);
row[3] = file.priority;
row[0] = file.priority;
row[1] = file.name;
row[2] = file.size;
row[3] = (file.progress*100).round(1);
row[4] = file.priority;
fTable.insertRow(i, row);
i++;
}.bind(this));
@@ -164,4 +220,4 @@ var createDownloadedCB = function(id, downloaded) {
fTable.setup($('filesTable'));
// Initial loading
loadTorrentFilesData();
</script>
</script>

View File

@@ -22,6 +22,116 @@
* THE SOFTWARE.
*/
// Debug
//alert(navigator.userAgent);
// From http://www.quirksmode.org/js/detect.html
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
//this.version = this.searchVersion(navigator.userAgent)
// || this.searchVersion(navigator.appVersion)
// || "an unknown version";
//this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{
string: navigator.userAgent,
subString: "Epiphany",
identity: "Epiphany"
},
{
string: navigator.userAgent,
subString: "Arora",
identity: "Arora"
},
{
string: navigator.userAgent,
subString: "midori",
identity: "Midori"
},
{
string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
]
};
BrowserDetect.init();
myTable = new dynamicTable();
ajaxfn = function(){};
setSortedColumn = function(index){
@@ -206,8 +316,10 @@ window.addEvent('load', function(){
}
};
ajaxfn();
loadTransferInfo();
// ajaxfn.periodical(5000);
if(BrowserDetect.browser != "Safari") {
// Safari has trouble with this
loadTransferInfo();
}
setFilter = function(f) {
// Visually Select the right filter
@@ -229,14 +341,6 @@ function closeWindows() {
MochaUI.closeAll();
}
// This runs when a person leaves your page.
//window.addEvent('unload', function(){
// if (MochaUI && Browser.Engine.trident != true) {
// MochaUI.garbageCleanUp();
// }
//});
window.addEvent('keydown', function(event){
if (event.key == 'a' && event.control) {
event.stop();

View File

@@ -358,7 +358,7 @@ var dynamicTable = new Class ({
if(!tr.hasClass('selected')) {
tr.addClass('selected');
}
});
}, this);
},
updateRow: function(id, row, status){