Merge branch 'development'
[quandoparte] / application / stationschedulemodel.cpp
index e648760..600d0f0 100644 (file)
@@ -22,33 +22,36 @@ Boston, MA 02110-1301, USA.
 #include "stationschedulemodel.h"
 
 #include "dataprovider.h"
+#include "settings.h"
 
+#include <QtGlobal>
 #include <QDebug>
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 1, 0))
+#include <QtWebKitWidgets>
+#else
 #include <QWebElement>
 #include <QWebFrame>
 #include <QWebPage>
+#endif
+
 StationScheduleModel::StationScheduleModel(const QString &name, QObject *parent) :
     QAbstractListModel(parent),
-    m_name(name)
-
+    m_name(name),
+    m_error(QString())
 {
     DataProvider *provider = DataProvider::instance();
-    QHash<int, QByteArray> roles;
-    roles[TrainRole] = "train";
-    roles[DepartureStationRole] = "departureStation";
-    roles[DepartureTimeRole] = "departureTime";
-    roles[ArrivalStationRole] = "arrivalStation";
-    roles[ArrivalTimeRole] = "ArrivalTime";
-    roles[DetailsUrlRole] = "DetailsUrl";
-    roles[DelayRole] = "delay";
-    roles[DelayClassRole] = "delayClassRole";
-    setRoleNames(roles);
-
     connect(provider, SIGNAL(stationScheduleReady(QByteArray,QUrl)),
             this, SLOT(parse(QByteArray,QUrl)));
+    connect(provider, SIGNAL(error()),
+            this, SLOT(onNetworkError()));
+    Settings *settings = Settings::instance();
+    m_scheduleType = settings->showArrivalsPreferred() ? ArrivalSchedule : DepartureSchedule;
+#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
+    setRoleNames(roleNames());
+#endif
 }
 
-QString & StationScheduleModel::name()
+const QString &StationScheduleModel::name()
 {
     return m_name;
 }
@@ -61,6 +64,68 @@ void StationScheduleModel::setName(const QString &name)
     }
 }
 
+const QString &StationScheduleModel::code()
+{
+    return m_code;
+}
+
+void StationScheduleModel::setCode(const QString &code)
+{
+    if (code != m_code) {
+        m_code = code;
+        emit codeChanged();
+    }
+}
+
+const QString &StationScheduleModel::error()
+{
+    return m_error;
+}
+
+void StationScheduleModel::setError(const QString &error)
+{
+    if (error != m_error) {
+        m_error = error;
+        emit errorChanged();
+    }
+}
+
+QHash<int, QByteArray> StationScheduleModel::roleNames() const
+{
+    QHash<int, QByteArray> roles;
+    roles[TrainRole] = "train";
+    roles[DepartureStationRole] = "departureStation";
+    roles[DepartureTimeRole] = "departureTime";
+    roles[ArrivalStationRole] = "arrivalStation";
+    roles[ArrivalTimeRole] = "arrivalTime";
+    roles[DetailsUrlRole] = "detailsUrl";
+    roles[DelayRole] = "delay";
+    roles[DelayClassRole] = "delayClass";
+    roles[ExpectedPlatformRole] = "expectedPlatform";
+    roles[ActualPlatformRole] = "actualPlatform";
+
+    return roles;
+}
+
+StationScheduleModel::ScheduleType StationScheduleModel::type()
+{
+    return m_scheduleType;
+}
+
+void StationScheduleModel::setType(StationScheduleModel::ScheduleType type)
+{
+    if (type != m_scheduleType) {
+        emit layoutAboutToBeChanged();
+        beginResetModel();
+        m_scheduleType = type;
+        emit typeChanged();
+        endResetModel();
+        emit layoutChanged();
+        Settings *settings = Settings::instance();
+        settings->setShowArrivalsPreferred(m_scheduleType == ArrivalSchedule ? true : false);
+    }
+}
+
 static void parseDelayClass(const QWebElement &element, StationScheduleItem &item)
 {
     if (!element.isNull()) {
@@ -110,7 +175,21 @@ static void parseTrain(const QString &text, StationScheduleItem &item)
             item.setArrivalStation(filter.cap(2));
             item.setArrivalTime(filter.cap(3));
         }
-        item.setDelay(filter.cap(6));
+        QString delayDescription = filter.cap(6);
+        if (delayDescription == "in orario") {
+            item.setDelay(QObject::tr("On time"));
+        } else {
+            QRegExp delayRegExp("ritardo ([0-9]+)(| minuti)");
+            int pos = delayRegExp.indexIn(delayDescription);
+            if (pos >= 0) {
+                item.setDelay(QString(QObject::tr("Delay: %1 minutes")).arg(delayRegExp.cap(1)));
+            } else {
+                // Does not match, let the user parse it
+                item.setDelay(delayDescription);
+            }
+        }
+        item.setExpectedPlatform(filter.cap(4));
+        item.setActualPlatform(filter.cap(5));
     } else {
         qDebug() << "could not parse" << text;
     }
@@ -137,6 +216,8 @@ StationScheduleItem parseResult(const QWebElement &result)
     qDebug() << "departureTime:" << item.departureTime();
     qDebug() << "arrivalStation:" << item.arrivalStation();
     qDebug() << "arrivalTime:" << item.arrivalTime();
+    qDebug() << "expectedPlatform:" << item.expectedPlatform();
+    qDebug() << "actualPlatform:" << item.actualPlatform();
     qDebug() << "delay:" << item.delay();
     return item;
 }
@@ -149,15 +230,28 @@ void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUr
     qDebug() << "--- end of query result ----- cut here ------";
 
     emit layoutAboutToBeChanged();
-    beginInsertRows(QModelIndex(), 0, 0);
+    beginResetModel();
     QWebPage page;
     page.mainFrame()->setContent(htmlReply, "text/html", baseUrl);
     QWebElement doc = page.mainFrame()->documentElement();
 
+    // Check if the page is reporting an error before parsing it
+    QWebElement errorElement = doc.findFirst("span.errore");
+    if (!errorElement.isNull()) {
+        m_departureSchedules.clear();
+        m_arrivalSchedules.clear();
+        QString errorText = errorElement.toPlainText().trimmed();
+        if (errorText == "localita' non trovata") {
+            setError(tr("Unknown station"));
+        } else {
+            setError(tr("Unknown error"));
+        }
+        qDebug() << "error:" << error();
+        return;
+    }
     // Find the first div
     QWebElement current = doc.findFirst("div");
 
-    QStringList departures, arrivals;
     qDebug() << "skipping to the departures";
     // Skip to the first div of class corpocentrale, which contains the first
     // departure-related contents
@@ -172,7 +266,6 @@ void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUr
     qDebug() << "marking departures";
     do {
         if (current.classes().contains("bloccorisultato")) {
-            departures << current.toPlainText();
             StationScheduleItem schedule = parseResult(current);
             if (schedule.isValid()) {
                 m_departureSchedules << schedule;
@@ -187,7 +280,6 @@ void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUr
     // Mark everything as an arrival, until reaching the footer
     while (!current.classes().contains("footer")) {
         if (current.classes().contains("bloccorisultato")) {
-            arrivals << current.toPlainText();
             StationScheduleItem schedule = parseResult(current);
             if (schedule.isValid()) {
                 m_arrivalSchedules << schedule;
@@ -198,34 +290,51 @@ void StationScheduleModel::parse(const QByteArray &htmlReply, const QUrl &baseUr
         if (current.isNull())
             break;
     }
-    endInsertRows();
+    endResetModel();
     emit layoutChanged();
 }
 
-void StationScheduleModel::fetch(const QString &name)
+void StationScheduleModel::onNetworkError()
+{
+    qDebug()<< "Station Schedule Model got a Network Error";
+    m_error = tr("Network error");
+    emit errorChanged();
+}
+
+void StationScheduleModel::fetch(const QString &name, const QString &code)
 {
     DataProvider *provider = DataProvider::instance();
 
-    provider->fetchStationSchedule(name);
+    if (!error().isEmpty())
+        setError(QString());
+    m_departureSchedules.clear();
+    m_arrivalSchedules.clear();
+    provider->fetchStationSchedule(name, code);
     setName(name);
+    setCode(code);
 }
 
 int StationScheduleModel::rowCount(const QModelIndex &parent) const
 {
-    qDebug() << "schedule.count" << m_departureSchedules.count();
-    return m_departureSchedules.count();
+    Q_UNUSED(parent);
+    if (m_scheduleType == DepartureSchedule) {
+        return m_departureSchedules.count();
+    } else {
+        return m_arrivalSchedules.count();
+    }
 }
 
 QVariant StationScheduleModel::data(const QModelIndex &index, int role) const
 {
-    qDebug() << "getting data for role" << role;
     if (!index.isValid()) {
         return QVariant();
     }
-    if (index.row() >= m_departureSchedules.count()) {
+    const QList<StationScheduleItem> &schedules =
+            (m_scheduleType == DepartureSchedule) ? m_departureSchedules : m_arrivalSchedules;
+    if (index.row() < 0 || index.row() >= schedules.count()) {
         return QVariant();
     }
-    StationScheduleItem item = m_departureSchedules[index.row()];
+    StationScheduleItem item = schedules[index.row()];
     switch (role) {
     case Qt::DisplayRole:
     case TrainRole:
@@ -244,6 +353,10 @@ QVariant StationScheduleModel::data(const QModelIndex &index, int role) const
         return QVariant::fromValue(item.delay());
     case DelayClassRole:
         return QVariant::fromValue(item.delayClass());
+    case ExpectedPlatformRole:
+        return QVariant::fromValue(item.expectedPlatform());
+    case ActualPlatformRole:
+        return QVariant::fromValue(item.actualPlatform());
     default:
         return QVariant::fromValue(QString("Unknown role requested"));
     }