[Marble-commits] KDE/kdeedu/marble/src/lib

Jens-Michael Hoffmann jensmh at gmx.de
Sat Mar 27 21:05:20 CET 2010


SVN commit 1108097 by jmhoffmann:

Implement reloading of tiles properly, using the layered StackedTileLoader.

Until now update request did not go through StackedTileLoader which would
have caused only tiles of the first texture layer being reloaded in the future.

Apart from that, it feels more right this way.

 M  +1 -7      MarbleModel.cpp  
 M  +0 -3      MarbleModel.h  
 M  +5 -0      StackedTile.cpp  
 M  +2 -0      StackedTile.h  
 M  +69 -0     StackedTileLoader.cpp  
 M  +3 -0      StackedTileLoader.h  
 M  +58 -0     TileLoader.cpp  
 M  +3 -0      TileLoader.h  


--- trunk/KDE/kdeedu/marble/src/lib/MarbleModel.cpp #1108096:1108097
@@ -160,8 +160,6 @@
     QTime t;
     t.start();
     MarbleModelPrivate::refCounter.ref();
-    connect( this, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage )),
-             d->m_downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage )));
     d->m_dataFacade = new MarbleDataFacade( this );
 
     d->m_tileLoader = new StackedTileLoader( d->m_mapThemeManager, d->m_downloadManager, this );
@@ -914,11 +912,7 @@
     QList<TileId>::const_iterator pos = displayed.constBegin();
     QList<TileId>::const_iterator const end = displayed.constEnd();
     for (; pos != end; ++pos ) {
-        TileId const & id = *pos;
-        QUrl sourceUrl = TileLoaderHelper::downloadUrl( texture, id.zoomLevel(), id.x(), id.y() );
-        QString destFileName = TileLoaderHelper::relativeTileFileName( texture, id.zoomLevel(),
-                                                                       id.x(), id.y() );
-        emit downloadTile( sourceUrl, destFileName, id.toString(), DownloadBrowse );
+        d->m_tileLoader->reloadTile( *pos );
     }
 }
 
--- trunk/KDE/kdeedu/marble/src/lib/MarbleModel.h #1108096:1108097
@@ -366,9 +366,6 @@
      */
     void repaintNeeded( QRegion dirtyRegion = QRegion() );
 
-    void downloadTile( const QUrl& sourceUrl, const QString& destinationFileName,
-                       const QString& id, DownloadUsage ) const;
-    
     /**
      * @brief Signal that a render item has been initialized
      */
--- trunk/KDE/kdeedu/marble/src/lib/StackedTile.cpp #1108096:1108097
@@ -364,6 +364,11 @@
     return d->m_byteCount;
 }
 
+QVector<QSharedPointer<TextureTile> > * StackedTile::tiles()
+{
+    return &d->m_tiles;
+}
+
 QImage const * StackedTile::resultTile() const
 {
     return &d->m_resultTile;
--- trunk/KDE/kdeedu/marble/src/lib/StackedTile.h #1108096:1108097
@@ -18,6 +18,7 @@
 #define MARBLE_STACKED_TILE_H
 
 #include <QtCore/QSharedPointer>
+#include <QtCore/QVector>
 #include <QtGui/QColor>
 
 #include "AbstractTile.h"
@@ -49,6 +50,7 @@
     bool forMergedLayerDecorator() const;
     void setForMergedLayerDecorator();
 
+    QVector<QSharedPointer<TextureTile> > * tiles();
     QImage const * resultTile() const;
     QImage * resultTile();
 
--- trunk/KDE/kdeedu/marble/src/lib/StackedTileLoader.cpp #1108096:1108097
@@ -209,6 +209,57 @@
     return tile;
 }
 
+// The tile to be reloaded might be (alternatively):
+// 1) in the "hash" (m_tilesOnDisplay), which means it is currently displayed
+// 2) not in the hash, but in the "cache", which means it is not currently displayed
+// 3) neither in "hash" nor in "cache"
+StackedTile* StackedTileLoader::reloadTile( TileId const & stackedTileId )
+{
+    StackedTile * const displayedTile = d->m_tilesOnDisplay.value( stackedTileId, 0 );
+    if ( displayedTile ) {
+        reloadCachedTile( displayedTile );
+        return displayedTile;
+    }
+    StackedTile * const cachedTile = d->m_tileCache.object( stackedTileId );
+    if ( cachedTile ) {
+        // It would be more correct to update the cost for the cache also, but let's ignore it at
+        // least for now.
+        // Perhaps more relevant is, that as a consequence of leaving the tile in the cache
+        // reloadCachedTile must not alter the cache to prevent this tile from being deleted.
+        // So, all in all it might be better to take the tile out of the cache before calling
+        // reloadCachedTile and put it in again afterwards.
+        // FIXME: discuss/decide
+        reloadCachedTile( cachedTile );
+        return cachedTile;
+    }
+
+    StackedTile * const stackedTile = new StackedTile( stackedTileId );
+    d->m_tilesOnDisplay[ stackedTileId ] = stackedTile;
+
+    QVector<GeoSceneTexture const *> const textureLayers = findRelevantTextureLayers( stackedTileId );
+    QVector<GeoSceneTexture const *>::const_iterator pos = textureLayers.constBegin();
+    QVector<GeoSceneTexture const *>::const_iterator const end = textureLayers.constEnd();
+    for (; pos != end; ++pos ) {
+        GeoSceneTexture const * const textureLayer = *pos;
+        TileId const tileId( textureLayer->sourceDir(), stackedTileId.zoomLevel(),
+                             stackedTileId.x(), stackedTileId.y() );
+        QSharedPointer<TextureTile> const tile = d->m_tileLoader->reloadTile( stackedTileId, tileId );
+        // hack to try clouds, first tile is not handled here, MergeCopy is the default,
+        // the merge rule for following tiles is set to MergeMultiply here
+        if ( tile ) {
+            if ( stackedTile->hasTiles() )
+                tile->setMergeRule( TextureTile::MergeMultiply );
+            stackedTile->addTile( tile );
+        }
+    }
+    Q_ASSERT( stackedTile->hasTiles() );
+
+    if ( stackedTile->state() != StackedTile::TileEmpty ) {
+        stackedTile->initResultTile();
+    }
+    return stackedTile;
+}
+
 quint64 StackedTileLoader::volatileCacheLimit() const
 {
     return d->m_tileCache.maxCost() / 1024;
@@ -397,6 +448,24 @@
         m_parent->paintTile( tile, textureLayer );
 }
 
+// This method should not alter m_tileCache, as the given tile is managed
+// by the cache and may be evicted at any time (that is usually when inserting
+// other tiles in the cache)
+void StackedTileLoader::reloadCachedTile( StackedTile * const cachedTile )
+{
+    Q_ASSERT( cachedTile );
+    QVector<QSharedPointer<TextureTile> > * tiles = cachedTile->tiles();
+    QVector<QSharedPointer<TextureTile> >::const_iterator pos = tiles->constBegin();
+    QVector<QSharedPointer<TextureTile> >::const_iterator const end = tiles->constEnd();
+    for (; pos != end; ++pos ) {
+        d->m_tileLoader->reloadTile( *pos );
+    }
+    cachedTile->deriveCompletionState();
+    cachedTile->initResultTile();
+    mergeDecorations( cachedTile, findTextureLayer( cachedTile->id() ));
+    emit tileUpdateAvailable();
 }
 
+}
+
 #include "StackedTileLoader.moc"
--- trunk/KDE/kdeedu/marble/src/lib/StackedTileLoader.h #1108096:1108097
@@ -85,6 +85,8 @@
         StackedTile* loadTile( TileId const &stackedTileId,
                                bool const forMergedLayerDecorator = false );
 
+        StackedTile* reloadTile( TileId const & stackedTileId );
+
         /**
          * Resets the internal tile hash.
          */
@@ -162,6 +164,7 @@
             findRelevantTextureLayers( TileId const & stackedTileId ) const;
         void initTextureLayers();
         void mergeDecorations( StackedTile * const, GeoSceneTexture * const ) const;
+        void reloadCachedTile( StackedTile * const cachedTile );
 
         StackedTileLoaderPrivate* const d;
         MarbleModel* m_parent;
--- trunk/KDE/kdeedu/marble/src/lib/TileLoader.cpp #1108096:1108097
@@ -83,6 +83,64 @@
     return tile;
 }
 
+// This method loads a tile from the filesystem and additionally triggers a
+// download of that tile (without checking expiration). It is called by upper
+// layer (StackedTileLoader) when the tile that should be reloaded is not
+// currently loaded in memory.
+// It is (theoretically) used for map refresh/reload (F5 key) and will be used
+// for the (hopefully) coming download region feature.
+//
+// post condition
+//     - tile object is being returned, with download triggered,
+//       pointer is kept in m_waitingForUpdate until tile is downloaded
+QSharedPointer<TextureTile> TileLoader::reloadTile( TileId const & stackedTileId, TileId const & tileId )
+{
+    QSharedPointer<TextureTile> tile =
+        m_waitingForUpdate.value( tileId, QSharedPointer<TextureTile>() );
+    if ( tile )
+        // tile is being downloaded already and waiting for update,
+        // no need to reload 2 times => just return the tile
+        return tile;
+
+    QString const fileName = tileFileName( tileId );
+    QFileInfo const fileInfo( fileName );
+    if ( fileInfo.exists() ) {
+        tile = QSharedPointer<TextureTile>( new TextureTile( tileId, fileName ));
+        tile->setLastModified( fileInfo.lastModified() );
+    }
+    else {
+        tile = QSharedPointer<TextureTile>( new TextureTile( tileId ));
+        QImage * const replacementTile = scaledLowerLevelTile( tileId );
+        if ( replacementTile ) {
+            tile->setImage( replacementTile );
+            tile->setState( TextureTile::StateScaled );
+        }
+    }
+
+    GeoSceneTexture const * const textureLayer = findTextureLayer( tileId );
+    tile->setExpireSecs( textureLayer->expire() );
+    tile->setStackedTileId( stackedTileId );
+    m_waitingForUpdate.insert( tileId, tile );
+    triggerDownload( tileId );
+    return tile;
+}
+
+// This method triggers a download of the given tile (without checking
+// expiration). It is called by upper layer (StackedTileLoader) when the tile
+// that should be reloaded is currently loaded in memory.
+//
+// post condition
+//     - download is triggered, but only if not in progress (indicated by
+//       m_waitingForUpdate)
+void TileLoader::reloadTile( QSharedPointer<TextureTile> const & tile )
+{
+    if ( m_waitingForUpdate.contains( tile->id() ))
+        return;
+    tile->setState( TextureTile::StateExpired );
+    m_waitingForUpdate.insert( tile->id(), tile );
+    triggerDownload( tile->id() );
+}
+
 void TileLoader::updateTile( QByteArray const & data, QString const & tileId )
 {
     TileId const id = TileId::fromString( tileId );
--- trunk/KDE/kdeedu/marble/src/lib/TileLoader.h #1108096:1108097
@@ -43,6 +43,9 @@
     TileLoader( MapThemeManager const * const, HttpDownloadManager * const );
 
     QSharedPointer<TextureTile> loadTile( TileId const & stackedTileId, TileId const & tileId );
+    QSharedPointer<TextureTile> reloadTile( TileId const & stackedTileId, TileId const & tileId );
+    void reloadTile( QSharedPointer<TextureTile> const & tile );
+
     void setTextureLayers( QHash<uint, GeoSceneTexture*> const & );
 
  public Q_SLOTS:


More information about the Marble-commits mailing list