[Marble-devel] RFC: Download Region, first try

Jens-Michael Hoffmann jensmh at gmx.de
Tue Jan 12 03:31:43 CET 2010


Hi,

please see below for a draft implementation for the download region feature.
It is not indended for committing but for discussing.
This patch applies to current svn, key points as follows:

working:
- download current region with range of tile levels
- download policy restrictions regarding concurrent connections
    
missing/not working:
- download specified (by lat/lon box) region
- restriction of total number of tiles (like <100k per download region request)
- perhaps display some kind of bar which indicates how many tiles are going
  to be downloaded

some other issue:
- new code in MarbleModel is not very nice and also undocumented
- TileId becomes visible and has to be exported, should be avoided
  (possibly by moving the corresponding method to MarbleModelPrivate)
- UI needs work
- perhaps only allow download of current region? makes UI simpler and
  covers the (imho) most important use case.

Any feedback appreciated.


Best Regards,
Jens-Michael




diff --git a/marble/src/lib/CMakeLists.txt b/marble/src/lib/CMakeLists.txt
index a36d287..a60efd7 100644
--- a/marble/src/lib/CMakeLists.txt
+++ b/marble/src/lib/CMakeLists.txt
@@ -75,7 +75,10 @@ set(marblewidget_SRCS
     MarbleDataFacade.cpp
     MarbleDebug.cpp
 
+    DownloadRegionDialog.cpp
+    LatLonBoxWidget.cpp
     QtMarbleConfigDialog.cpp
+    TileLevelRangeWidget.cpp
     ClipPainter.cpp
     DownloadPolicy.cpp
     DownloadQueueSet.cpp
@@ -198,6 +201,8 @@ set (marblewidget_UI
     MarbleAboutDialog.ui
     SunControlWidget.ui
     LatLonEdit.ui
+    LatLonBoxWidget.ui
+    TileLevelRangeWidget.ui
 )
 
 # FIXME: cleaner approach of src/lib/MarbleControlBox.* vs. marble.qrc
diff --git a/marble/src/lib/DownloadRegionDialog.cpp b/marble/src/lib/DownloadRegionDialog.cpp
new file mode 100644
index 0000000..55a8f22
--- /dev/null
+++ b/marble/src/lib/DownloadRegionDialog.cpp
@@ -0,0 +1,91 @@
+// Copyright 2009, 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "DownloadRegionDialog.h"
+
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QPushButton>
+
+#include "TileLevelRangeWidget.h"
+
+namespace Marble
+{
+
+class DownloadRegionDialog::Private
+{
+public:
+    explicit Private( QWidget * parent = 0 );
+
+    TileLevelRangeWidget *m_tileLevelRangeWidget;
+    int m_originatingTileLevel;
+    int m_minimumAllowedTileLevel;
+    int m_maximumAllowedTileLevel;
+};
+
+DownloadRegionDialog::Private::Private( QWidget * parent )
+    : m_tileLevelRangeWidget( new TileLevelRangeWidget( parent )),
+      m_originatingTileLevel( -1 ),
+      m_minimumAllowedTileLevel( -1 ),
+      m_maximumAllowedTileLevel( -1 )
+{
+}
+
+DownloadRegionDialog::DownloadRegionDialog( QWidget * parent, Qt::WindowFlags f )
+    : QDialog( parent, f ),
+      d( new Private )
+{
+    QHBoxLayout *buttonBox = new QHBoxLayout;
+    QPushButton *okButton = new QPushButton( "Ok" );
+    connect( okButton, SIGNAL( clicked () ), this, SLOT( accept() ));
+    QPushButton *cancelButton = new QPushButton( "Cancel" );
+    connect( cancelButton, SIGNAL( clicked () ), this, SLOT( reject() ));
+    buttonBox->addWidget( okButton );
+    buttonBox->addWidget( cancelButton );
+
+    QVBoxLayout *layout = new QVBoxLayout;
+    layout->addWidget( d->m_tileLevelRangeWidget );
+    layout->addLayout( buttonBox );
+
+    setLayout( layout );
+}
+
+void DownloadRegionDialog::setOriginatingTileLevel( const int tileLevel )
+{
+    d->m_originatingTileLevel = tileLevel;
+    d->m_tileLevelRangeWidget->setDefaultTileLevel( tileLevel );
+}
+
+void DownloadRegionDialog::setAllowedTileLevelRange( const int minimumTileLevel,
+                                                     const int maximumTileLevel )
+{
+    d->m_minimumAllowedTileLevel = minimumTileLevel;
+    d->m_maximumAllowedTileLevel = maximumTileLevel;
+    d->m_tileLevelRangeWidget->setAllowedTileLevelRange( minimumTileLevel, maximumTileLevel );
+}
+
+int DownloadRegionDialog::fromTileLevel() const
+{
+    return d->m_tileLevelRangeWidget->fromTileLevel();
+}
+
+int DownloadRegionDialog::toTileLevel() const
+{
+    return d->m_tileLevelRangeWidget->toTileLevel();
+}
+
+}
+
+#include "DownloadRegionDialog.moc"
diff --git a/marble/src/lib/DownloadRegionDialog.h b/marble/src/lib/DownloadRegionDialog.h
new file mode 100644
index 0000000..db50876
--- /dev/null
+++ b/marble/src/lib/DownloadRegionDialog.h
@@ -0,0 +1,49 @@
+// Copyright 2009, 2010  Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MARBLE_DOWNLOAD_REGION_DIALOG_H
+#define MARBLE_DOWNLOAD_REGION_DIALOG_H
+
+#include <QtGui/QDialog>
+
+#include "marble_export.h"
+
+namespace Marble
+{
+
+class TileLevelRangeWidget;
+
+class MARBLE_EXPORT DownloadRegionDialog: public QDialog
+{
+    Q_OBJECT
+
+ public:
+    explicit DownloadRegionDialog( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+
+    void setOriginatingTileLevel( const int tileLevel );
+    void setAllowedTileLevelRange( const int minimumTileLevel,
+                                   const int maximumTileLevel );
+
+    int fromTileLevel() const;
+    int toTileLevel() const;
+
+ private:
+    class Private;
+    Private * const d;
+};
+
+}
+
+#endif
diff --git a/marble/src/lib/LatLonBoxWidget.cpp b/marble/src/lib/LatLonBoxWidget.cpp
new file mode 100644
index 0000000..4a35fdf
--- /dev/null
+++ b/marble/src/lib/LatLonBoxWidget.cpp
@@ -0,0 +1,29 @@
+// Copyright 2009, 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "LatLonBoxWidget.h"
+
+namespace Marble
+{
+
+LatLonBoxWidget::LatLonBoxWidget( QWidget * parent, Qt::WindowFlags f )
+    : QWidget( parent, f )
+{
+    m_ui.setupUi( this );
+}
+
+}
+
+#include "LatLonBoxWidget.moc"
diff --git a/marble/src/lib/LatLonBoxWidget.h b/marble/src/lib/LatLonBoxWidget.h
new file mode 100644
index 0000000..e8f1f65
--- /dev/null
+++ b/marble/src/lib/LatLonBoxWidget.h
@@ -0,0 +1,40 @@
+// Copyright 2009, 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MARBLE_LAT_LON_BOX_WIDGET_H
+#define MARBLE_LAT_LON_BOX_WIDGET_H
+
+#include <QtGui/QWidget>
+
+#include "ui_LatLonBoxWidget.h"
+#include "marble_export.h"
+
+namespace Marble
+{
+
+class MARBLE_EXPORT LatLonBoxWidget: public QWidget
+{
+    Q_OBJECT
+
+ public:
+    explicit LatLonBoxWidget( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+
+ private:
+    Ui::LatLonBoxWidget m_ui;
+};
+
+}
+
+#endif
diff --git a/marble/src/lib/LatLonBoxWidget.ui b/marble/src/lib/LatLonBoxWidget.ui
new file mode 100644
index 0000000..1f889c7
--- /dev/null
+++ b/marble/src/lib/LatLonBoxWidget.ui
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Marble::LatLonBoxWidget</class>
+ <widget class="QWidget" name="latLonBoxWidget">
+  <property name="enabled">
+   <bool>true</bool>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>312</width>
+    <height>100</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Select a geographic region</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <spacer name="horizontalSpacer_5">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>13</width>
+       <height>13</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="0" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QDoubleSpinBox" name="northSpinBox">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="toolTip">
+        <string>Northern Latitude</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-90.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>90.000000000000000</double>
+       </property>
+       <property name="value">
+        <double>90.000000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="northLabel">
+       <property name="text">
+        <string>&amp;N</string>
+       </property>
+       <property name="buddy">
+        <cstring>northSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="0" column="2">
+    <spacer name="horizontalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>13</width>
+       <height>13</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="1" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QDoubleSpinBox" name="westSpinBox">
+       <property name="toolTip">
+        <string>Western Longitude</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-180.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>180.000000000000000</double>
+       </property>
+       <property name="value">
+        <double>-180.000000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="westLabel">
+       <property name="text">
+        <string>&amp;W</string>
+       </property>
+       <property name="buddy">
+        <cstring>westSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="1">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>13</width>
+       <height>13</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="1" column="2">
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QDoubleSpinBox" name="eastSpinBox">
+       <property name="toolTip">
+        <string>Eastern Longitude</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-180.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>180.000000000000000</double>
+       </property>
+       <property name="value">
+        <double>180.000000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="eastLabel">
+       <property name="text">
+        <string>&amp;E</string>
+       </property>
+       <property name="buddy">
+        <cstring>eastSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="2" column="0">
+    <spacer name="horizontalSpacer_4">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>13</width>
+       <height>13</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="2" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QDoubleSpinBox" name="southSpinBox">
+       <property name="toolTip">
+        <string>Southern Latitude</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-90.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>90.000000000000000</double>
+       </property>
+       <property name="value">
+        <double>-90.000000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="southLabel">
+       <property name="text">
+        <string>&amp;S</string>
+       </property>
+       <property name="buddy">
+        <cstring>southSpinBox</cstring>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="2" column="2">
+    <spacer name="horizontalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>13</width>
+       <height>13</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>northSpinBox</tabstop>
+  <tabstop>westSpinBox</tabstop>
+  <tabstop>eastSpinBox</tabstop>
+  <tabstop>southSpinBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/marble/src/lib/MarbleModel.cpp b/marble/src/lib/MarbleModel.cpp
index 065865a..342f145 100644
--- a/marble/src/lib/MarbleModel.cpp
+++ b/marble/src/lib/MarbleModel.cpp
@@ -16,6 +16,7 @@
 #include <cmath>
 
 #include <QtCore/QAtomicInt>
+#include <QtCore/QMap>
 #include <QtCore/QPointer>
 #include <QtCore/QTime>
 #include <QtCore/QTimer>
@@ -917,6 +918,128 @@ void MarbleModel::reloadMap() const
     }
 }
 
+QRect MarbleModel::tileRect( const QList<TileId> & tileIds ) const
+{
+    if ( tileIds.isEmpty() )
+        return QRect();
+
+    int minimumTileX = tileIds.first().x();
+    int minimumTileY = tileIds.first().y();
+    int maximumTileX = tileIds.first().x();
+    int maximumTileY = tileIds.first().y();
+    const int currentTileLevel = tileZoomLevel();
+
+    QList<TileId>::const_iterator pos = tileIds.constBegin();
+    QList<TileId>::const_iterator const end = tileIds.constEnd();
+    for (; pos != end; ++pos ) {
+        TileId const & id = *pos;
+        Q_ASSERT( id.zoomLevel() == currentTileLevel );
+
+        if ( id.x() < minimumTileX )
+            minimumTileX = id.x();
+        else if ( id.x() > maximumTileX )
+            maximumTileX = id.x();
+
+        if ( id.y() < minimumTileY )
+            minimumTileY = id.y();
+        else if ( id.y() > maximumTileY )
+            maximumTileY = id.y();
+    }
+    return QRect( minimumTileX, minimumTileY, maximumTileX - minimumTileX + 1,
+                  maximumTileY - minimumTileY + 1 );
+}
+
+void MarbleModel::downloadCurrentRegion( const int fromTileLevel, const int toTileLevel ) const
+{
+    Q_ASSERT( fromTileLevel <= toTileLevel );
+    mDebug() << "MarbleModel::downloadCurrentRegion"
+             << "from" << fromTileLevel << "to" << toTileLevel;
+
+    // 1) first current tile level,
+    // 2) then lower tile levels (as it is likely only very few tiles),
+    // 3) finally higher tile levels as this will take most time
+    if ( !d->m_mapTheme->map()->hasTextureLayers() )
+        return;
+
+    const QString themeId = d->m_mapTheme->head()->theme();
+    GeoSceneLayer * const layer = static_cast<GeoSceneLayer*>( d->m_mapTheme->map()->
+                                                               layer( themeId ));
+    Q_ASSERT( layer );
+    GeoSceneTexture * const texture = static_cast<GeoSceneTexture*>( layer->groundDataset() );
+    Q_ASSERT( texture );
+
+
+    const int currentTileLevel = tileZoomLevel();
+
+    Q_ASSERT( d->m_tileLoader );
+    QList<TileId> displayed = d->m_tileLoader->tilesOnDisplay();
+    //mDebug() << "tilesOnDisplay" << displayed;
+
+    QRect currentTileRect = tileRect( displayed );
+    mDebug() << "currentTileRect" << currentTileRect;
+
+    // we have now the tile coordinates reactangle for the current (in view)
+    // tile level, now we need to transform it for levels
+    // fromTileLevel..toTileLevel
+    QRect fromTileRect;
+    if ( fromTileLevel != currentTileLevel ) {
+        int x1, y1, x2, y2;
+        currentTileRect.getCoords( &x1, &y1, &x2, &y2 );
+        if ( fromTileLevel < currentTileLevel ) {
+            const int levelDiff = currentTileLevel - fromTileLevel;
+            fromTileRect.setCoords( x1 >> levelDiff, y1 >> levelDiff,
+                                    x2 >> levelDiff, y2 >> levelDiff );
+        }
+        else {
+            const int levelDiff = fromTileLevel - currentTileLevel;
+            fromTileRect.setCoords( x1 << levelDiff, y1 << levelDiff,
+                                    (( x2 + 1 ) << levelDiff ) - 1,
+                                    (( y2 + 1 ) << levelDiff ) - 1 );
+        }
+    }
+    else {
+        fromTileRect = currentTileRect;
+    }
+
+    // put all the tile rects (one per level) into a map
+    QMap<int, QRect> tileRectsToBeDownloaded;
+    int x1, x2, y1, y2;
+    fromTileRect.getCoords( &x1, &y1, &x2, &y2 );
+
+    for ( int level = fromTileLevel; level <= toTileLevel; ++level ) {
+        QRect rect;
+        rect.setCoords( x1, y1, x2, y2 );
+        tileRectsToBeDownloaded[ level ] = rect;
+        qDebug() << "rect level/x1/y1/x2/y2=" << level << x1 << y1 << x2 << y2
+                 << " => #tiles=" << (x2-x1+1)*(y2-y1+1);
+        x1 <<= 1;
+        y1 <<= 1;
+        x2 = ( x2 << 1 ) + 1;
+        y2 = ( y2 << 1 ) + 1;
+    }
+
+    // create download jobs for all the levels
+    QMap<int, QRect>::const_iterator pos = tileRectsToBeDownloaded.constBegin();
+    QMap<int, QRect>::const_iterator const end = tileRectsToBeDownloaded.constEnd();
+    for (; pos != end; ++pos ) {
+        const int level = pos.key();
+        const QRect rect = pos.value();
+        int x1, x2, y1, y2;
+        rect.getCoords( &x1, &y1, &x2, &y2 );
+
+        for ( int x = x1; x <= x2; ++x ) {
+            for ( int y = y1; y <= y2; ++y ) {
+                const TileId id( level, x, y );
+                QUrl sourceUrl = TileLoaderHelper::downloadUrl( texture, level, x, y );
+                QString destFileName = TileLoaderHelper::relativeTileFileName( texture,
+                                                                               level, x, y );
+                emit downloadTile( sourceUrl, destFileName, TileId( level, x, y ).toString(),
+                                   DownloadBulk );
+            }
+        }
+    }
+}
+
 void MarbleModel::addDownloadPolicies( GeoSceneDocument *mapTheme )
 {
     if ( !mapTheme )
diff --git a/marble/src/lib/MarbleModel.h b/marble/src/lib/MarbleModel.h
index b1e9629..661fa1e 100644
--- a/marble/src/lib/MarbleModel.h
+++ b/marble/src/lib/MarbleModel.h
@@ -35,6 +35,7 @@
 #include <QtCore/QVector>
 #include <QtGui/QRegion>
 
+#include "TileId.h"
 #include "global.h"
 
 class QItemSelectionModel;
@@ -302,6 +303,10 @@ class MARBLE_EXPORT MarbleModel : public QObject
 
     void reloadMap() const;
 
+    QRect tileRect( const QList<TileId> & tileIds ) const;
+    void downloadCurrentRegion( const int fromTileLevel, const int toTileLevel ) const;
+    void reloadTiles( GeoSceneTexture * const texture, const QVector<TileId>& tileIds ) const;
+
  public Q_SLOTS:
     void clearVolatileTileCache();
     /**
diff --git a/marble/src/lib/TileLevelRangeWidget.cpp b/marble/src/lib/TileLevelRangeWidget.cpp
new file mode 100644
index 0000000..5735795
--- /dev/null
+++ b/marble/src/lib/TileLevelRangeWidget.cpp
@@ -0,0 +1,72 @@
+// Copyright 2009, 2010  Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "TileLevelRangeWidget.h"
+
+#include "ui_TileLevelRangeWidget.h"
+
+namespace Marble
+{
+
+class TileLevelRangeWidget::Private
+{
+public:
+    explicit Private( QWidget * parent = 0 );
+
+    Ui::TileLevelRangeWidget m_ui;
+};
+
+TileLevelRangeWidget::Private::Private( QWidget * parent )
+{
+    m_ui.setupUi( parent );
+}
+
+TileLevelRangeWidget::TileLevelRangeWidget( QWidget * parent, Qt::WindowFlags f )
+    : QWidget( parent, f ),
+      d( new Private( this ))
+{
+}
+
+TileLevelRangeWidget::~TileLevelRangeWidget()
+{
+    delete d;
+}
+
+void TileLevelRangeWidget::setAllowedTileLevelRange( const int minimumTileLevel,
+                                                     const int maximumTileLevel )
+{
+    d->m_ui.minSpinBox->setRange( minimumTileLevel, maximumTileLevel );
+    d->m_ui.maxSpinBox->setRange( minimumTileLevel, maximumTileLevel );
+}
+
+void TileLevelRangeWidget::setDefaultTileLevel( const int tileLevel )
+{
+    d->m_ui.minSpinBox->setValue( tileLevel );
+    d->m_ui.maxSpinBox->setValue( tileLevel );
+}
+
+int TileLevelRangeWidget::fromTileLevel() const
+{
+    return d->m_ui.minSpinBox->value();
+}
+
+int TileLevelRangeWidget::toTileLevel() const
+{
+    return d->m_ui.maxSpinBox->value();
+}
+
+}
+
+#include "TileLevelRangeWidget.moc"
diff --git a/marble/src/lib/TileLevelRangeWidget.h b/marble/src/lib/TileLevelRangeWidget.h
new file mode 100644
index 0000000..604075c
--- /dev/null
+++ b/marble/src/lib/TileLevelRangeWidget.h
@@ -0,0 +1,48 @@
+// Copyright 2009, 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MARBLE_TILE_LEVEL_RANGE_WIDGET_H
+#define MARBLE_TILE_LEVEL_RANGE_WIDGET_H
+
+#include <QtGui/QWidget>
+
+#include "marble_export.h"
+
+namespace Marble
+{
+
+class MARBLE_EXPORT TileLevelRangeWidget: public QWidget
+{
+    Q_OBJECT
+
+ public:
+    explicit TileLevelRangeWidget( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+    ~TileLevelRangeWidget();
+
+    void setAllowedTileLevelRange( const int minimumTileLevel,
+                                   const int maximumTileLevel );
+    void setDefaultTileLevel( const int );
+
+    int fromTileLevel() const;
+    int toTileLevel() const;
+
+ private:
+    class Private;
+    Private * const d;
+};
+
+}
+
+#endif
diff --git a/marble/src/lib/TileLevelRangeWidget.ui b/marble/src/lib/TileLevelRangeWidget.ui
new file mode 100644
index 0000000..ca0a72c
--- /dev/null
+++ b/marble/src/lib/TileLevelRangeWidget.ui
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Marble::TileLevelRangeWidget</class>
+ <widget class="QWidget" name="tileLevelRangeWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>458</width>
+    <height>335</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Select Download Region</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <widget class="QLabel" name="descriptionLabel">
+     <property name="text">
+      <string>Here you can download regional map data for future offline usage.</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <property name="margin">
+      <number>7</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Selected Region</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_4">
+      <item>
+       <widget class="QRadioButton" name="currentRadioButton">
+        <property name="text">
+         <string>&amp;Current Map View</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QRadioButton" name="specifiedRadioButton">
+        <property name="text">
+         <string>&amp;Specified Area</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <item>
+         <spacer name="horizontalSpacer_6">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Fixed</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="Marble::LatLonBoxWidget" name="latLonBoxWidget" native="true">
+          <property name="minimumSize">
+           <size>
+            <width>100</width>
+            <height>50</height>
+           </size>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_7">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Zoom</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <item>
+         <widget class="QLabel" name="tileLevelLabel">
+          <property name="text">
+           <string>&amp;Tile Level Range:</string>
+          </property>
+          <property name="buddy">
+           <cstring>minSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="minSpinBox">
+          <property name="toolTip">
+           <string>Minimum Tile Level</string>
+          </property>
+          <property name="minimum">
+           <number>0</number>
+          </property>
+          <property name="maximum">
+           <number>20</number>
+          </property>
+          <property name="value">
+           <number>0</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="toLabel">
+          <property name="text">
+           <string>to</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="maxSpinBox">
+          <property name="toolTip">
+           <string>Maximum Tile Level</string>
+          </property>
+          <property name="minimum">
+           <number>0</number>
+          </property>
+          <property name="maximum">
+           <number>20</number>
+          </property>
+          <property name="value">
+           <number>4</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_8">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>68</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Marble::LatLonBoxWidget</class>
+   <extends>QWidget</extends>
+   <header>LatLonBoxWidget.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>specifiedRadioButton</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>marbleLatLonWidget</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>101</x>
+     <y>106</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>117</x>
+     <y>154</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/marble/src/marble_part.cpp b/marble/src/marble_part.cpp
index c93f621..ed32ad4 100644
--- a/marble/src/marble_part.cpp
+++ b/marble/src/marble_part.cpp
@@ -53,6 +53,7 @@
 #include <kdeprintdialog.h>
 
 // Marble library
+#include "DownloadRegionDialog.h"
 #include "GeoDataCoordinates.h"
 #include "lib/SunControlWidget.h"
 
@@ -592,6 +593,13 @@ void MarblePart::writeStatusBarSettings()
 
 void MarblePart::setupActions()
 {
+    // Action: Download Region
+    m_downloadRegionAction = new KAction( this );
+    m_downloadRegionAction->setText( i18nc( "Action for downloading an entire region of a map",
+                                            "Download Region..." ));
+    actionCollection()->addAction( "file_download_region", m_downloadRegionAction );
+    connect( m_downloadRegionAction, SIGNAL( triggered() ), SLOT( showDownloadRegionDialog() ));
+
     // Action: Print Map
     m_printMapAction = KStandardAction::print( this, SLOT( printMapScreenShot() ),
                                                actionCollection() );
@@ -1168,6 +1176,26 @@ void MarblePart::reload()
     m_controlView->marbleWidget()->map()->reload();
 }
 
+void MarblePart::showDownloadRegionDialog()
+{
+    QPointer<DownloadRegionDialog> dialog = new DownloadRegionDialog;
+    dialog->setOriginatingTileLevel( m_controlView->marbleWidget()->map()
+                                     ->model()->tileZoomLevel() );
+    // FIXME: get range
+    dialog->setAllowedTileLevelRange( 0, 18 );
+    if ( dialog->exec() == QDialog::Accepted ) {
+        bool downloadCurrentRegion = true; // FIXME
+        bool downloadSpecifiedRegion = false; // FIXME
+        if ( downloadCurrentRegion ) {
+            m_controlView->marbleWidget()->map()->model()
+                ->downloadCurrentRegion( dialog->fromTileLevel(), dialog->toTileLevel() );
+        }
+        else if ( downloadSpecifiedRegion ) {
+        }
+    }
+    delete dialog;
+}
+
 void MarblePart::showPluginAboutDialog( QString nameId )
 {
     QList<RenderPlugin *> renderItemList = m_controlView->marbleWidget()->renderPlugins();
diff --git a/marble/src/marble_part.h b/marble/src/marble_part.h
index 2b7f44c..7ff318c 100644
--- a/marble/src/marble_part.h
+++ b/marble/src/marble_part.h
@@ -125,6 +125,7 @@ class MarblePart: public KParts::ReadOnlyPart
 
     void  slotUpdateSettings();
     void reload();
+    void showDownloadRegionDialog();
 
     /**
      * Shows the about dialog for the plugin with the corresponding @p nameId.
@@ -180,6 +181,7 @@ class MarblePart: public KParts::ReadOnlyPart
     KAction      *m_fullScreenAct;
     KAction      *m_openAct;
     KAction      *m_newStuffAction;
+    KAction      *m_downloadRegionAction;
     KAction      *m_controlSunAction;
     KAction      *m_lockFloatItemsAct;
 
diff --git a/marble/src/marble_part.rc b/marble/src/marble_part.rc
index 584d371..e10b67c 100644
--- a/marble/src/marble_part.rc
+++ b/marble/src/marble_part.rc
@@ -6,6 +6,7 @@
     <text>&amp;File</text>
     <Action name="file_open"/>
     <Action name="new_stuff"/>
+    <Action name="file_download_region"/>
     <Action name="exportMap"/>
     <Separator/>
     <Action name="file_print"/>


More information about the Marble-devel mailing list