Merge https://vcs.maemo.org/git/movie-schedule
[movie-schedule] / src / control / moviecontroller.cpp
1 // Copyright 2010 Jochen Becher
2 //
3 // This file is part of MovieSchedule.
4 //
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.
9 //
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.
14 //
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/>.
17
18 #include "moviecontroller.h"
19
20 #include "data/movie.h"
21 #include "data/cinemaschedule.h"
22 #include "control/actioncontroller.h"
23 #include "control/itemmodelsortclient.h"
24 #include "ui/moviewindow.h"
25 #include "ui/movieschedulemodel.h"
26 #include "ui/contextdialog.h"
27 #include "ui/uiutils.h"
28 #include "searchclients/movieschedulesearchclient.h"
29 #include "utils/assertedlocker.h"
30 #include "utils/asynccall.h"
31
32 #include <QSortFilterProxyModel>
33 #include <iostream>
34
35 static const char *MSG_NO_MOVIE_SCHEDULE_FOUND = QT_TRANSLATE_NOOP("MovieController", "No schedule found for %1.");
36 static const char *MSG_MOVIE_SCHEDULE_ERROR = QT_TRANSLATE_NOOP("MovieController", "Error on fetching movie schedule.");
37
38 MovieController::MovieController(MovieWindow *movie_window, CinemaSchedule *cinema_schedule,
39                                  ActionController *action_controller, ItemModelSortController *sort_controller,
40                                  QThread *search_worker)
41                                      : QObject(0),
42                                      _movie_window(movie_window),
43                                      _cinema_schedule(cinema_schedule),
44                                      _action_controller(action_controller),
45                                      _sort_controller(sort_controller),
46                                      _search_worker(search_worker),
47                                      _current_search_task_id(MovieScheduleSearchClient::INVALID_SEARCH_TASK_ID),
48                                      _movie_schedule_model(0),
49                                      _movie_schedule_proxy_model(new QSortFilterProxyModel(this))
50 {
51     connect(_movie_window, SIGNAL(ScheduleEntrySelected(ScheduleEntryKey)), this, SLOT(ScheduleEntrySelected(ScheduleEntryKey)));
52 }
53
54 void MovieController::ShowMovie(MovieKey movie_key)
55 {
56     CancelSearch();
57     AssertedReadLocker locker(_cinema_schedule->GetLock());
58     _movie_key = movie_key;
59     const Movie *movie = ((const CinemaSchedule *) _cinema_schedule)->FindMovie(movie_key);
60     if (movie != 0) {
61         SetModel(0);
62         _movie_window->SetMovieName(movie->GetName());
63         _movie_window->SetMovieScheduleModel(_movie_schedule_proxy_model);
64         _movie_window->show();
65         MovieScheduleSearchClient *client = new MovieScheduleSearchClient(_cinema_schedule);
66         _current_search_task_id = client->GetSearchTaskId();
67         connect(client, SIGNAL(SearchStarted(int)), this, SLOT(SearchStarted(int)));
68         connect(client, SIGNAL(Reply(int, bool)), this, SLOT(Reply(int, bool)));
69         connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(SearchFinished(int, bool)));
70         connect(client, SIGNAL(Error(int)), this, SLOT(Error(int)));
71         client->moveToThread(_search_worker);
72         CallAsync(client, &MovieScheduleSearchClient::SearchSchedule, movie->GetKey(), movie->GetTheatersUrl());
73         // search client deletes itself
74     }
75 }
76
77 void MovieController::Cancel()
78 {
79     _movie_window->hide();
80     CancelSearch();
81 }
82
83 void MovieController::CancelSearch()
84 {
85     SetModel(0);
86     AssertedWriteLocker locker(_cinema_schedule->GetLock());
87     _current_search_task_id = MovieScheduleSearchClient::INVALID_SEARCH_TASK_ID;
88     MovieScheduleSearchClient::CancelAllRunningSearchs();
89 }
90
91 void MovieController::ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key)
92 {
93     ContextDialog *dialog = new ContextDialog(_cinema_schedule, _movie_window);
94     connect(dialog, SIGNAL(AddToCalendar(ScheduleEntryKey)), _action_controller, SLOT(AddToCalendar(ScheduleEntryKey)));
95     connect(dialog, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
96     connect(dialog, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
97     connect(dialog, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
98     connect(dialog, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
99     dialog->Show(schedule_entry_key);
100     // dialog deletes itself
101 }
102
103 void MovieController::SearchStarted(int search_task_id)
104 {
105     if (search_task_id != _current_search_task_id) {
106         return;
107     }
108     _movie_window->SetBusy(true);
109 }
110
111 void MovieController::Reply(int search_task_id, bool intermediate)
112 {
113     if (search_task_id != _current_search_task_id) {
114         return;
115     }
116     Sort(intermediate, SLOT(SortFinished(QAbstractItemModel*,int,bool)));
117 }
118
119 void MovieController::Error(int search_task_id)
120 {
121     if (search_task_id != _current_search_task_id) {
122         return;
123     }
124     Sort(false, SLOT(SortErrorFinished(QAbstractItemModel*,int,bool)));
125 }
126
127 void MovieController::SearchFinished(int search_task_id, bool success)
128 {
129     Q_UNUSED(success);
130     if (search_task_id != _current_search_task_id) {
131         return;
132     }
133     _movie_window->SetBusy(false);
134 }
135
136 void MovieController::Sort(bool intermediate, const char *slot)
137 {
138     MovieScheduleModel *movie_schedule_model = new MovieScheduleModel(_cinema_schedule, _movie_key, this);
139     movie_schedule_model->Update();
140     QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
141     sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
142     sort_model->setSortRole(MovieScheduleModel::SortRole);
143     sort_model->setDynamicSortFilter(false);
144     sort_model->setSourceModel(movie_schedule_model);
145     ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
146     connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
147     sort_client->Sort(sort_model, _current_search_task_id, intermediate);
148     // proxy deletes itself
149 }
150
151 void MovieController::SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
152 {
153     if (search_task_id != _current_search_task_id) {
154         return;
155     }
156     SetModel(model);
157     if (!intermediate) {
158         if (_movie_schedule_model->rowCount() == 0) {
159             _movie_window->SetError(tr(MSG_NO_MOVIE_SCHEDULE_FOUND).arg(_movie_key.GetName()));
160         }
161     }
162 }
163
164 void MovieController::SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
165 {
166     Q_UNUSED(intermediate);
167     if (search_task_id != _current_search_task_id) {
168         return;
169     }
170     SetModel(model);
171     if (_movie_schedule_model->rowCount() == 0) {
172         _movie_window->SetError(tr(MSG_MOVIE_SCHEDULE_ERROR));
173     } else {
174         UiUtils::ShowError(tr(MSG_MOVIE_SCHEDULE_ERROR));
175     }
176 }
177
178 void MovieController::SetModel(QAbstractItemModel *model)
179 {
180     delete _movie_schedule_proxy_model->sourceModel();
181     _movie_schedule_proxy_model->setSourceModel(model);
182     delete _movie_schedule_model;
183     if (model != 0) {
184         _movie_schedule_model = (MovieScheduleModel *) ((QSortFilterProxyModel *) model)->sourceModel();
185     } else {
186         _movie_schedule_model = 0;
187     }
188 }