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"
27 #include <QWebElement>
30 StationScheduleModel::StationScheduleModel(const QString &name, QObject *parent) :
31 QAbstractListModel(parent),
35 DataProvider *provider = DataProvider::instance();
36 QHash<int, QByteArray> roles;
37 roles[TrainRole] = "train";
38 roles[DepartureStationRole] = "departureStation";
39 roles[DepartureTimeRole] = "departureTime";
40 roles[ArrivalStationRole] = "arrivalStation";
41 roles[ArrivalTimeRole] = "ArrivalTime";
42 roles[DetailsUrlRole] = "DetailsUrl";
43 roles[DelayRole] = "delay";
44 roles[DelayClassRole] = "delayClassRole";
47 connect(provider, SIGNAL(stationScheduleReady(QByteArray,QUrl)),
48 this, SLOT(parse(QByteArray,QUrl)));
51 QString & StationScheduleModel::name()
56 void StationScheduleModel::setName(const QString &name)
64 static void parseDelayClass(const QWebElement &element, StationScheduleItem &item)
66 if (!element.isNull()) {
67 QWebElement image = element.findFirst("img");
68 if (!image.isNull()) {
70 QString imageName = image.attribute("src");
71 if (!imageName.isEmpty()) {
72 QRegExp delayClassRegexp("pallinoRit([0-9])\\.png");
73 int pos = delayClassRegexp.indexIn(imageName);
74 qDebug() << "regexp matched at pos:" << pos << "match:" << delayClassRegexp.cap(0);
75 delayClass = (pos >= 0) ? delayClassRegexp.cap(1).toInt() : 0;
77 item.setDelayClass(delayClass);
79 qDebug() << "img not found";
82 qDebug() << "div.bloccotreno not found";
86 static void parseDetailsUrl(const QWebElement &element, StationScheduleItem &item)
88 if (!element.isNull()) {
89 QWebElement link = element.findFirst("a");
90 QString url = link.attribute("href");
91 item.setDetailsUrl(url);
93 qDebug() << "link not found";
97 static void parseTrain(const QString &text, StationScheduleItem &item)
99 QRegExp filter("^(Per|Da) (.*)\\n"
101 "Binario Previsto: (.*)\n"
102 "Binario Reale: (.*)\n"
104 int pos = filter.indexIn(text);
106 if (filter.cap(1) == "Per") {
107 item.setDepartureStation(filter.cap(2));
108 item.setDepartureTime(filter.cap(3));
110 item.setArrivalStation(filter.cap(2));
111 item.setArrivalTime(filter.cap(3));
113 item.setDelay(filter.cap(6));
115 qDebug() << "could not parse" << text;
119 StationScheduleItem parseResult(const QWebElement &result)
121 StationScheduleItem item;
123 QWebElement current = result.findFirst("h2");
124 if (!current.isNull()) {
125 item.setTrain(current.toPlainText());
127 parseDetailsUrl(result, item);
128 current = result.findFirst("div.bloccotreno");
129 parseDelayClass(current, item);
130 QString rawText = current.toPlainText();
131 parseTrain(rawText, item);
133 qDebug() << "train:" << item.train();
134 qDebug() << "delayClass:" << item.delayClass();
135 qDebug() << "detailsUrl:" << item.detailsUrl();
136 qDebug() << "departureStation:" << item.departureStation();
137 qDebug() << "departureTime:" << item.departureTime();
138 qDebug() << "arrivalStation:" << item.arrivalStation();
139 qDebug() << "arrivalTime:" << item.arrivalTime();
140 qDebug() << "delay:" << item.delay();
144 void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUrl)
147 qDebug() << "--- start of query result --- cut here ------";
148 qDebug() << QString::fromUtf8(htmlReply.constData());
149 qDebug() << "--- end of query result ----- cut here ------";
151 emit layoutAboutToBeChanged();
152 beginInsertRows(QModelIndex(), 0, 0);
154 page.mainFrame()->setContent(htmlReply, "text/html", baseUrl);
155 QWebElement doc = page.mainFrame()->documentElement();
157 // Find the first div
158 QWebElement current = doc.findFirst("div");
160 QStringList departures, arrivals;
161 qDebug() << "skipping to the departures";
162 // Skip to the first div of class corpocentrale, which contains the first
163 // departure-related contents
164 while (!current.classes().contains("corpocentrale")) {
165 current = current.nextSibling();
166 qDebug() << "skipping to the next element";
167 if (current.isNull())
170 // Mark every div as a departure class element; the next corpocentrale
171 // marks the start of the arrivals section
172 qDebug() << "marking departures";
174 if (current.classes().contains("bloccorisultato")) {
175 departures << current.toPlainText();
176 StationScheduleItem schedule = parseResult(current);
177 if (schedule.isValid()) {
178 m_schedules << schedule;
181 current = current.nextSibling();
182 qDebug() << "marking as departures";
183 if (current.isNull())
185 } while (!current.classes().contains("corpocentrale"));
187 // Mark everything as an arrival, until reaching the footer
188 while (!current.classes().contains("footer")) {
189 if (current.classes().contains("bloccorisultato")) {
190 arrivals << current.toPlainText();
192 current = current.nextSibling();
193 qDebug() << "marking as arrival";
194 if (current.isNull())
198 qDebug() << "departures list contain:";
199 qDebug() << departures;
200 //qDebug() << "arrivals list contain:";
201 //qDebug() << arrivals;
203 emit layoutChanged();
206 void StationScheduleModel::fetch(const QString &name)
208 DataProvider *provider = DataProvider::instance();
210 provider->fetchStationSchedule(name);
214 int StationScheduleModel::rowCount(const QModelIndex &parent) const
216 qDebug() << "schedule.count" << m_schedules.count();
217 return m_schedules.count();
220 QVariant StationScheduleModel::data(const QModelIndex &index, int role) const
222 qDebug() << "getting data for role" << role;
223 if (!index.isValid()) {
226 if (index.row() >= m_schedules.count()) {
229 StationScheduleItem item = m_schedules[index.row()];
231 case Qt::DisplayRole:
233 return QVariant::fromValue(item.train());
234 case DepartureStationRole:
235 return QVariant::fromValue(item.departureStation());
236 case DepartureTimeRole:
237 return QVariant::fromValue(item.departureTime());
238 case ArrivalStationRole:
239 return QVariant::fromValue(item.arrivalStation());
240 case ArrivalTimeRole:
241 return QVariant::fromValue(item.arrivalTime());
243 return QVariant::fromValue(item.detailsUrl());
245 return QVariant::fromValue(item.delay());
247 return QVariant::fromValue(item.delayClass());
249 return QVariant::fromValue(QString("Unknown role requested"));