FEATURE: Search engine results can now be opened in a Web browser (plugins will be progressively ported, only btjunkie is working atm)

This commit is contained in:
Christophe Dumez 2010-12-26 09:51:37 +00:00
parent 35ea06214a
commit c14deec893
14 changed files with 224 additions and 177 deletions

View file

@ -7,6 +7,7 @@
- FEATURE: Added "Time Active/Seeded" column to transfer list - FEATURE: Added "Time Active/Seeded" column to transfer list
- FEATURE: Give feedback regarding the IP filter parsing - FEATURE: Give feedback regarding the IP filter parsing
- FEATURE: Added a button to reload the IP filter - FEATURE: Added a button to reload the IP filter
- FEATURE: Search engine results can now be opened in a Web browser
- COSMETIC: Same deletion confirmation dialog in the GUI and Web UI - COSMETIC: Same deletion confirmation dialog in the GUI and Web UI
- COSMETIC: Simplified the top toolbar - COSMETIC: Simplified the top toolbar
- COSMETIC: Display execution log as a tab instead of a modal window - COSMETIC: Display execution log as a tab instead of a modal window

View file

@ -39,11 +39,7 @@
#include <QProgressBar> #include <QProgressBar>
#include <QApplication> #include <QApplication>
#include "misc.h" #include "misc.h"
#include "previewselect.h"
// Defines for properties list columns
#define NAME 0
#define SIZE 1
#define PROGRESS 2
class PreviewListDelegate: public QItemDelegate { class PreviewListDelegate: public QItemDelegate {
Q_OBJECT Q_OBJECT
@ -58,11 +54,11 @@ class PreviewListDelegate: public QItemDelegate {
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){ switch(index.column()){
case SIZE: case PreviewSelect::SIZE:
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break; break;
case PROGRESS:{ case PreviewSelect::PROGRESS:{
float progress = index.data().toDouble()*100.; float progress = index.data().toDouble()*100.;
QStyleOptionProgressBarV2 newopt; QStyleOptionProgressBarV2 newopt;
newopt.rect = opt.rect; newopt.rect = opt.rect;

92
src/previewselect.cpp Normal file
View file

@ -0,0 +1,92 @@
#include <QStandardItemModel>
#include <QHeaderView>
#include <QMessageBox>
#include <QFile>
#include <libtorrent/version.hpp>
#include <libtorrent/session.hpp>
#include "misc.h"
#include "previewlistdelegate.h"
#include "previewselect.h"
PreviewSelect::PreviewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent), h(h){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
// Preview list
previewListModel = new QStandardItemModel(0, 3);
previewListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name"));
previewListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size"));
previewListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress"));
previewList->setModel(previewListModel);
listDelegate = new PreviewListDelegate(this);
previewList->setItemDelegate(listDelegate);
previewList->header()->resizeSection(0, 200);
// Fill list in
std::vector<libtorrent::size_type> fp;
h.file_progress(fp);
unsigned int nbFiles = h.num_files();
for(unsigned int i=0; i<nbFiles; ++i){
QString fileName = h.filename_at(i);
QString extension = fileName.split(QString::fromUtf8(".")).last().toUpper();
if(misc::isPreviewable(extension)) {
int row = previewListModel->rowCount();
previewListModel->insertRow(row);
previewListModel->setData(previewListModel->index(row, NAME), QVariant(fileName));
previewListModel->setData(previewListModel->index(row, SIZE), QVariant((qlonglong)h.filesize_at(i)));
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant((double)fp[i]/h.filesize_at(i)));
indexes << i;
}
}
previewList->selectionModel()->select(previewListModel->index(0, NAME), QItemSelectionModel::Select);
previewList->selectionModel()->select(previewListModel->index(0, SIZE), QItemSelectionModel::Select);
previewList->selectionModel()->select(previewListModel->index(0, PROGRESS), QItemSelectionModel::Select);
if(!previewListModel->rowCount()){
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
close();
}
connect(this, SIGNAL(readyToPreviewFile(QString)), parent, SLOT(previewFile(QString)));
if(previewListModel->rowCount() == 1){
qDebug("Torrent file only contains one file, no need to display selection dialog before preview");
// Only one file : no choice
on_previewButton_clicked();
}else{
qDebug("Displaying media file selection dialog for preview");
show();
}
}
PreviewSelect::~PreviewSelect(){
delete previewListModel;
delete listDelegate;
}
void PreviewSelect::on_previewButton_clicked(){
QModelIndex index;
QModelIndexList selectedIndexes = previewList->selectionModel()->selectedRows(NAME);
if(selectedIndexes.size() == 0) return;
#if LIBTORRENT_VERSION_MINOR > 14
// Flush data
h.flush_cache();
#endif
QString path;
foreach(index, selectedIndexes){
path = h.files_path().at(indexes.at(index.row()));
// File
if(QFile::exists(path)){
emit readyToPreviewFile(path);
} else {
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
}
close();
return;
}
qDebug("Cannot find file: %s", path.toLocal8Bit().data());
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
close();
}
void PreviewSelect::on_cancelButton_clicked(){
close();
}

View file

@ -32,114 +32,36 @@
#define PREVIEWSELECT_H #define PREVIEWSELECT_H
#include <QDialog> #include <QDialog>
#include <QStandardItemModel> #include <QList>
#include <QHeaderView>
#include <QMessageBox>
#include <QFile>
#include <libtorrent/version.hpp>
#include <libtorrent/session.hpp>
#include "ui_preview.h" #include "ui_preview.h"
#include "previewlistdelegate.h"
#include "misc.h"
#include "qtorrenthandle.h" #include "qtorrenthandle.h"
#define NAME 0 class QStandardItemModel;
#define SIZE 1 class PreviewListDelegate;
#define PROGRESS 2
class previewSelect: public QDialog, private Ui::preview { class PreviewSelect: public QDialog, private Ui::preview {
Q_OBJECT Q_OBJECT
public:
enum PreviewColumn { NAME, SIZE, PROGRESS };
public:
PreviewSelect(QWidget* parent, QTorrentHandle h);
~PreviewSelect();
signals:
void readyToPreviewFile(QString) const;
protected slots:
void on_previewButton_clicked();
void on_cancelButton_clicked();
private: private:
QStandardItemModel *previewListModel; QStandardItemModel *previewListModel;
PreviewListDelegate *listDelegate; PreviewListDelegate *listDelegate;
QTorrentHandle h; QTorrentHandle h;
QList<int> indexes; QList<int> indexes;
signals:
void readyToPreviewFile(QString) const;
protected slots:
void on_previewButton_clicked(){
QModelIndex index;
QModelIndexList selectedIndexes = previewList->selectionModel()->selectedRows(NAME);
if(selectedIndexes.size() == 0) return;
#if LIBTORRENT_VERSION_MINOR > 14
// Flush data
h.flush_cache();
#endif
QString path;
foreach(index, selectedIndexes){
path = h.files_path().at(indexes.at(index.row()));
// File
if(QFile::exists(path)){
emit readyToPreviewFile(path);
} else {
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
}
close();
return;
}
qDebug("Cannot find file: %s", path.toLocal8Bit().data());
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
close();
}
void on_cancelButton_clicked(){
close();
}
public:
previewSelect(QWidget* parent, QTorrentHandle h): QDialog(parent), h(h){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
// Preview list
previewListModel = new QStandardItemModel(0, 3);
previewListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name"));
previewListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size"));
previewListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress"));
previewList->setModel(previewListModel);
listDelegate = new PreviewListDelegate(this);
previewList->setItemDelegate(listDelegate);
previewList->header()->resizeSection(0, 200);
// Fill list in
std::vector<libtorrent::size_type> fp;
h.file_progress(fp);
unsigned int nbFiles = h.num_files();
for(unsigned int i=0; i<nbFiles; ++i){
QString fileName = h.filename_at(i);
QString extension = fileName.split(QString::fromUtf8(".")).last().toUpper();
if(misc::isPreviewable(extension)) {
int row = previewListModel->rowCount();
previewListModel->insertRow(row);
previewListModel->setData(previewListModel->index(row, NAME), QVariant(fileName));
previewListModel->setData(previewListModel->index(row, SIZE), QVariant((qlonglong)h.filesize_at(i)));
previewListModel->setData(previewListModel->index(row, PROGRESS), QVariant((double)fp[i]/h.filesize_at(i)));
indexes << i;
}
}
previewList->selectionModel()->select(previewListModel->index(0, NAME), QItemSelectionModel::Select);
previewList->selectionModel()->select(previewListModel->index(0, SIZE), QItemSelectionModel::Select);
previewList->selectionModel()->select(previewListModel->index(0, PROGRESS), QItemSelectionModel::Select);
if(!previewListModel->rowCount()){
QMessageBox::critical(0, tr("Preview impossible"), tr("Sorry, we can't preview this file"));
close();
}
connect(this, SIGNAL(readyToPreviewFile(QString)), parent, SLOT(previewFile(QString)));
if(previewListModel->rowCount() == 1){
qDebug("Torrent file only contains one file, no need to display selection dialog before preview");
// Only one file : no choice
on_previewButton_clicked();
}else{
qDebug("Displaying media file selection dialog for preview");
show();
}
}
~previewSelect(){
delete previewListModel;
delete listDelegate;
}
}; };
#endif #endif

View file

@ -1,4 +1,4 @@
#VERSION: 2.23 #VERSION: 2.31
#AUTHORS: Christophe Dumez (chris@qbittorrent.org) #AUTHORS: Christophe Dumez (chris@qbittorrent.org)
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -54,10 +54,13 @@ class btjunkie(object):
def start_a(self, attr): def start_a(self, attr):
params = dict(attr) params = dict(attr)
#print params #print params
if params.has_key('href') and params['href'].startswith("http://dl.btjunkie.org/torrent"): if params.has_key('href'):
self.current_item = {} if params['href'].startswith("http://dl.btjunkie.org/torrent"):
self.th_counter = 0 self.current_item = {}
self.current_item['link']=params['href'].strip() self.th_counter = 0
self.current_item['link']=params['href'].strip()
elif self.th_counter == 0 and params['href'].startswith("/torrent/") and params['href'].find('/files/') == -1:
self.current_item['desc_link'] = 'http://btjunkie.org'+params['href'].strip()
def handle_data(self, data): def handle_data(self, data):
if self.th_counter == 0: if self.th_counter == 0:
@ -116,4 +119,4 @@ class btjunkie(object):
if len(results) <= 0: if len(results) <= 0:
break break
i += 1 i += 1

View file

@ -1,6 +1,6 @@
isohunt: 1.32 isohunt: 1.32
torrentreactor: 1.21 torrentreactor: 1.21
btjunkie: 2.23 btjunkie: 2.31
mininova: 1.40 mininova: 1.40
piratebay: 1.30 piratebay: 1.30
vertor: 1.1 vertor: 1.1

View file

@ -1,4 +1,4 @@
#VERSION: 1.33 #VERSION: 1.41
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: # modification, are permitted provided that the following conditions are met:
@ -35,7 +35,10 @@ def prettyPrinter(dictionary):
if isinstance(dictionary[key], str): if isinstance(dictionary[key], str):
dictionary[key] = unicode(dictionary[key], 'utf-8') dictionary[key] = unicode(dictionary[key], 'utf-8')
dictionary['size'] = anySizeToBytes(dictionary['size']) dictionary['size'] = anySizeToBytes(dictionary['size'])
print u"%s|%s|%s|%s|%s|%s"%(dictionary['link'],dictionary['name'],dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url']) if dictionary.has_key('desc_link'):
print u"%s|%s|%s|%s|%s|%s|%s"%(dictionary['link'],dictionary['name'],dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url'],dictionary['desc_link'])
else:
print u"%s|%s|%s|%s|%s|%s"%(dictionary['link'],dictionary['name'],dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url'])
def anySizeToBytes(size_string): def anySizeToBytes(size_string):
""" """

View file

@ -136,6 +136,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="goToDescBtn">
<property name="text">
<string>Go to description page</string>
</property>
</widget>
</item>
<item> <item>
<spacer> <spacer>
<property name="orientation"> <property name="orientation">

View file

@ -42,6 +42,7 @@
#include <QMimeData> #include <QMimeData>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QFileDialog> #include <QFileDialog>
#include <QDesktopServices>
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
#include <stdlib.h> #include <stdlib.h>
@ -64,6 +65,7 @@ SearchEngine::SearchEngine(MainWindow *parent) : QWidget(parent), mp_mainWindow(
// Icons // Icons
search_button->setIcon(misc::getIcon("edit-find")); search_button->setIcon(misc::getIcon("edit-find"));
download_button->setIcon(misc::getIcon("download")); download_button->setIcon(misc::getIcon("download"));
goToDescBtn->setIcon(misc::getIcon("application-x-mswinurl"));
enginesButton->setIcon(misc::getIcon("preferences-system-network")); enginesButton->setIcon(misc::getIcon("preferences-system-network"));
// new qCompleter to the search pattern // new qCompleter to the search pattern
startSearchHistory(); startSearchHistory();
@ -253,8 +255,10 @@ void SearchEngine::tab_changed(int t)
{//-1 = no more tab {//-1 = no more tab
if(all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel()->rowCount()) { if(all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel()->rowCount()) {
download_button->setEnabled(true); download_button->setEnabled(true);
goToDescBtn->setEnabled(true);
} else { } else {
download_button->setEnabled(false); download_button->setEnabled(false);
goToDescBtn->setEnabled(false);
} }
} }
} }
@ -487,39 +491,39 @@ void SearchEngine::updateNova() {
package_file2.close(); package_file2.close();
// Copy search plugin files (if necessary) // Copy search plugin files (if necessary)
QString filePath = search_dir.absoluteFilePath("nova2.py"); QString filePath = search_dir.absoluteFilePath("nova2.py");
if(getPluginVersion(":/nova/nova2.py") > getPluginVersion(filePath)) { if(getPluginVersion(":/nova2/nova2.py") > getPluginVersion(filePath)) {
if(QFile::exists(filePath)) { if(QFile::exists(filePath)) {
misc::safeRemove(filePath); misc::safeRemove(filePath);
misc::safeRemove(filePath+"c"); misc::safeRemove(filePath+"c");
} }
QFile::copy(":/nova/nova2.py", filePath); QFile::copy(":/nova2/nova2.py", filePath);
} }
filePath = search_dir.absoluteFilePath("nova2dl.py"); filePath = search_dir.absoluteFilePath("nova2dl.py");
if(getPluginVersion(":/nova/nova2dl.py") > getPluginVersion(filePath)) { if(getPluginVersion(":/nova2/nova2dl.py") > getPluginVersion(filePath)) {
if(QFile::exists(filePath)){ if(QFile::exists(filePath)){
misc::safeRemove(filePath); misc::safeRemove(filePath);
misc::safeRemove(filePath+"c"); misc::safeRemove(filePath+"c");
} }
QFile::copy(":/nova/nova2dl.py", filePath); QFile::copy(":/nova2/nova2dl.py", filePath);
} }
filePath = search_dir.absoluteFilePath("novaprinter.py"); filePath = search_dir.absoluteFilePath("novaprinter.py");
if(getPluginVersion(":/nova/novaprinter.py") > getPluginVersion(filePath)) { if(getPluginVersion(":/nova2/novaprinter.py") > getPluginVersion(filePath)) {
if(QFile::exists(filePath)){ if(QFile::exists(filePath)){
misc::safeRemove(filePath); misc::safeRemove(filePath);
misc::safeRemove(filePath+"c"); misc::safeRemove(filePath+"c");
} }
QFile::copy(":/nova/novaprinter.py", filePath); QFile::copy(":/nova2/novaprinter.py", filePath);
} }
filePath = search_dir.absoluteFilePath("helpers.py"); filePath = search_dir.absoluteFilePath("helpers.py");
if(getPluginVersion(":/nova/helpers.py") > getPluginVersion(filePath)) { if(getPluginVersion(":/nova2/helpers.py") > getPluginVersion(filePath)) {
if(QFile::exists(filePath)){ if(QFile::exists(filePath)){
misc::safeRemove(filePath); misc::safeRemove(filePath);
misc::safeRemove(filePath+"c"); misc::safeRemove(filePath+"c");
} }
QFile::copy(":/nova/helpers.py", filePath); QFile::copy(":/nova2/helpers.py", filePath);
} }
filePath = search_dir.absoluteFilePath("socks.py"); filePath = search_dir.absoluteFilePath("socks.py");
@ -527,9 +531,9 @@ void SearchEngine::updateNova() {
misc::safeRemove(filePath); misc::safeRemove(filePath);
misc::safeRemove(filePath+"c"); misc::safeRemove(filePath+"c");
} }
QFile::copy(":/nova/socks.py", filePath); QFile::copy(":/nova2/socks.py", filePath);
QDir destDir(QDir(misc::searchEngineLocation()).absoluteFilePath("engines")); QDir destDir(QDir(misc::searchEngineLocation()).absoluteFilePath("engines"));
QDir shipped_subDir(":/nova/engines/"); QDir shipped_subDir(":/nova2/engines/");
QStringList files = shipped_subDir.entryList(); QStringList files = shipped_subDir.entryList();
foreach(const QString &file, files){ foreach(const QString &file, files){
QString shipped_file = shipped_subDir.absoluteFilePath(file); QString shipped_file = shipped_subDir.absoluteFilePath(file);
@ -598,7 +602,7 @@ void SearchEngine::searchFinished(int exitcode,QProcess::ExitStatus){
// SLOT to append one line to search results list // SLOT to append one line to search results list
// Line is in the following form : // Line is in the following form :
// file url | file name | file size | nb seeds | nb leechers | Search engine url // file url | file name | file size | nb seeds | nb leechers | Search engine url
void SearchEngine::appendSearchResult(QString line){ void SearchEngine::appendSearchResult(const QString &line){
if(!currentSearchTab) { if(!currentSearchTab) {
if(searchProcess->state() != QProcess::NotRunning){ if(searchProcess->state() != QProcess::NotRunning){
searchProcess->terminate(); searchProcess->terminate();
@ -609,8 +613,9 @@ void SearchEngine::appendSearchResult(QString line){
search_stopped = true; search_stopped = true;
return; return;
} }
QStringList parts = line.split("|"); const QStringList parts = line.split("|");
if(parts.size() != 6){ const int nb_fields = parts.size();
if(nb_fields < NB_PLUGIN_COLUMNS-1){ //-1 because desc_link is optional
return; return;
} }
Q_ASSERT(currentSearchTab); Q_ASSERT(currentSearchTab);
@ -620,28 +625,32 @@ void SearchEngine::appendSearchResult(QString line){
int row = cur_model->rowCount(); int row = cur_model->rowCount();
cur_model->insertRow(row); cur_model->insertRow(row);
cur_model->setData(cur_model->index(row, 5), parts.at(0).trimmed()); // download URL cur_model->setData(cur_model->index(row, DL_LINK), parts.at(PL_DL_LINK).trimmed()); // download URL
cur_model->setData(cur_model->index(row, 0), parts.at(1).trimmed()); // Name cur_model->setData(cur_model->index(row, NAME), parts.at(PL_NAME).trimmed()); // Name
cur_model->setData(cur_model->index(row, 1), parts.at(2).trimmed().toLongLong()); // Size cur_model->setData(cur_model->index(row, SIZE), parts.at(PL_SIZE).trimmed().toLongLong()); // Size
bool ok = false; bool ok = false;
qlonglong nb_seeders = parts.at(3).trimmed().toLongLong(&ok); qlonglong nb_seeders = parts.at(PL_SEEDS).trimmed().toLongLong(&ok);
if(!ok || nb_seeders < 0) { if(!ok || nb_seeders < 0) {
cur_model->setData(cur_model->index(row, 2), tr("Unknown")); // Seeders cur_model->setData(cur_model->index(row, SEEDS), tr("Unknown")); // Seeders
} else { } else {
cur_model->setData(cur_model->index(row, 2), nb_seeders); // Seeders cur_model->setData(cur_model->index(row, SEEDS), nb_seeders); // Seeders
} }
qlonglong nb_leechers = parts.at(4).trimmed().toLongLong(&ok); qlonglong nb_leechers = parts.at(PL_LEECHS).trimmed().toLongLong(&ok);
if(!ok || nb_leechers < 0) { if(!ok || nb_leechers < 0) {
cur_model->setData(cur_model->index(row, 3), tr("Unknown")); // Leechers cur_model->setData(cur_model->index(row, LEECHS), tr("Unknown")); // Leechers
} else { } else {
cur_model->setData(cur_model->index(row, 3), nb_leechers); // Leechers cur_model->setData(cur_model->index(row, LEECHS), nb_leechers); // Leechers
} }
cur_model->setData(cur_model->index(row, 4), parts.at(5).trimmed()); // Engine URL cur_model->setData(cur_model->index(row, ENGINE_URL), parts.at(PL_ENGINE_URL).trimmed()); // Engine URL
// Description Link
if(nb_fields == NB_PLUGIN_COLUMNS)
cur_model->setData(cur_model->index(row, DESC_LINK), parts.at(PL_DESC_LINK).trimmed());
no_search_results = false; no_search_results = false;
++nb_search_results; ++nb_search_results;
// Enable clear & download buttons // Enable clear & download buttons
download_button->setEnabled(true); download_button->setEnabled(true);
goToDescBtn->setEnabled(true);
} }
#if QT_VERSION >= 0x040500 #if QT_VERSION >= 0x040500
@ -660,6 +669,7 @@ void SearchEngine::closeTab(int index) {
delete all_tab.takeAt(index); delete all_tab.takeAt(index);
if(!all_tab.size()) { if(!all_tab.size()) {
download_button->setEnabled(false); download_button->setEnabled(false);
goToDescBtn->setEnabled(false);
} }
} }
#else #else
@ -703,3 +713,16 @@ void SearchEngine::on_download_button_clicked(){
} }
} }
} }
void SearchEngine::on_goToDescBtn_clicked()
{
QModelIndexList selectedIndexes = all_tab.at(tabWidget->currentIndex())->getCurrentTreeView()->selectionModel()->selectedIndexes();
foreach(const QModelIndex &index, selectedIndexes){
if(index.column() == NAME) {
QSortFilterProxyModel* model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListProxy();
const QString desc_url = model->data(model->index(index.row(), DESC_LINK)).toString();
if(!desc_url.isEmpty())
QDesktopServices::openUrl(QUrl(desc_url));
}
}
}

View file

@ -50,6 +50,11 @@ class SearchEngine : public QWidget, public Ui::search_engine{
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(SearchEngine) Q_DISABLE_COPY(SearchEngine)
public:
enum SearchColumn { NAME, SIZE, SEEDS, LEECHS, ENGINE_URL, DL_LINK, DESC_LINK, NB_SEARCH_COLUMNS };
private:
enum PluginColumn { PL_DL_LINK, PL_NAME, PL_SIZE, PL_SEEDS, PL_LEECHS, PL_ENGINE_URL, PL_DESC_LINK, NB_PLUGIN_COLUMNS };
public: public:
SearchEngine(MainWindow *mp_mainWindow); SearchEngine(MainWindow *mp_mainWindow);
~SearchEngine(); ~SearchEngine();
@ -91,7 +96,7 @@ protected slots:
#else #else
void closeTab(int index); void closeTab(int index);
#endif #endif
void appendSearchResult(QString line); void appendSearchResult(const QString &line);
void searchFinished(int exitcode,QProcess::ExitStatus); void searchFinished(int exitcode,QProcess::ExitStatus);
void readSearchOutput(); void readSearchOutput();
void searchStarted(); void searchStarted();
@ -113,6 +118,9 @@ protected slots:
void pythonDownloadFailure(QString url, QString error); void pythonDownloadFailure(QString url, QString error);
#endif #endif
private slots:
void on_goToDescBtn_clicked();
private: private:
// Search related // Search related
QProcess *searchProcess; QProcess *searchProcess;

View file

@ -38,13 +38,7 @@
#include <QPainter> #include <QPainter>
#include <QProgressBar> #include <QProgressBar>
#include "misc.h" #include "misc.h"
#include "searchengine.h"
// Defines for search results list columns
#define NAME 0
#define SIZE 1
#define SEEDERS 2
#define LEECHERS 3
#define ENGINE 4
class SearchListDelegate: public QItemDelegate { class SearchListDelegate: public QItemDelegate {
Q_OBJECT Q_OBJECT
@ -58,7 +52,7 @@ class SearchListDelegate: public QItemDelegate {
painter->save(); painter->save();
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option); QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){ switch(index.column()){
case SIZE: case SearchEngine::SIZE:
QItemDelegate::drawBackground(painter, opt, index); QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong())); QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break; break;

View file

@ -40,12 +40,6 @@
#include "searchengine.h" #include "searchengine.h"
#include "qinisettings.h" #include "qinisettings.h"
#define SEARCH_NAME 0
#define SEARCH_SIZE 1
#define SEARCH_SEEDERS 2
#define SEARCH_LEECHERS 3
#define SEARCH_ENGINE 4
SearchTab::SearchTab(SearchEngine *parent) : QWidget(), parent(parent) SearchTab::SearchTab(SearchEngine *parent) : QWidget(), parent(parent)
{ {
box=new QVBoxLayout(); box=new QVBoxLayout();
@ -57,12 +51,12 @@ SearchTab::SearchTab(SearchEngine *parent) : QWidget(), parent(parent)
setLayout(box); setLayout(box);
// Set Search results list model // Set Search results list model
SearchListModel = new QStandardItemModel(0,6); SearchListModel = new QStandardItemModel(0, SearchEngine::NB_SEARCH_COLUMNS);
SearchListModel->setHeaderData(SEARCH_NAME, Qt::Horizontal, tr("Name", "i.e: file name")); SearchListModel->setHeaderData(SearchEngine::NAME, Qt::Horizontal, tr("Name", "i.e: file name"));
SearchListModel->setHeaderData(SEARCH_SIZE, Qt::Horizontal, tr("Size", "i.e: file size")); SearchListModel->setHeaderData(SearchEngine::SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
SearchListModel->setHeaderData(SEARCH_SEEDERS, Qt::Horizontal, tr("Seeders", "i.e: Number of full sources")); SearchListModel->setHeaderData(SearchEngine::SEEDS, Qt::Horizontal, tr("Seeders", "i.e: Number of full sources"));
SearchListModel->setHeaderData(SEARCH_LEECHERS, Qt::Horizontal, tr("Leechers", "i.e: Number of partial sources")); SearchListModel->setHeaderData(SearchEngine::LEECHS, Qt::Horizontal, tr("Leechers", "i.e: Number of partial sources"));
SearchListModel->setHeaderData(SEARCH_ENGINE, Qt::Horizontal, tr("Search engine")); SearchListModel->setHeaderData(SearchEngine::ENGINE_URL, Qt::Horizontal, tr("Search engine"));
proxyModel = new QSortFilterProxyModel(); proxyModel = new QSortFilterProxyModel();
proxyModel->setDynamicSortFilter(true); proxyModel->setDynamicSortFilter(true);
@ -72,7 +66,8 @@ SearchTab::SearchTab(SearchEngine *parent) : QWidget(), parent(parent)
SearchDelegate = new SearchListDelegate(); SearchDelegate = new SearchListDelegate();
resultsBrowser->setItemDelegate(SearchDelegate); resultsBrowser->setItemDelegate(SearchDelegate);
resultsBrowser->hideColumn(URL_COLUMN); // Hide url column resultsBrowser->hideColumn(SearchEngine::DL_LINK); // Hide url column
resultsBrowser->hideColumn(SearchEngine::DESC_LINK);
resultsBrowser->setRootIsDecorated(false); resultsBrowser->setRootIsDecorated(false);
resultsBrowser->setAllColumnsShowFocus(true); resultsBrowser->setAllColumnsShowFocus(true);
@ -87,12 +82,12 @@ SearchTab::SearchTab(SearchEngine *parent) : QWidget(), parent(parent)
} }
// Sort by Seeds // Sort by Seeds
resultsBrowser->sortByColumn(SEEDERS, Qt::DescendingOrder); resultsBrowser->sortByColumn(SearchEngine::SEEDS, Qt::DescendingOrder);
} }
void SearchTab::downloadSelectedItem(const QModelIndex& index) { void SearchTab::downloadSelectedItem(const QModelIndex& index) {
QString engine_url = proxyModel->data(proxyModel->index(index.row(), ENGINE_URL_COLUMN)).toString(); QString engine_url = proxyModel->data(proxyModel->index(index.row(), SearchEngine::ENGINE_URL)).toString();
QString torrent_url = proxyModel->data(proxyModel->index(index.row(), URL_COLUMN)).toString(); QString torrent_url = proxyModel->data(proxyModel->index(index.row(), SearchEngine::DL_LINK)).toString();
setRowColor(index.row(), "red"); setRowColor(index.row(), "red");
parent->downloadTorrent(engine_url, torrent_url); parent->downloadTorrent(engine_url, torrent_url);
} }

View file

@ -139,7 +139,8 @@ nox {
torrentadditiondlg.cpp \ torrentadditiondlg.cpp \
sessionapplication.cpp \ sessionapplication.cpp \
torrentimportdlg.cpp \ torrentimportdlg.cpp \
executionlog.cpp executionlog.cpp \
previewselect.cpp
win32 { win32 {
HEADERS += programupdater.h HEADERS += programupdater.h

View file

@ -28,6 +28,23 @@
* Contact : chris@qbittorrent.org * Contact : chris@qbittorrent.org
*/ */
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QDesktopServices>
#include <QTimer>
#include <QClipboard>
#include <QInputDialog>
#include <QColor>
#include <QUrl>
#include <QMenu>
#include <QRegExp>
#include <QFileDialog>
#include <QMessageBox>
#include <libtorrent/version.hpp>
#include <vector>
#include <queue>
#include "transferlistwidget.h" #include "transferlistwidget.h"
#include "qbtsession.h" #include "qbtsession.h"
#include "torrentpersistentdata.h" #include "torrentpersistentdata.h"
@ -40,21 +57,6 @@
#include "torrentmodel.h" #include "torrentmodel.h"
#include "deletionconfirmationdlg.h" #include "deletionconfirmationdlg.h"
#include "propertieswidget.h" #include "propertieswidget.h"
#include <libtorrent/version.hpp>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QDesktopServices>
#include <QTimer>
#include <QClipboard>
#include <QInputDialog>
#include <QColor>
#include <QUrl>
#include <QMenu>
#include <QRegExp>
#include <QFileDialog>
#include <vector>
#include <queue>
#include "qinisettings.h" #include "qinisettings.h"
using namespace libtorrent; using namespace libtorrent;
@ -426,7 +428,7 @@ void TransferListWidget::previewSelectedTorrents() {
foreach(const QString &hash, hashes) { foreach(const QString &hash, hashes) {
const QTorrentHandle h = BTSession->getTorrentHandle(hash); const QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(h.is_valid() && h.has_metadata()) { if(h.is_valid() && h.has_metadata()) {
new previewSelect(this, h); new PreviewSelect(this, h);
} }
} }
} }