Mercurial > minori
view src/gui/pages/search.cc @ 324:5d3c9b31aa6e
anime: add completed date member
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 12 Jun 2024 23:03:22 -0400 |
parents | 91ac90a34003 |
children | b5d6c27c308f |
line wrap: on
line source
#include "gui/pages/search.h" #include "core/anime.h" #include "core/anime_db.h" #include "core/filesystem.h" #include "core/http.h" #include "core/session.h" #include "core/strings.h" #include "gui/dialog/information.h" #include "gui/translate/anime.h" #include "gui/widgets/text.h" #include "services/services.h" #include "track/media.h" #include <QDate> #include <QHeaderView> #include <QMenu> #include <QToolBar> #include <QTreeView> #include <QVBoxLayout> #include <algorithm> #include <fstream> #include <iostream> #include <sstream> #include "anitomy/anitomy.h" #include "pugixml.hpp" SearchPageSearchThread::SearchPageSearchThread(QObject* parent) : QThread(parent) { } void SearchPageSearchThread::SetSearch(const std::string& search) { search_ = search; } void SearchPageSearchThread::run() { emit GotResults(Services::Search(search_)); } SearchPageListSortFilter::SearchPageListSortFilter(QObject* parent) : QSortFilterProxyModel(parent) { } bool SearchPageListSortFilter::lessThan(const QModelIndex& l, const QModelIndex& r) const { QVariant left = sourceModel()->data(l, sortRole()); QVariant right = sourceModel()->data(r, sortRole()); switch (left.userType()) { case QMetaType::Int: case QMetaType::UInt: case QMetaType::LongLong: case QMetaType::ULongLong: return left.toInt() < right.toInt(); case QMetaType::QDate: return left.toDate() < right.toDate(); case QMetaType::QString: default: // meh return QString::compare(left.toString(), right.toString(), Qt::CaseInsensitive) < 0; } } /* -------------------------------------------- */ SearchPageListModel::SearchPageListModel(QObject* parent) : QAbstractListModel(parent) { } void SearchPageListModel::ParseSearch(const std::vector<int>& ids) { /* hack!!! */ if (!rowCount(index(0))) { beginInsertRows(QModelIndex(), 0, 0); endInsertRows(); } beginResetModel(); this->ids = ids; endResetModel(); } int SearchPageListModel::rowCount(const QModelIndex& parent) const { return ids.size(); (void)(parent); } int SearchPageListModel::columnCount(const QModelIndex& parent) const { return NB_COLUMNS; (void)(parent); } QVariant SearchPageListModel::headerData(const int section, const Qt::Orientation orientation, const int role) const { switch (role) { case Qt::DisplayRole: { switch (section) { case SR_TITLE: return tr("Anime title"); case SR_EPISODES: return tr("Episode"); case SR_TYPE: return tr("Type"); case SR_SCORE: return tr("Score"); case SR_SEASON: return tr("Season"); default: return {}; } break; } case Qt::TextAlignmentRole: { switch (section) { case SR_TITLE: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); case SR_TYPE: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); case SR_EPISODES: case SR_SCORE: case SR_SEASON: return QVariant(Qt::AlignRight | Qt::AlignVCenter); default: return {}; } break; } } return QAbstractListModel::headerData(section, orientation, role); } QVariant SearchPageListModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); const Anime::Anime& anime = Anime::db.items[ids[index.row()]]; switch (role) { case Qt::DisplayRole: switch (index.column()) { case SR_TITLE: return Strings::ToQString(anime.GetUserPreferredTitle()); case SR_TYPE: return Strings::ToQString(Translate::ToLocalString(anime.GetFormat())); case SR_EPISODES: return anime.GetEpisodes(); case SR_SCORE: return QString::number(anime.GetAudienceScore()) + "%"; case SR_SEASON: return Strings::ToQString(Translate::ToLocalString(anime.GetSeason())) + " " + QString::number(anime.GetStartedDate().GetYear().value_or(2000)); default: return {}; } break; case Qt::UserRole: switch (index.column()) { case SR_SCORE: return anime.GetAudienceScore(); case SR_EPISODES: return anime.GetEpisodes(); case SR_SEASON: return anime.GetStartedDate().GetAsQDate(); /* We have to use this to work around some stupid * "conversion ambiguous" error on Linux */ default: return data(index, Qt::DisplayRole); } break; case Qt::SizeHintRole: { switch (index.column()) { default: { /* max horizontal size of 100, height size = size of current font */ const QString d = data(index, Qt::DisplayRole).toString(); const QFontMetrics metric = QFontMetrics(QFont()); return QSize(std::max(metric.boundingRect(d).width(), 100), metric.height()); } } break; } case Qt::TextAlignmentRole: return headerData(index.column(), Qt::Horizontal, Qt::TextAlignmentRole); } return QVariant(); } Qt::ItemFlags SearchPageListModel::flags(const QModelIndex& index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } Anime::Anime* SearchPageListModel::GetAnimeFromIndex(const QModelIndex& index) const { return &Anime::db.items[ids[index.row()]]; } void SearchPage::DisplayListMenu() { QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); menu->setToolTipsVisible(true); const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection()); bool add_to_list_enable = true; std::set<Anime::Anime*> animes; for (const auto& index : selection.indexes()) { if (!index.isValid()) continue; Anime::Anime* anime = model->GetAnimeFromIndex(index); if (anime) { animes.insert(anime); if (anime->IsInUserList()) add_to_list_enable = false; } } menu->addAction(tr("Information"), [this, animes] { for (auto& anime : animes) { InformationDialog* dialog = new InformationDialog( anime, [this](Anime::Anime* anime) { // UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this); dialog->show(); dialog->raise(); dialog->activateWindow(); } }); menu->addSeparator(); { QMenu* submenu = menu->addMenu(tr("Add to list...")); for (const auto& status : Anime::ListStatuses) { submenu->addAction(Strings::ToQString(Translate::ToLocalString(status)), [animes, status] { for (auto& anime : animes) { if (!anime->IsInUserList()) anime->AddToUserList(); anime->SetUserStatus(status); Services::UpdateAnimeEntry(anime->GetId()); } }); } submenu->setEnabled(add_to_list_enable); } menu->popup(QCursor::pos()); } void SearchPage::ItemDoubleClicked() { /* throw out any other garbage */ const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection()); if (!selection.indexes().first().isValid()) return; const QModelIndex index = model->index(selection.indexes().first().row()); Anime::Anime* anime = model->GetAnimeFromIndex(index); InformationDialog* dialog = new InformationDialog( anime, [this](Anime::Anime* anime) { // UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this); dialog->show(); dialog->raise(); dialog->activateWindow(); } SearchPage::SearchPage(QWidget* parent) : QFrame(parent) { setFrameShape(QFrame::Box); setFrameShadow(QFrame::Sunken); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); { /* Toolbar */ QToolBar* toolbar = new QToolBar(this); toolbar->setMovable(false); { QLineEdit* line_edit = new QLineEdit("", toolbar); connect(line_edit, &QLineEdit::returnPressed, this, [this, line_edit] { /* static thread here. */ if (thread_.isRunning()) thread_.exit(1); /* fail */ thread_.SetSearch(Strings::ToUtf8String(line_edit->text())); thread_.start(); }); connect(&thread_, &SearchPageSearchThread::GotResults, this, [this](const std::vector<int>& search) { model->ParseSearch(search); }); toolbar->addWidget(line_edit); } layout->addWidget(toolbar); } { QFrame* line = new QFrame(this); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); line->setLineWidth(1); layout->addWidget(line); } { treeview = new QTreeView(this); treeview->setUniformRowHeights(true); treeview->setAllColumnsShowFocus(false); treeview->setAlternatingRowColors(true); treeview->setSortingEnabled(true); treeview->setSelectionMode(QAbstractItemView::ExtendedSelection); treeview->setItemsExpandable(false); treeview->setRootIsDecorated(false); treeview->setContextMenuPolicy(Qt::CustomContextMenu); treeview->setFrameShape(QFrame::NoFrame); { sort_model = new SearchPageListSortFilter(treeview); model = new SearchPageListModel(treeview); sort_model->setSourceModel(model); sort_model->setSortRole(Qt::UserRole); sort_model->setSortCaseSensitivity(Qt::CaseInsensitive); treeview->setModel(sort_model); } // set column sizes treeview->setColumnWidth(SearchPageListModel::SR_TITLE, 400); treeview->setColumnWidth(SearchPageListModel::SR_TYPE, 60); treeview->setColumnWidth(SearchPageListModel::SR_EPISODES, 60); treeview->setColumnWidth(SearchPageListModel::SR_SCORE, 60); treeview->setColumnWidth(SearchPageListModel::SR_SEASON, 100); treeview->header()->setStretchLastSection(false); /* Double click stuff */ connect(treeview, &QAbstractItemView::doubleClicked, this, &SearchPage::ItemDoubleClicked); connect(treeview, &QWidget::customContextMenuRequested, this, &SearchPage::DisplayListMenu); layout->addWidget(treeview); } }