10
|
1 /**
|
|
2 * anime_list.cpp: defines the anime list page
|
|
3 * and widgets.
|
|
4 *
|
|
5 * much of this file is based around
|
|
6 * Qt's original QTabWidget implementation, because
|
|
7 * I needed a somewhat native way to create a tabbed
|
|
8 * widget with only one subwidget that worked exactly
|
|
9 * like a native tabbed widget.
|
|
10 **/
|
|
11 #include "gui/pages/anime_list.h"
|
|
12 #include "core/anime.h"
|
|
13 #include "core/anime_db.h"
|
|
14 #include "core/session.h"
|
|
15 #include "core/time.h"
|
|
16 #include "gui/dialog/information.h"
|
|
17 #include "gui/translate/anime.h"
|
|
18 #include "services/anilist.h"
|
15
|
19 #include <QDebug>
|
10
|
20 #include <QHBoxLayout>
|
|
21 #include <QHeaderView>
|
|
22 #include <QMenu>
|
|
23 #include <QProgressBar>
|
|
24 #include <QShortcut>
|
|
25 #include <QStylePainter>
|
|
26 #include <QStyledItemDelegate>
|
|
27 #include <cmath>
|
|
28
|
|
29 AnimeListWidgetDelegate::AnimeListWidgetDelegate(QObject* parent) : QStyledItemDelegate(parent) {
|
|
30 }
|
|
31
|
|
32 QWidget* AnimeListWidgetDelegate::createEditor(QWidget*, const QStyleOptionViewItem&, const QModelIndex&) const {
|
|
33 // no edit 4 u
|
|
34 return nullptr;
|
|
35 }
|
|
36
|
|
37 void AnimeListWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
|
15
|
38 const QModelIndex& index) const {
|
10
|
39 switch (index.column()) {
|
15
|
40 #if 0
|
10
|
41 case AnimeListWidgetModel::AL_PROGRESS: {
|
|
42 const int progress = static_cast<int>(index.data(Qt::UserRole).toReal());
|
|
43 const int episodes =
|
15
|
44 static_cast<int>(index.siblingAtColumn(AnimeListWidgetModel::AL_EPISODES).data(Qt::UserRole).toReal());
|
10
|
45
|
|
46 int text_width = 59;
|
|
47 QRectF text_rect(option.rect.x() + text_width, option.rect.y(), text_width, option.decorationSize.height());
|
|
48 painter->save();
|
|
49 painter->drawText(text_rect, "/", QTextOption(Qt::AlignCenter | Qt::AlignVCenter));
|
15
|
50 // drawText(const QRectF &rectangle, const QString &text, const QTextOption &option =
|
|
51 QTextOption()) painter->drawText(QRectF(text_rect.x(), text_rect.y(), text_width / 2 - 2,
|
|
52 text_rect.height()), QString::number(progress), QTextOption(Qt::AlignRight | Qt::AlignVCenter));
|
|
53 painter->drawText(
|
|
54 QRectF(text_rect.x() + text_width / 2 + 2, text_rect.y(), text_width / 2 - 2, text_rect.height()),
|
|
55 QString::number(episodes), QTextOption(Qt::AlignLeft | Qt::AlignVCenter));
|
|
56 painter->restore();
|
|
57 QStyledItemDelegate::paint(painter, option, index);
|
|
58 break;
|
10
|
59 }
|
15
|
60 #endif
|
10
|
61 default: QStyledItemDelegate::paint(painter, option, index); break;
|
|
62 }
|
|
63 }
|
|
64
|
|
65 AnimeListWidgetSortFilter::AnimeListWidgetSortFilter(QObject* parent) : QSortFilterProxyModel(parent) {
|
|
66 }
|
|
67
|
|
68 bool AnimeListWidgetSortFilter::lessThan(const QModelIndex& l, const QModelIndex& r) const {
|
|
69 QVariant left = sourceModel()->data(l, sortRole());
|
|
70 QVariant right = sourceModel()->data(r, sortRole());
|
|
71
|
|
72 switch (left.userType()) {
|
|
73 case QMetaType::Int:
|
|
74 case QMetaType::UInt:
|
|
75 case QMetaType::LongLong:
|
|
76 case QMetaType::ULongLong: return left.toInt() < right.toInt();
|
|
77 case QMetaType::QDate: return left.toDate() < right.toDate();
|
|
78 case QMetaType::QString:
|
|
79 default: return QString::compare(left.toString(), right.toString(), Qt::CaseInsensitive) < 0;
|
|
80 }
|
|
81 }
|
|
82
|
|
83 AnimeListWidgetModel::AnimeListWidgetModel(QWidget* parent, Anime::ListStatus _status) : QAbstractListModel(parent) {
|
|
84 status = _status;
|
|
85 return;
|
|
86 }
|
|
87
|
|
88 int AnimeListWidgetModel::rowCount(const QModelIndex& parent) const {
|
|
89 return list.size();
|
|
90 (void)(parent);
|
|
91 }
|
|
92
|
|
93 int AnimeListWidgetModel::columnCount(const QModelIndex& parent) const {
|
|
94 return NB_COLUMNS;
|
|
95 (void)(parent);
|
|
96 }
|
|
97
|
|
98 QVariant AnimeListWidgetModel::headerData(const int section, const Qt::Orientation orientation, const int role) const {
|
|
99 if (role == Qt::DisplayRole) {
|
|
100 switch (section) {
|
15
|
101 case AL_TITLE: return tr("Anime title");
|
|
102 case AL_PROGRESS: return tr("Progress");
|
|
103 case AL_EPISODES: return tr("Episodes");
|
|
104 case AL_TYPE: return tr("Type");
|
|
105 case AL_SCORE: return tr("Score");
|
|
106 case AL_SEASON: return tr("Season");
|
|
107 case AL_STARTED: return tr("Date started");
|
|
108 case AL_COMPLETED: return tr("Date completed");
|
|
109 case AL_NOTES: return tr("Notes");
|
|
110 case AL_AVG_SCORE: return tr("Average score");
|
|
111 case AL_UPDATED: return tr("Last updated");
|
|
112 default: return {};
|
10
|
113 }
|
|
114 } else if (role == Qt::TextAlignmentRole) {
|
|
115 switch (section) {
|
15
|
116 case AL_TITLE:
|
|
117 case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
|
|
118 case AL_PROGRESS:
|
|
119 case AL_EPISODES:
|
|
120 case AL_TYPE:
|
|
121 case AL_SCORE:
|
|
122 case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
|
|
123 case AL_SEASON:
|
|
124 case AL_STARTED:
|
|
125 case AL_COMPLETED:
|
|
126 case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter);
|
|
127 default: return QAbstractListModel::headerData(section, orientation, role);
|
10
|
128 }
|
|
129 }
|
|
130 return QAbstractListModel::headerData(section, orientation, role);
|
|
131 }
|
|
132
|
|
133 QVariant AnimeListWidgetModel::data(const QModelIndex& index, int role) const {
|
|
134 if (!index.isValid())
|
|
135 return QVariant();
|
|
136 switch (role) {
|
|
137 case Qt::DisplayRole:
|
15
|
138 switch (index.column()) {
|
|
139 case AL_TITLE: return QString::fromUtf8(list[index.row()].GetUserPreferredTitle().c_str());
|
|
140 case AL_PROGRESS:
|
|
141 return QString::number(list[index.row()].GetUserProgress()) + "/" +
|
|
142 QString::number(list[index.row()].GetEpisodes());
|
|
143 case AL_EPISODES: return list[index.row()].GetEpisodes();
|
|
144 case AL_SCORE: return list[index.row()].GetUserScore();
|
|
145 case AL_TYPE: return QString::fromStdString(Translate::ToString(list[index.row()].GetFormat()));
|
|
146 case AL_SEASON:
|
|
147 return QString::fromStdString(Translate::ToString(list[index.row()].GetSeason())) + " " +
|
|
148 QString::number(list[index.row()].GetAirDate().GetYear());
|
|
149 case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%";
|
|
150 case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate();
|
|
151 case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate();
|
|
152 case AL_UPDATED: {
|
|
153 if (list[index.row()].GetUserTimeUpdated() == 0)
|
|
154 return QString("-");
|
|
155 Time::Duration duration(Time::GetSystemTime() - list[index.row()].GetUserTimeUpdated());
|
|
156 return QString::fromUtf8(duration.AsRelativeString().c_str());
|
|
157 }
|
|
158 case AL_NOTES: return QString::fromUtf8(list[index.row()].GetUserNotes().c_str());
|
|
159 default: return "";
|
|
160 }
|
|
161 break;
|
10
|
162 case Qt::UserRole:
|
15
|
163 switch (index.column()) {
|
|
164 case AL_PROGRESS: return list[index.row()].GetUserProgress();
|
|
165 case AL_TYPE: return static_cast<int>(list[index.row()].GetFormat());
|
|
166 case AL_SEASON: return list[index.row()].GetAirDate().GetAsQDate();
|
|
167 case AL_AVG_SCORE: return list[index.row()].GetAudienceScore();
|
|
168 case AL_UPDATED: return list[index.row()].GetUserTimeUpdated();
|
|
169 default: return data(index, Qt::DisplayRole);
|
|
170 }
|
|
171 break;
|
10
|
172 case Qt::TextAlignmentRole:
|
15
|
173 switch (index.column()) {
|
|
174 case AL_TITLE:
|
|
175 case AL_NOTES: return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
|
|
176 case AL_PROGRESS:
|
|
177 case AL_EPISODES:
|
|
178 case AL_TYPE:
|
|
179 case AL_SCORE:
|
|
180 case AL_AVG_SCORE: return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
|
|
181 case AL_SEASON:
|
|
182 case AL_STARTED:
|
|
183 case AL_COMPLETED:
|
|
184 case AL_UPDATED: return QVariant(Qt::AlignRight | Qt::AlignVCenter);
|
|
185 default: break;
|
|
186 }
|
|
187 break;
|
10
|
188 }
|
|
189 return QVariant();
|
|
190 }
|
|
191
|
|
192 void AnimeListWidgetModel::UpdateAnime(int id) {
|
|
193 /* meh... it might be better to just reinit the entire list */
|
|
194 int i = 0;
|
11
|
195 for (const auto& a : Anime::db.items) {
|
|
196 if (a.second.IsInUserList() && a.first == id && a.second.GetUserStatus() == status) {
|
15
|
197 emit dataChanged(index(i), index(i));
|
10
|
198 }
|
|
199 i++;
|
|
200 }
|
|
201 }
|
|
202
|
|
203 Anime::Anime* AnimeListWidgetModel::GetAnimeFromIndex(QModelIndex index) {
|
|
204 return &list.at(index.row());
|
|
205 }
|
|
206
|
|
207 void AnimeListWidgetModel::RefreshList() {
|
|
208 bool has_children = !!rowCount(index(0));
|
15
|
209 if (has_children)
|
|
210 beginResetModel();
|
|
211 else {
|
|
212 int count = 0;
|
|
213 for (const auto& a : Anime::db.items)
|
|
214 if (a.second.IsInUserList() && a.second.GetUserStatus() == status)
|
|
215 count++;
|
|
216 beginInsertRows(index(0), 0, count - 1);
|
|
217 }
|
|
218
|
10
|
219 list.clear();
|
|
220
|
11
|
221 for (const auto& a : Anime::db.items) {
|
|
222 if (a.second.IsInUserList() && a.second.GetUserStatus() == status) {
|
15
|
223 list.push_back(a.second);
|
10
|
224 }
|
|
225 }
|
15
|
226
|
|
227 if (has_children)
|
|
228 endResetModel();
|
|
229 else
|
|
230 endInsertRows();
|
10
|
231 }
|
|
232
|
|
233 int AnimeListWidget::VisibleColumnsCount() const {
|
|
234 int count = 0;
|
|
235
|
|
236 for (int i = 0, end = tree_view->header()->count(); i < end; i++) {
|
|
237 if (!tree_view->isColumnHidden(i))
|
15
|
238 count++;
|
10
|
239 }
|
|
240
|
|
241 return count;
|
|
242 }
|
|
243
|
|
244 void AnimeListWidget::SetColumnDefaults() {
|
|
245 tree_view->setColumnHidden(AnimeListWidgetModel::AL_SEASON, false);
|
|
246 tree_view->setColumnHidden(AnimeListWidgetModel::AL_TYPE, false);
|
|
247 tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, false);
|
|
248 tree_view->setColumnHidden(AnimeListWidgetModel::AL_PROGRESS, false);
|
|
249 tree_view->setColumnHidden(AnimeListWidgetModel::AL_SCORE, false);
|
|
250 tree_view->setColumnHidden(AnimeListWidgetModel::AL_TITLE, false);
|
|
251 tree_view->setColumnHidden(AnimeListWidgetModel::AL_EPISODES, true);
|
|
252 tree_view->setColumnHidden(AnimeListWidgetModel::AL_AVG_SCORE, true);
|
|
253 tree_view->setColumnHidden(AnimeListWidgetModel::AL_STARTED, true);
|
|
254 tree_view->setColumnHidden(AnimeListWidgetModel::AL_COMPLETED, true);
|
|
255 tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, true);
|
|
256 tree_view->setColumnHidden(AnimeListWidgetModel::AL_NOTES, true);
|
|
257 }
|
|
258
|
|
259 void AnimeListWidget::DisplayColumnHeaderMenu() {
|
|
260 QMenu* menu = new QMenu(this);
|
|
261 menu->setAttribute(Qt::WA_DeleteOnClose);
|
|
262 menu->setTitle(tr("Column visibility"));
|
|
263 menu->setToolTipsVisible(true);
|
|
264
|
|
265 for (int i = 0; i < AnimeListWidgetModel::NB_COLUMNS; i++) {
|
15
|
266 if (i == AnimeListWidgetModel::AL_TITLE)
|
|
267 continue;
|
10
|
268 const auto column_name =
|
15
|
269 sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
|
10
|
270 QAction* action = menu->addAction(column_name, this, [this, i](const bool checked) {
|
|
271 if (!checked && (VisibleColumnsCount() <= 1))
|
|
272 return;
|
|
273
|
|
274 tree_view->setColumnHidden(i, !checked);
|
|
275
|
|
276 if (checked && (tree_view->columnWidth(i) <= 5))
|
|
277 tree_view->resizeColumnToContents(i);
|
|
278
|
|
279 // SaveSettings();
|
|
280 });
|
|
281 action->setCheckable(true);
|
|
282 action->setChecked(!tree_view->isColumnHidden(i));
|
|
283 }
|
|
284
|
|
285 menu->addSeparator();
|
|
286 QAction* resetAction = menu->addAction(tr("Reset to defaults"), this, [this]() {
|
|
287 for (int i = 0, count = tree_view->header()->count(); i < count; ++i) {
|
|
288 SetColumnDefaults();
|
|
289 }
|
|
290 // SaveSettings();
|
|
291 });
|
|
292 menu->popup(QCursor::pos());
|
|
293 (void)(resetAction);
|
|
294 }
|
|
295
|
|
296 void AnimeListWidget::DisplayListMenu() {
|
|
297 QMenu* menu = new QMenu(this);
|
|
298 menu->setAttribute(Qt::WA_DeleteOnClose);
|
|
299 menu->setTitle(tr("Column visibility"));
|
|
300 menu->setToolTipsVisible(true);
|
|
301
|
15
|
302 const QItemSelection selection =
|
|
303 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
|
10
|
304 if (!selection.indexes().first().isValid()) {
|
|
305 return;
|
|
306 }
|
|
307
|
|
308 QAction* action = menu->addAction("Information", [this, selection] {
|
|
309 const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
|
15
|
310 ->index(selection.indexes().first().row());
|
10
|
311 Anime::Anime* anime =
|
15
|
312 ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
|
10
|
313 if (!anime) {
|
|
314 return;
|
|
315 }
|
|
316
|
|
317 InformationDialog* dialog = new InformationDialog(
|
15
|
318 *anime,
|
|
319 [this, anime] {
|
|
320 ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
|
|
321 ->UpdateAnime(anime->GetId());
|
|
322 },
|
|
323 this);
|
10
|
324
|
|
325 dialog->show();
|
|
326 dialog->raise();
|
|
327 dialog->activateWindow();
|
|
328 });
|
|
329 menu->popup(QCursor::pos());
|
|
330 }
|
|
331
|
|
332 void AnimeListWidget::ItemDoubleClicked() {
|
|
333 /* throw out any other garbage */
|
|
334 const QItemSelection selection =
|
15
|
335 sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
|
10
|
336 if (!selection.indexes().first().isValid()) {
|
|
337 return;
|
|
338 }
|
|
339
|
|
340 const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
|
15
|
341 ->index(selection.indexes().first().row());
|
10
|
342 Anime::Anime* anime =
|
15
|
343 ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
|
10
|
344
|
|
345 InformationDialog* dialog = new InformationDialog(
|
15
|
346 *anime,
|
|
347 [this, anime] {
|
|
348 ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId());
|
|
349 },
|
|
350 this);
|
10
|
351
|
|
352 dialog->show();
|
|
353 dialog->raise();
|
|
354 dialog->activateWindow();
|
|
355 }
|
|
356
|
|
357 void AnimeListWidget::paintEvent(QPaintEvent*) {
|
|
358 QStylePainter p(this);
|
|
359
|
|
360 QStyleOptionTabWidgetFrame opt;
|
|
361 InitStyle(&opt);
|
|
362 opt.rect = panelRect;
|
|
363 p.drawPrimitive(QStyle::PE_FrameTabWidget, opt);
|
|
364 }
|
|
365
|
|
366 void AnimeListWidget::resizeEvent(QResizeEvent* e) {
|
|
367 QWidget::resizeEvent(e);
|
|
368 SetupLayout();
|
|
369 }
|
|
370
|
|
371 void AnimeListWidget::showEvent(QShowEvent*) {
|
|
372 SetupLayout();
|
|
373 }
|
|
374
|
|
375 void AnimeListWidget::InitBasicStyle(QStyleOptionTabWidgetFrame* option) const {
|
|
376 if (!option)
|
|
377 return;
|
|
378
|
|
379 option->initFrom(this);
|
|
380 option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this);
|
|
381 option->shape = QTabBar::RoundedNorth;
|
|
382 option->tabBarRect = tab_bar->geometry();
|
|
383 }
|
|
384
|
|
385 void AnimeListWidget::InitStyle(QStyleOptionTabWidgetFrame* option) const {
|
|
386 if (!option)
|
|
387 return;
|
|
388
|
|
389 InitBasicStyle(option);
|
|
390
|
|
391 // int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, nullptr, this);
|
|
392 QSize t(0, tree_view->frameWidth());
|
|
393 if (tab_bar->isVisibleTo(this)) {
|
|
394 t = tab_bar->sizeHint();
|
|
395 t.setWidth(width());
|
|
396 }
|
|
397 option->tabBarSize = t;
|
|
398
|
|
399 QRect selected_tab_rect = tab_bar->tabRect(tab_bar->currentIndex());
|
|
400 selected_tab_rect.moveTopLeft(selected_tab_rect.topLeft() + option->tabBarRect.topLeft());
|
|
401 option->selectedTabRect = selected_tab_rect;
|
|
402
|
|
403 option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, nullptr, this);
|
|
404 }
|
|
405
|
|
406 void AnimeListWidget::SetupLayout() {
|
|
407 QStyleOptionTabWidgetFrame option;
|
|
408 InitStyle(&option);
|
|
409
|
|
410 QRect tabRect = style()->subElementRect(QStyle::SE_TabWidgetTabBar, &option, this);
|
|
411 tabRect.setLeft(tabRect.left() + 1);
|
|
412 panelRect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
|
|
413 QRect contentsRect = style()->subElementRect(QStyle::SE_TabWidgetTabContents, &option, this);
|
|
414
|
|
415 tab_bar->setGeometry(tabRect);
|
|
416 tree_view->parentWidget()->setGeometry(contentsRect);
|
|
417 }
|
|
418
|
|
419 AnimeListWidget::AnimeListWidget(QWidget* parent) : QWidget(parent) {
|
|
420 /* Tab bar */
|
|
421 tab_bar = new QTabBar(this);
|
|
422 tab_bar->setExpanding(false);
|
|
423 tab_bar->setDrawBase(false);
|
|
424
|
|
425 /* Tree view... */
|
|
426 QWidget* tree_widget = new QWidget(this);
|
|
427 tree_view = new QTreeView(tree_widget);
|
|
428 tree_view->setItemDelegate(new AnimeListWidgetDelegate(tree_view));
|
|
429 tree_view->setUniformRowHeights(true);
|
|
430 tree_view->setAllColumnsShowFocus(false);
|
|
431 tree_view->setAlternatingRowColors(true);
|
|
432 tree_view->setSortingEnabled(true);
|
|
433 tree_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
434 tree_view->setItemsExpandable(false);
|
|
435 tree_view->setRootIsDecorated(false);
|
|
436 tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
437 tree_view->setFrameShape(QFrame::NoFrame);
|
|
438
|
|
439 for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) {
|
15
|
440 tab_bar->addTab(QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
|
|
441 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
|
10
|
442 sort_models[i] = new AnimeListWidgetSortFilter(tree_view);
|
15
|
443 sort_models[i]->setSourceModel(new AnimeListWidgetModel(this, Anime::ListStatuses[i]));
|
10
|
444 sort_models[i]->setSortRole(Qt::UserRole);
|
|
445 sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
446 }
|
15
|
447 tree_view->setModel(sort_models[0]);
|
10
|
448
|
|
449 QHBoxLayout* layout = new QHBoxLayout;
|
|
450 layout->addWidget(tree_view);
|
|
451 layout->setMargin(0);
|
|
452 tree_widget->setLayout(layout);
|
|
453
|
|
454 /* Double click stuff */
|
|
455 connect(tree_view, &QAbstractItemView::doubleClicked, this, &AnimeListWidget::ItemDoubleClicked);
|
|
456 connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayListMenu);
|
|
457
|
|
458 /* Enter & return keys */
|
15
|
459 connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
|
|
460 &AnimeListWidget::ItemDoubleClicked);
|
10
|
461
|
15
|
462 connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
|
|
463 &AnimeListWidget::ItemDoubleClicked);
|
10
|
464
|
|
465 tree_view->header()->setStretchLastSection(false);
|
|
466 tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
15
|
467 connect(tree_view->header(), &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayColumnHeaderMenu);
|
10
|
468
|
|
469 connect(tab_bar, &QTabBar::currentChanged, this, [this](int index) {
|
|
470 if (sort_models[index])
|
|
471 tree_view->setModel(sort_models[index]);
|
|
472 });
|
|
473
|
|
474 setFocusPolicy(Qt::TabFocus);
|
|
475 setFocusProxy(tab_bar);
|
|
476 }
|
|
477
|
|
478 void AnimeListWidget::RefreshList() {
|
15
|
479 for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
|
10
|
480 ((AnimeListWidgetModel*)sort_models[i]->sourceModel())->RefreshList();
|
|
481 }
|
|
482
|
15
|
483 void AnimeListWidget::RefreshTabs() {
|
|
484 for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
|
|
485 tab_bar->setTabText(i, QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
|
|
486 QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
|
|
487 }
|
|
488
|
|
489 void AnimeListWidget::Refresh() {
|
|
490 RefreshList();
|
|
491 RefreshTabs();
|
|
492 }
|
|
493
|
|
494 /* This function, really, really should not be called.
|
|
495 Ever. Why would you ever need to clear the anime list?
|
|
496 Also, this sucks. */
|
10
|
497 void AnimeListWidget::Reset() {
|
|
498 while (tab_bar->count())
|
|
499 tab_bar->removeTab(0);
|
|
500 for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
|
|
501 delete sort_models[i];
|
|
502 }
|
|
503
|
|
504 #include "gui/pages/moc_anime_list.cpp"
|