diff --git a/config.cc b/config.cc index 77eb5605..892a8d34 100644 --- a/config.cc +++ b/config.cc @@ -22,14 +22,25 @@ #include "atomic_rename.hh" #include "qt4x5.hh" +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) +#include +#else +#include +#endif + namespace Config { namespace { + QString portableHomeDirPath() + { + return QCoreApplication::applicationDirPath() + "/portable"; + } + QDir getHomeDir() { if ( isPortableVersion() ) - return QDir( QCoreApplication::applicationDirPath() + "/portable" ); + return QDir( portableHomeDirPath() ); QDir result; @@ -199,6 +210,8 @@ Preferences::Preferences(): disallowContentFromOtherSites( false ), enableWebPlugins( false ), hideGoldenDictHeader( false ), + maxNetworkCacheSize( 50 ), + clearNetworkCacheOnExit( true ), zoomFactor( 1 ), helpZoomFactor( 1 ), wordsZoomLevel( 0 ), @@ -897,6 +910,12 @@ Class load() THROW_SPEC( exError ) if ( !preferences.namedItem( "hideGoldenDictHeader" ).isNull() ) c.preferences.hideGoldenDictHeader = ( preferences.namedItem( "hideGoldenDictHeader" ).toElement().text() == "1" ); + if ( !preferences.namedItem( "maxNetworkCacheSize" ).isNull() ) + c.preferences.maxNetworkCacheSize = preferences.namedItem( "maxNetworkCacheSize" ).toElement().text().toInt(); + + if ( !preferences.namedItem( "clearNetworkCacheOnExit" ).isNull() ) + c.preferences.clearNetworkCacheOnExit = ( preferences.namedItem( "clearNetworkCacheOnExit" ).toElement().text() == "1" ); + if ( !preferences.namedItem( "maxStringsInHistory" ).isNull() ) c.preferences.maxStringsInHistory = preferences.namedItem( "maxStringsInHistory" ).toElement().text().toUInt() ; @@ -1859,6 +1878,14 @@ void save( Class const & c ) THROW_SPEC( exError ) opt.appendChild( dd.createTextNode( c.preferences.hideGoldenDictHeader ? "1" : "0" ) ); preferences.appendChild( opt ); + opt = dd.createElement( "maxNetworkCacheSize" ); + opt.appendChild( dd.createTextNode( QString::number( c.preferences.maxNetworkCacheSize ) ) ); + preferences.appendChild( opt ); + + opt = dd.createElement( "clearNetworkCacheOnExit" ); + opt.appendChild( dd.createTextNode( c.preferences.clearNetworkCacheOnExit ? "1" : "0" ) ); + preferences.appendChild( opt ); + opt = dd.createElement( "maxStringsInHistory" ); opt.appendChild( dd.createTextNode( QString::number( c.preferences.maxStringsInHistory ) ) ); preferences.appendChild( opt ); @@ -2246,7 +2273,7 @@ bool isPortableVersion() throw() { bool isPortable; - IsPortable(): isPortable( QFileInfo( QCoreApplication::applicationDirPath() + "/portable" ).isDir() ) + IsPortable(): isPortable( QFileInfo( portableHomeDirPath() ).isDir() ) {} }; @@ -2283,4 +2310,19 @@ QString getStylesDir() throw() return result.path() + QDir::separator(); } +QString getCacheDir() throw() +{ + return isPortableVersion() ? portableHomeDirPath() + "/cache" +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + : QStandardPaths::writableLocation( QStandardPaths::CacheLocation ); +#else + : QDesktopServices::storageLocation( QDesktopServices::CacheLocation ); +#endif +} + +QString getNetworkCacheDir() throw() +{ + return getCacheDir() + "/network"; +} + } diff --git a/config.hh b/config.hh index c7eba46d..cadf99a1 100644 --- a/config.hh +++ b/config.hh @@ -302,6 +302,8 @@ struct Preferences bool disallowContentFromOtherSites; bool enableWebPlugins; bool hideGoldenDictHeader; + int maxNetworkCacheSize; + bool clearNetworkCacheOnExit; qreal zoomFactor; qreal helpZoomFactor; @@ -792,6 +794,12 @@ QString getPortableVersionMorphoDir() throw(); /// Returns the add-on styles directory. QString getStylesDir() throw(); +/// Returns the directory where user-specific non-essential (cached) data should be written. +QString getCacheDir() throw(); + +/// Returns the article network disk cache directory. +QString getNetworkCacheDir() throw(); + } #endif diff --git a/mainwindow.cc b/mainwindow.cc index 2575287a..0bc4910d 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -763,6 +763,8 @@ MainWindow::MainWindow( Config::Class & cfg_ ): connect( &articleNetMgr, SIGNAL( proxyAuthenticationRequired( QNetworkProxy, QAuthenticator * ) ), this, SLOT( proxyAuthentication( QNetworkProxy, QAuthenticator * ) ) ); + setupNetworkCache( cfg.preferences.maxNetworkCacheSize ); + makeDictionaries(); // After we have dictionaries and groups, we can populate history @@ -1068,6 +1070,10 @@ void MainWindow::commitData( QSessionManager & ) void MainWindow::commitData() { + if( cfg.preferences.clearNetworkCacheOnExit ) + if( QAbstractNetworkCache * cache = articleNetMgr.cache() ) + cache->clear(); + try { // Save MainWindow state and geometry @@ -1287,6 +1293,33 @@ void MainWindow::applyWebSettings() defaultSettings->setAttribute( QWebSettings::DeveloperExtrasEnabled, true ); } +void MainWindow::setupNetworkCache( int maxSize ) +{ + // x << 20 == x * 2^20 converts mebibytes to bytes. + qint64 const maxCacheSizeInBytes = maxSize <= 0 ? qint64( 0 ) : static_cast< qint64 >( maxSize ) << 20; + + if( QAbstractNetworkCache * abstractCache = articleNetMgr.cache() ) + { + QNetworkDiskCache * const diskCache = qobject_cast< QNetworkDiskCache * >( abstractCache ); + Q_ASSERT_X( diskCache, Q_FUNC_INFO, "Unexpected network cache type." ); + diskCache->setMaximumCacheSize( maxCacheSizeInBytes ); + return; + } + if( maxCacheSizeInBytes == 0 ) + return; // There is currently no cache and it is not needed. + + QString const cacheDirectory = Config::getNetworkCacheDir(); + if( !QDir().mkpath( cacheDirectory ) ) + { + gdWarning( "Cannot create a cache directory %s. Disabling network cache.", cacheDirectory.toUtf8().constData() ); + return; + } + QNetworkDiskCache * const diskCache = new QNetworkDiskCache( this ); + diskCache->setMaximumCacheSize( maxCacheSizeInBytes ); + diskCache->setCacheDirectory( cacheDirectory ); + articleNetMgr.setCache( diskCache ); +} + void MainWindow::makeDictionaries() { Q_ASSERT( !scanPopup && "Scan popup must not exist while dictionaries are initialized. " @@ -2139,6 +2172,8 @@ void MainWindow::editPreferences() if( cfg.preferences.favoritesStoreInterval != p.favoritesStoreInterval ) ui.favoritesPaneWidget->setSaveInterval( p.favoritesStoreInterval ); + if( cfg.preferences.maxNetworkCacheSize != p.maxNetworkCacheSize ) + setupNetworkCache( p.maxNetworkCacheSize ); cfg.preferences = p; audioPlayerFactory.setPreferences( cfg.preferences ); diff --git a/mainwindow.hh b/mainwindow.hh index 820df6c1..19a8ff60 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -201,6 +201,7 @@ private: void applyProxySettings(); void applyWebSettings(); + void setupNetworkCache( int maxSize ); void makeDictionaries(); void updateStatusLine(); void updateGroupList(); diff --git a/preferences.cc b/preferences.cc index 3f261efe..02934e71 100644 --- a/preferences.cc +++ b/preferences.cc @@ -153,6 +153,12 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ): break; } +#ifdef Q_OS_WIN32 + // 1 MB stands for 2^20 bytes on Windows. "MiB" is never used by this OS. + ui.maxNetworkCacheSize->setSuffix( tr( " MB" ) ); +#endif + ui.maxNetworkCacheSize->setToolTip( ui.maxNetworkCacheSize->toolTip().arg( Config::getNetworkCacheDir() ) ); + ui.newTabsOpenAfterCurrentOne->setChecked( p.newTabsOpenAfterCurrentOne ); ui.newTabsOpenInBackground->setChecked( p.newTabsOpenInBackground ); ui.hideSingleTab->setChecked( p.hideSingleTab ); @@ -319,6 +325,8 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ): ui.disallowContentFromOtherSites->setChecked( p.disallowContentFromOtherSites ); ui.enableWebPlugins->setChecked( p.enableWebPlugins ); ui.hideGoldenDictHeader->setChecked( p.hideGoldenDictHeader ); + ui.maxNetworkCacheSize->setValue( p.maxNetworkCacheSize ); + ui.clearNetworkCacheOnExit->setChecked( p.clearNetworkCacheOnExit ); // Add-on styles ui.addonStylesLabel->setVisible( ui.addonStyles->count() > 1 ); @@ -449,6 +457,8 @@ Config::Preferences Preferences::getPreferences() p.disallowContentFromOtherSites = ui.disallowContentFromOtherSites->isChecked(); p.enableWebPlugins = ui.enableWebPlugins->isChecked(); p.hideGoldenDictHeader = ui.hideGoldenDictHeader->isChecked(); + p.maxNetworkCacheSize = ui.maxNetworkCacheSize->value(); + p.clearNetworkCacheOnExit = ui.clearNetworkCacheOnExit->isChecked(); p.addonStyle = ui.addonStyles->getCurrentStyle(); @@ -639,6 +649,11 @@ void Preferences::customProxyToggled( bool ) && ui.useProxyServer->isChecked() ); } +void Preferences::on_maxNetworkCacheSize_valueChanged( int value ) +{ + ui.clearNetworkCacheOnExit->setEnabled( value != 0 ); +} + void Preferences::helpRequested() { if( !helpWindow ) diff --git a/preferences.hh b/preferences.hh index b9fcfccc..66e6227d 100644 --- a/preferences.hh +++ b/preferences.hh @@ -52,6 +52,7 @@ private slots: void on_useExternalPlayer_toggled( bool enabled ); void customProxyToggled( bool ); + void on_maxNetworkCacheSize_valueChanged( int value ); void helpRequested(); void closeHelp(); diff --git a/preferences.ui b/preferences.ui index 91a86218..c90a2779 100644 --- a/preferences.ui +++ b/preferences.ui @@ -1152,6 +1152,59 @@ Enable this option to workaround the problem. + + + + + + Maximum network cache size: + + + + + + + Maximum disk space occupied by GoldenDict's network cache in +%1 +If set to 0 the network disk cache will be disabled. + + + MiB + + + 2000 + + + 50 + + + + + + + When this option is enabled, GoldenDict +clears its network cache from disk during exit. + + + Clear network cache on exit + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + +