comparison src/gui/pages/anime_list.cc @ 258:862d0d8619f6

*: HUUUGE changes animia has been renamed to animone, so instead of thinking of a health condition, you think of a beautiful flower :) I've also edited some of the code for animone, but I have no idea if it even works or not because I don't have a mac or windows machine lying around. whoops! ... anyway, all of the changes divergent from Anisthesia are now licensed under BSD. it's possible that I could even rewrite most of the code to where I don't even have to keep the MIT license, but that's thinking too far into the future I've been slacking off on implementing the anime seasons page, mostly out of laziness. I think I'd have to create another db file specifically for the seasons anyway, this code is being pushed *primarily* because the hard drive it's on is failing! yay :)
author Paper <paper@paper.us.eu.org>
date Mon, 01 Apr 2024 02:43:44 -0400
parents c130f47f6f48
children f31305b9f60a
comparison
equal deleted inserted replaced
257:699a20c57dc8 258:862d0d8619f6
23 #include <QHBoxLayout> 23 #include <QHBoxLayout>
24 #include <QHeaderView> 24 #include <QHeaderView>
25 #include <QMenu> 25 #include <QMenu>
26 #include <QProgressBar> 26 #include <QProgressBar>
27 #include <QShortcut> 27 #include <QShortcut>
28 #include <QTreeView>
29 #include <QStylePainter> 28 #include <QStylePainter>
30 #include <QStyledItemDelegate> 29 #include <QStyledItemDelegate>
31 #include <QThread> 30 #include <QThread>
31 #include <QTreeView>
32 32
33 #include <set> 33 #include <set>
34 34
35 AnimeListPageSortFilter::AnimeListPageSortFilter(QObject* parent) : QSortFilterProxyModel(parent) { 35 AnimeListPageSortFilter::AnimeListPageSortFilter(QObject* parent) : QSortFilterProxyModel(parent) {
36 } 36 }
109 case Qt::DisplayRole: 109 case Qt::DisplayRole:
110 switch (index.column()) { 110 switch (index.column()) {
111 case AL_TITLE: return Strings::ToQString(list[index.row()].GetUserPreferredTitle()); 111 case AL_TITLE: return Strings::ToQString(list[index.row()].GetUserPreferredTitle());
112 case AL_PROGRESS: 112 case AL_PROGRESS:
113 return QString::number(list[index.row()].GetUserProgress()) + "/" + 113 return QString::number(list[index.row()].GetUserProgress()) + "/" +
114 QString::number(list[index.row()].GetEpisodes()); 114 QString::number(list[index.row()].GetEpisodes());
115 case AL_EPISODES: return list[index.row()].GetEpisodes(); 115 case AL_EPISODES: return list[index.row()].GetEpisodes();
116 case AL_SCORE: return Strings::ToQString(list[index.row()].GetUserPresentableScore()); 116 case AL_SCORE: return Strings::ToQString(list[index.row()].GetUserPresentableScore());
117 case AL_TYPE: return Strings::ToQString(Translate::ToString(list[index.row()].GetFormat())); 117 case AL_TYPE: return Strings::ToQString(Translate::ToString(list[index.row()].GetFormat()));
118 case AL_SEASON: { 118 case AL_SEASON: {
119 std::optional<unsigned int> year = list[index.row()].GetAirDate().GetYear(); 119 std::optional<unsigned int> year = list[index.row()].GetAirDate().GetYear();
120 if (!year) 120 if (!year)
121 return "Unknown Unknown"; 121 return "Unknown Unknown";
122 return Strings::ToQString(Translate::ToLocalString(list[index.row()].GetSeason()) + " " + Strings::ToUtf8String(year.value())); 122 return Strings::ToQString(Translate::ToLocalString(list[index.row()].GetSeason()) + " " +
123 Strings::ToUtf8String(year.value()));
123 } 124 }
124 case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%"; 125 case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%";
125 case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate(); 126 case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate();
126 case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate(); 127 case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate();
127 case AL_UPDATED: { 128 case AL_UPDATED: {
216 tree_view->setColumnHidden(AnimeListPageModel::AL_UPDATED, true); 217 tree_view->setColumnHidden(AnimeListPageModel::AL_UPDATED, true);
217 tree_view->setColumnHidden(AnimeListPageModel::AL_NOTES, true); 218 tree_view->setColumnHidden(AnimeListPageModel::AL_NOTES, true);
218 } 219 }
219 220
220 void AnimeListPage::UpdateAnime(int id) { 221 void AnimeListPage::UpdateAnime(int id) {
221 QThread* thread = QThread::create([this, id] { 222 QThread* thread = QThread::create([this, id] { Services::UpdateAnimeEntry(id); });
222 Services::UpdateAnimeEntry(id);
223 });
224 223
225 connect(thread, &QThread::finished, this, &AnimeListPage::Refresh); 224 connect(thread, &QThread::finished, this, &AnimeListPage::Refresh);
226 connect(thread, &QThread::finished, thread, &QThread::deleteLater); 225 connect(thread, &QThread::finished, thread, &QThread::deleteLater);
227 226
228 thread->start(); 227 thread->start();
242 241
243 for (int i = 0; i < AnimeListPageModel::NB_COLUMNS; i++) { 242 for (int i = 0; i < AnimeListPageModel::NB_COLUMNS; i++) {
244 if (i == AnimeListPageModel::AL_TITLE) 243 if (i == AnimeListPageModel::AL_TITLE)
245 continue; 244 continue;
246 const auto column_name = 245 const auto column_name =
247 sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); 246 sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
248 247
249 QAction* action = menu->addAction(column_name, this, [this, i](const bool checked) { 248 QAction* action = menu->addAction(column_name, this, [this, i](const bool checked) {
250 if (!checked && (VisibleColumnsCount() <= 1)) 249 if (!checked && (VisibleColumnsCount() <= 1))
251 return; 250 return;
252 251
276 QMenu* menu = new QMenu(this); 275 QMenu* menu = new QMenu(this);
277 menu->setAttribute(Qt::WA_DeleteOnClose); 276 menu->setAttribute(Qt::WA_DeleteOnClose);
278 menu->setToolTipsVisible(true); 277 menu->setToolTipsVisible(true);
279 278
280 AnimeListPageModel* source_model = 279 AnimeListPageModel* source_model =
281 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel()); 280 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel());
282 const QItemSelection selection = 281 const QItemSelection selection =
283 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); 282 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
284 283
285 std::set<Anime::Anime*> animes; 284 std::set<Anime::Anime*> animes;
286 for (const auto& index : selection.indexes()) { 285 for (const auto& index : selection.indexes()) {
287 if (!index.isValid()) 286 if (!index.isValid())
288 continue; 287 continue;
291 animes.insert(anime); 290 animes.insert(anime);
292 } 291 }
293 292
294 menu->addAction(tr("Information"), [this, animes] { 293 menu->addAction(tr("Information"), [this, animes] {
295 for (auto& anime : animes) { 294 for (auto& anime : animes) {
296 InformationDialog* dialog = new InformationDialog(*anime, [this, anime] { 295 InformationDialog* dialog = new InformationDialog(
297 UpdateAnime(anime->GetId()); 296 *anime, [this, anime] { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this);
298 }, InformationDialog::PAGE_MAIN_INFO, this);
299 297
300 dialog->show(); 298 dialog->show();
301 dialog->raise(); 299 dialog->raise();
302 dialog->activateWindow(); 300 dialog->activateWindow();
303 } 301 }
304 }); 302 });
305 menu->addSeparator(); 303 menu->addSeparator();
306 menu->addAction(tr("Edit"), [this, animes] { 304 menu->addAction(tr("Edit"), [this, animes] {
307 for (auto& anime : animes) { 305 for (auto& anime : animes) {
308 InformationDialog* dialog = new InformationDialog(*anime, [this, anime] { 306 InformationDialog* dialog = new InformationDialog(
309 UpdateAnime(anime->GetId()); 307 *anime, [this, anime] { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MY_LIST, this);
310 }, InformationDialog::PAGE_MY_LIST, this);
311 308
312 dialog->show(); 309 dialog->show();
313 dialog->raise(); 310 dialog->raise();
314 dialog->activateWindow(); 311 dialog->activateWindow();
315 } 312 }
323 } 320 }
324 321
325 void AnimeListPage::ItemDoubleClicked() { 322 void AnimeListPage::ItemDoubleClicked() {
326 /* throw out any other garbage */ 323 /* throw out any other garbage */
327 const QItemSelection selection = 324 const QItemSelection selection =
328 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection()); 325 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
329 if (!selection.indexes().first().isValid()) { 326 if (!selection.indexes().first().isValid()) {
330 return; 327 return;
331 } 328 }
332 329
333 AnimeListPageModel* source_model = 330 AnimeListPageModel* source_model =
334 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel()); 331 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel());
335 332
336 const QModelIndex index = source_model->index(selection.indexes().first().row()); 333 const QModelIndex index = source_model->index(selection.indexes().first().row());
337 Anime::Anime* anime = source_model->GetAnimeFromIndex(index); 334 Anime::Anime* anime = source_model->GetAnimeFromIndex(index);
338 335
339 InformationDialog* dialog = new InformationDialog(*anime, [this, anime] { 336 InformationDialog* dialog = new InformationDialog(
340 UpdateAnime(anime->GetId()); 337 *anime, [this, anime] { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this);
341 }, InformationDialog::PAGE_MAIN_INFO, this);
342 338
343 dialog->show(); 339 dialog->show();
344 dialog->raise(); 340 dialog->raise();
345 dialog->activateWindow(); 341 dialog->activateWindow();
346 } 342 }
351 } 347 }
352 348
353 void AnimeListPage::RefreshTabs() { 349 void AnimeListPage::RefreshTabs() {
354 for (unsigned int i = 0; i < sort_models.size(); i++) 350 for (unsigned int i = 0; i < sort_models.size(); i++)
355 tab_bar->setTabText(i, Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])) + " (" + 351 tab_bar->setTabText(i, Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
356 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")"); 352 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
357 } 353 }
358 354
359 void AnimeListPage::Refresh() { 355 void AnimeListPage::Refresh() {
360 RefreshList(); 356 RefreshList();
361 RefreshTabs(); 357 RefreshTabs();
447 tree_view->setContextMenuPolicy(Qt::CustomContextMenu); 443 tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
448 tree_view->setFrameShape(QFrame::NoFrame); 444 tree_view->setFrameShape(QFrame::NoFrame);
449 445
450 for (unsigned int i = 0; i < sort_models.size(); i++) { 446 for (unsigned int i = 0; i < sort_models.size(); i++) {
451 tab_bar->addTab(Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])) + " (" + 447 tab_bar->addTab(Strings::ToQString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
452 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")"); 448 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
453 sort_models[i] = new AnimeListPageSortFilter(tree_view); 449 sort_models[i] = new AnimeListPageSortFilter(tree_view);
454 sort_models[i]->setSourceModel(new AnimeListPageModel(this, Anime::ListStatuses[i])); 450 sort_models[i]->setSourceModel(new AnimeListPageModel(this, Anime::ListStatuses[i]));
455 sort_models[i]->setSortRole(Qt::UserRole); 451 sort_models[i]->setSortRole(Qt::UserRole);
456 sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive); 452 sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive);
457 } 453 }
478 connect(tree_view, &QAbstractItemView::doubleClicked, this, &AnimeListPage::ItemDoubleClicked); 474 connect(tree_view, &QAbstractItemView::doubleClicked, this, &AnimeListPage::ItemDoubleClicked);
479 connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListPage::DisplayListMenu); 475 connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListPage::DisplayListMenu);
480 476
481 /* Enter & return keys */ 477 /* Enter & return keys */
482 connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, 478 connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
483 &AnimeListPage::ItemDoubleClicked); 479 &AnimeListPage::ItemDoubleClicked);
484 480
485 connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this, 481 connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
486 &AnimeListPage::ItemDoubleClicked); 482 &AnimeListPage::ItemDoubleClicked);
487 483
488 tree_view->header()->setStretchLastSection(false); 484 tree_view->header()->setStretchLastSection(false);
489 tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu); 485 tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu);
490 connect(tree_view->header(), &QWidget::customContextMenuRequested, this, &AnimeListPage::DisplayColumnHeaderMenu); 486 connect(tree_view->header(), &QWidget::customContextMenuRequested, this, &AnimeListPage::DisplayColumnHeaderMenu);
491 487