Fixed searchclients to handle new Google URLs correctly; added GUI
[movie-schedule] / src / control / theatercontroller.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 "theatercontroller.h"
19
20 #include "data/cinema.h"
21 #include "data/cinemaschedule.h"
22 #include "control/actioncontroller.h"
23 #include "control/itemmodelsortclient.h"
24 #include "ui/theaterwindow.h"
25 #include "ui/theaterschedulemodel.h"
26 #include "ui/contextdialog.h"
27 #include "ui/uiutils.h"
28 #include "searchclients/theaterschedulesearchclient.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_THEATER_SCHEDULE_FOUND = QT_TRANSLATE_NOOP("TheaterController", "No schedule found for %1.");
36 static const char *MSG_THEATER_SCHEDULE_ERROR = QT_TRANSLATE_NOOP("TheaterController", "Error on fetching theater schedule.");
37
38 TheaterController::TheaterController(TheaterWindow *theater_window, CinemaSchedule *cinema_schedule, ActionController *action_controller,
39                                      ItemModelSortController *sort_controller, QThread *search_worker)
40                                          : QObject(0),
41                                          _theater_window(theater_window),
42                                          _cinema_schedule(cinema_schedule),
43                                          _action_controller(action_controller),
44                                          _sort_controller(sort_controller),
45                                          _search_worker(search_worker),
46                                          _current_search_task_id(TheaterScheduleSearchClient::INVALID_SEARCH_TASK_ID),
47                                          _theater_schedule_model(0),
48                                          _theater_schedule_proxy_model(new QSortFilterProxyModel(this))
49 {
50     connect(_theater_window, SIGNAL(ScheduleEntrySelected(ScheduleEntryKey)), this, SLOT(ScheduleEntrySelected(ScheduleEntryKey)));
51 }
52
53 void TheaterController::ShowTheater(CinemaKey cinema_key)
54 {
55     CancelSearch();
56     AssertedReadLocker locker(_cinema_schedule->GetLock());
57     _cinema_key = cinema_key;
58     const Cinema *cinema = ((const CinemaSchedule *) _cinema_schedule)->FindCinema(cinema_key);
59     if (cinema != 0) {
60         SetModel(0);
61         _theater_window->SetTheaterName(cinema->GetName());
62         _theater_window->SetTheaterScheduleModel(_theater_schedule_proxy_model);
63         _theater_window->show();
64         TheaterScheduleSearchClient *client = new TheaterScheduleSearchClient(_cinema_schedule);
65         _current_search_task_id = client->GetSearchTaskId();
66         connect(client, SIGNAL(SearchStarted(int)), this, SLOT(SearchStarted(int)));
67         connect(client, SIGNAL(Reply(int,bool)), this, SLOT(Reply(int,bool)));
68         connect(client, SIGNAL(SearchFinished(int,bool)), this, SLOT(SearchFinished(int,bool)));
69         connect(client, SIGNAL(Error(int)), this, SLOT(Error(int)));
70         client->moveToThread(_search_worker);
71         CallAsync(client, &TheaterScheduleSearchClient::SearchSchedule, cinema->GetKey(), cinema->GetMoviesUrl());
72         // client deletes itself
73     }
74 }
75
76 void TheaterController::Cancel()
77 {
78     _theater_window->hide();
79     CancelSearch();
80 }
81
82 void TheaterController::CancelSearch()
83 {
84     SetModel(0);
85     AssertedWriteLocker locker(_cinema_schedule->GetLock());
86     _current_search_task_id = TheaterScheduleSearchClient::INVALID_SEARCH_TASK_ID;
87     TheaterScheduleSearchClient::CancelAllRunningSearchs();
88 }
89
90 void TheaterController::ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key)
91 {
92     ContextDialog *dialog = new ContextDialog(_cinema_schedule, _theater_window);
93     connect(dialog, SIGNAL(AddToCalendar(ScheduleEntryKey)), _action_controller, SLOT(AddToCalendar(ScheduleEntryKey)));
94     connect(dialog, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
95     connect(dialog, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
96     connect(dialog, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
97     connect(dialog, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
98     dialog->Show(schedule_entry_key);
99     // dialog deletes itself
100 }
101
102 void TheaterController::SearchStarted(int search_task_id)
103 {
104     if (search_task_id != _current_search_task_id) {
105         return;
106     }
107     _theater_window->SetBusy(true);
108 }
109
110 void TheaterController::Reply(int search_task_id, bool intermediate)
111 {
112     if (search_task_id != _current_search_task_id) {
113         return;
114     }
115     Sort(intermediate, SLOT(SortFinished(QAbstractItemModel*,int,bool)));
116 }
117
118 void TheaterController::Error(int search_task_id)
119 {
120     if (search_task_id != _current_search_task_id) {
121         return;
122     }
123     Sort(false, SLOT(SortErrorFinished(QAbstractItemModel*,int,bool)));
124 }
125
126 void TheaterController::SearchFinished(int search_task_id, bool success)
127 {
128     Q_UNUSED(success);
129     if (search_task_id != _current_search_task_id) {
130         return;
131     }
132     _theater_window->SetBusy(false);
133 }
134
135 void TheaterController::Sort(bool intermediate, const char *slot)
136 {
137     TheaterScheduleModel *theater_schedule_model = new TheaterScheduleModel(_cinema_schedule, _cinema_key, this);
138     theater_schedule_model->Update();
139     QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
140     sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
141     sort_model->setSortRole(TheaterScheduleModel::SortRole);
142     sort_model->setDynamicSortFilter(false);
143     sort_model->setSourceModel(theater_schedule_model);
144     ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
145     connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
146     sort_client->Sort(sort_model, _current_search_task_id, intermediate);
147     // proxy deletes itself
148 }
149
150 void TheaterController::SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
151 {
152     if (search_task_id != _current_search_task_id) {
153         return;
154     }
155     SetModel(model);
156     if (!intermediate) {
157         if (_theater_schedule_model->rowCount() == 0) {
158             _theater_window->SetError(tr(MSG_NO_THEATER_SCHEDULE_FOUND).arg(_cinema_key.GetName()));
159         }
160     }
161 }
162
163 void TheaterController::SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
164 {
165     Q_UNUSED(intermediate);
166     if (search_task_id != _current_search_task_id) {
167         return;
168     }
169     SetModel(model);
170     if (_theater_schedule_model->rowCount() == 0) {
171         _theater_window->SetError(tr(MSG_THEATER_SCHEDULE_ERROR));
172     } else {
173         UiUtils::ShowError(tr(MSG_THEATER_SCHEDULE_ERROR));
174     }
175 }
176
177 void TheaterController::SetModel(QAbstractItemModel *model)
178 {
179     delete _theater_schedule_proxy_model->sourceModel();
180     _theater_schedule_proxy_model->setSourceModel(model);
181     delete _theater_schedule_model;
182     if (model != 0) {
183         _theater_schedule_model = (TheaterScheduleModel *) ((QSortFilterProxyModel *) model)->sourceModel();
184     } else {
185         _theater_schedule_model = 0;
186     }
187 }