comparison src/gui/window.cc @ 273:f31305b9f60a

*: various code safety changes this also makes the code build on Qt 5.7. I can't test it though because I don't have it working... FAIL!
author Paper <paper@paper.us.eu.org>
date Thu, 18 Apr 2024 16:53:17 -0400
parents 862d0d8619f6
children 657fda1b9cac
comparison
equal deleted inserted replaced
272:5437009cb10e 273:f31305b9f60a
46 # include "sys/osx/permissions.h" 46 # include "sys/osx/permissions.h"
47 #elif defined(WIN32) 47 #elif defined(WIN32)
48 # include "sys/win32/dark_theme.h" 48 # include "sys/win32/dark_theme.h"
49 #endif 49 #endif
50 50
51 void PlayingThread::run() { 51 void MainWindowPlayingThread::run() {
52 std::vector<std::string> files; 52 std::vector<std::string> files;
53 Track::Media::GetCurrentlyPlaying(files); 53 Track::Media::GetCurrentlyPlaying(files);
54 emit Done(files); 54 emit Done(files);
55 } 55 }
56 56
57 MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { 57 MainWindowAsyncSynchronizeThread::MainWindowAsyncSynchronizeThread(QAction* action, AnimeListPage* page, QObject* parent) : QThread(parent) {
58 SetAction(action);
59 SetPage(page);
60 }
61
62 void MainWindowAsyncSynchronizeThread::SetAction(QAction* action) {
63 action_ = action;
64 }
65
66 void MainWindowAsyncSynchronizeThread::SetPage(AnimeListPage* page) {
67 page_ = page;
68 }
69
70 void MainWindowAsyncSynchronizeThread::run() {
71 action_->setEnabled(false);
72 Services::Synchronize();
73 page_->Refresh();
74 action_->setEnabled(true);
75 }
76
77 MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), async_synchronize_thread_(nullptr, nullptr) {
58 setWindowIcon(QIcon(":/icons/favicon.png")); 78 setWindowIcon(QIcon(":/icons/favicon.png"));
59 79
60 main_widget.reset(new QWidget(this)); 80 sidebar_.setFixedWidth(128);
61 new QHBoxLayout(main_widget.get()); 81 sidebar_.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
82
83 connect(&sidebar_, &SideBar::CurrentItemChanged, &stack_, &QStackedWidget::setCurrentIndex);
84
85 new QHBoxLayout(&main_widget_);
62 86
63 AddMainWidgets(); 87 AddMainWidgets();
64 setCentralWidget(main_widget.get()); 88 setCentralWidget(&main_widget_);
65 89
66 CreateBars(); 90 CreateBars();
67 91
68 NowPlayingPage* page = reinterpret_cast<NowPlayingPage*>(stack->widget(static_cast<int>(Pages::NOW_PLAYING))); 92 NowPlayingPage* page = reinterpret_cast<NowPlayingPage*>(stack_.widget(static_cast<int>(Pages::NOW_PLAYING)));
69 93
70 qRegisterMetaType<std::vector<std::string>>(); 94 connect(&playing_thread_, &MainWindowPlayingThread::Done, this, [page](const std::vector<std::string>& files) {
71
72 /* This thread will be destroyed on
73 * close of the program OR on the destruction
74 * of MainWindow
75 */
76 thread.reset(new PlayingThread(this));
77
78 connect(thread.get(), &PlayingThread::Done, this, [page](const std::vector<std::string>& files) {
79 for (const auto& file : files) { 95 for (const auto& file : files) {
80 anitomy::Anitomy anitomy; 96 anitomy::Anitomy anitomy;
81 anitomy.Parse(Strings::ToWstring(file)); 97 anitomy.Parse(Strings::ToWstring(file));
82 98
83 const auto& elements = anitomy.elements(); 99 const auto& elements = anitomy.elements();
90 page->SetPlaying(Anime::db.items[id], elements); 106 page->SetPlaying(Anime::db.items[id], elements);
91 break; 107 break;
92 } 108 }
93 }); 109 });
94 110
95 QTimer* timer = new QTimer(this); 111 connect(&playing_thread_timer_, &QTimer::timeout, this, [this] {
96 112 if (playing_thread_.isRunning())
97 connect(timer, &QTimer::timeout, this, [this, page] {
98 if (!thread.get() || thread->isRunning())
99 return; 113 return;
100 114
101 thread->start(); 115 playing_thread_.start();
102 }); 116 });
103 117
104 #ifdef MACOSX 118 #ifdef MACOSX
105 if (!osx::AskForPermissions()) 119 if (!osx::AskForPermissions())
106 return; 120 return;
107 #endif 121 #endif
108 122
109 timer->start(5000); 123 playing_thread_timer_.start(5000);
110 } 124 }
111 125
112 void MainWindow::AddMainWidgets() { 126 void MainWindow::AddMainWidgets() {
113 int page = static_cast<int>(Pages::ANIME_LIST); 127 int page = static_cast<int>(Pages::ANIME_LIST);
114 128
115 if (sidebar.get()) { 129 sidebar_.clear();
116 main_widget->layout()->removeWidget(sidebar.get()); 130
117 sidebar.reset(); 131 sidebar_.AddItem(tr("Now Playing"), SideBar::CreateIcon(":/icons/16x16/film.png"));
118 } 132 sidebar_.AddSeparator();
119 133 sidebar_.AddItem(tr("Anime List"), SideBar::CreateIcon(":/icons/16x16/document-list.png"));
120 if (stack.get()) { 134 sidebar_.AddItem(tr("History"), SideBar::CreateIcon(":/icons/16x16/clock-history-frame.png"));
121 page = stack->currentIndex(); 135 sidebar_.AddItem(tr("Statistics"), SideBar::CreateIcon(":/icons/16x16/chart.png"));
122 main_widget->layout()->removeWidget(stack.get()); 136 sidebar_.AddSeparator();
123 } 137 sidebar_.AddItem(tr("Search"), SideBar::CreateIcon(":/icons/16x16/magnifier.png"));
124 138 sidebar_.AddItem(tr("Seasons"), SideBar::CreateIcon(":/icons/16x16/calendar.png"));
125 sidebar.reset(new SideBar(main_widget.get())); 139 sidebar_.AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/16x16/feed.png"));
126 sidebar->setFixedWidth(128); 140
127 sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); 141 while (stack_.count())
128 142 stack_.removeWidget(stack_.widget(0));
129 sidebar->AddItem(tr("Now Playing"), SideBar::CreateIcon(":/icons/16x16/film.png")); 143
130 sidebar->AddSeparator(); 144 /* can we allocate these on the stack? */
131 sidebar->AddItem(tr("Anime List"), SideBar::CreateIcon(":/icons/16x16/document-list.png")); 145 stack_.addWidget(new NowPlayingPage(&main_widget_));
132 sidebar->AddItem(tr("History"), SideBar::CreateIcon(":/icons/16x16/clock-history-frame.png"));
133 sidebar->AddItem(tr("Statistics"), SideBar::CreateIcon(":/icons/16x16/chart.png"));
134 sidebar->AddSeparator();
135 sidebar->AddItem(tr("Search"), SideBar::CreateIcon(":/icons/16x16/magnifier.png"));
136 sidebar->AddItem(tr("Seasons"), SideBar::CreateIcon(":/icons/16x16/calendar.png"));
137 sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/16x16/feed.png"));
138
139 stack.reset(new QStackedWidget(main_widget.get()));
140
141 stack->addWidget(new NowPlayingPage(main_widget.get()));
142 /* ---- */ 146 /* ---- */
143 stack->addWidget(new AnimeListPage(main_widget.get())); 147 stack_.addWidget(new AnimeListPage(&main_widget_));
144 stack->addWidget(new HistoryPage(main_widget.get())); 148 stack_.addWidget(new HistoryPage(&main_widget_));
145 stack->addWidget(new StatisticsPage(main_widget.get())); 149 stack_.addWidget(new StatisticsPage(&main_widget_));
146 /* ---- */ 150 /* ---- */
147 stack->addWidget(new SearchPage(main_widget.get())); 151 stack_.addWidget(new SearchPage(&main_widget_));
148 stack->addWidget(new SeasonsPage(main_widget.get())); 152 stack_.addWidget(new SeasonsPage(&main_widget_));
149 stack->addWidget(new TorrentsPage(main_widget.get())); 153 stack_.addWidget(new TorrentsPage(&main_widget_));
150 154
151 connect(sidebar.get(), &SideBar::CurrentItemChanged, stack.get(), &QStackedWidget::setCurrentIndex); 155 sidebar_.SetCurrentItem(page);
152 sidebar->SetCurrentItem(page); 156
153 157 main_widget_.layout()->addWidget(&sidebar_);
154 main_widget->layout()->addWidget(sidebar.get()); 158 main_widget_.layout()->addWidget(&stack_);
155 main_widget->layout()->addWidget(stack.get());
156 } 159 }
157 160
158 void MainWindow::CreateBars() { 161 void MainWindow::CreateBars() {
159 QMenuBar* menubar = new QMenuBar(this); 162 QMenuBar* menubar = new QMenuBar(this);
160 QAction* sync_action; 163 QAction* sync_action;
199 { 202 {
200 { 203 {
201 sync_action = menu->addAction(tr("Synchronize &list")); 204 sync_action = menu->addAction(tr("Synchronize &list"));
202 205
203 connect(sync_action, &QAction::triggered, this, 206 connect(sync_action, &QAction::triggered, this,
204 [this, sync_action] { AsyncSynchronize(sync_action, stack.get()); }); 207 [this, sync_action] { AsyncSynchronize(sync_action, &stack_); });
205 208
206 sync_action->setIcon(QIcon(":/icons/24x24/arrow-circle-double-135.png")); 209 sync_action->setIcon(QIcon(":/icons/24x24/arrow-circle-double-135.png"));
207 sync_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); 210 sync_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
208 } 211 }
209 212
288 pages_group->setExclusive(true); 291 pages_group->setExclusive(true);
289 292
290 { 293 {
291 QAction* action = pages_group->addAction(menu->addAction(tr("&Now Playing"))); 294 QAction* action = pages_group->addAction(menu->addAction(tr("&Now Playing")));
292 action->setCheckable(true); 295 action->setCheckable(true);
293 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(0); }); 296 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(0); });
294 } 297 }
295 298
296 { 299 {
297 QAction* action = pages_group->addAction(menu->addAction(tr("&Anime List"))); 300 QAction* action = pages_group->addAction(menu->addAction(tr("&Anime List")));
298 action->setCheckable(true); 301 action->setCheckable(true);
299 action->setChecked(true); 302 action->setChecked(true);
300 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(1); }); 303 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(1); });
301 } 304 }
302 305
303 { 306 {
304 QAction* action = pages_group->addAction(menu->addAction(tr("&History"))); 307 QAction* action = pages_group->addAction(menu->addAction(tr("&History")));
305 action->setCheckable(true); 308 action->setCheckable(true);
306 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(2); }); 309 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(2); });
307 } 310 }
308 311
309 { 312 {
310 QAction* action = pages_group->addAction(menu->addAction(tr("&Statistics"))); 313 QAction* action = pages_group->addAction(menu->addAction(tr("&Statistics")));
311 action->setCheckable(true); 314 action->setCheckable(true);
312 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(3); }); 315 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(3); });
313 } 316 }
314 317
315 { 318 {
316 QAction* action = pages_group->addAction(menu->addAction(tr("S&earch"))); 319 QAction* action = pages_group->addAction(menu->addAction(tr("S&earch")));
317 action->setCheckable(true); 320 action->setCheckable(true);
318 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(4); }); 321 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(4); });
319 } 322 }
320 323
321 { 324 {
322 QAction* action = pages_group->addAction(menu->addAction(tr("Se&asons"))); 325 QAction* action = pages_group->addAction(menu->addAction(tr("Se&asons")));
323 action->setCheckable(true); 326 action->setCheckable(true);
324 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(5); }); 327 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(5); });
325 } 328 }
326 329
327 { 330 {
328 QAction* action = pages_group->addAction(menu->addAction(tr("&Torrents"))); 331 QAction* action = pages_group->addAction(menu->addAction(tr("&Torrents")));
329 action->setCheckable(true); 332 action->setCheckable(true);
330 connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(6); }); 333 connect(action, &QAction::toggled, this, [this] { sidebar_.SetCurrentItem(6); });
331 } 334 }
332 335
333 /* pain in my ass */ 336 /* pain in the ass */
334 connect(sidebar.get(), &SideBar::CurrentItemChanged, this, [pages_group](int index) { 337 connect(&sidebar_, &SideBar::CurrentItemChanged, this, [pages_group](int index) {
335 QAction* checked = pages_group->checkedAction(); 338 QAction* checked = pages_group->checkedAction();
336 339
337 const QList<QAction*>& actions = pages_group->actions(); 340 const QList<QAction*>& actions = pages_group->actions();
338 if (index > actions.size()) 341 if (index > actions.size())
339 return; 342 return;
493 SettingsDialog dialog; 496 SettingsDialog dialog;
494 dialog.exec(); 497 dialog.exec();
495 } 498 }
496 } 499 }
497 500
498 QThreadPool::globalInstance()->start([stack, action] { 501 /* FIXME: make this use a QThread; this is *very* unsafe */
499 action->setEnabled(false); 502 AnimeListPage* page = reinterpret_cast<AnimeListPage*>(stack->widget(static_cast<int>(Pages::ANIME_LIST)));
500 Services::Synchronize(); 503 if (!async_synchronize_thread_.isRunning()) {
501 reinterpret_cast<AnimeListPage*>(stack->widget(static_cast<int>(Pages::ANIME_LIST)))->Refresh(); 504 async_synchronize_thread_.SetAction(action);
502 action->setEnabled(true); 505 async_synchronize_thread_.SetPage(page);
503 }); 506 async_synchronize_thread_.start();
507 }
504 } 508 }
505 509
506 void MainWindow::RetranslateUI() { 510 void MainWindow::RetranslateUI() {
507 /* This kinda sucks but nobody's really going to be changing 511 /* This kinda sucks but nobody's really going to be changing
508 the application language all the time :p */ 512 the application language all the time :p */