1 #include "departureboard.h"
2 #include "ui_departureboard.h"
4 DepartureBoard::DepartureBoard(QWidget *parent) : QMainWindow(parent), ui(new Ui::DepartureBoard)
8 manager = new QNetworkAccessManager(this);
9 connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(readResponse(QNetworkReply*)));
11 ui->scrollArea->setProperty("FingerScrollable", true);
16 * Initialises the progress dialog for the network request
18 void DepartureBoard::setupDialog()
20 dialog = new QDialog(0);
21 layout = new QHBoxLayout();
22 progress = new QProgressBar();
23 progress->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
24 cancelButton = new QPushButton("Cancel");
26 layout->addWidget(progress);
27 layout->addWidget(cancelButton);
28 dialog->setLayout(layout);
31 connect(cancelButton, SIGNAL(clicked()), dialog, SLOT(reject()));
32 connect(dialog, SIGNAL(rejected()), this, SLOT(cancel()));
36 * Loads the departure board for the requested station
38 void DepartureBoard::show(QString fromCode)
41 //Load the departure board data.
44 //Note that QMainWindow::show() is absent here. Instead we show a progress dialog, then show the
45 //departure board only when we have loaded the data & created the display.
51 * Creates the network request, including the SOAP request XML.
53 void DepartureBoard::setupRequest()
55 QDomDocument document;
57 QDomElement env = document.createElement("soapenv:Envelope");
58 env.setAttribute("xmlns:soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
59 env.setAttribute("xmlns:typ", "http://thalesgroup.com/RTTI/2008-02-20/ldb/types");
61 QDomElement header = document.createElement("soapenv:Header");
62 QDomElement body = document.createElement("soapenv:Body");
64 QDomElement typ = document.createElement("typ:GetDepartureBoardRequest");
66 QDomElement numRows = document.createElement("typ:numRows");
67 numRows.appendChild(document.createTextNode("20"));
68 QDomElement crs = document.createElement("typ:crs");
69 crs.appendChild(document.createTextNode(from));
70 //QDomElement filterCrs = document.createElement("typ:filterCrs");
71 //filterCrs.appendChild(document.createTextNode(to));
72 QDomElement filterType = document.createElement("typ:filterType");
73 filterType.appendChild(document.createTextNode("to"));
74 //QDomElement timeOffset = document.createElement("typ:timeOffset");
75 //timeOffset.appendChild(document.createTextNode("0"));
77 document.appendChild(env);
78 env.appendChild(header);
79 env.appendChild(body);
80 body.appendChild(typ);
81 typ.appendChild(numRows);
83 //typ.appendChild(filterCrs);
84 typ.appendChild(filterType);
85 //typ.appendChild(timeOffset);
87 requestData = document.toString(-1).prepend("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
89 request = QNetworkRequest(QUrl("http://realtime.nationalrail.co.uk/LDBWS/ldb2.asmx"));
90 request.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/xml;charset=utf-8"));
91 request.setRawHeader("SOAPAction", "http://thalesgroup.com/RTTI/2008-02-20/ldb/GetDepartureBoard");
95 * Sends the SOAP request
97 void DepartureBoard::sendRequest()
99 m_reply = manager->post(request, requestData.toUtf8().constData());
100 connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
101 connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64, qint64)));
102 connect(m_reply, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(uploadProgress(qint64, qint64)));
106 * Cancel the current request
108 void DepartureBoard::cancel()
110 //Abort the request; an error signal will be emitted, so we don't need to delete the network reply here
115 * Updates the progress bar when making the request
117 void DepartureBoard::uploadProgress(qint64 rec, qint64 total)
119 dialog->setWindowTitle("Sending request");
120 progress->setRange(0, total);
121 progress->setValue(rec);
125 * Updates the progress bar when receiving the reply to the request
127 void DepartureBoard::downloadProgress(qint64 rec, qint64 total)
129 dialog->setWindowTitle("Receiving reply");
130 progress->setRange(0, total);
131 progress->setValue(rec);
135 * Slot for when there is a network error
137 void DepartureBoard::networkError(QNetworkReply::NetworkError error)
139 //If the request was cancelled, we show no error message
140 if(error == QNetworkReply::OperationCanceledError)
143 //Set the error flag to true, so that we can exit out of the readResponse method
148 //If this error is a result of the first network request, we assume there is no connection to the internet
158 msg.setText(QString("Network error: %1, %2").arg(m_reply->errorString()).arg(error));
167 * Attempt to wait for connection on either wifi or gprs
169 void DepartureBoard::ensureConnection()
171 dialog->setWindowTitle("Connecting");
173 QNetworkInterface wlan = QNetworkInterface::interfaceFromName("wlan0");
174 QNetworkInterface gprs = QNetworkInterface::interfaceFromName("gprs0");
176 //qDebug() << "wlan0" << wlan.flags().testFlag(QNetworkInterface::IsUp) << wlan.flags().testFlag(QNetworkInterface::IsRunning);
177 //qDebug() << "\tgprs0" << gprs.flags().testFlag(QNetworkInterface::IsUp) << gprs.flags().testFlag(QNetworkInterface::IsRunning);
179 if( (wlan.isValid() && wlan.flags().testFlag(QNetworkInterface::IsUp)) || (gprs.isValid() && gprs.flags().testFlag(QNetworkInterface::IsUp)) )
181 //We are connected, so try sending the network request again
187 QTimer::singleShot(100, this, SLOT(ensureConnection()));
191 #define NAMESPACE "declare namespace t=\"http://thalesgroup.com/RTTI/2007-10-10/ldb/types\";" \
192 "declare function local:if-absent( $arg as item()*, $value as item()* ) as item()* { if (exists($arg)) then $arg else $value } ;"
195 * Reads the response to the network request, and extracts the data we want.
197 void DepartureBoard::readResponse(QNetworkReply* reply)
199 QByteArray in = reply->readAll();
201 if(errorFlag == true)
203 m_reply->deleteLater();
207 received.setData(in);
208 received.open(QIODevice::ReadOnly);
211 query.bindVariable("data", &received);
213 QString name = queryOne(query, "for $x in doc($data)//t:GetDepartureBoardResult/t:locationName/text() return fn:string($x)");
214 ui->label_name->setText(name);
216 QString time = queryOne(query, "for $x in doc($data)//t:generatedAt/text() return fn:string($x)");
217 time.mid(time.indexOf('T') + 1, 8);
219 setWindowTitle(time.mid(time.indexOf('T') + 1, 8).prepend("Last updated: "));
221 QStringList serviceFrom = queryList(query, "for $x in doc($data)//t:trainServices//t:origin//t:locationName/text() return fn:string($x)");
222 QStringList serviceTo = queryList(query, "for $x in doc($data)//t:trainServices//t:destination//t:locationName/text() return fn:string($x)");
223 QStringList serviceVia = queryList(query, "for $x in doc($data)//t:trainServices/t:service/t:destination/t:location return string(local:if-absent($x/t:via, ''))");
225 QStringList std = queryList(query, "for $x in doc($data)//t:trainServices//t:std/text() return fn:string($x)");
226 QStringList etd = queryList(query, "for $x in doc($data)//t:trainServices//t:etd/text() return fn:string($x)");
227 QStringList platform = queryList(query, "for $x in doc($data)//t:trainServices/t:service return string(local:if-absent($x/t:platform, '-'))");
228 //QStringList op = queryList(query, "for $x in doc($data)//t:trainServices//t:operator/text() return fn:string($x)");
229 serviceID = queryList(query, "for $x in doc($data)//t:trainServices//t:serviceID/text() return fn:string($x)");
231 for(int i = 0; i < serviceFrom.size(); i++)
233 QString to = QString("%1 %2").arg(serviceTo.at(i)).arg(serviceVia.at(i));
234 DepartureWidget * w = new DepartureWidget(std.at(i), to, etd.at(i), platform.at(i), serviceID.at(i), ui->departures);
235 departureWidgets.append(w);
236 w->setObjectName(QString("%1").arg(i));
237 connect(w, SIGNAL(clicked()), this, SLOT(departureClicked()));
238 ui->departures->layout()->addWidget(w);
242 m_reply->deleteLater();
249 * Shows the details of a service when it is clicked in the list of departures
251 void DepartureBoard::departureClicked()
253 int i = sender()->objectName().toInt();
254 QString id = departureWidgets.at(i)->getServiceID();
256 serviceWindow = new ServiceWindow();
257 serviceWindow->show(id);
260 QString DepartureBoard::queryOne(QXmlQuery & q, QString query)
264 q.setQuery(query.prepend(NAMESPACE));
265 q.evaluateTo(&output);
266 return (output.size() == 0) ? QString() : output.at(0);
269 QStringList DepartureBoard::queryList(QXmlQuery & q, QString query)
273 q.setQuery(query.prepend(NAMESPACE));
274 q.evaluateTo(&output);
278 DepartureBoard::~DepartureBoard()
285 void DepartureBoard::changeEvent(QEvent *e)
287 QMainWindow::changeEvent(e);
289 case QEvent::LanguageChange:
290 ui->retranslateUi(this);