mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-13 16:53:08 -07:00
Implement search filters in the proxy model. Partially closes #972
This commit is contained in:
parent
93d8cadaaf
commit
1336cb7a61
16 changed files with 704 additions and 133 deletions
|
@ -86,7 +86,9 @@ static struct { const char *source; const char *comment; } units[] = {
|
||||||
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
|
QT_TRANSLATE_NOOP3("misc", "KiB", "kibibytes (1024 bytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "MiB", "mebibytes (1024 kibibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
|
QT_TRANSLATE_NOOP3("misc", "GiB", "gibibytes (1024 mibibytes)"),
|
||||||
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)")
|
QT_TRANSLATE_NOOP3("misc", "TiB", "tebibytes (1024 gibibytes)"),
|
||||||
|
QT_TRANSLATE_NOOP3("misc", "PiB", "pebibytes (1024 tebibytes)"),
|
||||||
|
QT_TRANSLATE_NOOP3("misc", "EiB", "exbibytes (1024 pebibytes)")
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef DISABLE_GUI
|
#ifndef DISABLE_GUI
|
||||||
|
@ -318,30 +320,58 @@ QString Utils::Misc::pythonVersionComplete() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
|
QString Utils::Misc::unitString(Utils::Misc::SizeUnit unit)
|
||||||
|
{
|
||||||
|
return QCoreApplication::translate("misc",
|
||||||
|
units[static_cast<int>(unit)].source, units[static_cast<int>(unit)].comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB, ...)
|
||||||
// use Binary prefix standards from IEC 60027-2
|
// use Binary prefix standards from IEC 60027-2
|
||||||
// see http://en.wikipedia.org/wiki/Kilobyte
|
// see http://en.wikipedia.org/wiki/Kilobyte
|
||||||
// value must be given in bytes
|
// value must be given in bytes
|
||||||
// to send numbers instead of strings with suffixes
|
// to send numbers instead of strings with suffixes
|
||||||
QString Utils::Misc::friendlyUnit(qreal val, bool is_speed)
|
bool Utils::Misc::friendlyUnit(qint64 sizeInBytes, qreal &val, Utils::Misc::SizeUnit &unit)
|
||||||
{
|
{
|
||||||
if (val < 0)
|
if (sizeInBytes < 0) return false;
|
||||||
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(val >= 1024. && i < 4) {
|
qreal rawVal = static_cast<qreal>(sizeInBytes);
|
||||||
val /= 1024.;
|
|
||||||
|
while ((rawVal >= 1024.) && (i <= static_cast<int>(SizeUnit::ExbiByte))) {
|
||||||
|
rawVal /= 1024.;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
val = rawVal;
|
||||||
|
unit = static_cast<SizeUnit>(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Utils::Misc::friendlyUnit(qint64 bytesValue, bool isSpeed)
|
||||||
|
{
|
||||||
|
SizeUnit unit;
|
||||||
|
qreal friendlyVal;
|
||||||
|
if (!friendlyUnit(bytesValue, friendlyVal, unit)) {
|
||||||
|
return QCoreApplication::translate("misc", "Unknown", "Unknown (size)");
|
||||||
|
}
|
||||||
QString ret;
|
QString ret;
|
||||||
if (i == 0)
|
if (unit == SizeUnit::Byte)
|
||||||
ret = QString::number((long)val) + " " + QCoreApplication::translate("misc", units[0].source, units[0].comment);
|
ret = QString::number(bytesValue) + " " + unitString(unit);
|
||||||
else
|
else
|
||||||
ret = Utils::String::fromDouble(val, 1) + " " + QCoreApplication::translate("misc", units[i].source, units[i].comment);
|
ret = Utils::String::fromDouble(friendlyVal, 1) + " " + unitString(unit);
|
||||||
if (is_speed)
|
if (isSpeed)
|
||||||
ret += QCoreApplication::translate("misc", "/s", "per second");
|
ret += QCoreApplication::translate("misc", "/s", "per second");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qlonglong Utils::Misc::sizeInBytes(qreal size, Utils::Misc::SizeUnit unit)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(unit); ++i) {
|
||||||
|
size *= 1024;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
bool Utils::Misc::isPreviewable(const QString& extension)
|
bool Utils::Misc::isPreviewable(const QString& extension)
|
||||||
{
|
{
|
||||||
static QSet<QString> multimedia_extensions;
|
static QSet<QString> multimedia_extensions;
|
||||||
|
|
|
@ -48,6 +48,22 @@ namespace Utils
|
||||||
{
|
{
|
||||||
namespace Misc
|
namespace Misc
|
||||||
{
|
{
|
||||||
|
// use binary prefix standards from IEC 60027-2
|
||||||
|
// see http://en.wikipedia.org/wiki/Kilobyte
|
||||||
|
enum class SizeUnit
|
||||||
|
{
|
||||||
|
Byte, // 1024^0,
|
||||||
|
KibiByte, // 1024^1,
|
||||||
|
MebiByte, // 1024^2,
|
||||||
|
GibiByte, // 1024^3,
|
||||||
|
TebiByte, // 1024^4,
|
||||||
|
PebiByte, // 1024^5,
|
||||||
|
ExbiByte // 1024^6,
|
||||||
|
// int64 is used for sizes and thus the next units can not be handled
|
||||||
|
// ZebiByte, // 1024^7,
|
||||||
|
// YobiByte, // 1024^8
|
||||||
|
};
|
||||||
|
|
||||||
QString parseHtmlLinks(const QString &raw_text);
|
QString parseHtmlLinks(const QString &raw_text);
|
||||||
bool isUrl(const QString &s);
|
bool isUrl(const QString &s);
|
||||||
|
|
||||||
|
@ -64,11 +80,15 @@ namespace Utils
|
||||||
int pythonVersion();
|
int pythonVersion();
|
||||||
QString pythonExecutable();
|
QString pythonExecutable();
|
||||||
QString pythonVersionComplete();
|
QString pythonVersionComplete();
|
||||||
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
|
|
||||||
// use Binary prefix standards from IEC 60027-2
|
QString unitString(SizeUnit unit);
|
||||||
// see http://en.wikipedia.org/wiki/Kilobyte
|
|
||||||
|
// return best user friendly storage unit (B, KiB, MiB, GiB, TiB)
|
||||||
// value must be given in bytes
|
// value must be given in bytes
|
||||||
QString friendlyUnit(qreal val, bool is_speed = false);
|
bool friendlyUnit(qint64 sizeInBytes, qreal& val, SizeUnit& unit);
|
||||||
|
QString friendlyUnit(qint64 bytesValue, bool isSpeed = false);
|
||||||
|
qint64 sizeInBytes(qreal size, SizeUnit unit);
|
||||||
|
|
||||||
bool isPreviewable(const QString& extension);
|
bool isPreviewable(const QString& extension);
|
||||||
|
|
||||||
// Take a number of seconds and return an user-friendly
|
// Take a number of seconds and return an user-friendly
|
||||||
|
|
|
@ -113,6 +113,7 @@ FORMS += \
|
||||||
$$PWD/torrentcreatordlg.ui \
|
$$PWD/torrentcreatordlg.ui \
|
||||||
$$PWD/search/searchwidget.ui \
|
$$PWD/search/searchwidget.ui \
|
||||||
$$PWD/search/pluginselectdlg.ui \
|
$$PWD/search/pluginselectdlg.ui \
|
||||||
$$PWD/search/pluginsourcedlg.ui
|
$$PWD/search/pluginsourcedlg.ui \
|
||||||
|
$$PWD/search/searchtab.ui
|
||||||
|
|
||||||
RESOURCES += $$PWD/about.qrc
|
RESOURCES += $$PWD/about.qrc
|
||||||
|
|
|
@ -56,7 +56,7 @@ void SearchListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
||||||
QItemDelegate::drawBackground(painter, opt, index);
|
QItemDelegate::drawBackground(painter, opt, index);
|
||||||
QItemDelegate::drawDisplay(painter, opt, option.rect, (index.data().toLongLong() >= 0) ? index.data().toString() : tr("Unknown"));
|
QItemDelegate::drawDisplay(painter, opt, option.rect, (index.data().toLongLong() >= 0) ? index.data().toString() : tr("Unknown"));
|
||||||
break;
|
break;
|
||||||
case SearchSortModel::LEECHS:
|
case SearchSortModel::LEECHES:
|
||||||
QItemDelegate::drawBackground(painter, opt, index);
|
QItemDelegate::drawBackground(painter, opt, index);
|
||||||
QItemDelegate::drawDisplay(painter, opt, option.rect, (index.data().toLongLong() >= 0) ? index.data().toString() : tr("Unknown"));
|
QItemDelegate::drawDisplay(painter, opt, option.rect, (index.data().toLongLong() >= 0) ? index.data().toString() : tr("Unknown"));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -29,26 +29,136 @@
|
||||||
#include "searchsortmodel.h"
|
#include "searchsortmodel.h"
|
||||||
|
|
||||||
SearchSortModel::SearchSortModel(QObject *parent)
|
SearchSortModel::SearchSortModel(QObject *parent)
|
||||||
: QSortFilterProxyModel(parent)
|
: base(parent)
|
||||||
|
, m_isNameFilterEnabled(false)
|
||||||
|
, m_minSeeds(0)
|
||||||
|
, m_maxSeeds(-1)
|
||||||
|
, m_minLeeches(0)
|
||||||
|
, m_maxLeeches(-1)
|
||||||
|
, m_minSize(0)
|
||||||
|
, m_maxSize(-1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchSortModel::enableNameFilter(bool enable)
|
||||||
|
{
|
||||||
|
m_isNameFilterEnabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSortModel::setNameFilter(const QString &searchTerm)
|
||||||
|
{
|
||||||
|
m_searchTerm = searchTerm;
|
||||||
|
if (searchTerm.length() > 2
|
||||||
|
&& searchTerm.startsWith(QLatin1Char('"')) && searchTerm.endsWith(QLatin1Char('"'))) {
|
||||||
|
m_searchTermWords = QStringList(m_searchTerm.mid(1, m_searchTerm.length() - 2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_searchTermWords = searchTerm.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSortModel::setSizeFilter(qint64 minSize, qint64 maxSize)
|
||||||
|
{
|
||||||
|
m_minSize = std::max(static_cast<qint64>(0), minSize);
|
||||||
|
m_maxSize = std::max(static_cast<qint64>(-1), maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSortModel::setSeedsFilter(int minSeeds, int maxSeeds)
|
||||||
|
{
|
||||||
|
m_minSeeds = std::max(0, minSeeds);
|
||||||
|
m_maxSeeds = std::max(-1, maxSeeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSortModel::setLeechesFilter(int minLeeches, int maxLeeches)
|
||||||
|
{
|
||||||
|
m_minLeeches = std::max(0, minLeeches);
|
||||||
|
m_maxLeeches = std::max(-1, maxLeeches);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchSortModel::isNameFilterEnabled() const
|
||||||
|
{
|
||||||
|
return m_isNameFilterEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SearchSortModel::searchTerm() const
|
||||||
|
{
|
||||||
|
return m_searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SearchSortModel::minSeeds() const
|
||||||
|
{
|
||||||
|
return m_minSeeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SearchSortModel::maxSeeds() const
|
||||||
|
{
|
||||||
|
return m_maxSeeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SearchSortModel::minSize() const
|
||||||
|
{
|
||||||
|
return m_minSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 SearchSortModel::maxSize() const
|
||||||
|
{
|
||||||
|
return m_maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
bool SearchSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
bool SearchSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||||
{
|
{
|
||||||
if ((sortColumn() == NAME) || (sortColumn() == ENGINE_URL)) {
|
if ((sortColumn() == NAME) || (sortColumn() == ENGINE_URL)) {
|
||||||
QVariant vL = sourceModel()->data(left);
|
QVariant vL = sourceModel()->data(left);
|
||||||
QVariant vR = sourceModel()->data(right);
|
QVariant vR = sourceModel()->data(right);
|
||||||
if (!(vL.isValid() && vR.isValid()))
|
if (!(vL.isValid() && vR.isValid()))
|
||||||
return QSortFilterProxyModel::lessThan(left, right);
|
return base::lessThan(left, right);
|
||||||
Q_ASSERT(vL.isValid());
|
Q_ASSERT(vL.isValid());
|
||||||
Q_ASSERT(vR.isValid());
|
Q_ASSERT(vR.isValid());
|
||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
if (Utils::String::naturalSort(vL.toString(), vR.toString(), res))
|
if (Utils::String::naturalSort(vL.toString(), vR.toString(), res))
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
return QSortFilterProxyModel::lessThan(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSortFilterProxyModel::lessThan(left, right);
|
return base::lessThan(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchSortModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
|
{
|
||||||
|
const QAbstractItemModel* const sourceModel = this->sourceModel();
|
||||||
|
if (m_isNameFilterEnabled && !m_searchTerm.isEmpty()) {
|
||||||
|
QString name = sourceModel->data(sourceModel->index(sourceRow, NAME, sourceParent)).toString();
|
||||||
|
for (const QString& word: m_searchTermWords) {
|
||||||
|
int i = name.indexOf(word, 0, Qt::CaseInsensitive);
|
||||||
|
if (i == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_minSize > 0 || m_maxSize >= 0) {
|
||||||
|
qlonglong size = sourceModel->data(sourceModel->index(sourceRow, SIZE, sourceParent)).toLongLong();
|
||||||
|
if ((m_minSize > 0 && size < m_minSize)
|
||||||
|
|| (m_maxSize > 0 && size > m_maxSize)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_minSeeds > 0 || m_maxSeeds >= 0) {
|
||||||
|
int seeds = sourceModel->data(sourceModel->index(sourceRow, SEEDS, sourceParent)).toInt();
|
||||||
|
if ((m_minSeeds > 0 && seeds < m_minSeeds)
|
||||||
|
|| (m_maxSeeds > 0 && seeds > m_maxSeeds)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_minLeeches > 0 || m_maxLeeches >= 0) {
|
||||||
|
int leeches = sourceModel->data(sourceModel->index(sourceRow, LEECHES, sourceParent)).toInt();
|
||||||
|
if ((m_minLeeches > 0 && leeches < m_minLeeches)
|
||||||
|
|| (m_maxLeeches > 0 && leeches > m_maxLeeches)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return base::filterAcceptsRow(sourceRow, sourceParent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,17 +30,20 @@
|
||||||
#define SEARCHSORTMODEL_H
|
#define SEARCHSORTMODEL_H
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QStringList>
|
||||||
#include "base/utils/string.h"
|
#include "base/utils/string.h"
|
||||||
|
|
||||||
class SearchSortModel: public QSortFilterProxyModel
|
class SearchSortModel: public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
|
using base = QSortFilterProxyModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum SearchColumn
|
enum SearchColumn
|
||||||
{
|
{
|
||||||
NAME,
|
NAME,
|
||||||
SIZE,
|
SIZE,
|
||||||
SEEDS,
|
SEEDS,
|
||||||
LEECHS,
|
LEECHES,
|
||||||
ENGINE_URL,
|
ENGINE_URL,
|
||||||
DL_LINK,
|
DL_LINK,
|
||||||
DESC_LINK,
|
DESC_LINK,
|
||||||
|
@ -49,8 +52,45 @@ public:
|
||||||
|
|
||||||
explicit SearchSortModel(QObject *parent = 0);
|
explicit SearchSortModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
void enableNameFilter(bool enabled);
|
||||||
|
void setNameFilter(const QString& searchTerm = QString());
|
||||||
|
|
||||||
|
//! \brief Sets parameters for filtering by size
|
||||||
|
//! \param minSize minimal size in bytes
|
||||||
|
//! \param maxSize maximal size in bytes, negative value to disable filtering
|
||||||
|
void setSizeFilter(qint64 minSize, qint64 maxSize);
|
||||||
|
|
||||||
|
//! \brief Sets parameters for filtering by seeds number
|
||||||
|
//! \param minSeeds minimal number of seeders
|
||||||
|
//! \param maxSeeds maximal number of seeders, negative value to disable filtering
|
||||||
|
void setSeedsFilter(int minSeeds, int maxSeeds);
|
||||||
|
|
||||||
|
//! \brief Sets parameters for filtering by leeches number
|
||||||
|
//! \param minLeeches minimal number of leechers
|
||||||
|
//! \param maxLeeches maximal number of leechers, negative value to disable filtering
|
||||||
|
void setLeechesFilter(int minLeeches, int maxLeeches);
|
||||||
|
|
||||||
|
bool isNameFilterEnabled() const;
|
||||||
|
|
||||||
|
QString searchTerm() const;
|
||||||
|
|
||||||
|
int minSeeds() const;
|
||||||
|
int maxSeeds() const;
|
||||||
|
|
||||||
|
qint64 minSize() const;
|
||||||
|
qint64 maxSize() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isNameFilterEnabled;
|
||||||
|
QString m_searchTerm;
|
||||||
|
QStringList m_searchTermWords;
|
||||||
|
int m_minSeeds, m_maxSeeds;
|
||||||
|
int m_minLeeches, m_maxLeeches;
|
||||||
|
qint64 m_minSize, m_maxSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHSORTMODEL_H
|
#endif // SEARCHSORTMODEL_H
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMetaEnum>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
@ -41,16 +42,28 @@
|
||||||
|
|
||||||
#include "base/utils/misc.h"
|
#include "base/utils/misc.h"
|
||||||
#include "base/preferences.h"
|
#include "base/preferences.h"
|
||||||
|
#include "base/settingsstorage.h"
|
||||||
|
#include "guiiconprovider.h"
|
||||||
#include "searchsortmodel.h"
|
#include "searchsortmodel.h"
|
||||||
#include "searchlistdelegate.h"
|
#include "searchlistdelegate.h"
|
||||||
#include "searchwidget.h"
|
#include "searchwidget.h"
|
||||||
#include "searchtab.h"
|
#include "searchtab.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
#define SETTINGS_KEY(name) "Search/" name
|
||||||
|
|
||||||
|
const QString KEY_FILTER_MODE_SETTING_NAME = SETTINGS_KEY("FilteringMode");
|
||||||
|
}
|
||||||
|
|
||||||
SearchTab::SearchTab(SearchWidget *parent)
|
SearchTab::SearchTab(SearchWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_parent(parent)
|
, m_parent(parent)
|
||||||
{
|
{
|
||||||
m_box = new QVBoxLayout(this);
|
setupUi(this);
|
||||||
|
retranslateUi(this);
|
||||||
|
|
||||||
|
m_box = static_cast<QVBoxLayout*>(this->layout());
|
||||||
m_resultsLbl = new QLabel(this);
|
m_resultsLbl = new QLabel(this);
|
||||||
m_resultsBrowser = new QTreeView(this);
|
m_resultsBrowser = new QTreeView(this);
|
||||||
#ifdef QBT_USES_QT5
|
#ifdef QBT_USES_QT5
|
||||||
|
@ -65,14 +78,12 @@ SearchTab::SearchTab(SearchWidget *parent)
|
||||||
m_box->addWidget(m_resultsLbl);
|
m_box->addWidget(m_resultsLbl);
|
||||||
m_box->addWidget(m_resultsBrowser);
|
m_box->addWidget(m_resultsBrowser);
|
||||||
|
|
||||||
setLayout(m_box);
|
|
||||||
|
|
||||||
// Set Search results list model
|
// Set Search results list model
|
||||||
m_searchListModel = new QStandardItemModel(0, SearchSortModel::NB_SEARCH_COLUMNS, this);
|
m_searchListModel = new QStandardItemModel(0, SearchSortModel::NB_SEARCH_COLUMNS, this);
|
||||||
m_searchListModel->setHeaderData(SearchSortModel::NAME, Qt::Horizontal, tr("Name", "i.e: file name"));
|
m_searchListModel->setHeaderData(SearchSortModel::NAME, Qt::Horizontal, tr("Name", "i.e: file name"));
|
||||||
m_searchListModel->setHeaderData(SearchSortModel::SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
|
m_searchListModel->setHeaderData(SearchSortModel::SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
|
||||||
m_searchListModel->setHeaderData(SearchSortModel::SEEDS, Qt::Horizontal, tr("Seeders", "i.e: Number of full sources"));
|
m_searchListModel->setHeaderData(SearchSortModel::SEEDS, Qt::Horizontal, tr("Seeders", "i.e: Number of full sources"));
|
||||||
m_searchListModel->setHeaderData(SearchSortModel::LEECHS, Qt::Horizontal, tr("Leechers", "i.e: Number of partial sources"));
|
m_searchListModel->setHeaderData(SearchSortModel::LEECHES, Qt::Horizontal, tr("Leechers", "i.e: Number of partial sources"));
|
||||||
m_searchListModel->setHeaderData(SearchSortModel::ENGINE_URL, Qt::Horizontal, tr("Search engine"));
|
m_searchListModel->setHeaderData(SearchSortModel::ENGINE_URL, Qt::Horizontal, tr("Search engine"));
|
||||||
|
|
||||||
m_proxyModel = new SearchSortModel(this);
|
m_proxyModel = new SearchSortModel(this);
|
||||||
|
@ -99,6 +110,22 @@ SearchTab::SearchTab(SearchWidget *parent)
|
||||||
|
|
||||||
// Sort by Seeds
|
// Sort by Seeds
|
||||||
m_resultsBrowser->sortByColumn(SearchSortModel::SEEDS, Qt::DescendingOrder);
|
m_resultsBrowser->sortByColumn(SearchSortModel::SEEDS, Qt::DescendingOrder);
|
||||||
|
|
||||||
|
fillFilterComboBoxes();
|
||||||
|
|
||||||
|
updateFilter();
|
||||||
|
|
||||||
|
connect(filterMode, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
|
||||||
|
connect(minSeeds, SIGNAL(editingFinished()), this, SLOT(updateFilter()));
|
||||||
|
connect(minSeeds, SIGNAL(valueChanged(int)), this, SLOT(updateFilter()));
|
||||||
|
connect(maxSeeds, SIGNAL(editingFinished()), this, SLOT(updateFilter()));
|
||||||
|
connect(maxSeeds, SIGNAL(valueChanged(int)), this, SLOT(updateFilter()));
|
||||||
|
connect(minSize, SIGNAL(editingFinished()), this, SLOT(updateFilter()));
|
||||||
|
connect(minSize, SIGNAL(valueChanged(double)), this, SLOT(updateFilter()));
|
||||||
|
connect(maxSize, SIGNAL(editingFinished()), this, SLOT(updateFilter()));
|
||||||
|
connect(maxSize, SIGNAL(valueChanged(double)), this, SLOT(updateFilter()));
|
||||||
|
connect(minSizeUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
|
||||||
|
connect(maxSizeUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchTab::downloadSelectedItem(const QModelIndex &index)
|
void SearchTab::downloadSelectedItem(const QModelIndex &index)
|
||||||
|
@ -123,24 +150,18 @@ bool SearchTab::loadColWidthResultsList()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned int listSize = widthList.size();
|
unsigned int listSize = widthList.size();
|
||||||
for (unsigned int i = 0; i < listSize; ++i) {
|
for (unsigned int i = 0; i < listSize; ++i)
|
||||||
m_resultsBrowser->header()->resizeSection(i, widthList.at(i).toInt());
|
m_resultsBrowser->header()->resizeSection(i, widthList.at(i).toInt());
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLabel* SearchTab::getCurrentLabel() const
|
|
||||||
{
|
|
||||||
return m_resultsLbl;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeView* SearchTab::getCurrentTreeView() const
|
QTreeView* SearchTab::getCurrentTreeView() const
|
||||||
{
|
{
|
||||||
return m_resultsBrowser;
|
return m_resultsBrowser;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSortFilterProxyModel* SearchTab::getCurrentSearchListProxy() const
|
SearchSortModel* SearchTab::getCurrentSearchListProxy() const
|
||||||
{
|
{
|
||||||
return m_proxyModel;
|
return m_proxyModel;
|
||||||
}
|
}
|
||||||
|
@ -154,19 +175,128 @@ QStandardItemModel* SearchTab::getCurrentSearchListModel() const
|
||||||
void SearchTab::setRowColor(int row, QString color)
|
void SearchTab::setRowColor(int row, QString color)
|
||||||
{
|
{
|
||||||
m_proxyModel->setDynamicSortFilter(false);
|
m_proxyModel->setDynamicSortFilter(false);
|
||||||
for (int i = 0; i < m_proxyModel->columnCount(); ++i) {
|
for (int i = 0; i < m_proxyModel->columnCount(); ++i)
|
||||||
m_proxyModel->setData(m_proxyModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole);
|
m_proxyModel->setData(m_proxyModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole);
|
||||||
}
|
|
||||||
|
|
||||||
m_proxyModel->setDynamicSortFilter(true);
|
m_proxyModel->setDynamicSortFilter(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SearchTab::status() const
|
SearchTab::Status SearchTab::status() const
|
||||||
{
|
{
|
||||||
return m_status;
|
return m_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchTab::setStatus(const QString &value)
|
void SearchTab::setStatus(Status value)
|
||||||
{
|
{
|
||||||
m_status = value;
|
m_status = value;
|
||||||
|
setStatusTip(statusText(value));
|
||||||
|
const int thisTabIndex = m_parent->searchTabs()->indexOf(this);
|
||||||
|
m_parent->searchTabs()->setTabToolTip(thisTabIndex, statusTip());
|
||||||
|
m_parent->searchTabs()->setTabIcon(thisTabIndex, GuiIconProvider::instance()->getIcon(statusIconName(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchTab::updateResultsCount()
|
||||||
|
{
|
||||||
|
const int totalResults = getCurrentSearchListModel() ? getCurrentSearchListModel()->rowCount(QModelIndex()) : 0;
|
||||||
|
const int filteredResults = getCurrentSearchListProxy() ? getCurrentSearchListProxy()->rowCount(QModelIndex()) : totalResults;
|
||||||
|
m_resultsLbl->setText(tr("Results (showing <i>%1</i> out of <i>%2</i>):", "i.e: Search results")
|
||||||
|
.arg(filteredResults).arg(totalResults));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchTab::updateFilter()
|
||||||
|
{
|
||||||
|
using Utils::Misc::SizeUnit;
|
||||||
|
SearchSortModel* filterModel = getCurrentSearchListProxy();
|
||||||
|
filterModel->enableNameFilter(filteringMode() == OnlyNames);
|
||||||
|
// we update size and seeds filter parameters in the model even if they are disabled
|
||||||
|
// because we need to read them from the model when search tabs switch
|
||||||
|
filterModel->setSeedsFilter(minSeeds->value(), maxSeeds->value());
|
||||||
|
filterModel->setSizeFilter(
|
||||||
|
sizeInBytes(minSize->value(), static_cast<SizeUnit>(minSizeUnit->currentIndex())),
|
||||||
|
sizeInBytes(maxSize->value(), static_cast<SizeUnit>(maxSizeUnit->currentIndex())));
|
||||||
|
|
||||||
|
SettingsStorage::instance()->storeValue(KEY_FILTER_MODE_SETTING_NAME,
|
||||||
|
filterMode->itemData(filterMode->currentIndex()));
|
||||||
|
filterModel->invalidate();
|
||||||
|
updateResultsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchTab::fillFilterComboBoxes()
|
||||||
|
{
|
||||||
|
using Utils::Misc::SizeUnit;
|
||||||
|
QStringList unitStrings;
|
||||||
|
unitStrings.append(unitString(SizeUnit::Byte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::KibiByte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::MebiByte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::GibiByte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::TebiByte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::PebiByte));
|
||||||
|
unitStrings.append(unitString(SizeUnit::ExbiByte));
|
||||||
|
|
||||||
|
minSizeUnit->clear();
|
||||||
|
maxSizeUnit->clear();
|
||||||
|
minSizeUnit->addItems(unitStrings);
|
||||||
|
maxSizeUnit->addItems(unitStrings);
|
||||||
|
|
||||||
|
minSize->setValue(0);
|
||||||
|
minSizeUnit->setCurrentIndex(static_cast<int>(SizeUnit::MebiByte));
|
||||||
|
|
||||||
|
maxSize->setValue(-1);
|
||||||
|
maxSizeUnit->setCurrentIndex(static_cast<int>(SizeUnit::TebiByte));
|
||||||
|
|
||||||
|
filterMode->clear();
|
||||||
|
|
||||||
|
QMetaEnum nameFilteringModeEnum =
|
||||||
|
this->metaObject()->enumerator(this->metaObject()->indexOfEnumerator("NameFilteringMode"));
|
||||||
|
|
||||||
|
filterMode->addItem(tr("Torrent names only"), nameFilteringModeEnum.valueToKey(OnlyNames));
|
||||||
|
filterMode->addItem(tr("Everywhere"), nameFilteringModeEnum.valueToKey(Everywhere));
|
||||||
|
|
||||||
|
QVariant selectedMode = SettingsStorage::instance()->loadValue(
|
||||||
|
KEY_FILTER_MODE_SETTING_NAME, nameFilteringModeEnum.valueToKey(OnlyNames));
|
||||||
|
int index = filterMode->findData(selectedMode);
|
||||||
|
filterMode->setCurrentIndex(index == -1 ? 0 : index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SearchTab::statusText(SearchTab::Status st)
|
||||||
|
{
|
||||||
|
switch (st) {
|
||||||
|
case Status::Ongoing:
|
||||||
|
return tr("Searching...");
|
||||||
|
case Status::Finished:
|
||||||
|
return tr("Search has finished");
|
||||||
|
case Status::Aborted:
|
||||||
|
return tr("Search aborted");
|
||||||
|
case Status::Error:
|
||||||
|
return tr("An error occurred during search...");
|
||||||
|
case Status::NoResults:
|
||||||
|
return tr("Search returned no results");
|
||||||
|
default:
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SearchTab::statusIconName(SearchTab::Status st)
|
||||||
|
{
|
||||||
|
switch (st) {
|
||||||
|
case Status::Ongoing:
|
||||||
|
return QLatin1String("task-ongoing");
|
||||||
|
case Status::Finished:
|
||||||
|
return QLatin1String("task-complete");
|
||||||
|
case Status::Aborted:
|
||||||
|
return QLatin1String("task-reject");
|
||||||
|
case Status::Error:
|
||||||
|
return QLatin1String("task-attention");
|
||||||
|
case Status::NoResults:
|
||||||
|
return QLatin1String("task-attention");
|
||||||
|
default:
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchTab::NameFilteringMode SearchTab::filteringMode() const
|
||||||
|
{
|
||||||
|
QMetaEnum metaEnum =
|
||||||
|
this->metaObject()->enumerator(this->metaObject()->indexOfEnumerator("NameFilteringMode"));
|
||||||
|
return static_cast<NameFilteringMode>(metaEnum.keyToValue(filterMode->itemData(filterMode->currentIndex()).toByteArray()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,42 +31,71 @@
|
||||||
#ifndef SEARCHTAB_H
|
#ifndef SEARCHTAB_H
|
||||||
#define SEARCHTAB_H
|
#define SEARCHTAB_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QVariant> // I don't know why <QMetaType> is not enought for Qt's 4.8.7 moc
|
||||||
|
#include "ui_searchtab.h"
|
||||||
|
|
||||||
|
#define ENGINE_URL_COLUMN 4
|
||||||
|
#define URL_COLUMN 5
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
class QModelIndex;
|
||||||
class QTreeView;
|
class QTreeView;
|
||||||
class QHeaderView;
|
class QHeaderView;
|
||||||
class QStandardItemModel;
|
class QStandardItemModel;
|
||||||
class QSortFilterProxyModel;
|
|
||||||
class QModelIndex;
|
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
|
||||||
class SearchSortModel;
|
class SearchSortModel;
|
||||||
class SearchListDelegate;
|
class SearchListDelegate;
|
||||||
class SearchWidget;
|
class SearchWidget;
|
||||||
|
|
||||||
class SearchTab: public QWidget
|
class SearchTab: public QWidget, private Ui::SearchTab
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SearchTab(SearchWidget *m_parent);
|
|
||||||
|
|
||||||
QLabel* getCurrentLabel() const;
|
enum NameFilteringMode
|
||||||
|
{
|
||||||
|
Everywhere,
|
||||||
|
OnlyNames
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_ENUMS(NameFilteringMode)
|
||||||
|
|
||||||
|
explicit SearchTab(SearchWidget *parent);
|
||||||
|
|
||||||
QStandardItemModel* getCurrentSearchListModel() const;
|
QStandardItemModel* getCurrentSearchListModel() const;
|
||||||
QSortFilterProxyModel* getCurrentSearchListProxy() const;
|
SearchSortModel* getCurrentSearchListProxy() const;
|
||||||
QTreeView* getCurrentTreeView() const;
|
QTreeView* getCurrentTreeView() const;
|
||||||
QHeaderView* header() const;
|
QHeaderView* header() const;
|
||||||
QString status() const;
|
|
||||||
|
|
||||||
bool loadColWidthResultsList();
|
bool loadColWidthResultsList();
|
||||||
void setRowColor(int row, QString color);
|
void setRowColor(int row, QString color);
|
||||||
void setStatus(const QString &value);
|
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Ongoing,
|
||||||
|
Finished,
|
||||||
|
Error,
|
||||||
|
Aborted,
|
||||||
|
NoResults
|
||||||
|
};
|
||||||
|
|
||||||
|
void setStatus(Status value);
|
||||||
|
Status status() const;
|
||||||
|
|
||||||
|
void updateResultsCount();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void downloadSelectedItem(const QModelIndex &index);
|
void downloadSelectedItem(const QModelIndex &index);
|
||||||
|
void updateFilter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void fillFilterComboBoxes();
|
||||||
|
NameFilteringMode filteringMode() const;
|
||||||
|
static QString statusText(Status st);
|
||||||
|
static QString statusIconName(Status st);
|
||||||
|
|
||||||
QVBoxLayout *m_box;
|
QVBoxLayout *m_box;
|
||||||
QLabel *m_resultsLbl;
|
QLabel *m_resultsLbl;
|
||||||
QTreeView *m_resultsBrowser;
|
QTreeView *m_resultsBrowser;
|
||||||
|
@ -74,8 +103,9 @@ private:
|
||||||
SearchSortModel *m_proxyModel;
|
SearchSortModel *m_proxyModel;
|
||||||
SearchListDelegate *m_searchDelegate;
|
SearchListDelegate *m_searchDelegate;
|
||||||
SearchWidget *m_parent;
|
SearchWidget *m_parent;
|
||||||
QString m_status;
|
Status m_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHTAB_H
|
Q_DECLARE_METATYPE(SearchTab::NameFilteringMode)
|
||||||
|
|
||||||
|
#endif // SEARCHTAB_H
|
||||||
|
|
240
src/gui/search/searchtab.ui
Normal file
240
src/gui/search/searchtab.ui
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SearchTab</class>
|
||||||
|
<widget class="QWidget" name="SearchTab">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1216</width>
|
||||||
|
<height>364</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Search in:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>filterMode</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="filterMode">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Some search engines search in torrent description and in torrent file names too. Whether such results will be shown in the list below is controlled by this mode.</p><p><span style=" font-weight:600;">Everywhere </span>disables filtering and shows everyhing returned by the search engines.</p><p><span style=" font-weight:600;">Torrent names only</span> shows only torrents whose names match the search query.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Minimum</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>12</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Set minimal and maximal allowed number of seeders</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Seeds:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="minSeeds">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Minimal number of seeds</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="maxSeeds">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Maximal number of seeds</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>∞</string>
|
||||||
|
</property>
|
||||||
|
<property name="prefix">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Minimum</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>12</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Set minimal and maximal allowed size of a torrent</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Size:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="minSize">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Minimal torrent size</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1000.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="minSizeUnit">
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>to</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="maxSize">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Maximal torrent size</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="specialValueText">
|
||||||
|
<string>∞</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-1.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>1000.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>1000.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="maxSizeUnit">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -45,6 +45,7 @@
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -74,7 +75,6 @@ SearchWidget::SearchWidget(MainWindow *mainWindow)
|
||||||
, m_mainWindow(mainWindow)
|
, m_mainWindow(mainWindow)
|
||||||
, m_isNewQueryString(false)
|
, m_isNewQueryString(false)
|
||||||
, m_noSearchResults(true)
|
, m_noSearchResults(true)
|
||||||
, m_nbSearchResults(0)
|
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
|
@ -82,6 +82,26 @@ SearchWidget::SearchWidget(MainWindow *mainWindow)
|
||||||
searchBarLayout->insertWidget(0, m_searchPattern);
|
searchBarLayout->insertWidget(0, m_searchPattern);
|
||||||
connect(m_searchPattern, SIGNAL(returnPressed()), searchButton, SLOT(click()));
|
connect(m_searchPattern, SIGNAL(returnPressed()), searchButton, SLOT(click()));
|
||||||
|
|
||||||
|
QString searchPatternHint;
|
||||||
|
QTextStream stream(&searchPatternHint, QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
stream << "<html><head/><body><p>"
|
||||||
|
<< tr("A phrase to search for.") << "<br>"
|
||||||
|
<< tr("Spaces in a search term may be protected by double quotes.")
|
||||||
|
<< "</p><p>"
|
||||||
|
<< tr("Example:", "Search phrase example")
|
||||||
|
<< "<br>"
|
||||||
|
<< tr("<b>foo bar</b>: search for <b>foo</b> and <b>bar</b>",
|
||||||
|
"Search phrase example, illustrates quotes usage, a pair of "
|
||||||
|
"space delimited words, individal words are highlighted")
|
||||||
|
<< "<br>"
|
||||||
|
<< tr("<b>"foo bar"</b>: search for <b>foo bar</b>",
|
||||||
|
"Search phrase example, illustrates quotes usage, double quoted"
|
||||||
|
"pair of space delimited words, the whole pair is highlighted")
|
||||||
|
<< "</p></body></html>" << flush;
|
||||||
|
|
||||||
|
m_searchPattern->setToolTip(searchPatternHint);
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
searchButton->setIcon(GuiIconProvider::instance()->getIcon("edit-find"));
|
searchButton->setIcon(GuiIconProvider::instance()->getIcon("edit-find"));
|
||||||
downloadButton->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
downloadButton->setIcon(GuiIconProvider::instance()->getIcon("download"));
|
||||||
|
@ -158,7 +178,6 @@ void SearchWidget::tab_changed(int t)
|
||||||
goToDescBtn->setEnabled(false);
|
goToDescBtn->setEnabled(false);
|
||||||
copyURLBtn->setEnabled(false);
|
copyURLBtn->setEnabled(false);
|
||||||
}
|
}
|
||||||
searchStatus->setText(m_currentSearchTab->status());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +206,11 @@ void SearchWidget::giveFocusToSearchInput()
|
||||||
m_searchPattern->setFocus();
|
m_searchPattern->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTabWidget *SearchWidget::searchTabs() const
|
||||||
|
{
|
||||||
|
return tabWidget;
|
||||||
|
}
|
||||||
|
|
||||||
// Function called when we click on search button
|
// Function called when we click on search button
|
||||||
void SearchWidget::on_searchButton_clicked()
|
void SearchWidget::on_searchButton_clicked()
|
||||||
{
|
{
|
||||||
|
@ -222,6 +246,7 @@ void SearchWidget::on_searchButton_clicked()
|
||||||
tabName.replace(QRegExp("&{1}"), "&&");
|
tabName.replace(QRegExp("&{1}"), "&&");
|
||||||
tabWidget->addTab(m_currentSearchTab, tabName);
|
tabWidget->addTab(m_currentSearchTab, tabName);
|
||||||
tabWidget->setCurrentWidget(m_currentSearchTab);
|
tabWidget->setCurrentWidget(m_currentSearchTab);
|
||||||
|
m_currentSearchTab->getCurrentSearchListProxy()->setNameFilter(pattern);
|
||||||
|
|
||||||
QStringList plugins;
|
QStringList plugins;
|
||||||
if (selectedPlugin() == "all") plugins = m_searchEngine->allPlugins();
|
if (selectedPlugin() == "all") plugins = m_searchEngine->allPlugins();
|
||||||
|
@ -233,10 +258,9 @@ void SearchWidget::on_searchButton_clicked()
|
||||||
|
|
||||||
// Update SearchEngine widgets
|
// Update SearchEngine widgets
|
||||||
m_noSearchResults = true;
|
m_noSearchResults = true;
|
||||||
m_nbSearchResults = 0;
|
|
||||||
|
|
||||||
// Changing the text of the current label
|
// Changing the text of the current label
|
||||||
m_activeSearchTab->getCurrentLabel()->setText(tr("Results <i>(%1)</i>:", "i.e: Search results").arg(0));
|
m_activeSearchTab->updateResultsCount();
|
||||||
|
|
||||||
// Launch search
|
// Launch search
|
||||||
m_searchEngine->startSearch(pattern, selectedCategory(), plugins);
|
m_searchEngine->startSearch(pattern, selectedCategory(), plugins);
|
||||||
|
@ -268,9 +292,7 @@ void SearchWidget::downloadTorrent(QString url)
|
||||||
void SearchWidget::searchStarted()
|
void SearchWidget::searchStarted()
|
||||||
{
|
{
|
||||||
// Update SearchEngine widgets
|
// Update SearchEngine widgets
|
||||||
m_activeSearchTab->setStatus(tr("Searching..."));
|
m_activeSearchTab->setStatus(SearchTab::Status::Ongoing);
|
||||||
searchStatus->setText(m_currentSearchTab->status());
|
|
||||||
searchStatus->repaint();
|
|
||||||
searchButton->setText(tr("Stop"));
|
searchButton->setText(tr("Stop"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,13 +307,12 @@ void SearchWidget::searchFinished(bool cancelled)
|
||||||
if (m_activeSearchTab.isNull()) return; // The active tab was closed
|
if (m_activeSearchTab.isNull()) return; // The active tab was closed
|
||||||
|
|
||||||
if (cancelled)
|
if (cancelled)
|
||||||
m_activeSearchTab->setStatus(tr("Search aborted"));
|
m_activeSearchTab->setStatus(SearchTab::Status::Aborted);
|
||||||
else if (m_noSearchResults)
|
else if (m_noSearchResults)
|
||||||
m_activeSearchTab->setStatus(tr("Search returned no results"));
|
m_activeSearchTab->setStatus(SearchTab::Status::NoResults);
|
||||||
else
|
else
|
||||||
m_activeSearchTab->setStatus(tr("Search has finished"));
|
m_activeSearchTab->setStatus(SearchTab::Status::Finished);
|
||||||
|
|
||||||
searchStatus->setText(m_currentSearchTab->status());
|
|
||||||
m_activeSearchTab = 0;
|
m_activeSearchTab = 0;
|
||||||
searchButton->setText(tr("Search"));
|
searchButton->setText(tr("Search"));
|
||||||
}
|
}
|
||||||
|
@ -304,9 +325,9 @@ void SearchWidget::searchFailed()
|
||||||
if (m_activeSearchTab.isNull()) return; // The active tab was closed
|
if (m_activeSearchTab.isNull()) return; // The active tab was closed
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
m_activeSearchTab->setStatus(tr("Search aborted"));
|
m_activeSearchTab->setStatus(SearchTab::Status::Aborted);
|
||||||
#else
|
#else
|
||||||
m_activeSearchTab->setStatus(tr("An error occurred during search..."));
|
m_activeSearchTab->setStatus(SearchTab::Status::Error);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,14 +352,13 @@ void SearchWidget::appendSearchResults(const QList<SearchResult> &results)
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::NAME), result.fileName); // Name
|
curModel->setData(curModel->index(row, SearchSortModel::NAME), result.fileName); // Name
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::SIZE), result.fileSize); // Size
|
curModel->setData(curModel->index(row, SearchSortModel::SIZE), result.fileSize); // Size
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::SEEDS), result.nbSeeders); // Seeders
|
curModel->setData(curModel->index(row, SearchSortModel::SEEDS), result.nbSeeders); // Seeders
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::LEECHS), result.nbLeechers); // Leechers
|
curModel->setData(curModel->index(row, SearchSortModel::LEECHES), result.nbLeechers); // Leechers
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::ENGINE_URL), result.siteUrl); // Search site URL
|
curModel->setData(curModel->index(row, SearchSortModel::ENGINE_URL), result.siteUrl); // Search site URL
|
||||||
curModel->setData(curModel->index(row, SearchSortModel::DESC_LINK), result.descrLink); // Description Link
|
curModel->setData(curModel->index(row, SearchSortModel::DESC_LINK), result.descrLink); // Description Link
|
||||||
}
|
}
|
||||||
|
|
||||||
m_noSearchResults = false;
|
m_noSearchResults = false;
|
||||||
m_nbSearchResults += results.size();
|
m_activeSearchTab->updateResultsCount();
|
||||||
m_activeSearchTab->getCurrentLabel()->setText(tr("Results <i>(%1)</i>:", "i.e: Search results").arg(m_nbSearchResults));
|
|
||||||
|
|
||||||
// Enable clear & download buttons
|
// Enable clear & download buttons
|
||||||
downloadButton->setEnabled(true);
|
downloadButton->setEnabled(true);
|
||||||
|
@ -361,7 +381,6 @@ void SearchWidget::closeTab(int index)
|
||||||
if (!m_allTabs.size()) {
|
if (!m_allTabs.size()) {
|
||||||
downloadButton->setEnabled(false);
|
downloadButton->setEnabled(false);
|
||||||
goToDescBtn->setEnabled(false);
|
goToDescBtn->setEnabled(false);
|
||||||
searchStatus->setText(tr("Stopped"));
|
|
||||||
copyURLBtn->setEnabled(false);
|
copyURLBtn->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ public:
|
||||||
void downloadTorrent(QString url);
|
void downloadTorrent(QString url);
|
||||||
void giveFocusToSearchInput();
|
void giveFocusToSearchInput();
|
||||||
|
|
||||||
|
QTabWidget* searchTabs() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
// Search slots
|
// Search slots
|
||||||
void tab_changed(int); //to prevent the use of the download button when the tab is empty
|
void tab_changed(int); //to prevent the use of the download button when the tab is empty
|
||||||
|
@ -89,7 +91,6 @@ private:
|
||||||
bool m_isNewQueryString;
|
bool m_isNewQueryString;
|
||||||
bool m_noSearchResults;
|
bool m_noSearchResults;
|
||||||
QByteArray m_searchResultLineTruncated;
|
QByteArray m_searchResultLineTruncated;
|
||||||
unsigned long m_nbSearchResults;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SEARCHWIDGET_H
|
#endif // SEARCHWIDGET_H
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>820</width>
|
<width>1382</width>
|
||||||
<height>453</height>
|
<height>669</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Search</string>
|
<string>Search</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="searchBarLayout">
|
<layout class="QHBoxLayout" name="searchBarLayout">
|
||||||
<item>
|
<item>
|
||||||
|
@ -32,68 +32,15 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<item>
|
<property name="sizePolicy">
|
||||||
<widget class="QLabel" name="status_lbl">
|
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||||
<property name="maximumSize">
|
<horstretch>0</horstretch>
|
||||||
<size>
|
<verstretch>1</verstretch>
|
||||||
<width>16777215</width>
|
</sizepolicy>
|
||||||
<height>35</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Status:</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="searchStatus">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>200</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>16777215</width>
|
|
||||||
<height>35</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<italic>true</italic>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Stopped</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>188</width>
|
|
||||||
<height>21</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QTabWidget" name="tabWidget"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -306,6 +306,9 @@
|
||||||
<file>icons/oxygen/services.png</file>
|
<file>icons/oxygen/services.png</file>
|
||||||
<file>icons/oxygen/tab-close.png</file>
|
<file>icons/oxygen/tab-close.png</file>
|
||||||
<file>icons/oxygen/task-attention.png</file>
|
<file>icons/oxygen/task-attention.png</file>
|
||||||
|
<file>icons/oxygen/task-complete.png</file>
|
||||||
|
<file>icons/oxygen/task-ongoing.png</file>
|
||||||
|
<file>icons/oxygen/task-reject.png</file>
|
||||||
<file>icons/oxygen/text-plain.png</file>
|
<file>icons/oxygen/text-plain.png</file>
|
||||||
<file>icons/oxygen/tools-report-bug.png</file>
|
<file>icons/oxygen/tools-report-bug.png</file>
|
||||||
<file>icons/oxygen/unavailable.png</file>
|
<file>icons/oxygen/unavailable.png</file>
|
||||||
|
|
BIN
src/icons/oxygen/task-complete.png
Normal file
BIN
src/icons/oxygen/task-complete.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 756 B |
BIN
src/icons/oxygen/task-ongoing.png
Normal file
BIN
src/icons/oxygen/task-ongoing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 958 B |
BIN
src/icons/oxygen/task-reject.png
Normal file
BIN
src/icons/oxygen/task-reject.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 842 B |
Loading…
Add table
Add a link
Reference in a new issue