1 // Copyright 2010 Jochen Becher
3 // This file is part of MovieSchedule.
5 // MovieSchedule is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // MovieSchedule is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with MovieSchedule. If not, see <http://www.gnu.org/licenses/>.
18 #include "maincontroller.h"
20 #include "data/settings.h"
21 #include "data/cinemaschedule.h"
22 #include "data/movie.h"
23 #include "data/cinema.h"
24 #include "control/theatercontroller.h"
25 #include "control/moviecontroller.h"
26 #include "control/actioncontroller.h"
27 #include "control/locationcontroller.h"
28 #include "control/itemmodelsortclient.h"
29 #include "control/settingscontroller.h"
30 #include "ui/aboutdialog.h"
31 #include "ui/mainwindow.h"
32 #include "ui/theatermodel.h"
33 #include "ui/moviemodel.h"
34 #include "ui/uiutils.h"
35 #include "searchclients/theatersearchclient.h"
36 #include "searchclients/moviesearchclient.h"
37 #include "utils/assertedlocker.h"
38 #include "utils/asynccall.h"
39 #include "utils/connectivitymanager.h"
41 #include <QSortFilterProxyModel>
44 static const char *MSG_NETWORK_ERROR = QT_TRANSLATE_NOOP("MainController", "Unable to access network.");
45 static const char *MSG_NO_THEATERS_FOUND = QT_TRANSLATE_NOOP("MainController", "No theaters found near %1.");
46 static const char *MSG_NO_MOVIES_FOUND = QT_TRANSLATE_NOOP("MainController", "No movies found near %1.");
47 static const char *MSG_THEATERS_ERROR = QT_TRANSLATE_NOOP("MainController", "Error on fetching theaters.");
48 static const char *MSG_MOVIES_ERROR = QT_TRANSLATE_NOOP("MainController", "Error on fetching movies.");
50 MainController::MainController(MainWindow *main_window, Settings *settings, CinemaSchedule *cinema_schedule,
51 TheaterController *theater_controller,
52 MovieController *movie_controller,
53 LocationController *location_controller,
54 ActionController *action_controller,
55 SettingsController *settings_controller,
56 ItemModelSortController *sort_controller,
57 QThread *search_worker)
58 : _main_window(main_window),
60 _cinema_schedule(cinema_schedule),
61 _theater_controller(theater_controller),
62 _movie_controller(movie_controller),
63 _location_controller(location_controller),
64 _action_controller(action_controller),
65 _settings_controller(settings_controller),
66 _sort_controller(sort_controller),
67 _search_worker(search_worker),
68 _connectivity_manager(new ConnectivityManager(this)),
69 _current_theater_search_task_id(TheaterSearchClient::INVALID_SEARCH_TASK_ID),
70 _current_movies_search_task_id(MovieSearchClient::INVALID_SEARCH_TASK_ID),
71 _theater_model(new TheaterModel(cinema_schedule, this)),
72 _movie_model(new MovieModel(cinema_schedule, this)),
73 _theater_proxy_model(new QSortFilterProxyModel(this)),
74 _movie_proxy_model(new QSortFilterProxyModel(this)),
75 _last_search_settings()
77 connect(_main_window, SIGNAL(SearchTheaters()), this, SLOT(SearchTheaters()));
78 connect(_main_window, SIGNAL(SearchMovies()), this, SLOT(SearchMovies()));
79 connect(_main_window, SIGNAL(TheaterSelected(CinemaKey)), _theater_controller, SLOT(ShowTheater(CinemaKey)));
80 connect(_main_window, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
81 connect(_main_window, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
82 connect(_main_window, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
83 connect(_main_window, SIGNAL(MovieSelected(MovieKey)), _movie_controller, SLOT(ShowMovie(MovieKey)));
84 connect(_main_window, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
85 connect(_main_window, SIGNAL(OpenLocationDialog()), _location_controller, SLOT(OpenLocationDialog()));
86 connect(_main_window, SIGNAL(OpenOptionsDialog()), _settings_controller, SLOT(OpenSettingsDialog()));
87 connect(_main_window, SIGNAL(OpenAboutDialog()), this, SLOT(OpenAboutDialog()));
88 connect(_settings_controller, SIGNAL(SettingsChanged(Settings)), this, SLOT(SettingsChanged(Settings)));
89 connect(_location_controller, SIGNAL(Search(Location)), this, SLOT(Search(Location)));
90 connect(_connectivity_manager, SIGNAL(Connected()), this, SLOT(NetworkConnected()));
91 connect(_connectivity_manager, SIGNAL(Disconnected()), this, SLOT(NetworkDisconnected()));
92 connect(_connectivity_manager, SIGNAL(Error()), this, SLOT(NetworkError()));
93 _main_window->SetOrientation(settings->GetOrientationMode());
96 MainController::~MainController()
100 void MainController::Run()
102 _connectivity_manager->Connect();
105 void MainController::Search()
107 _location_controller->CancelAllGpsSearchs();
108 // TODO add some timer condition? How old are the loaded information
109 if (_settings->GetLocation() != _last_search_settings.GetLocation()) {
110 CancelTheaterSearch();
112 _movie_controller->Cancel();
113 _theater_controller->Cancel();
114 AssertedWriteLocker locker(_cinema_schedule->GetLock());
115 _cinema_schedule->Clear();
117 if (_settings->GetLocation().IsValid()) {
118 // Cancel searchs before _cinema_schedule is locked to avoid dead-locks
119 switch (_settings->GetSearchObjectsType()) {
120 case Settings::THEATERS:
121 CancelTheaterSearch();
123 case Settings::MOVIES:
127 AssertedReadLocker locker(_cinema_schedule->GetLock());
128 _main_window->SetLocation(_settings->GetLocation());
129 switch (_settings->GetSearchObjectsType()) {
130 case Settings::THEATERS:
131 _main_window->SetTheaterModel(_theater_proxy_model);
132 if (!_cinema_schedule->AreAllCinemasLoaded()) {
133 TheaterSearchClient *client = new TheaterSearchClient(_cinema_schedule);
134 _current_theater_search_task_id = client->GetSearchTaskId();
135 connect(client, SIGNAL(SearchStarted(int)), this, SLOT(TheatersSearchStarted(int)));
136 connect(client, SIGNAL(Reply(int, bool)), this, SLOT(TheatersSearchReply(int, bool)));
137 connect(client, SIGNAL(Error(int)), this, SLOT(TheatersSearchError(int)));
138 connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(TheatersSearchFinished(int, bool)));
139 client->moveToThread(_search_worker);
140 CallAsync(client, &TheaterSearchClient::SearchTheater, _settings->GetLocation().GetLocationName());
142 TheatersSearchStarted(_current_theater_search_task_id);
143 TheatersSearchReply(_current_theater_search_task_id, true);
144 TheatersSearchFinished(_current_theater_search_task_id, true);
147 case Settings::MOVIES:
148 _main_window->SetMovieModel(_movie_proxy_model);
149 if (!_cinema_schedule->AreAllMoviesLoaded()) {
150 MovieSearchClient *client = new MovieSearchClient(_cinema_schedule);
151 _current_movies_search_task_id = client->GetSearchTaskId();
152 connect(client, SIGNAL(SearchStarted(int)), this, SLOT(MoviesSearchStarted(int)));
153 connect(client, SIGNAL(Reply(int, bool)), this, SLOT(MoviesSearchReply(int, bool)));
154 connect(client, SIGNAL(Error(int)), this, SLOT(MoviesSearchError(int)));
155 connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(MoviesSearchFinished(int, bool)));
156 client->moveToThread(_search_worker);
157 CallAsync(client, &MovieSearchClient::SearchMovie, _settings->GetLocation().GetLocationName());
159 MoviesSearchStarted(_current_movies_search_task_id);
160 MoviesSearchReply(_current_movies_search_task_id, true);
161 MoviesSearchFinished(_current_movies_search_task_id, true);
165 _last_search_settings = *_settings;
167 _location_controller->OpenLocationDialog();
171 void MainController::Search(Location location)
173 _settings->SetLocation(location);
177 void MainController::NetworkConnected()
182 void MainController::NetworkDisconnected()
186 void MainController::NetworkError()
188 _main_window->SetError(tr(MSG_NETWORK_ERROR));
191 void MainController::SettingsChanged(const Settings &settings)
193 _main_window->SetOrientation(settings.GetOrientationMode());
196 void MainController::SearchTheaters()
198 _settings->SetSearchObjectsType(Settings::THEATERS);
202 void MainController::SearchMovies()
204 _settings->SetSearchObjectsType(Settings::MOVIES);
208 void MainController::OpenAboutDialog()
210 AboutDialog *about_dialog = new AboutDialog(_main_window);
211 connect(about_dialog, SIGNAL(ContactAuthor()), _action_controller, SLOT(ContactAuthor()));
212 about_dialog->show();
213 // dialog deletes itself
216 void MainController::CancelTheaterSearch()
218 AssertedWriteLocker locker(_cinema_schedule->GetLock());
219 _current_theater_search_task_id = TheaterSearchClient::INVALID_SEARCH_TASK_ID;
220 TheaterSearchClient::CancelAllRunningSearchs();
223 void MainController::CancelMovieSearch()
225 AssertedWriteLocker locker(_cinema_schedule->GetLock());
226 _current_movies_search_task_id = MovieSearchClient::INVALID_SEARCH_TASK_ID;
227 MovieSearchClient::CancelAllRunningSearchs();
230 void MainController::TheatersSearchStarted(int search_task_id)
232 if (search_task_id != _current_theater_search_task_id) {
235 _main_window->SetBusy(true);
236 SortTheaters(true, SLOT(TheatersSortFinished(QAbstractItemModel*,int,bool)));
239 void MainController::TheatersSearchReply(int search_task_id, bool intermediate)
241 if (search_task_id != _current_theater_search_task_id) {
244 SortTheaters(intermediate, SLOT(TheatersSortFinished(QAbstractItemModel*,int,bool)));
247 void MainController::TheatersSearchError(int search_task_id)
249 if (search_task_id != _current_theater_search_task_id) {
252 SortTheaters(false, SLOT(TheatersSortErrorFinished(QAbstractItemModel*,int,bool)));
255 void MainController::TheatersSearchFinished(int search_task_id, bool success)
258 if (search_task_id != _current_theater_search_task_id) {
261 _main_window->SetBusy(false);
264 void MainController::SortTheaters(bool intermediate, const char *slot)
266 TheaterModel *theater_model = new TheaterModel(_cinema_schedule, this);
267 QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
268 sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
269 sort_model->setSortRole(TheaterModel::SortRole);
270 sort_model->setDynamicSortFilter(false);
271 sort_model->setSourceModel(theater_model);
272 ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
273 connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
274 sort_client->Sort(sort_model, _current_theater_search_task_id, intermediate);
275 // proxy deletes itself
278 void MainController::TheatersSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
280 if (search_task_id != _current_theater_search_task_id) {
283 SetTheaterModel(model);
285 AssertedWriteLocker locker(_cinema_schedule->GetLock());
286 _cinema_schedule->SetAllCinemasLoaded(true);
287 if (_theater_model->rowCount() == 0) {
288 _main_window->SetError(tr(MSG_NO_THEATERS_FOUND).arg(_settings->GetLocation().GetLocationName()));
293 void MainController::TheatersSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
295 Q_UNUSED(intermediate);
296 if (search_task_id != _current_theater_search_task_id) {
299 SetTheaterModel(model);
300 if (_theater_model->rowCount() == 0) {
301 _main_window->SetError(tr(MSG_THEATERS_ERROR));
303 UiUtils::ShowError(tr(MSG_THEATERS_ERROR));
307 void MainController::SetTheaterModel(QAbstractItemModel *model)
309 delete _theater_proxy_model->sourceModel();
310 _theater_proxy_model->setSourceModel(model);
311 delete _theater_model;
312 _theater_model = (TheaterModel *) ((QSortFilterProxyModel *) model)->sourceModel();
315 void MainController::MoviesSearchStarted(int search_task_id)
317 if (search_task_id != _current_movies_search_task_id) {
320 SortMovies(true, SLOT(MoviesSortFinished(QAbstractItemModel*,int,bool)));
323 void MainController::MoviesSearchReply(int search_task_id, bool intermediate)
325 if (search_task_id != _current_movies_search_task_id) {
328 SortMovies(intermediate, SLOT(MoviesSortFinished(QAbstractItemModel*,int,bool)));
331 void MainController::MoviesSearchError(int search_task_id)
333 if (search_task_id != _current_movies_search_task_id) {
336 SortMovies(false, SLOT(MoviesSortErrorFinished(QAbstractItemModel*,int,bool)));
339 void MainController::MoviesSearchFinished(int search_task_id, bool success)
342 if (search_task_id != _current_movies_search_task_id) {
345 _main_window->SetBusy(false);
348 void MainController::SortMovies(bool intermediate, const char *slot)
350 MovieModel *movie_model = new MovieModel(_cinema_schedule, this);
351 QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
352 sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
353 sort_model->setSortRole(MovieModel::SortRole);
354 sort_model->setDynamicSortFilter(false);
355 sort_model->setSourceModel(movie_model);
356 ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
357 connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
358 sort_client->Sort(sort_model, _current_movies_search_task_id, intermediate);
359 // proxy deletes itself
362 void MainController::MoviesSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
364 if (search_task_id != _current_movies_search_task_id) {
367 SetMovieModel(model);
369 AssertedWriteLocker locker(_cinema_schedule->GetLock());
370 _cinema_schedule->SetAllMoviesLoaded(true);
371 if (_movie_model->rowCount() == 0) {
372 _main_window->SetError(tr(MSG_NO_MOVIES_FOUND).arg(_settings->GetLocation().GetLocationName()));
377 void MainController::MoviesSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
379 Q_UNUSED(intermediate);
380 if (search_task_id != _current_movies_search_task_id) {
383 SetMovieModel(model);
384 if (_movie_model->rowCount() == 0) {
385 _main_window->SetError(tr(MSG_MOVIES_ERROR));
387 UiUtils::ShowError(tr(MSG_MOVIES_ERROR));
391 void MainController::SetMovieModel(QAbstractItemModel *model)
393 delete _movie_proxy_model->sourceModel();
394 _movie_proxy_model->setSourceModel(model);
396 _movie_model = (MovieModel *) ((QSortFilterProxyModel *) model)->sourceModel();