18#ifndef QGSABSTRACTCONTENTCACHE_H 
   19#define QGSABSTRACTCONTENTCACHE_H 
   31#include <QRecursiveMutex> 
   37#include <QNetworkReply> 
   77    int mFileModifiedCheckTimeout = 30000;
 
   93      return other.
path == path;
 
 
 
  157    static bool parseBase64DataUrl( 
const QString &path, QString *mimeType 
SIP_OUT = 
nullptr, QString *data 
SIP_OUT = 
nullptr );
 
  164    static bool isBase64Data( 
const QString &path );
 
  179    virtual bool checkReply( QNetworkReply *reply, 
const QString &path )
 const 
 
  194    virtual void onRemoteContentFetched( 
const QString &url, 
bool success );
 
 
  231                             const QString &typeString = QString(),
 
  232                             long maxCacheSize = 20000000,
 
  233                             int fileModifiedCheckTimeout = 30000 )
 
  235      , mMaxCacheSize( maxCacheSize )
 
  236      , mFileModifiedCheckTimeout( fileModifiedCheckTimeout )
 
  237      , mTypeString( typeString.isEmpty() ? QObject::tr( 
"Content" ) : typeString )
 
 
  243      qDeleteAll( mEntryLookup );
 
 
  254      if ( mLeastRecentEntry == mMostRecentEntry )
 
  258      T *entry = mLeastRecentEntry;
 
  259      while ( entry && ( mTotalSize > mMaxCacheSize ) )
 
  262        entry = 
static_cast< T * 
>( entry->nextEntry );
 
  264        takeEntryFromList( bkEntry );
 
  265        mEntryLookup.remove( bkEntry->path, bkEntry );
 
  266        mTotalSize -= bkEntry->dataSize();
 
 
  284    QByteArray getContent( 
const QString &path, 
const QByteArray &missingContent, 
const QByteArray &fetchingContent, 
bool blocking = 
false ) 
const;
 
  288      const QMutexLocker locker( &mMutex );
 
  289      mPendingRemoteUrls.remove( url );
 
  291      T *nextEntry = mLeastRecentEntry;
 
  292      while ( T *entry = nextEntry )
 
  294        nextEntry = 
static_cast< T * 
>( entry->nextEntry );
 
  295        if ( entry->path == url )
 
  297          takeEntryFromList( entry );
 
  298          mEntryLookup.remove( entry->path, entry );
 
  299          mTotalSize -= entry->dataSize();
 
  305        emit remoteContentFetched( url );
 
 
  349      const QString path = entryTemplate->path;
 
  350      T *currentEntry = 
nullptr;
 
  351      const QList<T *> entries = mEntryLookup.values( path );
 
  353      for ( T *cacheEntry : entries )
 
  355        if ( cacheEntry->isEqual( entryTemplate ) )
 
  357          if ( mFileModifiedCheckTimeout <= 0 || cacheEntry->fileModifiedLastCheckTimer.hasExpired( mFileModifiedCheckTimeout ) )
 
  359            if ( !modified.isValid() )
 
  360              modified = QFileInfo( path ).lastModified();
 
  362            if ( cacheEntry->fileModified != modified )
 
  365              cacheEntry->fileModifiedLastCheckTimer.restart();
 
  367          currentEntry = cacheEntry;
 
  375        currentEntry = insertCacheEntry( entryTemplate );
 
  379        delete entryTemplate;
 
  380        entryTemplate = 
nullptr;
 
  381        ( void )entryTemplate;
 
  382        takeEntryFromList( currentEntry );
 
  383        if ( !mMostRecentEntry ) 
 
  385          mMostRecentEntry = currentEntry;
 
  386          mLeastRecentEntry = currentEntry;
 
  390          mMostRecentEntry->nextEntry = currentEntry;
 
  391          currentEntry->previousEntry = mMostRecentEntry;
 
  392          currentEntry->nextEntry = 
nullptr;
 
  393          mMostRecentEntry = currentEntry;
 
 
  408    long mMaxCacheSize = 20000000;
 
  417    T *insertCacheEntry( T *entry )
 
  419      entry->mFileModifiedCheckTimeout = mFileModifiedCheckTimeout;
 
  421      if ( !entry->path.startsWith( QLatin1String( 
"base64:" ) ) )
 
  423        entry->fileModified = QFileInfo( entry->path ).lastModified();
 
  424        entry->fileModifiedLastCheckTimer.start();
 
  427      mEntryLookup.insert( entry->path, entry );
 
  430      if ( !mMostRecentEntry ) 
 
  432        mLeastRecentEntry = entry;
 
  433        mMostRecentEntry = entry;
 
  434        entry->previousEntry = 
nullptr;
 
  435        entry->nextEntry = 
nullptr;
 
  439        entry->previousEntry = mMostRecentEntry;
 
  440        entry->nextEntry = 
nullptr;
 
  441        mMostRecentEntry->nextEntry = entry;
 
  442        mMostRecentEntry = entry;
 
  453    void takeEntryFromList( T *entry )
 
  460      if ( entry->previousEntry )
 
  462        entry->previousEntry->nextEntry = entry->nextEntry;
 
  466        mLeastRecentEntry = 
static_cast< T * 
>( entry->nextEntry );
 
  468      if ( entry->nextEntry )
 
  470        entry->nextEntry->previousEntry = entry->previousEntry;
 
  474        mMostRecentEntry = 
static_cast< T * 
>( entry->previousEntry );
 
  481    void printEntryList()
 
  483      QgsDebugMsgLevel( QStringLiteral( 
"****************cache entry list*************************" ), 1 );
 
  485      T *entry = mLeastRecentEntry;
 
  490        entry = 
static_cast< T * 
>( entry->nextEntry );
 
  495    QMultiHash< QString, T * > mEntryLookup;
 
  498    int mFileModifiedCheckTimeout = 30000;
 
  502    T *mLeastRecentEntry = 
nullptr;
 
  503    T *mMostRecentEntry = 
nullptr;
 
  505    mutable QCache< QString, QByteArray > mRemoteContentCache;
 
  506    mutable QSet< QString > mPendingRemoteUrls;
 
  510    friend class TestQgsSvgCache;
 
  511    friend class TestQgsImageCache;
 
 
A QObject derived base class for QgsAbstractContentCache.
 
void remoteContentFetched(const QString &url)
Emitted when the cache has finished retrieving content from a remote url.
 
virtual bool checkReply(QNetworkReply *reply, const QString &path) const
Runs additional checks on a network reply to ensure that the reply content is consistent with that re...
 
Base class for entries in a QgsAbstractContentCache.
 
virtual int dataSize() const =0
Returns the memory usage in bytes for the entry.
 
virtual void dump() const =0
Dumps debugging strings containing the item's properties.
 
virtual ~QgsAbstractContentCacheEntry()=default
 
QElapsedTimer fileModifiedLastCheckTimer
Time since last check of file modified date.
 
QgsAbstractContentCacheEntry(const QgsAbstractContentCacheEntry &rh)=delete
 
QgsAbstractContentCacheEntry & operator=(const QgsAbstractContentCacheEntry &rh)=delete
 
QString path
Represents the absolute path to a file, a remote URL, or a base64 encoded string.
 
virtual bool isEqual(const QgsAbstractContentCacheEntry *other) const =0
Tests whether this entry matches another entry.
 
QDateTime fileModified
Timestamp when file was last modified.
 
bool operator==(const QgsAbstractContentCacheEntry &other) const
 
Abstract base class for file content caches, such as SVG or raster image caches.
 
T * findExistingEntry(T *entryTemplate)
Returns the existing entry from the cache which matches entryTemplate (deleting entryTemplate when do...
 
~QgsAbstractContentCache() override
 
void onRemoteContentFetched(const QString &url, bool success) override
Triggered after remote content (i.e.
 
QgsAbstractContentCache(QObject *parent=nullptr, const QString &typeString=QString(), long maxCacheSize=20000000, int fileModifiedCheckTimeout=30000)
Constructor for QgsAbstractContentCache, with the specified parent object.
 
void trimToMaximumSize()
Removes the least used cache entries until the maximum cache size is under the predefined size limit.
 
bool waitForTaskFinished(QgsNetworkContentFetcherTask *task) const
Blocks the current thread until the task finishes (or user's preset network timeout expires)
 
static int timeout()
Returns the network timeout length, in milliseconds.
 
Handles HTTP network content fetching in a background task.
 
void fetched()
Emitted when the network content has been fetched, regardless of whether the fetch was successful or ...
 
TaskStatus status() const
Returns the current task status.
 
@ Complete
Task successfully completed.
 
bool waitForFinished(int timeout=30000)
Blocks the current thread until the task finishes or a maximum of timeout milliseconds.
 
#define QgsDebugMsgLevel(str, level)