Mercurial > minori
annotate src/gui/pages/search.cc @ 327:b5d6c27c308f
anime: refactor Anime::SeriesSeason to Season class
ToLocalString has also been altered to take in both season
and year because lots of locales actually treat formatting
seasons differently! most notably is Russian which adds a
suffix at the end to notate seasons(??)
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Thu, 13 Jun 2024 01:49:18 -0400 |
parents | 5d3c9b31aa6e |
children | 8d45d892be88 |
rev | line source |
---|---|
54
466ac9870df9
add stub pages (to be implemented)
Paper <mrpapersonic@gmail.com>
parents:
diff
changeset
|
1 #include "gui/pages/search.h" |
250 | 2 #include "core/anime.h" |
3 #include "core/anime_db.h" | |
258 | 4 #include "core/filesystem.h" |
250 | 5 #include "core/http.h" |
6 #include "core/session.h" | |
258 | 7 #include "core/strings.h" |
250 | 8 #include "gui/dialog/information.h" |
9 #include "gui/translate/anime.h" | |
258 | 10 #include "gui/widgets/text.h" |
250 | 11 #include "services/services.h" |
258 | 12 #include "track/media.h" |
250 | 13 |
258 | 14 #include <QDate> |
250 | 15 #include <QHeaderView> |
258 | 16 #include <QMenu> |
250 | 17 #include <QToolBar> |
18 #include <QTreeView> | |
258 | 19 #include <QVBoxLayout> |
250 | 20 |
258 | 21 #include <algorithm> |
22 #include <fstream> | |
250 | 23 #include <iostream> |
24 #include <sstream> | |
25 | |
258 | 26 #include "anitomy/anitomy.h" |
250 | 27 #include "pugixml.hpp" |
28 | |
273
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
29 SearchPageSearchThread::SearchPageSearchThread(QObject* parent) : QThread(parent) { |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
30 } |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
31 |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
32 void SearchPageSearchThread::SetSearch(const std::string& search) { |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
33 search_ = search; |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
34 } |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
35 |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
36 void SearchPageSearchThread::run() { |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
37 emit GotResults(Services::Search(search_)); |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
38 } |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
39 |
250 | 40 SearchPageListSortFilter::SearchPageListSortFilter(QObject* parent) : QSortFilterProxyModel(parent) { |
41 } | |
42 | |
43 bool SearchPageListSortFilter::lessThan(const QModelIndex& l, const QModelIndex& r) const { | |
44 QVariant left = sourceModel()->data(l, sortRole()); | |
45 QVariant right = sourceModel()->data(r, sortRole()); | |
46 | |
47 switch (left.userType()) { | |
48 case QMetaType::Int: | |
49 case QMetaType::UInt: | |
50 case QMetaType::LongLong: | |
258 | 51 case QMetaType::ULongLong: return left.toInt() < right.toInt(); |
52 case QMetaType::QDate: return left.toDate() < right.toDate(); | |
250 | 53 case QMetaType::QString: |
54 default: // meh | |
55 return QString::compare(left.toString(), right.toString(), Qt::CaseInsensitive) < 0; | |
56 } | |
57 } | |
58 | |
59 /* -------------------------------------------- */ | |
60 | |
61 SearchPageListModel::SearchPageListModel(QObject* parent) : QAbstractListModel(parent) { | |
62 } | |
63 | |
64 void SearchPageListModel::ParseSearch(const std::vector<int>& ids) { | |
65 /* hack!!! */ | |
66 if (!rowCount(index(0))) { | |
67 beginInsertRows(QModelIndex(), 0, 0); | |
68 endInsertRows(); | |
69 } | |
70 | |
71 beginResetModel(); | |
72 | |
73 this->ids = ids; | |
74 | |
75 endResetModel(); | |
76 } | |
77 | |
78 int SearchPageListModel::rowCount(const QModelIndex& parent) const { | |
79 return ids.size(); | |
80 (void)(parent); | |
81 } | |
82 | |
83 int SearchPageListModel::columnCount(const QModelIndex& parent) const { | |
84 return NB_COLUMNS; | |
85 (void)(parent); | |
86 } | |
87 | |
88 QVariant SearchPageListModel::headerData(const int section, const Qt::Orientation orientation, const int role) const { | |
89 switch (role) { | |
90 case Qt::DisplayRole: { | |
91 switch (section) { | |
92 case SR_TITLE: return tr("Anime title"); | |
93 case SR_EPISODES: return tr("Episode"); | |
94 case SR_TYPE: return tr("Type"); | |
95 case SR_SCORE: return tr("Score"); | |
96 case SR_SEASON: return tr("Season"); | |
97 default: return {}; | |
98 } | |
99 break; | |
100 } | |
101 case Qt::TextAlignmentRole: { | |
102 switch (section) { | |
103 case SR_TITLE: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); | |
104 case SR_TYPE: return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); | |
105 case SR_EPISODES: | |
106 case SR_SCORE: | |
107 case SR_SEASON: return QVariant(Qt::AlignRight | Qt::AlignVCenter); | |
108 default: return {}; | |
109 } | |
110 break; | |
111 } | |
112 } | |
113 return QAbstractListModel::headerData(section, orientation, role); | |
114 } | |
115 | |
116 QVariant SearchPageListModel::data(const QModelIndex& index, int role) const { | |
117 if (!index.isValid()) | |
118 return QVariant(); | |
119 | |
120 const Anime::Anime& anime = Anime::db.items[ids[index.row()]]; | |
121 | |
122 switch (role) { | |
123 case Qt::DisplayRole: | |
124 switch (index.column()) { | |
125 case SR_TITLE: return Strings::ToQString(anime.GetUserPreferredTitle()); | |
126 case SR_TYPE: return Strings::ToQString(Translate::ToLocalString(anime.GetFormat())); | |
127 case SR_EPISODES: return anime.GetEpisodes(); | |
128 case SR_SCORE: return QString::number(anime.GetAudienceScore()) + "%"; | |
327
b5d6c27c308f
anime: refactor Anime::SeriesSeason to Season class
Paper <paper@paper.us.eu.org>
parents:
324
diff
changeset
|
129 case SR_SEASON: return Strings::ToQString(Translate::ToLocalString(anime.GetSeason())); |
250 | 130 default: return {}; |
131 } | |
132 break; | |
133 case Qt::UserRole: | |
134 switch (index.column()) { | |
135 case SR_SCORE: return anime.GetAudienceScore(); | |
136 case SR_EPISODES: return anime.GetEpisodes(); | |
324
5d3c9b31aa6e
anime: add completed date member
Paper <paper@paper.us.eu.org>
parents:
305
diff
changeset
|
137 case SR_SEASON: return anime.GetStartedDate().GetAsQDate(); |
250 | 138 /* We have to use this to work around some stupid |
139 * "conversion ambiguous" error on Linux | |
258 | 140 */ |
250 | 141 default: return data(index, Qt::DisplayRole); |
142 } | |
143 break; | |
144 case Qt::SizeHintRole: { | |
145 switch (index.column()) { | |
146 default: { | |
147 /* max horizontal size of 100, height size = size of current font */ | |
148 const QString d = data(index, Qt::DisplayRole).toString(); | |
149 const QFontMetrics metric = QFontMetrics(QFont()); | |
150 | |
273
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
151 return QSize(std::max(metric.boundingRect(d).width(), 100), metric.height()); |
250 | 152 } |
153 } | |
154 break; | |
155 } | |
258 | 156 case Qt::TextAlignmentRole: return headerData(index.column(), Qt::Horizontal, Qt::TextAlignmentRole); |
250 | 157 } |
158 return QVariant(); | |
159 } | |
160 | |
161 Qt::ItemFlags SearchPageListModel::flags(const QModelIndex& index) const { | |
162 if (!index.isValid()) | |
163 return Qt::NoItemFlags; | |
164 | |
165 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; | |
166 } | |
167 | |
168 Anime::Anime* SearchPageListModel::GetAnimeFromIndex(const QModelIndex& index) const { | |
169 return &Anime::db.items[ids[index.row()]]; | |
170 } | |
171 | |
172 void SearchPage::DisplayListMenu() { | |
173 QMenu* menu = new QMenu(this); | |
174 menu->setAttribute(Qt::WA_DeleteOnClose); | |
175 menu->setToolTipsVisible(true); | |
176 | |
177 const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection()); | |
178 | |
179 bool add_to_list_enable = true; | |
54
466ac9870df9
add stub pages (to be implemented)
Paper <mrpapersonic@gmail.com>
parents:
diff
changeset
|
180 |
250 | 181 std::set<Anime::Anime*> animes; |
182 for (const auto& index : selection.indexes()) { | |
183 if (!index.isValid()) | |
184 continue; | |
185 | |
186 Anime::Anime* anime = model->GetAnimeFromIndex(index); | |
187 if (anime) { | |
188 animes.insert(anime); | |
189 if (anime->IsInUserList()) | |
190 add_to_list_enable = false; | |
191 } | |
192 } | |
193 | |
194 menu->addAction(tr("Information"), [this, animes] { | |
195 for (auto& anime : animes) { | |
258 | 196 InformationDialog* dialog = new InformationDialog( |
305
91ac90a34003
core/time: remove Duration class, use regular functions instead
Paper <paper@paper.us.eu.org>
parents:
279
diff
changeset
|
197 anime, |
91ac90a34003
core/time: remove Duration class, use regular functions instead
Paper <paper@paper.us.eu.org>
parents:
279
diff
changeset
|
198 [this](Anime::Anime* anime) { |
258 | 199 // UpdateAnime(anime->GetId()); |
200 }, | |
201 InformationDialog::PAGE_MAIN_INFO, this); | |
250 | 202 |
203 dialog->show(); | |
204 dialog->raise(); | |
205 dialog->activateWindow(); | |
206 } | |
207 }); | |
208 menu->addSeparator(); | |
209 { | |
210 QMenu* submenu = menu->addMenu(tr("Add to list...")); | |
279 | 211 for (const auto& status : Anime::ListStatuses) { |
212 submenu->addAction(Strings::ToQString(Translate::ToLocalString(status)), [animes, status] { | |
213 for (auto& anime : animes) { | |
214 if (!anime->IsInUserList()) | |
215 anime->AddToUserList(); | |
216 anime->SetUserStatus(status); | |
217 Services::UpdateAnimeEntry(anime->GetId()); | |
218 } | |
219 }); | |
220 } | |
250 | 221 submenu->setEnabled(add_to_list_enable); |
222 } | |
223 menu->popup(QCursor::pos()); | |
54
466ac9870df9
add stub pages (to be implemented)
Paper <mrpapersonic@gmail.com>
parents:
diff
changeset
|
224 } |
250 | 225 |
226 void SearchPage::ItemDoubleClicked() { | |
227 /* throw out any other garbage */ | |
228 const QItemSelection selection = sort_model->mapSelectionToSource(treeview->selectionModel()->selection()); | |
229 if (!selection.indexes().first().isValid()) | |
230 return; | |
231 | |
232 const QModelIndex index = model->index(selection.indexes().first().row()); | |
233 Anime::Anime* anime = model->GetAnimeFromIndex(index); | |
234 | |
258 | 235 InformationDialog* dialog = new InformationDialog( |
305
91ac90a34003
core/time: remove Duration class, use regular functions instead
Paper <paper@paper.us.eu.org>
parents:
279
diff
changeset
|
236 anime, |
91ac90a34003
core/time: remove Duration class, use regular functions instead
Paper <paper@paper.us.eu.org>
parents:
279
diff
changeset
|
237 [this](Anime::Anime* anime) { |
258 | 238 // UpdateAnime(anime->GetId()); |
239 }, | |
240 InformationDialog::PAGE_MAIN_INFO, this); | |
250 | 241 |
242 dialog->show(); | |
243 dialog->raise(); | |
244 dialog->activateWindow(); | |
245 } | |
246 | |
247 SearchPage::SearchPage(QWidget* parent) : QFrame(parent) { | |
248 setFrameShape(QFrame::Box); | |
249 setFrameShadow(QFrame::Sunken); | |
250 | |
251 QVBoxLayout* layout = new QVBoxLayout(this); | |
252 layout->setContentsMargins(0, 0, 0, 0); | |
253 layout->setSpacing(0); | |
254 | |
255 { | |
256 /* Toolbar */ | |
257 QToolBar* toolbar = new QToolBar(this); | |
258 toolbar->setMovable(false); | |
259 | |
260 { | |
261 QLineEdit* line_edit = new QLineEdit("", toolbar); | |
258 | 262 connect(line_edit, &QLineEdit::returnPressed, this, [this, line_edit] { |
250 | 263 /* static thread here. */ |
273
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
264 if (thread_.isRunning()) |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
265 thread_.exit(1); /* fail */ |
250 | 266 |
273
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
267 thread_.SetSearch(Strings::ToUtf8String(line_edit->text())); |
250 | 268 |
273
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
269 thread_.start(); |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
270 }); |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
271 connect(&thread_, &SearchPageSearchThread::GotResults, this, [this](const std::vector<int>& search) { |
f31305b9f60a
*: various code safety changes
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
272 model->ParseSearch(search); |
250 | 273 }); |
274 toolbar->addWidget(line_edit); | |
275 } | |
276 | |
277 layout->addWidget(toolbar); | |
278 } | |
279 | |
280 { | |
281 QFrame* line = new QFrame(this); | |
282 line->setFrameShape(QFrame::HLine); | |
283 line->setFrameShadow(QFrame::Sunken); | |
284 line->setLineWidth(1); | |
285 layout->addWidget(line); | |
286 } | |
287 | |
288 { | |
289 treeview = new QTreeView(this); | |
290 treeview->setUniformRowHeights(true); | |
291 treeview->setAllColumnsShowFocus(false); | |
292 treeview->setAlternatingRowColors(true); | |
293 treeview->setSortingEnabled(true); | |
294 treeview->setSelectionMode(QAbstractItemView::ExtendedSelection); | |
295 treeview->setItemsExpandable(false); | |
296 treeview->setRootIsDecorated(false); | |
297 treeview->setContextMenuPolicy(Qt::CustomContextMenu); | |
298 treeview->setFrameShape(QFrame::NoFrame); | |
299 | |
300 { | |
301 sort_model = new SearchPageListSortFilter(treeview); | |
302 model = new SearchPageListModel(treeview); | |
303 sort_model->setSourceModel(model); | |
304 sort_model->setSortRole(Qt::UserRole); | |
305 sort_model->setSortCaseSensitivity(Qt::CaseInsensitive); | |
306 treeview->setModel(sort_model); | |
307 } | |
308 | |
309 // set column sizes | |
258 | 310 treeview->setColumnWidth(SearchPageListModel::SR_TITLE, 400); |
311 treeview->setColumnWidth(SearchPageListModel::SR_TYPE, 60); | |
250 | 312 treeview->setColumnWidth(SearchPageListModel::SR_EPISODES, 60); |
258 | 313 treeview->setColumnWidth(SearchPageListModel::SR_SCORE, 60); |
314 treeview->setColumnWidth(SearchPageListModel::SR_SEASON, 100); | |
250 | 315 |
316 treeview->header()->setStretchLastSection(false); | |
317 | |
318 /* Double click stuff */ | |
319 connect(treeview, &QAbstractItemView::doubleClicked, this, &SearchPage::ItemDoubleClicked); | |
320 connect(treeview, &QWidget::customContextMenuRequested, this, &SearchPage::DisplayListMenu); | |
321 | |
322 layout->addWidget(treeview); | |
323 } | |
324 } |