3 Copyright (C) 2011 Luciano Montanaro <mikelima@cirulla.net>
5 This program 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 2 of the License, or
8 (at your option) any later version.
10 This program 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 GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 #include "stationschedulemodel.h"
24 #include "dataprovider.h"
28 #include <QWebElement>
32 StationScheduleModel::StationScheduleModel(const QString &name, QObject *parent) :
33 QAbstractListModel(parent),
37 DataProvider *provider = DataProvider::instance();
38 QHash<int, QByteArray> roles;
39 roles[TrainRole] = "train";
40 roles[DepartureStationRole] = "departureStation";
41 roles[DepartureTimeRole] = "departureTime";
42 roles[ArrivalStationRole] = "arrivalStation";
43 roles[ArrivalTimeRole] = "arrivalTime";
44 roles[DetailsUrlRole] = "detailsUrl";
45 roles[DelayRole] = "delay";
46 roles[DelayClassRole] = "delayClassRole";
49 connect(provider, SIGNAL(stationScheduleReady(QByteArray,QUrl)),
50 this, SLOT(parse(QByteArray,QUrl)));
53 QString & StationScheduleModel::name()
58 void StationScheduleModel::setName(const QString &name)
66 StationScheduleModel::ScheduleType StationScheduleModel::type()
68 return m_scheduleType;
71 void StationScheduleModel::setType(StationScheduleModel::ScheduleType type)
73 if (type != m_scheduleType) {
74 emit layoutAboutToBeChanged();
76 m_scheduleType = type;
80 Settings *settings = Settings::instance();
81 settings->setShowArrivalsPreferred(m_scheduleType == ArrivalSchedule ? true : false);
85 static void parseDelayClass(const QWebElement &element, StationScheduleItem &item)
87 if (!element.isNull()) {
88 QWebElement image = element.findFirst("img");
89 if (!image.isNull()) {
91 QString imageName = image.attribute("src");
92 if (!imageName.isEmpty()) {
93 QRegExp delayClassRegexp("pallinoRit([0-9])\\.png");
94 int pos = delayClassRegexp.indexIn(imageName);
95 qDebug() << "regexp matched at pos:" << pos << "match:" << delayClassRegexp.cap(0);
96 delayClass = (pos >= 0) ? delayClassRegexp.cap(1).toInt() : 0;
98 item.setDelayClass(delayClass);
100 qDebug() << "img not found";
103 qDebug() << "div.bloccotreno not found";
107 static void parseDetailsUrl(const QWebElement &element, StationScheduleItem &item)
109 if (!element.isNull()) {
110 QWebElement link = element.findFirst("a");
111 QString url = link.attribute("href");
112 item.setDetailsUrl(url);
114 qDebug() << "link not found";
118 static void parseTrain(const QString &text, StationScheduleItem &item)
120 QRegExp filter("^(Per|Da) (.*)\\n"
122 "Binario Previsto: (.*)\n"
123 "Binario Reale: (.*)\n"
125 int pos = filter.indexIn(text);
127 if (filter.cap(1) == "Per") {
128 item.setDepartureStation(filter.cap(2));
129 item.setDepartureTime(filter.cap(3));
131 item.setArrivalStation(filter.cap(2));
132 item.setArrivalTime(filter.cap(3));
134 item.setDelay(filter.cap(6));
136 qDebug() << "could not parse" << text;
140 StationScheduleItem parseResult(const QWebElement &result)
142 StationScheduleItem item;
144 QWebElement current = result.findFirst("h2");
145 if (!current.isNull()) {
146 item.setTrain(current.toPlainText());
148 parseDetailsUrl(result, item);
149 current = result.findFirst("div.bloccotreno");
150 parseDelayClass(current, item);
151 QString rawText = current.toPlainText();
152 parseTrain(rawText, item);
154 qDebug() << "train:" << item.train();
155 qDebug() << "delayClass:" << item.delayClass();
156 qDebug() << "detailsUrl:" << item.detailsUrl();
157 qDebug() << "departureStation:" << item.departureStation();
158 qDebug() << "departureTime:" << item.departureTime();
159 qDebug() << "arrivalStation:" << item.arrivalStation();
160 qDebug() << "arrivalTime:" << item.arrivalTime();
161 qDebug() << "delay:" << item.delay();
165 void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUrl)
168 qDebug() << "--- start of query result --- cut here ------";
169 qDebug() << QString::fromUtf8(htmlReply.constData());
170 qDebug() << "--- end of query result ----- cut here ------";
172 emit layoutAboutToBeChanged();
175 page.mainFrame()->setContent(htmlReply, "text/html", baseUrl);
176 QWebElement doc = page.mainFrame()->documentElement();
178 // Find the first div
179 QWebElement current = doc.findFirst("div");
181 QStringList departures, arrivals;
182 qDebug() << "skipping to the departures";
183 // Skip to the first div of class corpocentrale, which contains the first
184 // departure-related contents
185 while (!current.classes().contains("corpocentrale")) {
186 current = current.nextSibling();
187 qDebug() << "skipping to the next element";
188 if (current.isNull())
191 // Mark every div as a departure class element; the next corpocentrale
192 // marks the start of the arrivals section
193 qDebug() << "marking departures";
195 if (current.classes().contains("bloccorisultato")) {
196 departures << current.toPlainText();
197 StationScheduleItem schedule = parseResult(current);
198 if (schedule.isValid()) {
199 m_departureSchedules << schedule;
202 current = current.nextSibling();
203 qDebug() << "marking as departures";
204 if (current.isNull())
206 } while (!current.classes().contains("corpocentrale"));
208 // Mark everything as an arrival, until reaching the footer
209 while (!current.classes().contains("footer")) {
210 if (current.classes().contains("bloccorisultato")) {
211 arrivals << current.toPlainText();
212 StationScheduleItem schedule = parseResult(current);
213 if (schedule.isValid()) {
214 m_arrivalSchedules << schedule;
217 current = current.nextSibling();
218 qDebug() << "marking as arrival";
219 if (current.isNull())
223 emit layoutChanged();
226 void StationScheduleModel::fetch(const QString &name)
228 DataProvider *provider = DataProvider::instance();
230 provider->fetchStationSchedule(name);
234 int StationScheduleModel::rowCount(const QModelIndex &parent) const
237 if (m_scheduleType == DepartureSchedule) {
238 qDebug() << "schedule.count" << m_departureSchedules.count();
239 return m_departureSchedules.count();
241 qDebug() << "schedule.count" << m_arrivalSchedules.count();
242 return m_arrivalSchedules.count();
246 QVariant StationScheduleModel::data(const QModelIndex &index, int role) const
248 qDebug() << "getting data for role" << role;
249 if (!index.isValid()) {
252 const QList<StationScheduleItem> &schedules =
253 (m_scheduleType == DepartureSchedule) ? m_departureSchedules : m_arrivalSchedules;
254 if (index.row() < 0 || index.row() >= schedules.count()) {
257 StationScheduleItem item = schedules[index.row()];
259 case Qt::DisplayRole:
261 return QVariant::fromValue(item.train());
262 case DepartureStationRole:
263 return QVariant::fromValue(item.departureStation());
264 case DepartureTimeRole:
265 return QVariant::fromValue(item.departureTime());
266 case ArrivalStationRole:
267 return QVariant::fromValue(item.arrivalStation());
268 case ArrivalTimeRole:
269 return QVariant::fromValue(item.arrivalTime());
271 return QVariant::fromValue(item.detailsUrl());
273 return QVariant::fromValue(item.delay());
275 return QVariant::fromValue(item.delayClass());
277 return QVariant::fromValue(QString("Unknown role requested"));