6#include "DownloadRegionDialog.h"
10#include <QButtonGroup>
12#include <QDialogButtonBox>
18#include <QRadioButton>
23#include <QStandardItemModel>
27#include "DownloadRegion.h"
28#include "GeoDataCoordinates.h"
29#include "GeoDataLatLonAltBox.h"
30#include "GeoDataLineString.h"
31#include "GeoSceneDocument.h"
32#include "GeoSceneMap.h"
33#include "LatLonBoxWidget.h"
34#include "MarbleDebug.h"
38#include "TextureLayer.h"
39#include "TileCoordsPyramid.h"
42#include "TileLevelRangeWidget.h"
43#include "TileLoaderHelper.h"
44#include "VectorTileLayer.h"
45#include "routing/RoutingManager.h"
46#include "routing/RoutingModel.h"
51int const maxTilesCount = 100000;
52int const minimumRouteOffset = 0;
53int const maximumRouteOffset = 10000;
54int averageTextureTileSize = 13;
55int averageVectorTileSize = 30;
57class Q_DECL_HIDDEN DownloadRegionDialog::Private
60 Private(MarbleWidget *
const widget,
QDialog *
const dialog);
61 QWidget *createSelectionMethodBox();
63 QWidget *createOkCancelButtonBox();
65 bool hasRoute()
const;
66 bool hasTextureLayers()
const;
67 bool hasVectorLayers()
const;
74 LatLonBoxWidget *m_latLonBoxWidget;
75 TileLevelRangeWidget *m_tileLevelRangeWidget;
77 QLabel *m_routeOffsetLabel;
83 TextureLayer
const *m_textureLayer;
84 VectorTileLayer
const *m_vectorTileLayer;
85 int m_visibleTileLevel;
86 MarbleModel
const *
const m_model;
87 MarbleWidget *
const m_widget;
88 SelectionMethod m_selectionMethod;
89 GeoDataLatLonAltBox m_visibleRegion;
90 RoutingModel *m_routingModel;
91 DownloadRegion m_downloadRegion;
95DownloadRegionDialog::Private::Private(MarbleWidget *
const widget,
QDialog *
const dialog)
97 , m_layerLabel(nullptr)
98 , m_layerComboBox(nullptr)
99 , m_buttonGroup(nullptr)
100 , m_visibleRegionMethodButton(nullptr)
101 , m_specifiedRegionMethodButton(nullptr)
102 , m_latLonBoxWidget(new LatLonBoxWidget)
103 , m_tileLevelRangeWidget(new TileLevelRangeWidget)
104 , m_routeDownloadMethodButton(nullptr)
105 , m_routeOffsetLabel(nullptr)
106 , m_routeOffsetSpinBox(nullptr)
107 , m_tilesCountLabel(nullptr)
108 , m_tileSizeInfo(nullptr)
109 , m_okButton(nullptr)
110 , m_applyButton(nullptr)
111 , m_textureLayer(widget->textureLayer())
112 , m_vectorTileLayer(widget->vectorTileLayer())
113 , m_visibleTileLevel(0)
114 , m_model(widget->model())
116 , m_selectionMethod(VisibleRegionMethod)
118 , m_routingModel(widget->model()->routingManager()->routingModel())
120 m_latLonBoxWidget->setEnabled(
false);
121 m_latLonBoxWidget->setLatLonBox(m_visibleRegion);
122 m_tileLevelRangeWidget->setDefaultLevel(m_visibleTileLevel);
123 m_downloadRegion.setMarbleModel(widget->model());
126QWidget *DownloadRegionDialog::Private::createSelectionMethodBox()
129 m_buttonGroup->setExclusive(
true);
130 m_visibleRegionMethodButton =
new QRadioButton(tr(
"Visible region"));
131 m_buttonGroup->addButton(m_visibleRegionMethodButton);
132 m_specifiedRegionMethodButton =
new QRadioButton(tr(
"Specify region"));
133 m_buttonGroup->addButton(m_specifiedRegionMethodButton);
134 m_routeDownloadMethodButton =
new QRadioButton(tr(
"Download Route"));
135 m_buttonGroup->addButton(m_routeDownloadMethodButton);
136 m_routeDownloadMethodButton->setToolTip(tr(
"Enabled when a route exists"));
137 m_routeDownloadMethodButton->setEnabled(hasRoute());
138 m_routeDownloadMethodButton->setChecked(hasRoute());
140 m_routeOffsetSpinBox->setEnabled(hasRoute());
141 m_routeOffsetSpinBox->setRange(minimumRouteOffset, maximumRouteOffset);
142 int defaultOffset = 500;
143 m_routeOffsetSpinBox->setValue(defaultOffset);
144 m_routeOffsetSpinBox->setSingleStep(100);
145 m_routeOffsetSpinBox->setSuffix(QStringLiteral(
" m"));
146 m_routeOffsetSpinBox->setDecimals(0);
149 m_routeOffsetLabel =
new QLabel(tr(
"Offset from route:"));
152 connect(m_buttonGroup, SIGNAL(buttonToggled(
QAbstractButton *,
bool)), m_dialog, SLOT(toggleSelectionMethod()));
153 connect(m_routingModel, SIGNAL(modelReset()), m_dialog, SLOT(updateRouteDialog()));
154 connect(m_routingModel, SIGNAL(rowsInserted(
QModelIndex,
int,
int)), m_dialog, SLOT(updateRouteDialog()));
155 connect(m_routingModel, SIGNAL(rowsRemoved(
QModelIndex,
int,
int)), m_dialog, SLOT(updateRouteDialog()));
158 routeOffsetLayout->
addWidget(m_routeOffsetLabel);
159 routeOffsetLayout->insertSpacing(0, 25);
160 routeOffsetLayout->addWidget(m_routeOffsetSpinBox);
163 routeLayout->
addWidget(m_routeDownloadMethodButton);
164 routeLayout->addLayout(routeOffsetLayout);
167 layout->
addWidget(m_visibleRegionMethodButton);
168 layout->addLayout(routeLayout);
169 layout->addWidget(m_specifiedRegionMethodButton);
170 layout->addWidget(m_latLonBoxWidget);
172 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
173 m_specifiedRegionMethodButton->setVisible(!smallScreen);
174 m_latLonBoxWidget->setVisible(!smallScreen);
177 auto const selectionMethodWidget =
new QWidget;
178 selectionMethodWidget->
setLayout(layout);
179 return selectionMethodWidget;
181 auto const selectionMethodBox =
new QGroupBox(tr(
"Selection Method"));
182 selectionMethodBox->setLayout(layout);
183 return selectionMethodBox;
187QLayout *DownloadRegionDialog::Private::createTilesCounter()
189 auto const description =
new QLabel(tr(
"Number of tiles to download:"));
190 m_tilesCountLabel =
new QLabel;
191 m_tileSizeInfo =
new QLabel;
194 tilesCountLayout->
addWidget(description);
195 tilesCountLayout->addWidget(m_tilesCountLabel);
199 layout->addWidget(m_tileSizeInfo);
203QWidget *DownloadRegionDialog::Private::createOkCancelButtonBox()
208 if (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) {
209 buttonBox->removeButton(m_applyButton);
210 m_applyButton->setVisible(
false);
213 connect(buttonBox, SIGNAL(accepted()), m_dialog, SLOT(accept()));
214 connect(buttonBox, SIGNAL(rejected()), m_dialog, SLOT(reject()));
215 connect(m_applyButton, SIGNAL(clicked()), m_dialog, SIGNAL(applied()));
219bool DownloadRegionDialog::Private::hasRoute()
const
221 return !m_routingModel->route().path().isEmpty();
224bool DownloadRegionDialog::Private::hasTextureLayers()
const
226 return m_model->mapTheme()->map()->hasTextureLayers();
229bool DownloadRegionDialog::Private::hasVectorLayers()
const
231 return m_model->mapTheme()->map()->hasVectorLayers();
234DownloadRegionDialog::DownloadRegionDialog(MarbleWidget *
const widget,
QWidget *
const parent,
Qt::WindowFlags const f)
236 , d(new Private(widget, this))
238 setWindowTitle(tr(
"Download Region"));
240 d->m_layerLabel =
new QLabel(tr(
"Tile type to be downloaded:"));
242 d->m_layerComboBox->addItem(tr(
"Texture tiles"));
243 d->m_layerComboBox->addItem(tr(
"Vector tiles"));
244 d->m_layerComboBox->setToolTip(tr(
"Allows selection between layer types that are visibly being rendered."));
247 layout->addWidget(d->m_layerLabel);
248 layout->addWidget(d->m_layerComboBox);
249 layout->addWidget(d->createSelectionMethodBox());
250 layout->addWidget(d->m_tileLevelRangeWidget);
251 layout->addStretch();
252 layout->addLayout(d->createTilesCounter());
254 if (MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen) {
255 auto widget =
new QWidget(
this);
256 widget->setLayout(layout);
259 scrollArea->setWidget(widget);
262 mainLayout->addWidget(d->createOkCancelButtonBox());
263 setLayout(mainLayout);
265 layout->addWidget(d->createOkCancelButtonBox());
270 connect(d->m_latLonBoxWidget, &Marble::LatLonBoxWidget::valueChanged,
this, &DownloadRegionDialog::updateTileCount);
271 connect(d->m_tileLevelRangeWidget, &TileLevelRangeWidget::topLevelChanged,
this, &DownloadRegionDialog::updateTileCount);
272 connect(d->m_tileLevelRangeWidget, &TileLevelRangeWidget::bottomLevelChanged,
this, &DownloadRegionDialog::updateTileCount);
275 connect(d->m_model, &MarbleModel::themeChanged,
this, &DownloadRegionDialog::delayUpdateTileLayer);
278DownloadRegionDialog::~DownloadRegionDialog()
283void DownloadRegionDialog::setAllowedTileLevelRange(
int const minimumTileLevel,
int const maximumTileLevel)
285 d->m_tileLevelRangeWidget->setAllowedLevelRange(minimumTileLevel, maximumTileLevel);
288void DownloadRegionDialog::setVisibleTileLevel(
int const tileLevel)
290 d->m_visibleTileLevel = tileLevel;
291 d->m_tileLevelRangeWidget->setDefaultLevel(tileLevel);
292 d->m_downloadRegion.setVisibleTileLevel(tileLevel);
295void DownloadRegionDialog::setSelectionMethod(SelectionMethod
const selectionMethod)
297 d->m_selectionMethod = selectionMethod;
298 switch (selectionMethod) {
299 case VisibleRegionMethod:
300 d->m_visibleRegionMethodButton->setChecked(
true);
301 d->m_routeOffsetLabel->setEnabled(
false);
302 d->m_routeOffsetSpinBox->setEnabled(
false);
303 d->m_latLonBoxWidget->setEnabled(
false);
304 setSpecifiedLatLonAltBox(d->m_visibleRegion);
306 case SpecifiedRegionMethod:
307 d->m_specifiedRegionMethodButton->setChecked(
true);
308 d->m_routeOffsetLabel->setEnabled(
false);
309 d->m_routeOffsetSpinBox->setEnabled(
false);
310 d->m_latLonBoxWidget->setEnabled(
true);
312 case RouteDownloadMethod:
313 d->m_routeDownloadMethodButton->setChecked(
true);
314 d->m_routeOffsetLabel->setEnabled(
true);
315 d->m_routeOffsetSpinBox->setEnabled(
true);
316 d->m_latLonBoxWidget->setEnabled(
false);
324 if (!d->hasTextureLayers() && !d->hasVectorLayers()) {
328 d->m_visibleTileLevel = (tileType() ==
TextureTileType && d->m_textureLayer->tileZoomLevel() != -1) ? d->m_textureLayer->tileZoomLevel()
329 : d->m_vectorTileLayer->tileZoomLevel();
331 const TileLayer *tileLayer = (tileType() ==
TextureTileType && d->m_textureLayer->layerCount() > 0) ?
dynamic_cast<const TileLayer *
>(d->m_textureLayer)
332 :
dynamic_cast<const TileLayer *
>(d->m_vectorTileLayer);
334 d->m_downloadRegion.setTileLevelRange(d->m_tileLevelRangeWidget->topLevel(), d->m_tileLevelRangeWidget->bottomLevel());
335 d->m_downloadRegion.setVisibleTileLevel(d->m_visibleTileLevel);
338 GeoDataLatLonAltBox downloadRegion;
339 switch (d->m_selectionMethod) {
340 case VisibleRegionMethod:
341 downloadRegion = d->m_visibleRegion;
343 case SpecifiedRegionMethod:
344 downloadRegion = GeoDataLatLonAltBox(d->m_latLonBoxWidget->latLonBox(), 0, 0);
346 case RouteDownloadMethod:
347 qreal offset = d->m_routeOffsetSpinBox->value();
351 const GeoDataLineString waypoints = d->m_model->routingManager()->routingModel()->route().path();
352 return d->m_downloadRegion.fromPath(tileLayer, offset, waypoints);
356 if (tileLayer->tileProjection()->type() == GeoSceneAbstractTileProjection::Mercator) {
357 downloadRegion.setNorth(qMin(downloadRegion.north(), +1.4835));
358 downloadRegion.setSouth(qMax(downloadRegion.south(), -1.4835));
361 return d->m_downloadRegion.region(tileLayer, downloadRegion);
364TileType DownloadRegionDialog::tileType()
const
369void DownloadRegionDialog::setSpecifiedLatLonAltBox(GeoDataLatLonAltBox
const ®ion)
371 d->m_latLonBoxWidget->setLatLonBox(region);
374void DownloadRegionDialog::setVisibleLatLonAltBox(GeoDataLatLonAltBox
const ®ion)
376 d->m_visibleRegion = region;
380 if (d->m_selectionMethod == VisibleRegionMethod) {
381 setSpecifiedLatLonAltBox(region);
386void DownloadRegionDialog::updateTileLayer()
392void DownloadRegionDialog::delayUpdateTileLayer()
397void DownloadRegionDialog::hideEvent(
QHideEvent *event)
399 disconnect(d->m_widget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
this, SLOT(setVisibleLatLonAltBox(GeoDataLatLonAltBox)));
400 disconnect(d->m_widget, SIGNAL(themeChanged(
QString)),
this, SLOT(delayUpdateTileLayer()));
401 disconnect(d->m_widget, SIGNAL(propertyValueChanged(
QString,
bool)),
this, SLOT(delayUpdateTileLayer()));
407void DownloadRegionDialog::showEvent(
QShowEvent *event)
409 connect(d->m_widget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
this, SLOT(setVisibleLatLonAltBox(GeoDataLatLonAltBox)));
410 connect(d->m_widget, SIGNAL(themeChanged(
QString)),
this, SLOT(delayUpdateTileLayer()));
411 connect(d->m_widget, SIGNAL(propertyValueChanged(
QString,
bool)),
this, SLOT(delayUpdateTileLayer()));
413 setVisibleTileLevel(d->m_widget->tileZoomLevel());
421void DownloadRegionDialog::toggleSelectionMethod()
423 if (d->m_specifiedRegionMethodButton->isChecked()) {
424 setSelectionMethod(SpecifiedRegionMethod);
425 }
else if (d->m_routeDownloadMethodButton->isChecked()) {
426 setSelectionMethod(RouteDownloadMethod);
427 }
else if (d->m_specifiedRegionMethodButton->isChecked()) {
428 setSelectionMethod(SpecifiedRegionMethod);
432void DownloadRegionDialog::updateTileType()
434 bool hasVisibleTextureLayers = d->hasTextureLayers() && d->m_textureLayer->layerCount() > 0;
435 bool hasVisibleVectorLayers = d->hasVectorLayers() && d->m_vectorTileLayer->layerCount() > 0;
437 auto model = qobject_cast<QStandardItemModel *>(d->m_layerComboBox->model());
438 Q_ASSERT(model !=
nullptr);
440 item = model->item(0);
442 item = model->item(1);
445 bool allTileTypesAvailable = hasVisibleTextureLayers && hasVisibleVectorLayers;
447 d->m_layerComboBox->setEnabled(allTileTypesAvailable);
448 if (hasVisibleVectorLayers) {
449 d->m_layerComboBox->setCurrentIndex(1);
450 }
else if (hasVisibleTextureLayers && !hasVisibleVectorLayers) {
451 d->m_layerComboBox->setCurrentIndex(0);
455void DownloadRegionDialog::updateTileCount()
461 qint64 tilesCount = 0;
462 QString themeId(d->m_model->mapThemeId());
465 if (pyramid.
size() == 1) {
466 tilesCount = pyramid[0].tilesCount();
468 for (
int level = pyramid[0].bottomLevel();
level >= pyramid[0].topLevel(); --
level) {
470 for (
int i = 0; i < pyramid.
size(); ++i) {
471 QRect const coords = pyramid[i].coords(level);
474 for (
int x = x1; x <= x2; ++x) {
475 for (
int y = y1; y <= y2; ++y) {
476 TileId
const tileId(0, level, x, y);
481 tilesCount += tileIdSet.
count();
485 qreal tileDownloadSize = 0;
487 if (tilesCount > maxTilesCount) {
488 d->m_tileSizeInfo->setToolTip(
QString());
491 d->m_tileSizeInfo->setText(tr(
"There is a limit of %n tile(s) to download.",
"", maxTilesCount));
495 tileDownloadSize = tileType() ==
TextureTileType ? tilesCount * averageTextureTileSize : tilesCount * averageVectorTileSize;
497 d->m_tileSizeInfo->setToolTip(tr(
"Approximate size of the tiles to be downloaded"));
499 if (tileDownloadSize > 1024) {
500 tileDownloadSize = tileDownloadSize / 1024;
501 d->m_tileSizeInfo->setText(tr(
"Estimated download size: %1 MB").arg(ceil(tileDownloadSize)));
503 d->m_tileSizeInfo->setText(tr(
"Estimated download size: %1 kB").arg(tileDownloadSize));
506 d->m_tileSizeInfo->setToolTip(
QString());
507 d->m_tileSizeInfo->clear();
512 bool const tilesCountWithinLimits = tilesCount > 0 && tilesCount <= maxTilesCount;
513 d->m_okButton->setEnabled(tilesCountWithinLimits);
514 d->m_applyButton->setEnabled(tilesCountWithinLimits);
517void DownloadRegionDialog::updateRouteDialog()
519 d->m_routeDownloadMethodButton->setEnabled(d->hasRoute());
520 d->m_routeDownloadMethodButton->setChecked(d->hasRoute());
521 if (!d->hasRoute()) {
522 setSelectionMethod(VisibleRegionMethod);
526void DownloadRegionDialog::setOffsetUnit()
528 qreal offset = d->m_routeOffsetSpinBox->value();
530 if (offset >= 1100) {
531 d->m_routeOffsetSpinBox->setSuffix(QStringLiteral(
" km"));
532 d->m_routeOffsetSpinBox->setRange(minimumRouteOffset * METER2KM, maximumRouteOffset * METER2KM);
533 d->m_routeOffsetSpinBox->setDecimals(1);
534 d->m_routeOffsetSpinBox->setValue(offset * METER2KM);
535 d->m_routeOffsetSpinBox->setSingleStep(0.1);
536 }
else if (offset <= 1 && d->m_routeOffsetSpinBox->suffix() ==
QLatin1StringView(
" km")) {
537 d->m_routeOffsetSpinBox->setSuffix(QStringLiteral(
" m"));
538 d->m_routeOffsetSpinBox->setRange(minimumRouteOffset, maximumRouteOffset);
539 d->m_routeOffsetSpinBox->setDecimals(0);
540 d->m_routeOffsetSpinBox->setValue(offset * KM2METER);
541 d->m_routeOffsetSpinBox->setSingleStep(100);
547#include "moc_DownloadRegionDialog.cpp"
This file contains the headers for MarbleModel.
QStringView level(QStringView ifopt)
Binds a QML item to a specific geodetic location in screen coordinates.
@ TextureTileType
Tiles that consist of bitmap data.
@ VectorTileType
Tiles that consist of vector data.
void addLayout(QLayout *layout, int stretch)
void currentIndexChanged(int index)
void valueChanged(double d)
bool isEmpty() const const
qsizetype size() const const
void getCoords(int *x1, int *y1, int *x2, int *y2) const const
qsizetype count() const const
iterator insert(const T &value)
Qt::ItemFlags flags() const const
void setFlags(Qt::ItemFlags flags)
QString number(double n, char format, int precision)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)