Browse Source

Merge pull request #4936 from evsh/files-tooltip

Improve tooltips for torrent progress bar
adaptive-webui-19844
sledgehammer999 9 years ago
parent
commit
95fbff3a53
  1. 1
      src/base/CMakeLists.txt
  2. 1
      src/base/base.pri
  3. 33
      src/base/bittorrent/torrenthandle.cpp
  4. 1
      src/base/bittorrent/torrenthandle.h
  5. 78
      src/base/bittorrent/torrentinfo.cpp
  6. 13
      src/base/bittorrent/torrentinfo.h
  7. 130
      src/base/indexrange.h
  8. 2
      src/gui/properties/CMakeLists.txt
  9. 283
      src/gui/properties/downloadedpiecesbar.cpp
  10. 61
      src/gui/properties/downloadedpiecesbar.h
  11. 96
      src/gui/properties/pieceavailabilitybar.cpp
  12. 45
      src/gui/properties/pieceavailabilitybar.h
  13. 334
      src/gui/properties/piecesbar.cpp
  14. 109
      src/gui/properties/piecesbar.h
  15. 6
      src/gui/properties/properties.pri
  16. 1221
      src/gui/properties/propertieswidget.cpp
  17. 117
      src/gui/properties/propertieswidget.h

1
src/base/CMakeLists.txt

@ -46,6 +46,7 @@ utils/misc.h
utils/string.h utils/string.h
filesystemwatcher.h filesystemwatcher.h
iconprovider.h iconprovider.h
indexrange.h
logger.h logger.h
preferences.h preferences.h
qinisettings.h qinisettings.h

1
src/base/base.pri

@ -6,6 +6,7 @@ HEADERS += \
$$PWD/logger.h \ $$PWD/logger.h \
$$PWD/settingsstorage.h \ $$PWD/settingsstorage.h \
$$PWD/preferences.h \ $$PWD/preferences.h \
$$PWD/indexrange.h \
$$PWD/iconprovider.h \ $$PWD/iconprovider.h \
$$PWD/http/irequesthandler.h \ $$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \ $$PWD/http/connection.h \

33
src/base/bittorrent/torrenthandle.cpp

@ -597,25 +597,6 @@ QStringList TorrentHandle::absoluteFilePathsUnwanted() const
return res; return res;
} }
QPair<int, int> TorrentHandle::fileExtremityPieces(int index) const
{
if (!hasMetadata()) return qMakePair(-1, -1);
const int numPieces = piecesCount();
const qlonglong pieceSize = pieceLength();
// Determine the first and last piece of the file
int firstPiece = floor((m_torrentInfo.fileOffset(index) + 1) / (float) pieceSize);
Q_ASSERT((firstPiece >= 0) && (firstPiece < numPieces));
int numPiecesInFile = ceil(fileSize(index) / (float) pieceSize);
int lastPiece = firstPiece + numPiecesInFile - 1;
Q_ASSERT((lastPiece >= 0) && (lastPiece < numPieces));
Q_UNUSED(numPieces)
return qMakePair(firstPiece, lastPiece);
}
QVector<int> TorrentHandle::filePriorities() const QVector<int> TorrentHandle::filePriorities() const
{ {
std::vector<int> fp; std::vector<int> fp;
@ -733,13 +714,13 @@ bool TorrentHandle::hasFirstLastPiecePriority() const
std::vector<int> fp; std::vector<int> fp;
SAFE_GET(fp, file_priorities); SAFE_GET(fp, file_priorities);
QPair<int, int> extremities; TorrentInfo::PieceRange extremities;
bool found = false; bool found = false;
int count = static_cast<int>(fp.size()); int count = static_cast<int>(fp.size());
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const QString ext = Utils::Fs::fileExtension(filePath(i)); const QString ext = Utils::Fs::fileExtension(filePath(i));
if (Utils::Misc::isPreviewable(ext) && (fp[i] > 0)) { if (Utils::Misc::isPreviewable(ext) && (fp[i] > 0)) {
extremities = fileExtremityPieces(i); extremities = info().filePieces(i);
found = true; found = true;
break; break;
} }
@ -749,8 +730,8 @@ bool TorrentHandle::hasFirstLastPiecePriority() const
int first = 0; int first = 0;
int last = 0; int last = 0;
SAFE_GET(first, piece_priority, extremities.first); SAFE_GET(first, piece_priority, extremities.first());
SAFE_GET(last, piece_priority, extremities.second); SAFE_GET(last, piece_priority, extremities.last());
return ((first == 7) && (last == 7)); return ((first == 7) && (last == 7));
} }
@ -1245,13 +1226,13 @@ void TorrentHandle::setFirstLastPiecePriority(bool b)
// Determine the priority to set // Determine the priority to set
int prio = b ? 7 : fp[index]; int prio = b ? 7 : fp[index];
QPair<int, int> extremities = fileExtremityPieces(index); TorrentInfo::PieceRange extremities = info().filePieces(index);
// worst case: AVI index = 1% of total file size (at the end of the file) // worst case: AVI index = 1% of total file size (at the end of the file)
int nNumPieces = ceil(fileSize(index) * 0.01 / pieceLength()); int nNumPieces = ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i) { for (int i = 0; i < nNumPieces; ++i) {
pp[extremities.first + i] = prio; pp[extremities.first() + i] = prio;
pp[extremities.second - i] = prio; pp[extremities.last() - i] = prio;
} }
} }
} }

1
src/base/bittorrent/torrenthandle.h

@ -247,7 +247,6 @@ namespace BitTorrent
qlonglong fileSize(int index) const; qlonglong fileSize(int index) const;
QStringList absoluteFilePaths() const; QStringList absoluteFilePaths() const;
QStringList absoluteFilePathsUnwanted() const; QStringList absoluteFilePathsUnwanted() const;
QPair<int, int> fileExtremityPieces(int index) const;
QVector<int> filePriorities() const; QVector<int> filePriorities() const;
TorrentInfo info() const; TorrentInfo info() const;

78
src/base/bittorrent/torrentinfo.cpp

@ -26,6 +26,7 @@
* exception statement from your version. * exception statement from your version.
*/ */
#include <QDebug>
#include <QString> #include <QString>
#include <QList> #include <QList>
#include <QUrl> #include <QUrl>
@ -138,6 +139,12 @@ int TorrentInfo::pieceLength() const
return m_nativeInfo->piece_length(); return m_nativeInfo->piece_length();
} }
int TorrentInfo::pieceLength(int index) const
{
if (!isValid()) return -1;
return m_nativeInfo->piece_size(index);
}
int TorrentInfo::piecesCount() const int TorrentInfo::piecesCount() const
{ {
if (!isValid()) return -1; if (!isValid()) return -1;
@ -178,7 +185,7 @@ qlonglong TorrentInfo::fileSize(int index) const
qlonglong TorrentInfo::fileOffset(int index) const qlonglong TorrentInfo::fileOffset(int index) const
{ {
if (!isValid()) return -1; if (!isValid()) return -1;
return m_nativeInfo->file_at(index).offset; return m_nativeInfo->file_at(index).offset;
} }
@ -213,24 +220,79 @@ QByteArray TorrentInfo::metadata() const
QStringList TorrentInfo::filesForPiece(int pieceIndex) const QStringList TorrentInfo::filesForPiece(int pieceIndex) const
{ {
if (pieceIndex < 0) // no checks here because fileIndicesForPiece() will return an empty list
return QStringList(); QVector<int> fileIndices = fileIndicesForPiece(pieceIndex);
std::vector<libtorrent::file_slice> files(
nativeInfo()->map_block(pieceIndex, 0, nativeInfo()->piece_size(pieceIndex)));
QStringList res; QStringList res;
for (const libtorrent::file_slice& s: files) { res.reserve(fileIndices.size());
res.append(filePath(s.file_index)); std::transform(fileIndices.begin(), fileIndices.end(), std::back_inserter(res),
} [this](int i) { return filePath(i); });
return res; return res;
} }
QVector<int> TorrentInfo::fileIndicesForPiece(int pieceIndex) const
{
if (!isValid() || (pieceIndex < 0) || (pieceIndex >= piecesCount()))
return QVector<int>();
std::vector<libt::file_slice> files(
nativeInfo()->map_block(pieceIndex, 0, nativeInfo()->piece_size(pieceIndex)));
QVector<int> res;
res.reserve(files.size());
std::transform(files.begin(), files.end(), std::back_inserter(res),
[](const libt::file_slice &s) { return s.file_index; });
return res;
}
TorrentInfo::PieceRange TorrentInfo::filePieces(const QString& file) const
{
if (!isValid()) // if we do not check here the debug message will be printed, which would be not correct
return {};
int index = fileIndex(file);
if (index == -1) {
qDebug() << "Filename" << file << "was not found in torrent" << name();
return {};
}
return filePieces(index);
}
TorrentInfo::PieceRange TorrentInfo::filePieces(int fileIndex) const
{
if (!isValid())
return {};
if ((fileIndex < 0) || (fileIndex >= filesCount())) {
qDebug() << "File index (" << fileIndex << ") is out of range for torrent" << name();
return {};
}
const libt::file_storage &files = nativeInfo()->files();
const auto fileSize = files.file_size(fileIndex);
const auto firstOffset = files.file_offset(fileIndex);
return makeInterval(static_cast<int>(firstOffset / pieceLength()),
static_cast<int>((firstOffset + fileSize - 1) / pieceLength()));
}
void TorrentInfo::renameFile(uint index, const QString &newPath) void TorrentInfo::renameFile(uint index, const QString &newPath)
{ {
if (!isValid()) return; if (!isValid()) return;
nativeInfo()->rename_file(index, Utils::String::toStdString(newPath)); nativeInfo()->rename_file(index, Utils::String::toStdString(newPath));
} }
int BitTorrent::TorrentInfo::fileIndex(const QString& fileName) const
{
// the check whether the object valid is not needed here
// because filesCount() returns -1 in that case and the loop exits immediately
for (int i = 0; i < filesCount(); ++i)
if (fileName == filePath(i))
return i;
return -1;
}
TorrentInfo::NativePtr TorrentInfo::nativeInfo() const TorrentInfo::NativePtr TorrentInfo::nativeInfo() const
{ {
return m_nativeInfo; return m_nativeInfo;

13
src/base/bittorrent/torrentinfo.h

@ -34,12 +34,15 @@
#include <libtorrent/torrent_info.hpp> #include <libtorrent/torrent_info.hpp>
#include <libtorrent/version.hpp> #include <libtorrent/version.hpp>
#include "base/indexrange.h"
class QString; class QString;
class QUrl; class QUrl;
class QDateTime; class QDateTime;
class QStringList; class QStringList;
class QByteArray; class QByteArray;
template<typename T> class QList; template<typename T> class QList;
template<typename T> class QVector;
namespace BitTorrent namespace BitTorrent
{ {
@ -75,6 +78,7 @@ namespace BitTorrent
qlonglong totalSize() const; qlonglong totalSize() const;
int filesCount() const; int filesCount() const;
int pieceLength() const; int pieceLength() const;
int pieceLength(int index) const;
int piecesCount() const; int piecesCount() const;
QString filePath(int index) const; QString filePath(int index) const;
QStringList filePaths() const; QStringList filePaths() const;
@ -86,12 +90,21 @@ namespace BitTorrent
QList<QUrl> urlSeeds() const; QList<QUrl> urlSeeds() const;
QByteArray metadata() const; QByteArray metadata() const;
QStringList filesForPiece(int pieceIndex) const; QStringList filesForPiece(int pieceIndex) const;
QVector<int> fileIndicesForPiece(int pieceIndex) const;
using PieceRange = IndexRange<int>;
// returns pair of the first and the last pieces into which
// the given file extends (maybe partially).
PieceRange filePieces(const QString &file) const;
PieceRange filePieces(int fileIndex) const;
void renameFile(uint index, const QString &newPath); void renameFile(uint index, const QString &newPath);
NativePtr nativeInfo() const; NativePtr nativeInfo() const;
private: private:
// returns file index or -1 if fileName is not found
int fileIndex(const QString &fileName) const;
NativePtr m_nativeInfo; NativePtr m_nativeInfo;
}; };
} }

130
src/base/indexrange.h

@ -0,0 +1,130 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Eugene Shalygin
*
* 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.
*/
#ifndef QBT_INDEXRANGE_H
#define QBT_INDEXRANGE_H
#include <QtGlobal>
// Interval is defined via [first;last]
template <typename Index>
class IndexInterval
{
public:
using IndexType = Index;
IndexInterval(IndexType first, IndexType last)
: m_first {first}
, m_last {last}
{
Q_ASSERT(first <= last);
}
IndexType first() const
{
return m_first;
}
IndexType last() const
{
return m_last;
}
private:
IndexType m_first;
IndexType m_last;
};
template <typename T>
inline IndexInterval<T> makeInterval(T first, T last)
{
return {first, last};
}
// range is defined via first index and size
template <typename Index, typename IndexDiff = Index>
class IndexRange
{
public:
using IndexType = Index;
using IndexDiffType = IndexDiff;
constexpr IndexRange()
: m_first {0}
, m_size {0}
{
}
constexpr IndexRange(IndexType first, IndexDiffType size)
: m_first {first}
, m_size {size}
{
}
constexpr IndexRange(const IndexInterval<IndexType> &interval)
: m_first {interval.first()}
, m_size {interval.last() - interval.first() + 1}
{
}
constexpr IndexType begin() const
{
return m_first;
}
constexpr IndexType end() const
{
return m_first + m_size;
}
constexpr IndexDiffType size() const
{
return m_size;
}
constexpr IndexType first() const
{
return m_first;
}
constexpr IndexType last() const
{
return m_first + m_size - 1;
}
constexpr bool isEmpty() const
{
return m_size == 0;
}
private:
IndexType m_first;
IndexDiffType m_size;
};
#endif // QBT_INDEXRANGE_H

2
src/gui/properties/CMakeLists.txt

@ -16,6 +16,7 @@ peerlistwidget.h
proplistdelegate.h proplistdelegate.h
trackerlist.h trackerlist.h
downloadedpiecesbar.h downloadedpiecesbar.h
piecesbar.h
peerlistdelegate.h peerlistdelegate.h
peerlistsortmodel.h peerlistsortmodel.h
peersadditiondlg.h peersadditiondlg.h
@ -33,6 +34,7 @@ peerlistwidget.cpp
trackerlist.cpp trackerlist.cpp
peersadditiondlg.cpp peersadditiondlg.cpp
downloadedpiecesbar.cpp downloadedpiecesbar.cpp
piecesbar.cpp
trackersadditiondlg.cpp trackersadditiondlg.cpp
pieceavailabilitybar.cpp pieceavailabilitybar.cpp
proptabbar.cpp proptabbar.cpp

283
src/gui/properties/downloadedpiecesbar.cpp

@ -28,216 +28,153 @@
* Contact : chris@qbittorrent.org * Contact : chris@qbittorrent.org
*/ */
#include <cmath>
#include <QDebug>
#include "downloadedpiecesbar.h" #include "downloadedpiecesbar.h"
DownloadedPiecesBar::DownloadedPiecesBar(QWidget *parent): QWidget(parent) #include <cmath>
{
setToolTip(QString("%1\n%2\n%3").arg(tr("White: Missing pieces")).arg(tr("Green: Partial pieces")).arg(tr("Blue: Completed pieces")));
m_bgColor = 0xffffff; #include <QDebug>
m_borderColor = palette().color(QPalette::Dark).rgb();
m_pieceColor = 0x0000ff;
m_dlPieceColor = 0x00d000;
updatePieceColors(); DownloadedPiecesBar::DownloadedPiecesBar(QWidget *parent)
: base {parent}
, m_dlPieceColor {0, 0xd0, 0}
{
} }
QVector<float> DownloadedPiecesBar::bitfieldToFloatVector(const QBitArray &vecin, int reqSize) QVector<float> DownloadedPiecesBar::bitfieldToFloatVector(const QBitArray &vecin, int reqSize)
{ {
QVector<float> result(reqSize, 0.0); QVector<float> result(reqSize, 0.0);
if (vecin.isEmpty()) return result; if (vecin.isEmpty()) return result;
const float ratio = vecin.size() / (float)reqSize;
// simple linear transformation algorithm
// for example:
// image.x(0) = pieces.x(0.0 >= x < 1.7)
// image.x(1) = pieces.x(1.7 >= x < 3.4)
for (int x = 0; x < reqSize; ++x) {
// R - real
const float fromR = x * ratio;
const float toR = (x + 1) * ratio;
// C - integer
int fromC = fromR;// std::floor not needed
int toC = std::ceil(toR);
if (toC > vecin.size())
--toC;
// position in pieces table
int x2 = fromC;
// little speed up for really big pieces table, 10K+ size
const int toCMinusOne = toC - 1;
// value in returned vector
float value = 0;
// case when calculated range is (15.2 >= x < 15.7)
if (x2 == toCMinusOne) {
if (vecin[x2]) {
value += ratio;
}
++x2;
}
// case when (15.2 >= x < 17.8)
else {
// subcase (15.2 >= x < 16)
if (x2 != fromR) {
if (vecin[x2]) {
value += 1.0 - (fromR - fromC);
}
++x2;
}
// subcase (16 >= x < 17) const float ratio = vecin.size() / static_cast<float>(reqSize);
for (; x2 < toCMinusOne; ++x2) {
if (vecin[x2]) {
value += 1.0;
}
}
// subcase (17 >= x < 17.8) // simple linear transformation algorithm
if (x2 == toCMinusOne) { // for example:
if (vecin[x2]) { // image.x(0) = pieces.x(0.0 >= x < 1.7)
value += 1.0 - (toC - toR); // image.x(1) = pieces.x(1.7 >= x < 3.4)
}
++x2;
}
}
// normalization <0, 1> for (int x = 0; x < reqSize; ++x) {
value /= ratio; // R - real
const float fromR = x * ratio;
const float toR = (x + 1) * ratio;
// float precision sometimes gives > 1, because in not possible to store irrational numbers // C - integer
value = qMin(value, (float)1.0); int fromC = fromR; // std::floor not needed
int toC = std::ceil(toR);
if (toC > vecin.size())
--toC;
result[x] = value; // position in pieces table
} int x2 = fromC;
return result; // little speed up for really big pieces table, 10K+ size
} const int toCMinusOne = toC - 1;
// value in returned vector
float value = 0;
int DownloadedPiecesBar::mixTwoColors(int &rgb1, int &rgb2, float ratio) // case when calculated range is (15.2 >= x < 15.7)
{ if (x2 == toCMinusOne) {
int r1 = qRed(rgb1); if (vecin[x2])
int g1 = qGreen(rgb1); value += ratio;
int b1 = qBlue(rgb1); ++x2;
}
// case when (15.2 >= x < 17.8)
else {
// subcase (15.2 >= x < 16)
if (x2 != fromR) {
if (vecin[x2])
value += 1.0 - (fromR - fromC);
++x2;
}
// subcase (16 >= x < 17)
for (; x2 < toCMinusOne; ++x2)
if (vecin[x2])
value += 1.0;
// subcase (17 >= x < 17.8)
if (x2 == toCMinusOne) {
if (vecin[x2])
value += 1.0 - (toC - toR);
++x2;
}
}
int r2 = qRed(rgb2); // normalization <0, 1>
int g2 = qGreen(rgb2); value /= ratio;
int b2 = qBlue(rgb2);
float ratio_n = 1.0 - ratio; // float precision sometimes gives > 1, because in not possible to store irrational numbers
int r = (r1 * ratio_n) + (r2 * ratio); value = qMin(value, 1.0f);
int g = (g1 * ratio_n) + (g2 * ratio);
int b = (b1 * ratio_n) + (b2 * ratio);
return qRgb(r, g, b); result[x] = value;
}
return result;
} }
void DownloadedPiecesBar::updateImage() bool DownloadedPiecesBar::updateImage(QImage &image)
{ {
// qDebug() << "updateImage"; // qDebug() << "updateImage";
QImage image2(width() - 2, 1, QImage::Format_RGB888); QImage image2(width() - 2 * borderWidth, 1, QImage::Format_RGB888);
if (image2.isNull()) { if (image2.isNull()) {
qDebug() << "QImage image2() allocation failed, width():" << width(); qDebug() << "QImage image2() allocation failed, width():" << width();
return; return false;
}
if (m_pieces.isEmpty()) {
image2.fill(0xffffff);
m_image = image2;
update();
return;
}
QVector<float> scaled_pieces = bitfieldToFloatVector(m_pieces, image2.width());
QVector<float> scaled_pieces_dl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
// filling image
for (int x = 0; x < scaled_pieces.size(); ++x)
{
float pieces2_val = scaled_pieces.at(x);
float pieces2_val_dl = scaled_pieces_dl.at(x);
if (pieces2_val_dl != 0)
{
float fill_ratio = pieces2_val + pieces2_val_dl;
float ratio = pieces2_val_dl / fill_ratio;
int mixedColor = mixTwoColors(m_pieceColor, m_dlPieceColor, ratio);
mixedColor = mixTwoColors(m_bgColor, mixedColor, fill_ratio);
image2.setPixel(x, 0, mixedColor);
} }
else
{ if (m_pieces.isEmpty()) {
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]); image2.fill(Qt::white);
image = image2;
return true;
} }
}
m_image = image2; QVector<float> scaled_pieces = bitfieldToFloatVector(m_pieces, image2.width());
QVector<float> scaled_pieces_dl = bitfieldToFloatVector(m_downloadedPieces, image2.width());
// filling image
for (int x = 0; x < scaled_pieces.size(); ++x) {
float pieces2_val = scaled_pieces.at(x);
float pieces2_val_dl = scaled_pieces_dl.at(x);
if (pieces2_val_dl != 0) {
float fill_ratio = pieces2_val + pieces2_val_dl;
float ratio = pieces2_val_dl / fill_ratio;
QRgb mixedColor = mixTwoColors(pieceColor().rgb(), m_dlPieceColor.rgb(), ratio);
mixedColor = mixTwoColors(backgroundColor().rgb(), mixedColor, fill_ratio);
image2.setPixel(x, 0, mixedColor);
}
else {
image2.setPixel(x, 0, pieceColors()[pieces2_val * 255]);
}
}
image = image2;
return true;
} }
void DownloadedPiecesBar::setProgress(const QBitArray &pieces, const QBitArray &downloadedPieces) void DownloadedPiecesBar::setProgress(const QBitArray &pieces, const QBitArray &downloadedPieces)
{ {
m_pieces = pieces; m_pieces = pieces;
m_downloadedPieces = downloadedPieces; m_downloadedPieces = downloadedPieces;
updateImage(); requestImageUpdate();
update();
} }
void DownloadedPiecesBar::updatePieceColors() void DownloadedPiecesBar::setColors(const QColor &background, const QColor &border, const QColor &complete, const QColor &incomplete)
{ {
m_pieceColors = QVector<int>(256); m_dlPieceColor = incomplete;
for (int i = 0; i < 256; ++i) { base::setColors(background, border, complete);
float ratio = (i / 255.0);
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
}
} }
void DownloadedPiecesBar::clear() void DownloadedPiecesBar::clear()
{ {
m_image = QImage(); m_pieces.clear();
update(); m_downloadedPieces.clear();
base::clear();
} }
void DownloadedPiecesBar::paintEvent(QPaintEvent *) QString DownloadedPiecesBar::simpleToolTipText() const
{ {
QPainter painter(this); return tr("White: Missing pieces") + '\n'
QRect imageRect(1, 1, width() - 2, height() - 2); + tr("Green: Partial pieces") + '\n'
if (m_image.isNull()) + tr("Blue: Completed pieces") + '\n';
{
painter.setBrush(Qt::white);
painter.drawRect(imageRect);
}
else
{
if (m_image.width() != imageRect.width())
updateImage();
painter.drawImage(imageRect, m_image);
}
QPainterPath border;
border.addRect(0, 0, width() - 1, height() - 1);
painter.setPen(m_borderColor);
painter.drawPath(border);
} }
void DownloadedPiecesBar::setColors(int background, int border, int complete, int incomplete)
{
m_bgColor = background;
m_borderColor = border;
m_pieceColor = complete;
m_dlPieceColor = incomplete;
updatePieceColors();
updateImage();
update();
}

61
src/gui/properties/downloadedpiecesbar.h

@ -32,54 +32,39 @@
#define DOWNLOADEDPIECESBAR_H #define DOWNLOADEDPIECESBAR_H
#include <QWidget> #include <QWidget>
#include <QPainter>
#include <QImage>
#include <QBitArray> #include <QBitArray>
#include <QVector> #include <QVector>
class DownloadedPiecesBar: public QWidget { #include "piecesbar.h"
Q_OBJECT
Q_DISABLE_COPY(DownloadedPiecesBar)
private: class DownloadedPiecesBar: public PiecesBar
QImage m_image; {
using base = PiecesBar;
// I used values, because it should be possible to change colors in runtime Q_OBJECT
Q_DISABLE_COPY(DownloadedPiecesBar)
// background color
int m_bgColor;
// border color
int m_borderColor;
// complete piece color
int m_pieceColor;
// incomplete piece color
int m_dlPieceColor;
// buffered 256 levels gradient from bg_color to piece_color
QVector<int> m_pieceColors;
// last used bitfields, uses to better resize redraw public:
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster DownloadedPiecesBar(QWidget *parent);
QBitArray m_pieces;
QBitArray m_downloadedPieces;
// scale bitfield vector to float vector void setProgress(const QBitArray &pieces, const QBitArray &downloadedPieces);
QVector<float> bitfieldToFloatVector(const QBitArray &vecin, int reqSize);
// mix two colors by light model, ratio <0, 1>
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
// draw new image and replace actual image
void updateImage();
public: void setColors(const QColor &background, const QColor &border, const QColor &complete, const QColor &incomplete);
DownloadedPiecesBar(QWidget *parent);
void setProgress(const QBitArray &m_pieces, const QBitArray &downloadedPieces); // PiecesBar interface
void updatePieceColors(); void clear() override;
void clear();
void setColors(int background, int border, int complete, int incomplete); private:
// scale bitfield vector to float vector
QVector<float> bitfieldToFloatVector(const QBitArray &vecin, int reqSize);
virtual bool updateImage(QImage &image) override;
QString simpleToolTipText() const override;
protected: // incomplete piece color
void paintEvent(QPaintEvent *); QColor m_dlPieceColor;
// last used bitfields, uses to better resize redraw
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
QBitArray m_pieces;
QBitArray m_downloadedPieces;
}; };
#endif // DOWNLOADEDPIECESBAR_H #endif // DOWNLOADEDPIECESBAR_H

96
src/gui/properties/pieceavailabilitybar.cpp

@ -28,21 +28,15 @@
* Contact : chris@qbittorrent.org * Contact : chris@qbittorrent.org
*/ */
#include <cmath>
#include <QDebug>
#include "pieceavailabilitybar.h" #include "pieceavailabilitybar.h"
#include <cmath>
#include <QDebug>
PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent) PieceAvailabilityBar::PieceAvailabilityBar(QWidget *parent)
: QWidget(parent) : base {parent}
{ {
setToolTip(QString("%1\n%2").arg(tr("White: Unavailable pieces")).arg(tr("Blue: Available pieces")));
m_bgColor = 0xffffff;
m_borderColor = palette().color(QPalette::Dark).rgb();
m_pieceColor = 0x0000ff;
updatePieceColors();
} }
QVector<float> PieceAvailabilityBar::intToFloatVector(const QVector<int> &vecin, int reqSize) QVector<float> PieceAvailabilityBar::intToFloatVector(const QVector<int> &vecin, int reqSize)
@ -126,37 +120,18 @@ QVector<float> PieceAvailabilityBar::intToFloatVector(const QVector<int> &vecin,
return result; return result;
} }
int PieceAvailabilityBar::mixTwoColors(int &rgb1, int &rgb2, float ratio) bool PieceAvailabilityBar::updateImage(QImage &image)
{ {
int r1 = qRed(rgb1); QImage image2(width() - 2 * borderWidth, 1, QImage::Format_RGB888);
int g1 = qGreen(rgb1);
int b1 = qBlue(rgb1);
int r2 = qRed(rgb2);
int g2 = qGreen(rgb2);
int b2 = qBlue(rgb2);
float ratio_n = 1.0 - ratio;
int r = (r1 * ratio_n) + (r2 * ratio);
int g = (g1 * ratio_n) + (g2 * ratio);
int b = (b1 * ratio_n) + (b2 * ratio);
return qRgb(r, g, b);
}
void PieceAvailabilityBar::updateImage()
{
QImage image2(width() - 2, 1, QImage::Format_RGB888);
if (image2.isNull()) { if (image2.isNull()) {
qDebug() << "QImage image2() allocation failed, width():" << width(); qDebug() << "QImage image2() allocation failed, width():" << width();
return; return false;
} }
if (m_pieces.empty()) { if (m_pieces.empty()) {
image2.fill(0xffffff); image2.fill(Qt::white);
m_image = image2; image = image2;
update(); return true;
return;
} }
QVector<float> scaled_pieces = intToFloatVector(m_pieces, image2.width()); QVector<float> scaled_pieces = intToFloatVector(m_pieces, image2.width());
@ -164,61 +139,32 @@ void PieceAvailabilityBar::updateImage()
// filling image // filling image
for (int x = 0; x < scaled_pieces.size(); ++x) { for (int x = 0; x < scaled_pieces.size(); ++x) {
float pieces2_val = scaled_pieces.at(x); float pieces2_val = scaled_pieces.at(x);
image2.setPixel(x, 0, m_pieceColors[pieces2_val * 255]); image2.setPixel(x, 0, pieceColors()[pieces2_val * 255]);
} }
m_image = image2; image = image2;
return true;
} }
void PieceAvailabilityBar::setAvailability(const QVector<int> &avail) void PieceAvailabilityBar::setAvailability(const QVector<int> &avail)
{ {
m_pieces = avail; m_pieces = avail;
updateImage(); requestImageUpdate();
update();
}
void PieceAvailabilityBar::updatePieceColors()
{
m_pieceColors = QVector<int>(256);
for (int i = 0; i < 256; ++i) {
float ratio = (i / 255.0);
m_pieceColors[i] = mixTwoColors(m_bgColor, m_pieceColor, ratio);
}
} }
void PieceAvailabilityBar::clear() void PieceAvailabilityBar::clear()
{ {
m_image = QImage(); m_pieces.clear();
update(); base::clear();
} }
void PieceAvailabilityBar::paintEvent(QPaintEvent *) QString PieceAvailabilityBar::simpleToolTipText() const
{ {
QPainter painter(this); return tr("White: Unavailable pieces") + '\n'
QRect imageRect(1, 1, width() - 2, height() - 2); + tr("Blue: Available pieces") + '\n';
if (m_image.isNull()) {
painter.setBrush(Qt::white);
painter.drawRect(imageRect);
}
else {
if (m_image.width() != imageRect.width())
updateImage();
painter.drawImage(imageRect, m_image);
}
QPainterPath border;
border.addRect(0, 0, width() - 1, height() - 1);
painter.setPen(m_borderColor);
painter.drawPath(border);
} }
void PieceAvailabilityBar::setColors(int background, int border, int available) bool PieceAvailabilityBar::isFileNameCorrectionNeeded() const
{ {
m_bgColor = background; return true;
m_borderColor = border;
m_pieceColor = available;
updatePieceColors();
updateImage();
update();
} }

45
src/gui/properties/pieceavailabilitybar.h

@ -31,28 +31,26 @@
#ifndef PIECEAVAILABILITYBAR_H #ifndef PIECEAVAILABILITYBAR_H
#define PIECEAVAILABILITYBAR_H #define PIECEAVAILABILITYBAR_H
#include <QWidget> #include "piecesbar.h"
#include <QPainter>
#include <QImage>
class PieceAvailabilityBar: public QWidget class PieceAvailabilityBar: public PiecesBar
{ {
using base = PiecesBar;
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(PieceAvailabilityBar) Q_DISABLE_COPY(PieceAvailabilityBar)
private: public:
QImage m_image; PieceAvailabilityBar(QWidget *parent);
// I used values, because it should be possible to change colors in runtime void setAvailability(const QVector<int> &avail);
// background color // PiecesBar interface
int m_bgColor; void clear() override;
// border color
int m_borderColor; private:
// complete piece color bool updateImage(QImage &image) override;
int m_pieceColor; QString simpleToolTipText() const override;
// buffered 256 levels gradient from bg_color to piece_color bool isFileNameCorrectionNeeded() const override;
QVector<int> m_pieceColors;
// last used int vector, uses to better resize redraw // last used int vector, uses to better resize redraw
// TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster // TODO: make a diff pieces to new pieces and update only changed pixels, speedup when update > 20x faster
@ -60,23 +58,6 @@ private:
// scale int vector to float vector // scale int vector to float vector
QVector<float> intToFloatVector(const QVector<int> &vecin, int reqSize); QVector<float> intToFloatVector(const QVector<int> &vecin, int reqSize);
// mix two colors by light model, ratio <0, 1>
int mixTwoColors(int &rgb1, int &rgb2, float ratio);
// draw new image and replace actual image
void updateImage();
public:
PieceAvailabilityBar(QWidget *parent);
void setAvailability(const QVector<int> &avail);
void updatePieceColors();
void clear();
void setColors(int background, int border, int available);
protected:
void paintEvent(QPaintEvent *);
}; };
#endif // PIECEAVAILABILITYBAR_H #endif // PIECEAVAILABILITYBAR_H

334
src/gui/properties/piecesbar.cpp

@ -0,0 +1,334 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Eugene Shalygin
* 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.
*/
#include "piecesbar.h"
#include <QApplication>
#include <QDebug>
#include <QHelpEvent>
#include <QPainter>
#include <QTextStream>
#include <QToolTip>
#include "base/bittorrent/torrenthandle.h"
#include "base/utils/misc.h"
namespace
{
using ImageRange = IndexRange<int>;
// Computes approximate mapping from image scale (measured in pixels) onto the torrent contents scale (in pieces)
// However, taking the size of a screen to be ~ 1000 px and the torrent size larger than 10 MiB, the pointing error
// is well below 0.5 px and thus is negligible.
class PieceIndexToImagePos
{
public:
PieceIndexToImagePos(const BitTorrent::TorrentInfo &torrentInfo, const QImage &image)
: m_bytesPerPixel {image.width() > 0 ? torrentInfo.totalSize() / image.width() : -1}
, m_torrentInfo {torrentInfo}
{
if ((m_bytesPerPixel > 0) && (m_bytesPerPixel < 10))
qDebug() << "PieceIndexToImagePos: torrent size is too small for correct computaions."
<< "Torrent size =" << torrentInfo.totalSize() << "Image width = " << image.width();
}
ImageRange imagePos(const BitTorrent::TorrentInfo::PieceRange &pieces) const
{
if (m_bytesPerPixel < 0)
return {0, 0};
// the type conversion is used to prevent integer overflow with torrents of 2+ GiB size
const qlonglong pieceLength = m_torrentInfo.pieceLength();
return makeInterval<ImageRange::IndexType>(
(pieces.first() * pieceLength) / m_bytesPerPixel,
(pieces.last() * pieceLength + m_torrentInfo.pieceLength(pieces.last()) - 1) / m_bytesPerPixel);
}
int pieceIndex(int imagePos) const
{
return m_bytesPerPixel < 0 ? 0 : (imagePos * m_bytesPerPixel + m_bytesPerPixel / 2) / m_torrentInfo.pieceLength();
}
private:
const qlonglong m_bytesPerPixel; // how many bytes of the torrent are squeezed into a bar's pixel
const BitTorrent::TorrentInfo m_torrentInfo;
};
class DetailedTooltipRenderer
{
public:
DetailedTooltipRenderer(QTextStream &stream, const QString &header)
: m_stream(stream)
{
m_stream << header
<< R"(<table style="width:100%; padding: 3px; vertical-align: middle;">)";
}
~DetailedTooltipRenderer()
{
m_stream << "</table>";
}
void operator()(const QString &size, const QString &path)
{
m_stream << R"(<tr><td style="white-space:nowrap">)" << size << "</td><td>" << path << "</td></tr>";
}
private:
QTextStream &m_stream;
};
}
PiecesBar::PiecesBar(QWidget *parent)
: QWidget {parent}
, m_torrent {nullptr}
, m_borderColor {palette().color(QPalette::Dark)}
, m_bgColor {Qt::white}
, m_pieceColor {Qt::blue}
, m_hovered {false}
{
updatePieceColors();
setMouseTracking(true);
}
void PiecesBar::setTorrent(BitTorrent::TorrentHandle *torrent)
{
m_torrent = torrent;
if (!m_torrent)
clear();
}
void PiecesBar::clear()
{
m_image = QImage();
update();
}
void PiecesBar::setColors(const QColor &background, const QColor &border, const QColor &complete)
{
m_bgColor = background;
m_borderColor = border;
m_pieceColor = complete;
updatePieceColors();
requestImageUpdate();
}
bool PiecesBar::event(QEvent *e)
{
if (e->type() == QEvent::ToolTip) {
showToolTip(static_cast<QHelpEvent *>(e));
return true;
}
else {
return base::event(e);
}
}
void PiecesBar::enterEvent(QEvent *e)
{
m_hovered = true;
base::enterEvent(e);
}
void PiecesBar::leaveEvent(QEvent *e)
{
m_hovered = false;
m_highlitedRegion = QRect();
requestImageUpdate();
base::leaveEvent(e);
}
void PiecesBar::mouseMoveEvent(QMouseEvent *e)
{
// if user pointed to a piece which is a part of a single large file,
// we highlight the space, occupied by this file
highlightFile(e->pos().x() - borderWidth);
base::mouseMoveEvent(e);
}
void PiecesBar::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QRect imageRect(borderWidth, borderWidth, width() - 2 * borderWidth, height() - 2 * borderWidth);
if (m_image.isNull()) {
painter.setBrush(Qt::white);
painter.drawRect(imageRect);
}
else {
if (m_image.width() != imageRect.width())
updateImage(m_image);
painter.drawImage(imageRect, m_image);
}
if (!m_highlitedRegion.isNull()) {
QColor highlightColor {this->palette().color(QPalette::Active, QPalette::Highlight)};
highlightColor.setAlphaF(0.35);
QRect targetHighlightRect {m_highlitedRegion.adjusted(borderWidth, borderWidth, borderWidth, height() - 2 * borderWidth)};
painter.fillRect(targetHighlightRect, highlightColor);
}
QPainterPath border;
border.addRect(0, 0, width(), height());
painter.setPen(m_borderColor);
painter.drawPath(border);
}
void PiecesBar::requestImageUpdate()
{
if (updateImage(m_image))
update();
}
QColor PiecesBar::backgroundColor() const
{
return m_bgColor;
}
QColor PiecesBar::borderColor() const
{
return m_borderColor;
}
QColor PiecesBar::pieceColor() const
{
return m_pieceColor;
}
const QVector<QRgb> &PiecesBar::pieceColors() const
{
return m_pieceColors;
}
QRgb PiecesBar::mixTwoColors(QRgb rgb1, QRgb rgb2, float ratio)
{
int r1 = qRed(rgb1);
int g1 = qGreen(rgb1);
int b1 = qBlue(rgb1);
int r2 = qRed(rgb2);
int g2 = qGreen(rgb2);
int b2 = qBlue(rgb2);
float ratioN = 1.0f - ratio;
int r = (r1 * ratioN) + (r2 * ratio);
int g = (g1 * ratioN) + (g2 * ratio);
int b = (b1 * ratioN) + (b2 * ratio);
return qRgb(r, g, b);
}
void PiecesBar::showToolTip(const QHelpEvent *e)
{
if (!m_torrent)
return;
QString toolTipText;
QTextStream stream(&toolTipText, QIODevice::WriteOnly);
bool showDetailedInformation = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
if (showDetailedInformation) {
stream << "<html><body>";
const int imagePos = e->pos().x() - borderWidth;
if ((imagePos >=0) && (imagePos < m_image.width())) {
PieceIndexToImagePos transform {m_torrent->info(), m_image};
int pieceIndex = transform.pieceIndex(e->pos().x() - borderWidth);
QVector<int> files {m_torrent->info().fileIndicesForPiece(pieceIndex)};
QString tooltipTitle;
if (files.count() > 1) {
tooltipTitle = tr("Files in this piece:");
}
else {
if (m_torrent->info().fileSize(files.front()) == m_torrent->info().pieceLength(pieceIndex))
tooltipTitle = tr("File in this piece");
else
tooltipTitle = tr("File in these pieces");
}
DetailedTooltipRenderer renderer(stream, tooltipTitle);
const bool isFileNameCorrectionNeeded = this->isFileNameCorrectionNeeded();
for (int f: files) {
QString filePath {m_torrent->info().filePath(f)};
if (isFileNameCorrectionNeeded)
filePath.replace(QLatin1String("/.unwanted"), QString());
renderer(Utils::Misc::friendlyUnit(m_torrent->info().fileSize(f)), filePath);
}
}
stream << "</body></html>";
}
else {
stream << simpleToolTipText();
stream << '\n' << tr("Hold Shift key for detailed information");
}
stream.flush();
QToolTip::showText(e->globalPos(), toolTipText, this);
}
void PiecesBar::highlightFile(int imagePos)
{
if (!m_torrent || (imagePos < 0) || (imagePos >= m_image.width()))
return;
PieceIndexToImagePos transform {m_torrent->info(), m_image};
int pieceIndex = transform.pieceIndex(imagePos);
QVector<int> fileIndices {m_torrent->info().fileIndicesForPiece(pieceIndex)};
if (fileIndices.count() == 1) {
BitTorrent::TorrentInfo::PieceRange filePieces = m_torrent->info().filePieces(fileIndices.first());
ImageRange imageRange = transform.imagePos(filePieces);
QRect newHighlitedRegion {imageRange.first(), 0, imageRange.size(), m_image.height()};
if (newHighlitedRegion != m_highlitedRegion) {
m_highlitedRegion = newHighlitedRegion;
update();
}
}
else if (!m_highlitedRegion.isEmpty()) {
m_highlitedRegion = QRect();
update();
}
}
void PiecesBar::updatePieceColors()
{
m_pieceColors = QVector<QRgb>(256);
for (int i = 0; i < 256; ++i) {
float ratio = (i / 255.0);
m_pieceColors[i] = mixTwoColors(backgroundColor().rgb(), m_pieceColor.rgb(), ratio);
}
}
bool PiecesBar::isFileNameCorrectionNeeded() const
{
return false;
}

109
src/gui/properties/piecesbar.h

@ -0,0 +1,109 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2016 Eugene Shalygin
* 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.
*/
#ifndef PIECESBAR_H
#define PIECESBAR_H
#include <QColor>
#include <QImage>
#include <QWidget>
class QHelpEvent;
namespace BitTorrent
{
class TorrentHandle;
}
class PiecesBar: public QWidget
{
using base = QWidget;
Q_OBJECT
Q_DISABLE_COPY(PiecesBar)
public:
explicit PiecesBar(QWidget *parent = nullptr);
void setTorrent(BitTorrent::TorrentHandle *torrent);
void setColors(const QColor &background, const QColor &border, const QColor &complete);
virtual void clear();
// QObject interface
virtual bool event(QEvent*) override;
protected:
// QWidget interface
void enterEvent(QEvent*) override;
void leaveEvent(QEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void paintEvent(QPaintEvent*) override;
void requestImageUpdate();
QColor backgroundColor() const;
QColor borderColor() const;
QColor pieceColor() const;
const QVector<QRgb> &pieceColors() const;
// mix two colors by light model, ratio <0, 1>
static QRgb mixTwoColors(QRgb rgb1, QRgb rgb2, float ratio);
static constexpr int borderWidth = 1;
private:
void showToolTip(const QHelpEvent*);
void highlightFile(int imagePos);
virtual QString simpleToolTipText() const = 0;
/// whether to perform removing of ".unwanted" directory from paths
virtual bool isFileNameCorrectionNeeded() const;
// draw new image to replace the actual image
// returns true if image was successfully updated
virtual bool updateImage(QImage &image) = 0;
void updatePieceColors();
const BitTorrent::TorrentHandle *m_torrent;
QImage m_image;
// I used values, because it should be possible to change colors at run time
// border color
QColor m_borderColor;
// background color
QColor m_bgColor;
// complete piece color
QColor m_pieceColor;
// buffered 256 levels gradient from bg_color to piece_color
QVector<QRgb> m_pieceColors;
bool m_hovered;
QRect m_highlitedRegion; //!< part of the bar can be highlighted; this rectangle is in the same frame as m_image
};
#endif // PIECESBAR_H

6
src/gui/properties/properties.pri

@ -16,7 +16,8 @@ HEADERS += $$PWD/propertieswidget.h \
$$PWD/pieceavailabilitybar.h \ $$PWD/pieceavailabilitybar.h \
$$PWD/proptabbar.h \ $$PWD/proptabbar.h \
$$PWD/speedwidget.h \ $$PWD/speedwidget.h \
$$PWD/speedplotview.h $$PWD/speedplotview.h \
$$PWD/piecesbar.h
SOURCES += $$PWD/propertieswidget.cpp \ SOURCES += $$PWD/propertieswidget.cpp \
$$PWD/proplistdelegate.cpp \ $$PWD/proplistdelegate.cpp \
@ -28,4 +29,5 @@ SOURCES += $$PWD/propertieswidget.cpp \
$$PWD/pieceavailabilitybar.cpp \ $$PWD/pieceavailabilitybar.cpp \
$$PWD/proptabbar.cpp \ $$PWD/proptabbar.cpp \
$$PWD/speedwidget.cpp \ $$PWD/speedwidget.cpp \
$$PWD/speedplotview.cpp $$PWD/speedplotview.cpp \
$$PWD/piecesbar.cpp

1221
src/gui/properties/propertieswidget.cpp

File diff suppressed because it is too large Load Diff

117
src/gui/properties/propertieswidget.h

@ -55,80 +55,81 @@ class QAction;
class QTimer; class QTimer;
QT_END_NAMESPACE QT_END_NAMESPACE
class PropertiesWidget : public QWidget, private Ui::PropertiesWidget { class PropertiesWidget: public QWidget, private Ui::PropertiesWidget
Q_OBJECT {
Q_DISABLE_COPY(PropertiesWidget) Q_OBJECT
Q_DISABLE_COPY(PropertiesWidget)
public: public:
enum SlideState {REDUCED, VISIBLE}; enum SlideState {REDUCED, VISIBLE};
public: public:
PropertiesWidget(QWidget *parent, MainWindow* main_window, TransferListWidget *transferList); PropertiesWidget(QWidget *parent, MainWindow *main_window, TransferListWidget *transferList);
~PropertiesWidget(); ~PropertiesWidget();
BitTorrent::TorrentHandle *getCurrentTorrent() const; BitTorrent::TorrentHandle *getCurrentTorrent() const;
TrackerList* getTrackerList() const { return trackerList; } TrackerList *getTrackerList() const { return trackerList; }
PeerListWidget* getPeerList() const { return peersList; } PeerListWidget *getPeerList() const { return peersList; }
QTreeView* getFilesList() const { return filesList; } QTreeView *getFilesList() const { return filesList; }
SpeedWidget* getSpeedWidget() const { return speedWidget; } SpeedWidget *getSpeedWidget() const { return speedWidget; }
protected: protected:
QPushButton* getButtonFromIndex(int index); QPushButton *getButtonFromIndex(int index);
bool applyPriorities(); bool applyPriorities();
protected slots: protected slots:
void loadTorrentInfos(BitTorrent::TorrentHandle *const torrent); void loadTorrentInfos(BitTorrent::TorrentHandle *const torrent);
void updateTorrentInfos(BitTorrent::TorrentHandle *const torrent); void updateTorrentInfos(BitTorrent::TorrentHandle *const torrent);
void loadUrlSeeds(); void loadUrlSeeds();
void askWebSeed(); void askWebSeed();
void deleteSelectedUrlSeeds(); void deleteSelectedUrlSeeds();
void copySelectedWebSeedsToClipboard() const; void copySelectedWebSeedsToClipboard() const;
void editWebSeed(); void editWebSeed();
void displayFilesListMenu(const QPoint& pos); void displayFilesListMenu(const QPoint &pos);
void displayWebSeedListMenu(const QPoint& pos); void displayWebSeedListMenu(const QPoint &pos);
void filteredFilesChanged(); void filteredFilesChanged();
void showPiecesDownloaded(bool show); void showPiecesDownloaded(bool show);
void showPiecesAvailability(bool show); void showPiecesAvailability(bool show);
void renameSelectedFile(); void renameSelectedFile();
void openSelectedFile(); void openSelectedFile();
public slots: public slots:
void setVisibility(bool visible); void setVisibility(bool visible);
void loadDynamicData(); void loadDynamicData();
void clear(); void clear();
void readSettings(); void readSettings();
void saveSettings(); void saveSettings();
void reloadPreferences(); void reloadPreferences();
void openDoubleClickedFile(const QModelIndex &); void openDoubleClickedFile(const QModelIndex &);
void loadTrackers(BitTorrent::TorrentHandle *const torrent); void loadTrackers(BitTorrent::TorrentHandle *const torrent);
private: private:
void openFile(const QModelIndex &index); void openFile(const QModelIndex &index);
void openFolder(const QModelIndex &index, bool containing_folder); void openFolder(const QModelIndex &index, bool containing_folder);
private: private:
TransferListWidget *transferList; TransferListWidget *transferList;
MainWindow *main_window; MainWindow *main_window;
BitTorrent::TorrentHandle *m_torrent; BitTorrent::TorrentHandle *m_torrent;
QTimer *refreshTimer; QTimer *refreshTimer;
SlideState state; SlideState state;
TorrentContentFilterModel *PropListModel; TorrentContentFilterModel *PropListModel;
PropListDelegate *PropDelegate; PropListDelegate *PropDelegate;
PeerListWidget *peersList; PeerListWidget *peersList;
TrackerList *trackerList; TrackerList *trackerList;
SpeedWidget *speedWidget; SpeedWidget *speedWidget;
QList<int> slideSizes; QList<int> slideSizes;
DownloadedPiecesBar *downloaded_pieces; DownloadedPiecesBar *downloaded_pieces;
PieceAvailabilityBar *pieces_availability; PieceAvailabilityBar *pieces_availability;
PropTabBar *m_tabBar; PropTabBar *m_tabBar;
LineEdit *m_contentFilterLine; LineEdit *m_contentFilterLine;
QShortcut *editHotkeyFile; QShortcut *editHotkeyFile;
QShortcut *editHotkeyWeb; QShortcut *editHotkeyWeb;
QShortcut *deleteHotkeyWeb; QShortcut *deleteHotkeyWeb;
QShortcut *openHotkeyFile; QShortcut *openHotkeyFile;
private slots: private slots:
void filterText(const QString& filter); void filterText(const QString &filter);
void updateSavePath(BitTorrent::TorrentHandle *const torrent); void updateSavePath(BitTorrent::TorrentHandle *const torrent);
}; };
#endif // PROPERTIESWIDGET_H #endif // PROPERTIESWIDGET_H

Loading…
Cancel
Save