diff --git a/tools/cabana/streams/routes.cc b/tools/cabana/streams/routes.cc index c805e7d60d8273..d653db839b65c0 100644 --- a/tools/cabana/streams/routes.cc +++ b/tools/cabana/streams/routes.cc @@ -32,10 +32,19 @@ class RouteListWidget : public QListWidget { RoutesDialog::RoutesDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Remote routes")); + auto all_routes_widget = new QWidget; + auto all_routes_layout = new QVBoxLayout(all_routes_widget); + all_routes_layout->addWidget(period_selector_ = new QComboBox(this)); + all_routes_layout->addWidget(route_list_ = new RouteListWidget()); + + routes_type_selector_ = new QTabWidget(this); + routes_type_selector_->addTab(all_routes_widget, tr("&All")); + routes_type_selector_->addTab(preserved_route_list_ = new RouteListWidget, tr("&Preserved")); + QFormLayout *layout = new QFormLayout(this); layout->addRow(tr("Device"), device_list_ = new QComboBox(this)); - layout->addRow(tr("Duration"), period_selector_ = new QComboBox(this)); - layout->addRow(route_list_ = new RouteListWidget(this)); + layout->addRow(routes_type_selector_); + auto button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addRow(button_box); @@ -49,7 +58,9 @@ RoutesDialog::RoutesDialog(QWidget *parent) : QDialog(parent) { // Connect signals and slots connect(device_list_, QOverload::of(&QComboBox::currentIndexChanged), this, &RoutesDialog::fetchRoutes); connect(period_selector_, QOverload::of(&QComboBox::currentIndexChanged), this, &RoutesDialog::fetchRoutes); + connect(routes_type_selector_, &QTabWidget::currentChanged, this, &RoutesDialog::fetchRoutes); connect(route_list_, &QListWidget::itemDoubleClicked, this, &QDialog::accept); + connect(preserved_route_list_, &QListWidget::itemDoubleClicked, this, &QDialog::accept); QObject::connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept); QObject::connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); @@ -79,45 +90,83 @@ void RoutesDialog::fetchRoutes() { if (device_list_->currentIndex() == -1 || device_list_->currentData().isNull()) return; - route_list_->clear(); - route_list_->setEmptyText(tr("Loading...")); - - HttpRequest *http = new HttpRequest(this, !Hardware::PC()); - QObject::connect(http, &HttpRequest::requestDone, this, &RoutesDialog::parseRouteList); + currentRoutesList()->clear(); + currentRoutesList()->setEmptyText(tr("Loading...")); // Construct URL with selected device and date range auto dongle_id = device_list_->currentData().toString(); - QDateTime current = QDateTime::currentDateTime(); - QString url = QString("%1/v1/devices/%2/routes_segments?start=%3&end=%4") - .arg(CommaApi::BASE_URL).arg(dongle_id) - .arg(current.addDays(-(period_selector_->currentData().toInt())).toMSecsSinceEpoch()) - .arg(current.toMSecsSinceEpoch()); + QString url = QString("%1/v1/devices/%2") + .arg(CommaApi::BASE_URL) + .arg(dongle_id); + + if(isPreservedTabSelected()) { + url += "/routes/preserved"; + } else { + QDateTime current = QDateTime::currentDateTime(); + url += QString("/routes_segments?start=%2&end=%3") + .arg(current.addDays(-(period_selector_->currentData().toInt())).toMSecsSinceEpoch()) + .arg(current.toMSecsSinceEpoch()); + } + + HttpRequest *http = new HttpRequest(this, !Hardware::PC()); + QObject::connect( + http, + &HttpRequest::requestDone, + this, + isPreservedTabSelected() ? &RoutesDialog::parsePreservedRouteList : &RoutesDialog::parseRouteList + ); http->sendRequest(url); } -void RoutesDialog::parseRouteList(const QString &json, bool success, QNetworkReply::NetworkError err) { +void RoutesDialog::onFinish(RouteListWidget *list, bool success, const QDateTime &from, const QDateTime &to, QJsonValue fullName) { if (success) { - for (const QJsonValue &route : QJsonDocument::fromJson(json.toUtf8()).array()) { - uint64_t start_time = route["start_time_utc_millis"].toDouble(); - uint64_t end_time = route["end_time_utc_millis"].toDouble(); - auto datetime = QDateTime::fromMSecsSinceEpoch(start_time); - auto item = new QListWidgetItem(QString("%1 %2min").arg(datetime.toString()).arg((end_time - start_time) / (1000 * 60))); - item->setData(Qt::UserRole, route["fullname"].toString()); - route_list_->addItem(item); - } + QListWidgetItem *item = new QListWidgetItem(QString("%1 %2min").arg(from.toString()).arg(from.secsTo(to) / 60)); + item->setData(Qt::UserRole, fullName.toString()); + list->addItem(item); + // Select first route if available - if (route_list_->count() > 0) route_list_->setCurrentRow(0); + if (list->count() > 0) list->setCurrentRow(0); } else { QMessageBox::warning(this, tr("Error"), tr("Failed to fetch routes. Check your network connection.")); reject(); } - route_list_->setEmptyText(tr("No items")); + list->setEmptyText(tr("No items")); sender()->deleteLater(); } +void RoutesDialog::parsePreservedRouteList(const QString &json, bool success, QNetworkReply::NetworkError err) { + if (success) { + for (const QJsonValue &route : QJsonDocument::fromJson(json.toUtf8()).array()) { + QDateTime from = QDateTime::fromString(route["start_time"].toString(), Qt::ISODateWithMs); + QDateTime to = QDateTime::fromString(route["end_time"].toString(), Qt::ISODateWithMs); + + onFinish(preserved_route_list_, success, from, to, route["fullname"]); + } + } +} + +void RoutesDialog::parseRouteList(const QString &json, bool success, QNetworkReply::NetworkError err) { + if (success) { + for (const QJsonValue &route : QJsonDocument::fromJson(json.toUtf8()).array()) { + QDateTime from = QDateTime::fromMSecsSinceEpoch(route["start_time_utc_millis"].toDouble()); + QDateTime to = QDateTime::fromMSecsSinceEpoch(route["end_time_utc_millis"].toDouble()); + + onFinish(route_list_, success, from, to, route["fullname"]); + } + } +} + void RoutesDialog::accept() { - if (auto current_item = route_list_->currentItem()) { + if (auto current_item = currentRoutesList()->currentItem()) { route_ = current_item->data(Qt::UserRole).toString(); } QDialog::accept(); } + +bool RoutesDialog::isPreservedTabSelected() { + return routes_type_selector_->currentIndex() == 1; +} + +RouteListWidget* RoutesDialog::currentRoutesList() { + return isPreservedTabSelected() ? preserved_route_list_ : route_list_; +} diff --git a/tools/cabana/streams/routes.h b/tools/cabana/streams/routes.h index 31e42fb0750422..da64175bd2c9d8 100644 --- a/tools/cabana/streams/routes.h +++ b/tools/cabana/streams/routes.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include "selfdrive/ui/qt/api.h" @@ -15,12 +17,18 @@ class RoutesDialog : public QDialog { protected: void accept() override; + void onFinish(RouteListWidget *list, bool success, const QDateTime &from, const QDateTime &to, QJsonValue fullName); void parseDeviceList(const QString &json, bool success, QNetworkReply::NetworkError err); void parseRouteList(const QString &json, bool success, QNetworkReply::NetworkError err); + void parsePreservedRouteList(const QString &json, bool success, QNetworkReply::NetworkError err); void fetchRoutes(); + bool isPreservedTabSelected(); + RouteListWidget* currentRoutesList(); + QTabWidget *routes_type_selector_; QComboBox *device_list_; QComboBox *period_selector_; + RouteListWidget *preserved_route_list_; RouteListWidget *route_list_; QString route_; };