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 );
174 static bool parseEmbeddedStringData(
const QString &path, QString *mimeType
SIP_OUT =
nullptr, QString *data
SIP_OUT =
nullptr );
181 static bool isBase64Data(
const QString &path );
193 virtual bool invalidateCacheEntry(
const QString &path );
208 virtual bool checkReply( QNetworkReply *reply,
const QString &path )
const
208 virtual bool checkReply( QNetworkReply *reply,
const QString &path )
const {
…}
223 virtual void onRemoteContentFetched(
const QString &url,
bool success );
260 const QString &typeString = QString(),
261 long maxCacheSize = 20000000,
262 int fileModifiedCheckTimeout = 30000 )
264 , mMaxCacheSize( maxCacheSize )
265 , mFileModifiedCheckTimeout( fileModifiedCheckTimeout )
266 , mTypeString( typeString.isEmpty() ? QObject::tr(
"Content" ) : typeString )
272 qDeleteAll( mEntryLookup );
277 const QMutexLocker locker( &mMutex );
279 const QList<T *> entries = mEntryLookup.values( path );
280 if ( entries.isEmpty() )
283 for ( T *entry : entries )
285 takeEntryFromList( entry );
286 mEntryLookup.remove( path, entry );
287 mTotalSize -= entry->dataSize();
302 if ( mLeastRecentEntry == mMostRecentEntry )
306 T *entry = mLeastRecentEntry;
307 while ( entry && ( mTotalSize > mMaxCacheSize ) )
310 entry =
static_cast< T *
>( entry->nextEntry );
312 takeEntryFromList( bkEntry );
313 mEntryLookup.remove( bkEntry->path, bkEntry );
314 mTotalSize -= bkEntry->dataSize();
332 QByteArray getContent(
const QString &path,
const QByteArray &missingContent,
const QByteArray &fetchingContent,
bool blocking =
false )
const;
336 const QMutexLocker locker( &mMutex );
337 mPendingRemoteUrls.remove( url );
339 T *nextEntry = mLeastRecentEntry;
340 while ( T *entry = nextEntry )
342 nextEntry =
static_cast< T *
>( entry->nextEntry );
343 if ( entry->path == url )
345 takeEntryFromList( entry );
346 mEntryLookup.remove( entry->path, entry );
347 mTotalSize -= entry->dataSize();
353 emit remoteContentFetched( url );
397 const QString path = entryTemplate->path;
398 T *currentEntry =
nullptr;
399 const QList<T *> entries = mEntryLookup.values( path );
401 for ( T *cacheEntry : entries )
403 if ( cacheEntry->isEqual( entryTemplate ) )
405 if ( mFileModifiedCheckTimeout <= 0 || cacheEntry->fileModifiedLastCheckTimer.hasExpired( mFileModifiedCheckTimeout ) )
407 if ( !modified.isValid() )
408 modified = QFileInfo( path ).lastModified();
410 if ( cacheEntry->fileModified != modified )
413 cacheEntry->fileModifiedLastCheckTimer.restart();
415 currentEntry = cacheEntry;
423 currentEntry = insertCacheEntry( entryTemplate );
427 delete entryTemplate;
428 entryTemplate =
nullptr;
429 ( void )entryTemplate;
430 takeEntryFromList( currentEntry );
431 if ( !mMostRecentEntry )
433 mMostRecentEntry = currentEntry;
434 mLeastRecentEntry = currentEntry;
438 mMostRecentEntry->nextEntry = currentEntry;
439 currentEntry->previousEntry = mMostRecentEntry;
440 currentEntry->nextEntry =
nullptr;
441 mMostRecentEntry = currentEntry;
456 long mMaxCacheSize = 20000000;
465 T *insertCacheEntry( T *entry )
467 entry->mFileModifiedCheckTimeout = mFileModifiedCheckTimeout;
469 if ( !entry->path.startsWith( QLatin1String(
"base64:" ) ) )
471 entry->fileModified = QFileInfo( entry->path ).lastModified();
472 entry->fileModifiedLastCheckTimer.start();
475 mEntryLookup.insert( entry->path, entry );
478 if ( !mMostRecentEntry )
480 mLeastRecentEntry = entry;
481 mMostRecentEntry = entry;
482 entry->previousEntry =
nullptr;
483 entry->nextEntry =
nullptr;
487 entry->previousEntry = mMostRecentEntry;
488 entry->nextEntry =
nullptr;
489 mMostRecentEntry->nextEntry = entry;
490 mMostRecentEntry = entry;
501 void takeEntryFromList( T *entry )
508 if ( entry->previousEntry )
510 entry->previousEntry->nextEntry = entry->nextEntry;
514 mLeastRecentEntry =
static_cast< T *
>( entry->nextEntry );
516 if ( entry->nextEntry )
518 entry->nextEntry->previousEntry = entry->previousEntry;
522 mMostRecentEntry =
static_cast< T *
>( entry->previousEntry );
529 void printEntryList()
531 QgsDebugMsgLevel( QStringLiteral(
"****************cache entry list*************************" ), 1 );
533 T *entry = mLeastRecentEntry;
538 entry =
static_cast< T *
>( entry->nextEntry );
543 QMultiHash< QString, T * > mEntryLookup;
546 int mFileModifiedCheckTimeout = 30000;
550 T *mLeastRecentEntry =
nullptr;
551 T *mMostRecentEntry =
nullptr;
553 mutable QCache< QString, QByteArray > mRemoteContentCache;
554 mutable QSet< QString > mPendingRemoteUrls;
558 friend class TestQgsSvgCache;
559 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.
bool invalidateCacheEntry(const QString &path) override
Invalidates a cache entry for the specified path.
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)