Merge pull request #473 from YACReader/comic_vine_integration_improvements

Comic vine integration improvements
This commit is contained in:
Luis Ángel San Martín 2025-05-06 08:20:55 +02:00 committed by GitHub
commit f0b9d45033
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 431 additions and 204 deletions

View File

@ -13,6 +13,9 @@ Version counting is based on semantic versioning (Major.Feature.Patch)
* Fix setting the comic rating in the table view. * Fix setting the comic rating in the table view.
* Log libraries validation when the app starts. * Log libraries validation when the app starts.
* New toolbar on macos. * New toolbar on macos.
* New setting in Comic Vine scraper to force exact volume matches.
* Better default search query in the Comic Vine scraper.
* Improved navigation in Comic Vine scraper, including keeping the current query around to make edits and refined searches easier.
### YACReaderLibraryServer ### YACReaderLibraryServer
* Log libraries validation when the app starts. * Log libraries validation when the app starts.

View File

@ -1,6 +1,9 @@
HEADERS += \ HEADERS += \
$$PWD/comic_vine_json_parser.h \ $$PWD/comic_vine_json_parser.h \
$$PWD/model/selected_volume_info.h \
$$PWD/model/volume_search_query.h \
$$PWD/scraper_checkbox.h \
comic_vine/comic_vine_dialog.h \ comic_vine/comic_vine_dialog.h \
comic_vine/comic_vine_client.h \ comic_vine/comic_vine_client.h \
comic_vine/scraper_lineedit.h \ comic_vine/scraper_lineedit.h \
@ -20,12 +23,12 @@ HEADERS += \
comic_vine/model/volume_comics_model.h \ comic_vine/model/volume_comics_model.h \
comic_vine/scraper_scroll_label.h \ comic_vine/scraper_scroll_label.h \
comic_vine/scraper_results_paginator.h \ comic_vine/scraper_results_paginator.h \
comic_vine/scraper_selector.h \
comic_vine/api_key_dialog.h \ comic_vine/api_key_dialog.h \
$$PWD/comic_vine_all_volume_comics_retriever.h $$PWD/comic_vine_all_volume_comics_retriever.h
SOURCES += \ SOURCES += \
$$PWD/comic_vine_json_parser.cpp \ $$PWD/comic_vine_json_parser.cpp \
$$PWD/scraper_checkbox.cpp \
comic_vine/comic_vine_dialog.cpp \ comic_vine/comic_vine_dialog.cpp \
comic_vine/comic_vine_client.cpp \ comic_vine/comic_vine_client.cpp \
comic_vine/scraper_lineedit.cpp \ comic_vine/scraper_lineedit.cpp \
@ -45,6 +48,5 @@ SOURCES += \
comic_vine/model/volume_comics_model.cpp \ comic_vine/model/volume_comics_model.cpp \
comic_vine/scraper_scroll_label.cpp \ comic_vine/scraper_scroll_label.cpp \
comic_vine/scraper_results_paginator.cpp \ comic_vine/scraper_results_paginator.cpp \
comic_vine/scraper_selector.cpp \
comic_vine/api_key_dialog.cpp \ comic_vine/api_key_dialog.cpp \
$$PWD/comic_vine_all_volume_comics_retriever.cpp $$PWD/comic_vine_all_volume_comics_retriever.cpp

View File

@ -18,6 +18,13 @@ static const QString CV_SEARCH = CV_WEB_ADDRESS + "/search/?api_key=" + CV_API_K
"&query=%1&page=%2"; "&query=%1&page=%2";
// http://www.comicvine.com/api/search/?api_key=46680bebb358f1de690a5a365e15d325f9649f91&format=json&limit=100&resources=volume&field_list=name,start_year,publisher,id,image,count_of_issues,deck&query=superman // http://www.comicvine.com/api/search/?api_key=46680bebb358f1de690a5a365e15d325f9649f91&format=json&limit=100&resources=volume&field_list=name,start_year,publisher,id,image,count_of_issues,deck&query=superman
// look for exact match volumes
static const QString CV_EXACT_VOLUME_SEARCH = CV_WEB_ADDRESS + "/volumes/?api_key=" + CV_API_KEY +
"&format=json&limit=100"
"&field_list=name,start_year,publisher,id,image,count_of_issues,deck"
"&sort=name:asc"
"&filter=name:%1&offset=%2";
// gets the detail for a volume %1 // gets the detail for a volume %1
static const QString CV_SERIES_DETAIL = CV_WEB_ADDRESS + "/volume/4050-%1/?api_key=" + CV_API_KEY + static const QString CV_SERIES_DETAIL = CV_WEB_ADDRESS + "/volume/4050-%1/?api_key=" + CV_API_KEY +
"&format=json&field_list=name,start_year,publisher,image,count_of_issues,id,description"; "&format=json&field_list=name,start_year,publisher,image,count_of_issues,id,description";
@ -69,6 +76,17 @@ void ComicVineClient::search(const QString &query, int page)
connect(search, &QThread::finished, search, &QObject::deleteLater); connect(search, &QThread::finished, search, &QObject::deleteLater);
search->get(); search->get();
} }
// CV_EXACT_VOLUME_SEARCH
void ComicVineClient::searchExactVolume(const QString &query, int page)
{
HttpWorker *search = new HttpWorker(QString(CV_EXACT_VOLUME_SEARCH).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(query).arg((page - 1) * 100));
connect(search, &HttpWorker::dataReady, this, &ComicVineClient::proccessVolumesSearchData);
connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut);
connect(search, &QThread::finished, search, &QObject::deleteLater);
search->get();
}
// CV_SEARCH result // CV_SEARCH result
void ComicVineClient::proccessVolumesSearchData(const QByteArray &data) void ComicVineClient::proccessVolumesSearchData(const QByteArray &data)
{ {
@ -120,7 +138,7 @@ void ComicVineClient::getSeriesCover(const QString &url)
// CV_COMIC_IDS // CV_COMIC_IDS
void ComicVineClient::getVolumeComicsInfo(const QString &idVolume, int page) void ComicVineClient::getVolumeComicsInfo(const QString &idVolume, int page)
{ {
HttpWorker *search = new HttpWorker(QString(CV_COMICS_INFO).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(idVolume).arg((page - 1) * 100)); // page doesn't work for search, using offset instead HttpWorker *search = new HttpWorker(QString(CV_COMICS_INFO).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(idVolume).arg((page - 1) * 100));
connect(search, &HttpWorker::dataReady, this, &ComicVineClient::processVolumeComicsInfo); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::processVolumeComicsInfo);
connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); // TODO connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); // TODO
connect(search, &QThread::finished, search, &QObject::deleteLater); connect(search, &QThread::finished, search, &QObject::deleteLater);

View File

@ -24,6 +24,7 @@ signals:
void finished(); void finished();
public slots: public slots:
void search(const QString &query, int page = 1); void search(const QString &query, int page = 1);
void searchExactVolume(const QString &query, int page = 1);
void getSeriesDetail(const QString &id); void getSeriesDetail(const QString &id);
void getSeriesCover(const QString &url); void getSeriesCover(const QString &url);
void getVolumeComicsInfo(const QString &idVolume, int page = 1); void getVolumeComicsInfo(const QString &idVolume, int page = 1);

View File

@ -22,6 +22,7 @@
#include "search_volume.h" #include "search_volume.h"
#include "select_comic.h" #include "select_comic.h"
#include "select_volume.h" #include "select_volume.h"
#include "selected_volume_info.h"
#include "sort_volume_comics.h" #include "sort_volume_comics.h"
#include "db_helper.h" #include "db_helper.h"
#include "response_parser.h" #include "response_parser.h"
@ -93,7 +94,7 @@ void ComicVineDialog::doLayout()
setLayout(mainLayout); setLayout(mainLayout);
setWindowTitle("Comic Vine Scraper (beta)"); setWindowTitle("Comic Vine Scraper");
} }
void ComicVineDialog::doStackedWidgets() void ComicVineDialog::doStackedWidgets()
@ -115,9 +116,9 @@ void ComicVineDialog::doConnections()
connect(searchButton, &QAbstractButton::clicked, this, &ComicVineDialog::search); connect(searchButton, &QAbstractButton::clicked, this, &ComicVineDialog::search);
connect(skipButton, &QAbstractButton::clicked, this, &ComicVineDialog::goToNextComic); connect(skipButton, &QAbstractButton::clicked, this, &ComicVineDialog::goToNextComic);
connect(selectVolumeWidget, &ScraperSelector::loadPage, this, &ComicVineDialog::searchVolume); connect(selectVolumeWidget, &SelectVolume::loadPage, this, &ComicVineDialog::searchVolume);
connect(selectComicWidget, &ScraperSelector::loadPage, this, &ComicVineDialog::getVolumeComicsInfo); connect(selectComicWidget, &SelectComic::loadPage, this, &ComicVineDialog::getVolumeComicsInfo);
connect(sortVolumeComicsWidget, &ScraperSelector::loadPage, this, &ComicVineDialog::getVolumeComicsInfo); connect(sortVolumeComicsWidget, &SortVolumeComics::loadPage, this, &ComicVineDialog::getVolumeComicsInfo);
connect(this, &QDialog::accepted, this, &QWidget::close, Qt::QueuedConnection); connect(this, &QDialog::accepted, this, &QWidget::close, Qt::QueuedConnection);
} }
@ -130,21 +131,22 @@ void ComicVineDialog::goNext()
if (content->currentWidget() == seriesQuestionWidget) { if (content->currentWidget() == seriesQuestionWidget) {
if (seriesQuestionWidget->getYes()) { if (seriesQuestionWidget->getYes()) {
QString volumeSearchString = comics[0].getParentFolderName(); QString volumeSearchString = comics[0].getParentFolderName();
mode = Volume; mode = ScraperMode::Volume;
showSearchVolume(volumeSearchString); showSearchVolume(volumeSearchString);
} else { } else {
status = AutoSearching; status = ScraperStatus::AutoSearching;
mode = SingleComicInList; mode = ScraperMode::SingleComicInList;
ComicDB comic = comics[currentIndex]; ComicDB comic = comics[currentIndex];
QString title = comic.getTitleOrFileName(); QString title = comic.getTitleOrFileName();
titleHeader->setSubTitle(tr("comic %1 of %2 - %3").arg(currentIndex + 1).arg(comics.length()).arg(title)); titleHeader->setSubTitle(tr("comic %1 of %2 - %3").arg(currentIndex + 1).arg(comics.length()).arg(title));
showLoading(tr("Looking for volume...")); showLoading(tr("Looking for volume..."));
searchVolume(title);
searchVolume({ volumeSearchStringFromComic(comic), 1, true });
} }
} else if (content->currentWidget() == selectVolumeWidget) { } else if (content->currentWidget() == selectVolumeWidget) {
currentVolumeId = selectVolumeWidget->getSelectedVolumeId(); currentVolumeId = selectVolumeWidget->getSelectedVolumeInfo().id;
getVolumeComicsInfo(currentVolumeId); getVolumeComicsInfo(currentVolumeId);
} else if (content->currentWidget() == sortVolumeComicsWidget) { } else if (content->currentWidget() == sortVolumeComicsWidget) {
@ -152,24 +154,23 @@ void ComicVineDialog::goNext()
// ComicDB-ComicVineID // ComicDB-ComicVineID
QList<QPair<ComicDB, QString>> matchingInfo = sortVolumeComicsWidget->getMatchingInfo(); QList<QPair<ComicDB, QString>> matchingInfo = sortVolumeComicsWidget->getMatchingInfo();
int count = selectVolumeWidget->getSelectedVolumeNumIssues(); auto volumeInfo = selectVolumeWidget->getSelectedVolumeInfo();
QString publisher = selectVolumeWidget->getSelectedVolumePublisher();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QtConcurrent::run(&ComicVineDialog::getComicsInfo, this, matchingInfo, count, publisher); QtConcurrent::run(&ComicVineDialog::getComicsInfo, this, matchingInfo, volumeInfo);
#else #else
QtConcurrent::run(this, &ComicVineDialog::getComicsInfo, matchingInfo, count, publisher); QtConcurrent::run(this, &ComicVineDialog::getComicsInfo, matchingInfo, volumeInfo);
#endif #endif
} else if (content->currentWidget() == selectComicWidget) { } else if (content->currentWidget() == selectComicWidget) {
showLoading(); showLoading();
QString comicId = selectComicWidget->getSelectedComicId(); QString comicId = selectComicWidget->getSelectedComicId();
int count = selectVolumeWidget->getSelectedVolumeNumIssues(); auto volumeInfo = selectVolumeWidget->getSelectedVolumeInfo();
QString publisher = selectVolumeWidget->getSelectedVolumePublisher();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QtConcurrent::run(&ComicVineDialog::getComicInfo, this, comicId, count, publisher); QtConcurrent::run(&ComicVineDialog::getComicInfo, this, comicId, volumeInfo);
#else #else
QtConcurrent::run(this, &ComicVineDialog::getComicInfo, comicId, count, publisher); QtConcurrent::run(this, &ComicVineDialog::getComicInfo, comicId, volumeInfo);
#endif #endif
} }
} }
@ -179,30 +180,35 @@ void ComicVineDialog::goBack()
clearState(); clearState();
switch (status) { switch (status) {
case SelectingSeries: case ScraperStatus::SelectingSeries:
if (mode == Volume) if (mode == ScraperMode::Volume)
showSearchVolume(); showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
case SortingComics: case ScraperStatus::SortingComics:
showSelectVolume(); showSelectVolume();
break; break;
case SelectingComic: case ScraperStatus::SelectingComic:
if (mode == SingleComic) if (mode == ScraperMode::SingleComic)
showSelectVolume(); showSelectVolume();
break; break;
case AutoSearching: case ScraperStatus::AutoSearching:
if (mode == Volume) if (mode == ScraperMode::Volume)
showSearchVolume(); showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
default:
if (mode == Volume) case ScraperStatus::AskingForInfo:
showSearchVolume(); case ScraperStatus::SearchingSingleComic:
case ScraperStatus::SearchingVolume:
case ScraperStatus::SearchingExactVolume:
case ScraperStatus::GettingVolumeComics:
if (mode == ScraperMode::Volume)
showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
} }
} }
@ -248,16 +254,15 @@ void ComicVineDialog::show()
searchVolumeWidget->clean(); searchVolumeWidget->clean();
if (comics.length() == 1) { if (comics.length() == 1) {
status = AutoSearching; status = ScraperStatus::AskingForInfo;
mode = SingleComic; mode = ScraperMode::SingleComic;
ComicDB singleComic = comics[0]; ComicDB singleComic = comics[0];
QString title = singleComic.getTitleOrFileName(); QString title = singleComic.getTitleOrFileName();
titleHeader->setSubTitle(title); titleHeader->setSubTitle(title);
showLoading(tr("Looking for volume..."));
searchVolume(singleComic.getParentFolderName()); showSearchSingleComic(volumeSearchStringFromComic(singleComic));
QLOG_TRACE() << singleComic.getParentFolderName();
} else if (comics.length() > 1) { } else if (comics.length() > 1) {
titleHeader->setSubTitle(tr("%1 comics selected").arg(comics.length())); titleHeader->setSubTitle(tr("%1 comics selected").arg(comics.length()));
showSeriesQuestion(); showSeriesQuestion();
@ -286,7 +291,7 @@ void ComicVineDialog::doLoading()
content->addWidget(w); content->addWidget(w);
} }
void ComicVineDialog::debugClientResults(const QString &string) void ComicVineDialog::processClientResults(const QString &string)
{ {
ResponseParser p; ResponseParser p;
p.loadJSONResponse(string); p.loadJSONResponse(string);
@ -295,19 +300,20 @@ void ComicVineDialog::debugClientResults(const QString &string)
QMessageBox::critical(0, tr("Error connecting to ComicVine"), p.errorDescription()); QMessageBox::critical(0, tr("Error connecting to ComicVine"), p.errorDescription());
goBack(); goBack();
} else { } else {
switch (mode) { switch (mode) {
case SingleComic: case ScraperMode::SingleComic:
case SingleComicInList: case ScraperMode::SingleComicInList:
if (p.getNumResults() == 0) if (p.getNumResults() == 0)
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
else if (status == SearchingVolume) else if (status == ScraperStatus::SearchingVolume || status == ScraperStatus::SearchingExactVolume)
showSelectVolume(string); showSelectVolume(string);
else else
showSelectComic(string); showSelectComic(string);
break; break;
case Volume: case ScraperMode::Volume:
if (p.getNumResults() == 0) if (p.getNumResults() == 0)
showSearchVolume(); showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSelectVolume(string); showSelectVolume(string);
break; break;
@ -317,7 +323,7 @@ void ComicVineDialog::debugClientResults(const QString &string)
void ComicVineDialog::showSeriesQuestion() void ComicVineDialog::showSeriesQuestion()
{ {
status = AskingForInfo; status = ScraperStatus::AskingForInfo;
content->setCurrentWidget(seriesQuestionWidget); content->setCurrentWidget(seriesQuestionWidget);
backButton->setHidden(true); backButton->setHidden(true);
skipButton->setHidden(true); skipButton->setHidden(true);
@ -330,9 +336,11 @@ void ComicVineDialog::showSeriesQuestion()
toggleSkipButton(); toggleSkipButton();
} }
void ComicVineDialog::showSearchSingleComic() void ComicVineDialog::showSearchSingleComic(const QString &volume)
{ {
status = AskingForInfo; searchSingleComicWidget->setVolumeInfo(volume);
status = ScraperStatus::AskingForInfo;
content->setCurrentWidget(searchSingleComicWidget); content->setCurrentWidget(searchSingleComicWidget);
backButton->setHidden(true); backButton->setHidden(true);
skipButton->setHidden(true); skipButton->setHidden(true);
@ -349,7 +357,7 @@ void ComicVineDialog::showSearchVolume(const QString &volume)
{ {
searchVolumeWidget->setVolumeInfo(volume); searchVolumeWidget->setVolumeInfo(volume);
status = AskingForInfo; status = ScraperStatus::AskingForInfo;
content->setCurrentWidget(searchVolumeWidget); content->setCurrentWidget(searchVolumeWidget);
backButton->setHidden(true); backButton->setHidden(true);
nextButton->setHidden(true); nextButton->setHidden(true);
@ -364,12 +372,12 @@ void ComicVineDialog::showSearchVolume(const QString &volume)
void ComicVineDialog::showSelectVolume(const QString &json) void ComicVineDialog::showSelectVolume(const QString &json)
{ {
showSelectVolume(); showSelectVolume();
selectVolumeWidget->load(json, currentVolumeSearchString); selectVolumeWidget->load(json, currentVolumeSearchQuery);
} }
void ComicVineDialog::showSelectVolume() void ComicVineDialog::showSelectVolume()
{ {
status = SelectingSeries; status = ScraperStatus::SelectingSeries;
content->setCurrentWidget(selectVolumeWidget); content->setCurrentWidget(selectVolumeWidget);
@ -385,7 +393,7 @@ void ComicVineDialog::showSelectVolume()
void ComicVineDialog::showSelectComic(const QString &json) void ComicVineDialog::showSelectComic(const QString &json)
{ {
status = SelectingComic; status = ScraperStatus::SelectingComic;
content->setCurrentWidget(selectComicWidget); content->setCurrentWidget(selectComicWidget);
selectComicWidget->load(json, currentVolumeId); selectComicWidget->load(json, currentVolumeId);
@ -402,7 +410,7 @@ void ComicVineDialog::showSelectComic(const QString &json)
void ComicVineDialog::showSortVolumeComics(const QString &json) void ComicVineDialog::showSortVolumeComics(const QString &json)
{ {
status = SortingComics; status = ScraperStatus::SortingComics;
content->setCurrentWidget(sortVolumeComicsWidget); content->setCurrentWidget(sortVolumeComicsWidget);
@ -423,30 +431,35 @@ void ComicVineDialog::queryTimeOut()
QMessageBox::warning(this, "Comic Vine error", "Time out connecting to Comic Vine"); QMessageBox::warning(this, "Comic Vine error", "Time out connecting to Comic Vine");
switch (status) { switch (status) {
case AutoSearching: case ScraperStatus::AutoSearching:
if (mode == Volume) if (mode == ScraperMode::Volume)
showSearchVolume(); showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
case SearchingVolume: case ScraperStatus::SearchingVolume:
if (mode == Volume) case ScraperStatus::SearchingExactVolume:
showSearchVolume(); if (mode == ScraperMode::Volume)
showSearchVolume(currentVolumeSearchQuery.volume);
else else
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
case SearchingSingleComic: case ScraperStatus::SearchingSingleComic:
showSearchSingleComic(); showSearchSingleComic(currentVolumeSearchQuery.volume);
break; break;
case GettingVolumeComics: case ScraperStatus::GettingVolumeComics:
showSelectVolume(); showSelectVolume();
break; break;
default:
case ScraperStatus::AskingForInfo:
case ScraperStatus::SelectingComic:
case ScraperStatus::SelectingSeries:
case ScraperStatus::SortingComics:
break; break;
} }
} }
void ComicVineDialog::getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo, int count, const QString &publisher) void ComicVineDialog::getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo, const SelectedVolumeInfo &volumeInfo)
{ {
QPair<ComicDB, QString> p; QPair<ComicDB, QString> p;
QList<ComicDB> comics; QList<ComicDB> comics;
@ -460,7 +473,7 @@ void ComicVineDialog::getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo,
QByteArray result = comicVineClient->getComicDetail(p.second, error, timeout); // TODO check timeOut or Connection error QByteArray result = comicVineClient->getComicDetail(p.second, error, timeout); // TODO check timeOut or Connection error
if (error || timeout) if (error || timeout)
continue; // TODO continue; // TODO
ComicDB comic = YACReader::parseCVJSONComicInfo(p.first, result, count, publisher); // TODO check result error ComicDB comic = YACReader::parseCVJSONComicInfo(p.first, result, volumeInfo); // TODO check result error
comic.info.comicVineID = p.second; comic.info.comicVineID = p.second;
comics.push_back(comic); comics.push_back(comic);
@ -472,7 +485,7 @@ void ComicVineDialog::getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo,
emit accepted(); emit accepted();
} }
void ComicVineDialog::getComicInfo(const QString &comicId, int count, const QString &publisher) void ComicVineDialog::getComicInfo(const QString &comicId, const SelectedVolumeInfo &volumeInfo)
{ {
auto comicVineClient = new ComicVineClient; auto comicVineClient = new ComicVineClient;
@ -481,14 +494,14 @@ void ComicVineDialog::getComicInfo(const QString &comicId, int count, const QStr
QByteArray result = comicVineClient->getComicDetail(comicId, error, timeout); // TODO check timeOut or Connection error QByteArray result = comicVineClient->getComicDetail(comicId, error, timeout); // TODO check timeOut or Connection error
if (error || timeout) { if (error || timeout) {
// TODO // TODO
if (mode == SingleComic || currentIndex == (comics.count() - 1)) { if (mode == ScraperMode::SingleComic || currentIndex == (comics.count() - 1)) {
emit accepted(); emit accepted();
} else { } else {
goToNextComic(); goToNextComic();
} }
} }
ComicDB comic = YACReader::parseCVJSONComicInfo(comics[currentIndex], result, count, publisher); // TODO check result error ComicDB comic = YACReader::parseCVJSONComicInfo(comics[currentIndex], result, volumeInfo); // TODO check result error
comic.info.comicVineID = comicId; comic.info.comicVineID = comicId;
setLoadingMessage(tr("Retrieving tags for : %1").arg(comics[currentIndex].getFileName())); setLoadingMessage(tr("Retrieving tags for : %1").arg(comics[currentIndex].getFileName()));
QString connectionName = ""; QString connectionName = "";
@ -504,7 +517,7 @@ void ComicVineDialog::getComicInfo(const QString &comicId, int count, const QStr
} }
QSqlDatabase::removeDatabase(connectionName); QSqlDatabase::removeDatabase(connectionName);
if (mode == SingleComic || currentIndex == (comics.count() - 1)) { if (mode == ScraperMode::SingleComic || currentIndex == (comics.count() - 1)) {
emit accepted(); emit accepted();
} else { } else {
goToNextComic(); goToNextComic();
@ -513,26 +526,46 @@ void ComicVineDialog::getComicInfo(const QString &comicId, int count, const QStr
void ComicVineDialog::toggleSkipButton() void ComicVineDialog::toggleSkipButton()
{ {
if (mode == SingleComicInList) if (mode == ScraperMode::SingleComicInList)
skipButton->setVisible(true); skipButton->setVisible(true);
else else
skipButton->setHidden(true); skipButton->setHidden(true);
} }
QString ComicVineDialog::volumeSearchStringFromComic(const ComicDB &comic)
{
auto volume = comic.info.volume.toString().trimmed();
if (!volume.isEmpty())
return volume;
auto series = comic.info.series.toString().trimmed();
if (!series.isEmpty())
return series;
auto alternateSeries = comic.info.alternateSeries.toString().trimmed();
if (!alternateSeries.isEmpty())
return alternateSeries;
// extract information from file name
auto parentFolderName = comic.getParentFolderName();
return parentFolderName;
}
void ComicVineDialog::goToNextComic() void ComicVineDialog::goToNextComic()
{ {
if (mode == SingleComic || currentIndex == (comics.count() - 1)) { if (mode == ScraperMode::SingleComic || currentIndex == (comics.count() - 1)) {
emit accepted(); emit accepted();
return; return;
} }
currentIndex++; currentIndex++;
showSearchSingleComic();
ComicDB comic = comics[currentIndex]; ComicDB comic = comics[currentIndex];
QString title = comic.getTitleOrFileName(); QString title = comic.getTitleOrFileName();
titleHeader->setSubTitle(tr("comic %1 of %2 - %3").arg(currentIndex + 1).arg(comics.length()).arg(title)); titleHeader->setSubTitle(tr("comic %1 of %2 - %3").arg(currentIndex + 1).arg(comics.length()).arg(title));
showSearchSingleComic(volumeSearchStringFromComic(comic));
} }
void ComicVineDialog::clearState() void ComicVineDialog::clearState()
@ -559,38 +592,44 @@ void ComicVineDialog::setLoadingMessage(const QString &message)
void ComicVineDialog::search() void ComicVineDialog::search()
{ {
switch (mode) { switch (mode) {
case Volume: case ScraperMode::Volume:
launchSearchVolume(); launchSearchVolume();
break; break;
default:
case ScraperMode::SingleComic:
case ScraperMode::SingleComicInList:
launchSearchComic(); launchSearchComic();
break; break;
} }
} }
void ComicVineDialog::searchVolume(const QString &v, int page) void ComicVineDialog::searchVolume(const VolumeSearchQuery &query)
{ {
showLoading(tr("Looking for volume...")); showLoading(tr("Looking for volume..."));
currentVolumeSearchString = v; currentVolumeSearchQuery = query;
auto comicVineClient = new ComicVineClient; auto comicVineClient = new ComicVineClient;
connect(comicVineClient, &ComicVineClient::searchResult, this, &ComicVineDialog::debugClientResults); connect(comicVineClient, &ComicVineClient::searchResult, this, &ComicVineDialog::processClientResults);
connect(comicVineClient, &ComicVineClient::timeOut, this, &ComicVineDialog::queryTimeOut); connect(comicVineClient, &ComicVineClient::timeOut, this, &ComicVineDialog::queryTimeOut);
connect(comicVineClient, &ComicVineClient::finished, comicVineClient, &QObject::deleteLater); connect(comicVineClient, &ComicVineClient::finished, comicVineClient, &QObject::deleteLater);
comicVineClient->search(v, page); if (query.exactMatch) {
status = ScraperStatus::SearchingExactVolume;
status = SearchingVolume; comicVineClient->searchExactVolume(query.volume, query.page);
} else {
status = ScraperStatus::SearchingVolume;
comicVineClient->search(query.volume, query.page);
}
} }
void ComicVineDialog::getVolumeComicsInfo(const QString &vID, int /* page */) void ComicVineDialog::getVolumeComicsInfo(const QString &vID, int /* page */)
{ {
showLoading(tr("Retrieving volume info...")); showLoading(tr("Retrieving volume info..."));
status = GettingVolumeComics; status = ScraperStatus::GettingVolumeComics;
auto comicVineClient = new ComicVineClient; auto comicVineClient = new ComicVineClient;
if (mode == Volume) if (mode == ScraperMode::Volume)
connect(comicVineClient, &ComicVineClient::volumeComicsInfo, this, &ComicVineDialog::showSortVolumeComics); connect(comicVineClient, &ComicVineClient::volumeComicsInfo, this, &ComicVineDialog::showSortVolumeComics);
else else
connect(comicVineClient, &ComicVineClient::volumeComicsInfo, this, &ComicVineDialog::showSelectComic); connect(comicVineClient, &ComicVineClient::volumeComicsInfo, this, &ComicVineDialog::showSelectComic);
@ -602,21 +641,28 @@ void ComicVineDialog::getVolumeComicsInfo(const QString &vID, int /* page */)
comicVineClient->getAllVolumeComicsInfo(vID); comicVineClient->getAllVolumeComicsInfo(vID);
} }
// TODO: get the search configuration for exact match or not
void ComicVineDialog::launchSearchVolume() void ComicVineDialog::launchSearchVolume()
{ {
showLoading(tr("Looking for volume...")); showLoading(tr("Looking for volume..."));
// TODO: check if volume info is empty. // TODO: check if volume info is empty.
searchVolume(searchVolumeWidget->getVolumeInfo());
QString volumeInfo = searchVolumeWidget->getVolumeInfo();
bool exactMatch = searchVolumeWidget->getExactMatch();
searchVolume({ volumeInfo, 1, exactMatch });
} }
// TODO: get the search configuration for exact match or not
void ComicVineDialog::launchSearchComic() void ComicVineDialog::launchSearchComic()
{ {
showLoading(tr("Looking for comic...")); showLoading(tr("Looking for comic..."));
QString volumeInfo = searchSingleComicWidget->getVolumeInfo(); QString volumeInfo = searchSingleComicWidget->getVolumeInfo();
bool exactMatch = searchSingleComicWidget->getExactMatch();
// QString comicInfo = searchSingleComicWidget->getComicInfo(); // QString comicInfo = searchSingleComicWidget->getComicInfo();
// int comicNumber = searchSingleComicWidget->getComicNumber(); // int comicNumber = searchSingleComicWidget->getComicNumber();
// if(comicInfo.isEmpty() && comicNumber == -1) // if(comicInfo.isEmpty() && comicNumber == -1)
searchVolume(volumeInfo); searchVolume({ volumeInfo, 1, exactMatch });
} }

View File

@ -4,6 +4,7 @@
#include <QDialog> #include <QDialog>
#include "comic_db.h" #include "comic_db.h"
#include "volume_search_query.h"
class QPushButton; class QPushButton;
class QStackedWidget; class QStackedWidget;
@ -17,7 +18,9 @@ class SearchSingleComic;
class SearchVolume; class SearchVolume;
class SelectComic; class SelectComic;
class SelectVolume; class SelectVolume;
struct SelectedVolumeInfo;
class SortVolumeComics; class SortVolumeComics;
struct VolumeSearchQuery;
// TODO this should use a QStateMachine // TODO this should use a QStateMachine
//---------------------------------------- //----------------------------------------
@ -31,8 +34,8 @@ public:
void setComics(const QList<ComicDB> &comics); void setComics(const QList<ComicDB> &comics);
QSize sizeHint() const override; QSize sizeHint() const override;
QSize minimumSizeHint() const override; QSize minimumSizeHint() const override;
void getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo, int count, const QString &publisher); void getComicsInfo(QList<QPair<ComicDB, QString>> matchingInfo, const SelectedVolumeInfo &volumeInfo);
void getComicInfo(const QString &comicId, int count, const QString &publisher); void getComicInfo(const QString &comicId, const SelectedVolumeInfo &volumeInfo);
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
signals: signals:
@ -42,14 +45,14 @@ public slots:
protected slots: protected slots:
void goNext(); void goNext();
void goBack(); void goBack();
void debugClientResults(const QString &string); void processClientResults(const QString &string);
// show widget methods // show widget methods
void showSeriesQuestion(); void showSeriesQuestion();
void showSearchSingleComic(); void showSearchSingleComic(const QString &volume = "");
void showSearchVolume(const QString &volume = ""); void showSearchVolume(const QString &volume = "");
void showLoading(const QString &message = ""); void showLoading(const QString &message = "");
void search(); void search();
void searchVolume(const QString &v, int page = 1); void searchVolume(const VolumeSearchQuery &query);
void getVolumeComicsInfo(const QString &vID, int page = 1); void getVolumeComicsInfo(const QString &vID, int page = 1);
void launchSearchVolume(); void launchSearchVolume();
void launchSearchComic(); void launchSearchComic();
@ -63,22 +66,23 @@ protected slots:
private: private:
void clearState(); void clearState();
void toggleSkipButton(); void toggleSkipButton();
QString volumeSearchStringFromComic(const ComicDB &comic);
enum ScraperMode { enum class ScraperMode {
SingleComic, // the scraper has been opened for a single comic SingleComic, // the scraper has been opened for a single comic
Volume, // the scraper is trying to get comics info for a whole volume Volume, // the scraper is trying to get comics info for a whole volume
SingleComicInList // the scraper has been opened for a list of unrelated comics SingleComicInList // the scraper has been opened for a list of unrelated comics
}; };
enum ScraperStatus { enum class ScraperStatus {
AutoSearching, AutoSearching, // Searching for volumes maching a single comic
AskingForInfo, AskingForInfo, // The dialog is showing some UI to ask the user for some info
SelectingComic, SelectingComic,
SelectingSeries, SelectingSeries,
SearchingSingleComic, SearchingSingleComic,
SearchingVolume, SearchingVolume,
SearchingExactVolume,
SortingComics, SortingComics,
GettingVolumeComics GettingVolumeComics
}; };
@ -118,7 +122,7 @@ private:
SelectComic *selectComicWidget; SelectComic *selectComicWidget;
SortVolumeComics *sortVolumeComicsWidget; SortVolumeComics *sortVolumeComicsWidget;
QString currentVolumeSearchString; VolumeSearchQuery currentVolumeSearchQuery;
QString currentVolumeId; QString currentVolumeId;
}; };

View File

@ -2,6 +2,7 @@
#include "comic_vine_json_parser.h" #include "comic_vine_json_parser.h"
#include "comic_vine_client.h" #include "comic_vine_client.h"
#include "selected_volume_info.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonParseError> #include <QJsonParseError>
@ -12,7 +13,7 @@ QPair<QString, QString> getFirstStoryArcIdAndName(const QVariant &json_story_arc
QPair<QString, QString> getArcNumberAndArcCount(const QString &storyArcId, const QString &comicId); QPair<QString, QString> getArcNumberAndArcCount(const QString &storyArcId, const QString &comicId);
QList<QString> getNamesFromList(const QVariant &json_list); QList<QString> getNamesFromList(const QVariant &json_list);
ComicDB YACReader::parseCVJSONComicInfo(ComicDB &comic, const QString &json, int count, const QString &publisher) ComicDB YACReader::parseCVJSONComicInfo(ComicDB &comic, const QString &json, const SelectedVolumeInfo &volumeInfo)
{ {
QJsonParseError Err; QJsonParseError Err;
@ -61,8 +62,12 @@ ComicDB YACReader::parseCVJSONComicInfo(ComicDB &comic, const QString &json, int
} }
} }
if (result.contains("description") && !result.value("description").isNull()) { if (result.contains("description") && !result.value("description").isNull() && !result.value("description").toString().trimmed().isEmpty()) {
comic.info.synopsis = result.value("description"); comic.info.synopsis = result.value("description");
} else if (result.contains("deck") && !result.value("deck").isNull() && !result.value("deck").toString().trimmed().isEmpty()) {
comic.info.synopsis = result.value("deck");
} else if (!volumeInfo.description.trimmed().isEmpty() && volumeInfo.numIssues < 2) {
comic.info.synopsis = volumeInfo.description.trimmed();
} }
if (result.contains("character_credits") && !result.value("character_credits").isNull()) { if (result.contains("character_credits") && !result.value("character_credits").isNull()) {
@ -101,9 +106,9 @@ ComicDB YACReader::parseCVJSONComicInfo(ComicDB &comic, const QString &json, int
comic.info.characters = getNamesFromList(result.value("character_credits")).join("\n"); comic.info.characters = getNamesFromList(result.value("character_credits")).join("\n");
} }
comic.info.count = count; comic.info.count = volumeInfo.numIssues;
comic.info.publisher = publisher; comic.info.publisher = volumeInfo.publisher;
comic.info.edited = true; comic.info.edited = true;
} }

View File

@ -4,9 +4,11 @@
#include "comic_db.h" #include "comic_db.h"
struct SelectedVolumeInfo;
namespace YACReader { namespace YACReader {
ComicDB parseCVJSONComicInfo(ComicDB &comic, const QString &json, int count, const QString &publisher); ComicDB parseCVJSONComicInfo(ComicDB &comic, const QString &json, const SelectedVolumeInfo &volumeInfo);
} }

View File

@ -0,0 +1,13 @@
#ifndef SELECTED_VOLUME_INFO_H
#define SELECTED_VOLUME_INFO_H
#include <QString>
struct SelectedVolumeInfo {
QString id;
int numIssues;
QString publisher;
QString description;
};
#endif // SELECTED_VOLUME_INFO_H

View File

@ -0,0 +1,12 @@
#ifndef VOLUME_SEARCH_QUERY_H
#define VOLUME_SEARCH_QUERY_H
#include <QString>
struct VolumeSearchQuery {
QString volume;
int page;
bool exactMatch;
};
#endif // VOLUME_SEARCH_QUERY_H

View File

@ -0,0 +1,27 @@
#include "scraper_checkbox.h"
#include "qwidget.h"
ScraperCheckBox::ScraperCheckBox(const QString &text, QWidget *parent)
: QCheckBox(text, parent)
{
setStyleSheet(
"QCheckBox {"
" color: white;"
" font-size: 12px;"
" font-family: Arial;"
" spacing: 10px;"
"}"
"QCheckBox::indicator {"
" width: 13px;"
" height: 13px;"
" border: 1px solid #242424;"
" background: #2e2e2e;"
"}"
"QCheckBox::indicator:checked {"
" image: url(:/images/comic_vine/checkBoxTick.svg);"
" background: #2e2e2e;"
"}"
"QCheckBox::indicator:unchecked {"
" background: #2e2e2e;"
"}");
}

View File

@ -0,0 +1,12 @@
#ifndef SCRAPER_CHECKBOX_H
#define SCRAPER_CHECKBOX_H
#include <QCheckBox>
class ScraperCheckBox : public QCheckBox
{
public:
ScraperCheckBox(const QString &text, QWidget *parent = nullptr);
};
#endif // SCRAPER_CHECKBOX_H

View File

@ -1,25 +0,0 @@
#include "scraper_selector.h"
ScraperSelector::ScraperSelector(QWidget *parent)
: QWidget(parent)
{
paginator = new ScraperResultsPaginator;
connect(paginator, &ScraperResultsPaginator::loadNextPage, this, &ScraperSelector::loadNextPage);
connect(paginator, &ScraperResultsPaginator::loadPreviousPage, this, &ScraperSelector::loadPreviousPage);
}
void ScraperSelector::load(const QString &json, const QString &searchString)
{
currentSearchString = searchString;
paginator->update(json);
}
void ScraperSelector::loadNextPage()
{
emit loadPage(currentSearchString, paginator->getCurrentPage() + 1);
}
void ScraperSelector::loadPreviousPage()
{
emit loadPage(currentSearchString, paginator->getCurrentPage() - 1);
}

View File

@ -1,28 +0,0 @@
#ifndef SCRAPER_SELECTOR_H
#define SCRAPER_SELECTOR_H
#include <QWidget>
#include "scraper_results_paginator.h"
class ScraperSelector : public QWidget
{
Q_OBJECT
public:
explicit ScraperSelector(QWidget *parent = nullptr);
virtual void load(const QString &json, const QString &searchString);
public slots:
signals:
void loadPage(QString, int);
private slots:
void loadNextPage();
void loadPreviousPage();
protected:
QString currentSearchString;
ScraperResultsPaginator *paginator;
};
#endif // SCRAPER_SELECTOR_H

View File

@ -54,6 +54,8 @@ ScraperTableView::ScraperTableView(QWidget *parent)
setAlternatingRowColors(true); setAlternatingRowColors(true);
horizontalHeader()->setMinimumSectionSize(85);
verticalHeader()->hide(); verticalHeader()->hide();
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);

View File

@ -11,12 +11,16 @@ SearchSingleComic::SearchSingleComic(QWidget *parent)
{ {
// QLabel * label = new QLabel(tr("Please provide some additional information. At least one field is needed.")); // QLabel * label = new QLabel(tr("Please provide some additional information. At least one field is needed."));
QLabel *label = new QLabel(tr("Please provide some additional information.")); QLabel *label = new QLabel(tr("Please provide some additional information for this comic."));
label->setStyleSheet("QLabel {color:white; font-size:12px;font-family:Arial;}"); label->setStyleSheet("QLabel {color:white; font-size:12px;font-family:Arial;}");
// titleEdit = new ScraperLineEdit(tr("Title:")); // titleEdit = new ScraperLineEdit(tr("Title:"));
// numberEdit = new ScraperLineEdit(tr("Number:")); // numberEdit = new ScraperLineEdit(tr("Number:"));
volumeEdit = new ScraperLineEdit(tr("Series:")); volumeEdit = new ScraperLineEdit(tr("Series:"));
volumeEdit->setClearButtonEnabled(true);
exactMatchCheckBox = new ScraperCheckBox(tr("Use exact match search. Disable if you want to find volumes that match some of the words in the name."));
exactMatchCheckBox->setChecked(true);
// numberEdit->setMaximumWidth(126); // numberEdit->setMaximumWidth(126);
@ -29,6 +33,7 @@ SearchSingleComic::SearchSingleComic(QWidget *parent)
l->addWidget(label); l->addWidget(label);
// l->addLayout(hl); // l->addLayout(hl);
l->addWidget(volumeEdit); l->addWidget(volumeEdit);
l->addWidget(exactMatchCheckBox);
l->addStretch(); l->addStretch();
l->setContentsMargins(0, 0, 0, 0); l->setContentsMargins(0, 0, 0, 0);
@ -36,11 +41,16 @@ SearchSingleComic::SearchSingleComic(QWidget *parent)
setContentsMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0);
} }
QString SearchSingleComic::getVolumeInfo() QString SearchSingleComic::getVolumeInfo() const
{ {
return volumeEdit->text(); return volumeEdit->text();
} }
void SearchSingleComic::setVolumeInfo(const QString &volume)
{
volumeEdit->setText(volume);
}
QString SearchSingleComic::getComicInfo() QString SearchSingleComic::getComicInfo()
{ {
// return titleEdit->text(); // return titleEdit->text();

View File

@ -1,7 +1,9 @@
#ifndef SEARCH_SINGLE_COMIC_H #ifndef SEARCH_SINGLE_COMIC_H
#define SEARCH_SINGLE_COMIC_H #define SEARCH_SINGLE_COMIC_H
#include <QWidget> #include <QtWidgets>
#include "scraper_checkbox.h"
class ScraperLineEdit; class ScraperLineEdit;
@ -10,14 +12,17 @@ class SearchSingleComic : public QWidget
Q_OBJECT Q_OBJECT
public: public:
SearchSingleComic(QWidget *parent = nullptr); SearchSingleComic(QWidget *parent = nullptr);
QString getVolumeInfo(); QString getVolumeInfo() const;
bool getExactMatch() const { return exactMatchCheckBox->isChecked(); }
void setVolumeInfo(const QString &volume);
QString getComicInfo(); QString getComicInfo();
int getComicNumber(); int getComicNumber();
void clean(); void clean();
private: private:
ScraperLineEdit *titleEdit; // ScraperLineEdit *titleEdit;
ScraperLineEdit *numberEdit; // ScraperLineEdit *numberEdit;
ScraperLineEdit *volumeEdit; ScraperLineEdit *volumeEdit;
ScraperCheckBox *exactMatchCheckBox;
}; };
#endif // SEARCH_SINGLE_COMIC_H #endif // SEARCH_SINGLE_COMIC_H

View File

@ -1,6 +1,7 @@
#include "search_volume.h" #include "search_volume.h"
#include "scraper_lineedit.h" #include "scraper_lineedit.h"
#include "scraper_checkbox.h"
#include <QLabel> #include <QLabel>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -12,12 +13,17 @@ SearchVolume::SearchVolume(QWidget *parent)
label->setStyleSheet("QLabel {color:white; font-size:12px;font-family:Arial;}"); label->setStyleSheet("QLabel {color:white; font-size:12px;font-family:Arial;}");
volumeEdit = new ScraperLineEdit(tr("Series:")); volumeEdit = new ScraperLineEdit(tr("Series:"));
volumeEdit->setClearButtonEnabled(true);
exactMatchCheckBox = new ScraperCheckBox(tr("Use exact match search. Disable if you want to find volumes that match some of the words in the name."), this);
exactMatchCheckBox->setChecked(true);
QVBoxLayout *l = new QVBoxLayout; QVBoxLayout *l = new QVBoxLayout;
l->addSpacing(35); l->addSpacing(35);
l->addWidget(label); l->addWidget(label);
l->addWidget(volumeEdit); l->addWidget(volumeEdit);
l->addWidget(exactMatchCheckBox);
l->addStretch(); l->addStretch();
l->setContentsMargins(0, 0, 0, 0); l->setContentsMargins(0, 0, 0, 0);

View File

@ -1,9 +1,11 @@
#ifndef SEARCH_VOLUME_H #ifndef SEARCH_VOLUME_H
#define SEARCH_VOLUME_H #define SEARCH_VOLUME_H
#include <QWidget> #include <QtWidgets>
#include "scraper_checkbox.h"
class ScraperLineEdit; class ScraperLineEdit;
class ScraperCheckBox;
class SearchVolume : public QWidget class SearchVolume : public QWidget
{ {
@ -13,9 +15,11 @@ public:
void clean(); void clean();
void setVolumeInfo(const QString &volume); void setVolumeInfo(const QString &volume);
QString getVolumeInfo() const; QString getVolumeInfo() const;
bool getExactMatch() const { return exactMatchCheckBox->isChecked(); }
private: private:
ScraperLineEdit *volumeEdit; ScraperLineEdit *volumeEdit;
ScraperCheckBox *exactMatchCheckBox;
}; };
#endif // SEARCH_VOLUME_H #endif // SEARCH_VOLUME_H

View File

@ -11,7 +11,7 @@
#include <QLayout> #include <QLayout>
SelectComic::SelectComic(QWidget *parent) SelectComic::SelectComic(QWidget *parent)
: ScraperSelector(parent), model(0) : QWidget(parent), model(0)
{ {
QString labelStylesheet = "QLabel {color:white; font-size:12px;font-family:Arial;}"; QString labelStylesheet = "QLabel {color:white; font-size:12px;font-family:Arial;}";
@ -35,6 +35,9 @@ SelectComic::SelectComic(QWidget *parent)
// connections // connections
connect(tableComics, &QAbstractItemView::clicked, this, &SelectComic::loadComicInfo); connect(tableComics, &QAbstractItemView::clicked, this, &SelectComic::loadComicInfo);
paginator = new ScraperResultsPaginator;
connect(paginator, &ScraperResultsPaginator::loadNextPage, this, &SelectComic::loadNextPage);
connect(paginator, &ScraperResultsPaginator::loadPreviousPage, this, &SelectComic::loadPreviousPage);
paginator->setCustomLabel(tr("comics")); paginator->setCustomLabel(tr("comics"));
left->addWidget(cover); left->addWidget(cover);
@ -62,7 +65,7 @@ SelectComic::SelectComic(QWidget *parent)
setContentsMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0);
} }
void SelectComic::load(const QString &json, const QString &searchString) void SelectComic::load(const QString &json, const QString &volumeId)
{ {
auto tempM = new VolumeComicsModel(); auto tempM = new VolumeComicsModel();
tempM->load(json); tempM->load(json);
@ -80,7 +83,18 @@ void SelectComic::load(const QString &json, const QString &searchString)
tableComics->resizeColumnToContents(0); tableComics->resizeColumnToContents(0);
ScraperSelector::load(json, searchString); currentVolumeId = volumeId;
paginator->update(json);
}
void SelectComic::loadNextPage()
{
emit loadPage(currentVolumeId, paginator->getCurrentPage() + 1);
}
void SelectComic::loadPreviousPage()
{
emit loadPage(currentVolumeId, paginator->getCurrentPage() - 1);
} }
SelectComic::~SelectComic() { } SelectComic::~SelectComic() { }
@ -130,9 +144,20 @@ void SelectComic::setDescription(const QString &jsonDetail)
return; return;
} }
QVariant descriptionValues = sc.value("results").toMap().value("description"); auto resultMap = sc.value("results").toMap();
bool valid = !descriptionValues.isNull() && descriptionValues.isValid(); QVariant descriptionValues = resultMap.value("description");
detailLabel->setText(valid ? descriptionValues.toString().replace("<a", "<a style = 'color:#827A68; text-decoration:none;'") : tr("description unavailable")); auto description = descriptionValues.toString().trimmed();
QVariant deckValues = resultMap.value("deck");
auto deck = deckValues.toString().trimmed();
bool valid = !descriptionValues.isNull() && descriptionValues.isValid() && !description.isEmpty();
bool validDeck = !deckValues.isNull() && deckValues.isValid() && !deck.isEmpty();
if (valid) {
detailLabel->setText(description.replace("<a", "<a style = 'color:#827A68; text-decoration:none;'"));
} else if (validDeck) {
detailLabel->setText(deck.replace("<a", "<a style = 'color:#827A68; text-decoration:none;'"));
} else {
detailLabel->setText(tr("comic description unavailable"));
}
} }
QString SelectComic::getSelectedComicId() QString SelectComic::getSelectedComicId()

View File

@ -1,7 +1,9 @@
#ifndef SELECT_COMIC_H #ifndef SELECT_COMIC_H
#define SELECT_COMIC_H #define SELECT_COMIC_H
#include "scraper_selector.h" #include <QtWidgets>
#include "scraper_results_paginator.h"
class QLabel; class QLabel;
class VolumeComicsModel; class VolumeComicsModel;
@ -10,12 +12,12 @@ class QModelIndex;
class ScraperScrollLabel; class ScraperScrollLabel;
class ScraperTableView; class ScraperTableView;
class SelectComic : public ScraperSelector class SelectComic : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
SelectComic(QWidget *parent = nullptr); SelectComic(QWidget *parent = nullptr);
void load(const QString &json, const QString &searchString) override; void load(const QString &json, const QString &volumeId);
virtual ~SelectComic(); virtual ~SelectComic();
public slots: public slots:
@ -24,11 +26,20 @@ public slots:
void setDescription(const QString &jsonDetail); void setDescription(const QString &jsonDetail);
QString getSelectedComicId(); QString getSelectedComicId();
signals:
void loadPage(QString, int);
private slots:
void loadNextPage();
void loadPreviousPage();
private: private:
QLabel *cover; QLabel *cover;
ScraperScrollLabel *detailLabel; ScraperScrollLabel *detailLabel;
ScraperTableView *tableComics; ScraperTableView *tableComics;
VolumeComicsModel *model; VolumeComicsModel *model;
QString currentVolumeId;
ScraperResultsPaginator *paginator;
}; };
#endif // SELECT_COMIC_H #endif // SELECT_COMIC_H

View File

@ -24,8 +24,10 @@
#include "response_parser.h" #include "response_parser.h"
#include "scraper_results_paginator.h" #include "scraper_results_paginator.h"
#include "selected_volume_info.h"
SelectVolume::SelectVolume(QWidget *parent) SelectVolume::SelectVolume(QWidget *parent)
: ScraperSelector(parent), model(0) : QWidget(parent), model(0)
{ {
proxyModel = new QSortFilterProxyModel; proxyModel = new QSortFilterProxyModel;
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@ -61,6 +63,9 @@ SelectVolume::SelectVolume(QWidget *parent)
connect(tableVolumes->horizontalHeader(), qOverload<int, Qt::SortOrder>(&QHeaderView::sortIndicatorChanged), tableVolumes, qOverload<int, Qt::SortOrder>(&QTableView::sortByColumn)); connect(tableVolumes->horizontalHeader(), qOverload<int, Qt::SortOrder>(&QHeaderView::sortIndicatorChanged), tableVolumes, qOverload<int, Qt::SortOrder>(&QTableView::sortByColumn));
connect(tableVolumes, &QAbstractItemView::clicked, this, &SelectVolume::loadVolumeInfo); connect(tableVolumes, &QAbstractItemView::clicked, this, &SelectVolume::loadVolumeInfo);
paginator = new ScraperResultsPaginator;
connect(paginator, &ScraperResultsPaginator::loadNextPage, this, &SelectVolume::loadNextPage);
connect(paginator, &ScraperResultsPaginator::loadPreviousPage, this, &SelectVolume::loadPreviousPage);
paginator->setCustomLabel(tr("volumes")); paginator->setCustomLabel(tr("volumes"));
top->addWidget(label); top->addWidget(label);
@ -91,7 +96,7 @@ SelectVolume::SelectVolume(QWidget *parent)
setContentsMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0);
} }
void SelectVolume::load(const QString &json, const QString &searchString) void SelectVolume::load(const QString &json, const VolumeSearchQuery &searchQuery)
{ {
auto tempM = new VolumesModel(); auto tempM = new VolumesModel();
tempM->load(json); tempM->load(json);
@ -114,7 +119,18 @@ void SelectVolume::load(const QString &json, const QString &searchString)
tableVolumes->setColumnWidth(0, 350); tableVolumes->setColumnWidth(0, 350);
ScraperSelector::load(json, searchString); currentSearchQuery = searchQuery;
paginator->update(json);
}
void SelectVolume::loadNextPage()
{
emit loadPage({ currentSearchQuery.volume, paginator->getCurrentPage() + 1, currentSearchQuery.exactMatch });
}
void SelectVolume::loadPreviousPage()
{
emit loadPage({ currentSearchQuery.volume, paginator->getCurrentPage() - 1, currentSearchQuery.exactMatch });
} }
void SelectVolume::clearFilter() void SelectVolume::clearFilter()
@ -176,22 +192,29 @@ void SelectVolume::setDescription(const QString &jsonDetail)
return; return;
} }
QVariant descriptionValues = sc.value("results").toMap().value("description"); auto resultMap = sc.value("results").toMap();
bool valid = !descriptionValues.isNull() && descriptionValues.isValid(); QVariant descriptionValues = resultMap.value("description");
detailLabel->setText(valid ? descriptionValues.toString().replace("<a", "<a style = 'color:#827A68; text-decoration:none;'") : tr("description unavailable")); auto description = descriptionValues.toString().trimmed();
QVariant deckValues = resultMap.value("deck");
auto deck = deckValues.toString().trimmed();
bool valid = !descriptionValues.isNull() && descriptionValues.isValid() && !description.isEmpty();
bool validDeck = !deckValues.isNull() && deckValues.isValid() && !deck.isEmpty();
if (valid) {
selectedVolumeDescription = description;
detailLabel->setText(description.replace("<a", "<a style = 'color:#827A68; text-decoration:none;'"));
} else if (validDeck) {
selectedVolumeDescription = deck;
detailLabel->setText(deck.replace("<a", "<a style = 'color:#827A68; text-decoration:none;'"));
} else {
detailLabel->setText(tr("volume description unavailable"));
}
} }
QString SelectVolume::getSelectedVolumeId() SelectedVolumeInfo SelectVolume::getSelectedVolumeInfo()
{ {
return model->getVolumeId(proxyModel->mapToSource(tableVolumes->currentIndex())); auto volumeId = model->getVolumeId(proxyModel->mapToSource(tableVolumes->currentIndex()));
} auto numIssues = model->getNumIssues(proxyModel->mapToSource(tableVolumes->currentIndex()));
auto publisher = model->getPublisher(proxyModel->mapToSource(tableVolumes->currentIndex()));
int SelectVolume::getSelectedVolumeNumIssues() return { volumeId, numIssues, publisher, selectedVolumeDescription };
{
return model->getNumIssues(proxyModel->mapToSource(tableVolumes->currentIndex()));
}
QString SelectVolume::getSelectedVolumePublisher()
{
return model->getPublisher(proxyModel->mapToSource(tableVolumes->currentIndex()));
} }

View File

@ -1,7 +1,11 @@
#ifndef SELECT_VOLUME_H #ifndef SELECT_VOLUME_H
#define SELECT_VOLUME_H #define SELECT_VOLUME_H
#include "scraper_selector.h" #include <QtWidgets>
#include "scraper_results_paginator.h"
#include "selected_volume_info.h"
#include "volume_search_query.h"
class QLabel; class QLabel;
class VolumesModel; class VolumesModel;
@ -13,12 +17,12 @@ class ScraperScrollLabel;
class ScraperTableView; class ScraperTableView;
class ScraperLineEdit; class ScraperLineEdit;
class SelectVolume : public ScraperSelector class SelectVolume : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
SelectVolume(QWidget *parent = nullptr); SelectVolume(QWidget *parent = nullptr);
void load(const QString &json, const QString &searchString) override; void load(const QString &json, const VolumeSearchQuery &searchQuery);
void clearFilter(); void clearFilter();
virtual ~SelectVolume(); virtual ~SelectVolume();
@ -26,9 +30,14 @@ public slots:
void loadVolumeInfo(const QModelIndex &mi); void loadVolumeInfo(const QModelIndex &mi);
void setCover(const QByteArray &); void setCover(const QByteArray &);
void setDescription(const QString &jsonDetail); void setDescription(const QString &jsonDetail);
QString getSelectedVolumeId(); SelectedVolumeInfo getSelectedVolumeInfo();
int getSelectedVolumeNumIssues();
QString getSelectedVolumePublisher(); signals:
void loadPage(VolumeSearchQuery);
private slots:
void loadNextPage();
void loadPreviousPage();
private: private:
QLabel *cover; QLabel *cover;
@ -37,6 +46,9 @@ private:
VolumesModel *model; VolumesModel *model;
QSortFilterProxyModel *proxyModel; QSortFilterProxyModel *proxyModel;
ScraperLineEdit *filterEdit; ScraperLineEdit *filterEdit;
QString selectedVolumeDescription;
VolumeSearchQuery currentSearchQuery;
ScraperResultsPaginator *paginator;
}; };
#endif // SELECT_VOLUME_H #endif // SELECT_VOLUME_H

View File

@ -11,7 +11,7 @@
#include "volume_comics_model.h" #include "volume_comics_model.h"
SortVolumeComics::SortVolumeComics(QWidget *parent) SortVolumeComics::SortVolumeComics(QWidget *parent)
: ScraperSelector(parent) : QWidget(parent)
{ {
QString labelStylesheet = "QLabel {color:white; font-size:12px;font-family:Arial;}"; QString labelStylesheet = "QLabel {color:white; font-size:12px;font-family:Arial;}";
@ -55,6 +55,9 @@ SortVolumeComics::SortVolumeComics(QWidget *parent)
// connect(tableVolumeComics, SIGNAL(pressed(QModelIndex)), tableFiles, SLOT(setCurrentIndex(QModelIndex))); // connect(tableVolumeComics, SIGNAL(pressed(QModelIndex)), tableFiles, SLOT(setCurrentIndex(QModelIndex)));
// connect(tableFiles, SIGNAL(pressed(QModelIndex)), tableVolumeComics, SLOT(setCurrentIndex(QModelIndex))); // connect(tableFiles, SIGNAL(pressed(QModelIndex)), tableVolumeComics, SLOT(setCurrentIndex(QModelIndex)));
paginator = new ScraperResultsPaginator;
connect(paginator, &ScraperResultsPaginator::loadNextPage, this, &SortVolumeComics::loadNextPage);
connect(paginator, &ScraperResultsPaginator::loadPreviousPage, this, &SortVolumeComics::loadPreviousPage);
paginator->setCustomLabel(tr("issues")); paginator->setCustomLabel(tr("issues"));
paginator->setMinimumWidth(422); paginator->setMinimumWidth(422);
@ -119,7 +122,18 @@ void SortVolumeComics::setData(QList<ComicDB> &comics, const QString &json, cons
tableVolumeComics->resizeColumnToContents(0); tableVolumeComics->resizeColumnToContents(0);
ScraperSelector::load(json, vID); currentVolumeId = vID;
paginator->update(json);
}
void SortVolumeComics::loadNextPage()
{
emit loadPage(currentVolumeId, paginator->getCurrentPage() + 1);
}
void SortVolumeComics::loadPreviousPage()
{
emit loadPage(currentVolumeId, paginator->getCurrentPage() - 1);
} }
void SortVolumeComics::synchronizeScroll(int pos) void SortVolumeComics::synchronizeScroll(int pos)

View File

@ -1,13 +1,13 @@
#ifndef SORT_VOLUME_COMICS_H #ifndef SORT_VOLUME_COMICS_H
#define SORT_VOLUME_COMICS_H #define SORT_VOLUME_COMICS_H
#include "scraper_selector.h" #include <QtWidgets>
#include <QModelIndex> #include <QModelIndex>
#include <QPushButton> #include <QPushButton>
#include <QPainter> #include <QPainter>
#include "comic_db.h" #include "comic_db.h"
#include "scraper_results_paginator.h"
class ScraperTableView; class ScraperTableView;
class LocalComicListModel; class LocalComicListModel;
@ -63,14 +63,12 @@ private:
Appearance appearance; Appearance appearance;
}; };
class SortVolumeComics : public ScraperSelector class SortVolumeComics : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SortVolumeComics(QWidget *parent = nullptr); explicit SortVolumeComics(QWidget *parent = nullptr);
signals:
public slots: public slots:
void setData(QList<ComicDB> &comics, const QString &json, const QString &vID); void setData(QList<ComicDB> &comics, const QString &json, const QString &vID);
QList<QPair<ComicDB, QString>> getMatchingInfo(); QList<QPair<ComicDB, QString>> getMatchingInfo();
@ -86,6 +84,13 @@ protected slots:
void restoreAllComics(); void restoreAllComics();
void showRemovedComicsSelector(); void showRemovedComicsSelector();
signals:
void loadPage(QString, int);
private slots:
void loadNextPage();
void loadPreviousPage();
private: private:
ScraperTableView *tableFiles; ScraperTableView *tableFiles;
ScraperTableView *tableVolumeComics; ScraperTableView *tableVolumeComics;
@ -97,6 +102,9 @@ private:
ScrapperToolButton *moveDownButtonCL; ScrapperToolButton *moveDownButtonCL;
ScrapperToolButton *moveUpButtonIL; ScrapperToolButton *moveUpButtonIL;
ScrapperToolButton *moveDownButtonIL; ScrapperToolButton *moveDownButtonIL;
QString currentVolumeId;
ScraperResultsPaginator *paginator;
}; };
#endif // SORT_VOLUME_COMICS_H #endif // SORT_VOLUME_COMICS_H

View File

@ -10,6 +10,7 @@
<file>../images/comic_vine/rowDown.png</file> <file>../images/comic_vine/rowDown.png</file>
<file>../images/comic_vine/rowUp.png</file> <file>../images/comic_vine/rowUp.png</file>
<file>../images/comic_vine/upArrow.png</file> <file>../images/comic_vine/upArrow.png</file>
<file>../images/comic_vine/checkBoxTick.svg</file>
<file>../images/comics_view_toolbar/asignNumber.svg</file> <file>../images/comics_view_toolbar/asignNumber.svg</file>
<file>../images/comics_view_toolbar/big_size_grid_zoom.svg</file> <file>../images/comics_view_toolbar/big_size_grid_zoom.svg</file>
<file>../images/comics_view_toolbar/editComic.svg</file> <file>../images/comics_view_toolbar/editComic.svg</file>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13">
<defs>
<style>
.cls-1 {
fill: none;
stroke: #fff;
stroke-miterlimit: 10;
stroke-width: 1.5px;
}
</style>
</defs>
<polyline class="cls-1" points="11 4 6 9 3 6"/>
</svg>

After

Width:  |  Height:  |  Size: 358 B