diff --git a/.gitattributes b/.gitattributes index cc8ed4244..9c33a69f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1,11 @@ # List files and directories to exclude from git archive +/dependencies/7zip export-ignore +/dependencies/create-dmg export-ignore +/dependencies/openssl export-ignore /dependencies/pdfium export-ignore /dependencies/poppler export-ignore /dependencies/qrencode export-ignore /dependencies/unarr export-ignore -/dependencies/create-dmg export-ignore .gitignore export-ignore .gitattributes export-ignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 41dad39bd..653f9af9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,24 @@ spanish only. Sorry for the mess. Version counting is based on semantic versioning (Major.Feature.Patch) +## 9.7.0 (unreleased) +### YACReader +* Image enlargement/stretching can now be disabled for fit + to width and height +* New option to show covers as single pages in double page mode (enabled by default) + +### YACReaderLibrary +* update QsLog logger to version 2.1, snapshot 46b643d5bcbc +* fix object leaks in database code +* add bidirectional sync support + +### YACReaderLibraryServer +* add support for port setting from the commandline +* update internal server code to QtWebApp 1.7.11 + +### Refactoring +* Move QtWebApp and QsLog to new third_party directory + ## 9.6.0 ### Reader and Library * RAR5 support. diff --git a/QsLog/QsLog.cpp b/QsLog/QsLog.cpp deleted file mode 100644 index b099d6c72..000000000 --- a/QsLog/QsLog.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2013, Razvan Petru -// All rights reserved. - -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: - -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, this -// list of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// * The name of the contributors may not be used to endorse or promote products -// derived from this software without specific prior written permission. - -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -// OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "QsLog.h" -#include "QsLogDest.h" -#ifdef QS_LOG_SEPARATE_THREAD -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -namespace QsLogging -{ -typedef QVector DestinationList; - -static const char TraceString[] = "TRACE"; -static const char DebugString[] = "DEBUG"; -static const char InfoString[] = "INFO "; -static const char WarnString[] = "WARN "; -static const char ErrorString[] = "ERROR"; -static const char FatalString[] = "FATAL"; - -// not using Qt::ISODate because we need the milliseconds too -static const QString fmtDateTime("yyyy-MM-ddThh:mm:ss.zzz"); - -static Logger* sInstance = 0; - -static const char* LevelToText(Level theLevel) -{ - switch (theLevel) { - case TraceLevel: - return TraceString; - case DebugLevel: - return DebugString; - case InfoLevel: - return InfoString; - case WarnLevel: - return WarnString; - case ErrorLevel: - return ErrorString; - case FatalLevel: - return FatalString; - case OffLevel: - return ""; - default: { - assert(!"bad log level"); - return InfoString; - } - } -} - -#ifdef QS_LOG_SEPARATE_THREAD -class LogWriterRunnable : public QRunnable -{ -public: - LogWriterRunnable(QString message, Level level); - virtual void run(); - -private: - QString mMessage; - Level mLevel; -}; -#endif - -class LoggerImpl -{ -public: - LoggerImpl(); - -#ifdef QS_LOG_SEPARATE_THREAD - QThreadPool threadPool; -#endif - QMutex logMutex; - Level level; - DestinationList destList; -}; - -#ifdef QS_LOG_SEPARATE_THREAD -LogWriterRunnable::LogWriterRunnable(QString message, Level level) - : QRunnable() - , mMessage(message) - , mLevel(level) -{ -} - -void LogWriterRunnable::run() -{ - Logger::instance().write(mMessage, mLevel); -} -#endif - - -LoggerImpl::LoggerImpl() - : level(InfoLevel) -{ - // assume at least file + console - destList.reserve(2); -#ifdef QS_LOG_SEPARATE_THREAD - threadPool.setMaxThreadCount(1); - threadPool.setExpiryTimeout(-1); -#endif -} - - -Logger::Logger() - : d(new LoggerImpl) -{ -} - -Logger& Logger::instance() -{ - if (!sInstance) - sInstance = new Logger; - - return *sInstance; -} - -void Logger::destroyInstance() -{ - delete sInstance; - sInstance = 0; -} - -// tries to extract the level from a string log message. If available, conversionSucceeded will -// contain the conversion result. -Level Logger::levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded) -{ - if (conversionSucceeded) - *conversionSucceeded = true; - - if (logMessage.startsWith(QLatin1String(TraceString))) - return TraceLevel; - if (logMessage.startsWith(QLatin1String(DebugString))) - return DebugLevel; - if (logMessage.startsWith(QLatin1String(InfoString))) - return InfoLevel; - if (logMessage.startsWith(QLatin1String(WarnString))) - return WarnLevel; - if (logMessage.startsWith(QLatin1String(ErrorString))) - return ErrorLevel; - if (logMessage.startsWith(QLatin1String(FatalString))) - return FatalLevel; - - if (conversionSucceeded) - *conversionSucceeded = false; - return OffLevel; -} - -Logger::~Logger() -{ -#ifdef QS_LOG_SEPARATE_THREAD - d->threadPool.waitForDone(); -#endif - delete d; - d = 0; -} - -void Logger::addDestination(DestinationPtr destination) -{ - assert(destination.data()); - d->destList.push_back(destination); -} - -void Logger::setLoggingLevel(Level newLevel) -{ - d->level = newLevel; -} - -Level Logger::loggingLevel() const -{ - return d->level; -} - -//! creates the complete log message and passes it to the logger -void Logger::Helper::writeToLog() -{ - const char* const levelName = LevelToText(level); - const QString completeMessage(QString("%1 %2 %3") - .arg(levelName) - .arg(QDateTime::currentDateTime().toString(fmtDateTime)) - .arg(buffer) - ); - - Logger::instance().enqueueWrite(completeMessage, level); -} - -Logger::Helper::~Helper() -{ - try { - writeToLog(); - } - catch(std::exception&) { - // you shouldn't throw exceptions from a sink - assert(!"exception in logger helper destructor"); - //CHANGED throw; - } -} - -//! directs the message to the task queue or writes it directly -void Logger::enqueueWrite(const QString& message, Level level) -{ -#ifdef QS_LOG_SEPARATE_THREAD - LogWriterRunnable *r = new LogWriterRunnable(message, level); - d->threadPool.start(r); -#else - write(message, level); -#endif -} - -//! Sends the message to all the destinations. The level for this message is passed in case -//! it's useful for processing in the destination. -void Logger::write(const QString& message, Level level) -{ - QMutexLocker lock(&d->logMutex); - for (DestinationList::iterator it = d->destList.begin(), - endIt = d->destList.end();it != endIt;++it) { - (*it)->write(message, level); - } -} - -} // end namespace diff --git a/QsLog/QsLog.pri b/QsLog/QsLog.pri deleted file mode 100644 index 4afc6b47b..000000000 --- a/QsLog/QsLog.pri +++ /dev/null @@ -1,22 +0,0 @@ -INCLUDEPATH += $$PWD -#DEFINES += QS_LOG_LINE_NUMBERS # automatically writes the file and line for each log message -#DEFINES += QS_LOG_DISABLE # logging code is replaced with a no-op -#DEFINES += QS_LOG_SEPARATE_THREAD # messages are queued and written from a separate thread -SOURCES += $$PWD/QsLogDest.cpp \ - $$PWD/QsLog.cpp \ - $$PWD/QsLogDestConsole.cpp \ - $$PWD/QsLogDestFile.cpp \ - $$PWD/QsLogDestFunctor.cpp - -HEADERS += $$PWD/QSLogDest.h \ - $$PWD/QsLog.h \ - $$PWD/QsLogDestConsole.h \ - $$PWD/QsLogLevel.h \ - $$PWD/QsLogDestFile.h \ - $$PWD/QsLogDisableForThisFile.h \ - $$PWD/QsLogDestFunctor.h - -OTHER_FILES += \ - $$PWD/QsLogChanges.txt \ - $$PWD/QsLogReadme.txt \ - $$PWD/LICENSE.txt diff --git a/README.md b/README.md index 9fa2dd475..094b5deb1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +| Build | Master | Develop | +|---|---|---| +|Code Validation |[![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=master&jobName=CodeFormatValidation)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=master)|[![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=CodeFormatValidation)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| +|Linux | [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=master&jobName=Linux)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=master) | [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=Linux)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| +|Windows x86| [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=master&jobName=Windows_x86)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=master)|[![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=Windows_x86)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| +|Windows x64| [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=master&jobName=Windows_x64)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=master)|[![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=Windows_x64)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| +|MacOS | [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=master&jobName=MacOS)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=master) | [![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=MacOS)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| +|Publish Build||[![Build Status](https://dev.azure.com/luisangelsm/YACReader/_apis/build/status/YACReader.yacreader?branchName=develop&jobName=PublishDevBuilds)](https://dev.azure.com/luisangelsm/YACReader/_build/latest?definitionId=1&branchName=develop)| + # YACReader "Yet another comic reader" @@ -10,7 +19,7 @@ This software has been developed by Luis Ángel San Martín Rodríguez ## Getting YACReader ### Official releases: -[https://github.com/YACReader/yacreader/releases](Releases) +[https://github.com/YACReader/yacreader/releases](https://github.com/YACReader/yacreader/releases) ### As a package: @@ -36,12 +45,12 @@ See [INSTALL.md](./INSTALL.md) If you need help or have any suggestion, please, send me an e-mail. ## Contributing -If you are interested in contributing to the project the first step should be to contact me so we can plan together the best approach, you can send an e-mail or just open an issue in this repo. For small bug fixes it is usually ok to open a PR directly. +If you are interested in contributing to the project the first step should be to contact me so we can plan together the best approach, you can send an e-mail or just open an issue in this repo. For small bug fixes it is usually ok to open a PR directly. -Contributions are not restricted to code, you can help the project by bringning new UI/UX ideas, designing new assets, writting manuals or tutorials, translating the apps, etc. If you are interested in DevOps, YACReader uses Azure Pipelines for CI/CD, any improvements in that area are welcome. Testing pre-releases is also really appreciated. +Contributions are not restricted to code, you can help the project by bringing new UI/UX ideas, designing new assets, writing manuals or tutorials, translating the apps, etc. If you are interested in DevOps, YACReader uses Azure Pipelines for CI/CD, any improvements in that area are welcome. Testing pre-releases is also really appreciated. #### Code -YACReader uses `clang-format` to ensure a common style and avoid deviances from it. CI checks this and will fail if the correct format is not used. `clang-format` needs to be called recusivelly in all the folders because some of them have the own `.clang-format` file, mainly to exclude changing the format in thirdparty libraries which are included in the source code. I recommend to configure your development tools to use `clang-format`, you can try to use it manually, but please, do it always before commiting changes. I recommend using QtCreator configured properly, you can find a tutorial [here]( https://www.vikingsoftware.com/using-clang-format-with-qtcreator/). +YACReader uses `clang-format` to ensure a common style and avoid deviances from it. CI checks this and will fail if the correct format is not used. `clang-format` needs to be called recursively in all the folders because some of them have the own `.clang-format` file, mainly to exclude changing the format in third-party libraries which are included in the source code. I recommend to configure your development tools to use `clang-format`, you can try to use it manually, but please, do it always before committing changes. I recommend using QtCreator configured properly, you can find a tutorial [here]( https://www.vikingsoftware.com/using-clang-format-with-qtcreator/). #### CI/CD Any PR will be validated through CI, and it will not be merged if CI fails. diff --git a/YACReader/Info.plist b/YACReader/Info.plist index 00e5cac23..904643507 100644 --- a/YACReader/Info.plist +++ b/YACReader/Info.plist @@ -19,63 +19,25 @@ CFBundleDocumentTypes - CFBundleTypeName - YACReader Comic rar - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes - - com.yacreader.yacreader.rar - - - - CFBundleTypeName - YACReader Comic zip - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes + CFBundleTypeExtensions - com.yacreader.yacreader.zip - - - - CFBundleTypeName - YACReader Comic cbr - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes - - com.yacreader.yacreader.cbr + zip + rar + cbz + cbr + pdf - - - CFBundleTypeName - YACReader Comic cbz - CFBundleTypeRole - Viewer - LSHandlerRank - Owner - LSItemContentTypes + CFBundleTypeIconFiles - com.yacreader.yacreader.cbz + Icon - - CFBundleTypeName - YACReader Comic pdf - CFBundleTypeRole - Viewer + Unknown LSHandlerRank - Owner + Alternate LSItemContentTypes - com.adobe.pdf + public.data @@ -93,15 +55,17 @@ UTTypeTagSpecification public.filename-extension - rar + + rar + public.mime-type - application/comic-rar + application/x-rar-compressed UTTypeConformsTo - public.data + public.item UTTypeDescription YACReader Comic @@ -110,9 +74,11 @@ UTTypeTagSpecification public.filename-extension - zip + + zip + public.mime-type - application/comic-zip + application/zip @@ -127,9 +93,11 @@ UTTypeTagSpecification public.filename-extension - cbr + + cbr + public.mime-type - application/comic-cbr + application/x-rar-compressed @@ -144,9 +112,11 @@ UTTypeTagSpecification public.filename-extension - cbz + + cbz + public.mime-type - application/comic-cbz + application/zip @@ -161,9 +131,11 @@ UTTypeTagSpecification public.filename-extension - pdf + + pdf + public.mime-type - application/comic-pdf + application/pdf diff --git a/YACReader/YACReader.pro b/YACReader/YACReader.pro index ecad04619..3aec87906 100644 --- a/YACReader/YACReader.pro +++ b/YACReader/YACReader.pro @@ -177,7 +177,7 @@ win32:RESOURCES += yacreader_images_win.qrc unix:!macx:RESOURCES += yacreader_images_win.qrc macx:RESOURCES += yacreader_images_osx.qrc -include(../QsLog/QsLog.pri) +include(../third_party/QsLog/QsLog.pri) RC_FILE = icon.rc diff --git a/YACReader/configuration.cpp b/YACReader/configuration.cpp index a5208e87b..7fa04ca93 100644 --- a/YACReader/configuration.cpp +++ b/YACReader/configuration.cpp @@ -47,14 +47,6 @@ void Configuration::load(QSettings *settings) settings->setValue(SHOW_TOOLBARS, true); if (!settings->contains(QUICK_NAVI_MODE)) settings->setValue(QUICK_NAVI_MODE, false); - //old fit stuff - /*if(!settings->contains(FIT)) - settings->setValue(FIT,false); - if(!settings->contains(FIT_TO_WIDTH_RATIO)) - settings->setValue(FIT_TO_WIDTH_RATIO,1); - if(!settings->contains(ADJUST_TO_FULL_SIZE)) - settings->setValue(ADJUST_TO_FULL_SIZE,false); - */ } void Configuration::updateOpenRecentList(QString path) { diff --git a/YACReader/configuration.h b/YACReader/configuration.h index 652aff407..0c35dbc16 100644 --- a/YACReader/configuration.h +++ b/YACReader/configuration.h @@ -51,16 +51,6 @@ class Configuration : public QObject void updateOpenRecentList(QString path); void clearOpenRecentList() { settings->remove("recentFiles"); } - //Old fitmodes - /* - bool getAdjustToWidth() {return settings->value(FIT).toBool();} - void setAdjustToWidth(bool atw=true) {settings->setValue(FIT,atw);} - float getFitToWidthRatio(){return settings->value(FIT_TO_WIDTH_RATIO).toFloat();} - void setFitToWidthRatio(float r){settings->setValue(FIT_TO_WIDTH_RATIO,r);} - bool getAdjustToFullSize(){return settings->value(ADJUST_TO_FULL_SIZE).toBool();} - void setAdjustToFullSize(bool b){settings->setValue(ADJUST_TO_FULL_SIZE,b);} - */ - FlowType getFlowType() { return (FlowType)settings->value(FLOW_TYPE_SW).toInt(); } void setFlowType(FlowType type) { settings->setValue(FLOW_TYPE_SW, type); } bool getFullScreen() { return settings->value(FULLSCREEN).toBool(); } diff --git a/YACReader/main.cpp b/YACReader/main.cpp index a67cbc627..90a79e18c 100644 --- a/YACReader/main.cpp +++ b/YACReader/main.cpp @@ -53,8 +53,41 @@ class YACReaderApplication : public QApplication }; #endif +void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + Q_UNUSED(context); + + QByteArray localMsg = msg.toLocal8Bit(); + switch (type) { + case QtInfoMsg: { + QLOG_INFO() << localMsg.constData(); + break; + } + case QtDebugMsg: { + QLOG_DEBUG() << localMsg.constData(); + break; + } + + case QtWarningMsg: { + QLOG_WARN() << localMsg.constData(); + break; + } + + case QtCriticalMsg: { + QLOG_ERROR() << localMsg.constData(); + break; + } + + case QtFatalMsg: { + QLOG_FATAL() << localMsg.constData(); + break; + } + } +} + int main(int argc, char *argv[]) { + qInstallMessageHandler(messageHandler); #if defined(_MSC_VER) && defined(_DEBUG) _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); @@ -81,6 +114,7 @@ int main(int argc, char *argv[]) QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); + parser.addOption({ "loglevel", "Set log level. Valid values: trace, info, debug, warn, error.", "loglevel", "warning" }); parser.addPositionalArgument("[File|Directory]", "File or directory to open."); QCommandLineOption comicId("comicId", "", "comicId"); QCommandLineOption libraryId("libraryId", "", "libraryId"); @@ -104,11 +138,27 @@ int main(int argc, char *argv[]) Logger &logger = Logger::instance(); logger.setLoggingLevel(QsLogging::InfoLevel); - DestinationPtr fileDestination(DestinationFactory::MakeFileDestination( - destLog, EnableLogRotation, MaxSizeBytes(1048576), MaxOldLogCount(2))); - DestinationPtr debugDestination(DestinationFactory::MakeDebugOutputDestination()); - logger.addDestination(debugDestination); - logger.addDestination(fileDestination); + if (parser.isSet("loglevel")) { + if (parser.value("loglevel") == "trace") { + logger.setLoggingLevel(QsLogging::TraceLevel); + } else if (parser.value("loglevel") == "info") { + logger.setLoggingLevel(QsLogging::InfoLevel); + } else if (parser.value("loglevel") == "debug") { + logger.setLoggingLevel(QsLogging::DebugLevel); + } else if (parser.value("loglevel") == "warn") { + logger.setLoggingLevel(QsLogging::WarnLevel); + } else if (parser.value("loglevel") == "error") { + logger.setLoggingLevel(QsLogging::ErrorLevel); + } else { + parser.showHelp(); + } + } + + DestinationPtrU fileDestination(DestinationFactory::MakeFileDestination( + destLog, LogRotationOption::EnableLogRotation, MaxSizeBytes(1048576), MaxOldLogCount(2))); + DestinationPtrU debugDestination(DestinationFactory::MakeDebugOutputDestination()); + logger.addDestination(std::move(debugDestination)); + logger.addDestination(std::move(fileDestination)); QTranslator translator; QString sufix = QLocale::system().name(); @@ -137,5 +187,8 @@ int main(int argc, char *argv[]) //Configuration::getConfiguration().save(); YACReader::exitCheck(ret); +#ifdef Q_OS_WIN + logger.shutDownLoggerThread(); +#endif return ret; } diff --git a/YACReader/main_window_viewer.cpp b/YACReader/main_window_viewer.cpp index b3a87bf92..3d7de60ff 100644 --- a/YACReader/main_window_viewer.cpp +++ b/YACReader/main_window_viewer.cpp @@ -156,6 +156,7 @@ void MainWindowViewer::setupUI() connect(optionsDialog, SIGNAL(accepted()), viewer, SLOT(updateOptions())); connect(optionsDialog, SIGNAL(optionsChanged()), this, SLOT(reloadOptions())); connect(optionsDialog, SIGNAL(changedFilters(int, int, int)), viewer, SLOT(updateFilters(int, int, int))); + connect(optionsDialog, &OptionsDialog::changedImageOptions, viewer, &Viewer::updatePage); optionsDialog->restoreOptions(settings); //shortcutsDialog = new ShortcutsDialog(this); @@ -204,6 +205,26 @@ void MainWindowViewer::createActions() openAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(OPEN_ACTION_Y)); connect(openAction, SIGNAL(triggered()), this, SLOT(open())); +#ifdef Q_OS_MAC + newInstanceAction = new QAction(tr("New instance"), this); + newInstanceAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(NEW_INSTANCE_ACTION_Y)); + connect(newInstanceAction, &QAction::triggered, + [=]() { + QStringList possiblePaths { QDir::cleanPath(QCoreApplication::applicationDirPath() + "/../../../") }; + possiblePaths += QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + + for (auto &&ypath : possiblePaths) { + QString yacreaderPath = QDir::cleanPath(ypath + "/YACReader.app"); + if (QFileInfo(yacreaderPath).exists()) { + QStringList parameters { "-n", "-a", yacreaderPath }; + QProcess::startDetached("open", parameters); + break; + } + } + }); + newInstanceAction->setData(NEW_INSTANCE_ACTION_Y); +#endif + openFolderAction = new QAction(tr("Open Folder"), this); openFolderAction->setIcon(QIcon(":/images/viewer_toolbar/openFolder.png")); openFolderAction->setToolTip(tr("Open image folder")); @@ -645,6 +666,8 @@ void MainWindowViewer::createToolBars() //file auto fileMenu = new QMenu(tr("File")); + fileMenu->addAction(newInstanceAction); + fileMenu->addSeparator(); fileMenu->addAction(openAction); fileMenu->addAction(openLatestComicAction); fileMenu->addAction(openFolderAction); @@ -1195,11 +1218,7 @@ void MainWindowViewer::checkNewVersion() connect(versionChecker, SIGNAL(newVersionDetected()), this, SLOT(newVersion())); - auto tT = new QTimer; - tT->setSingleShot(true); - connect(tT, SIGNAL(timeout()), versionChecker, SLOT(get())); - //versionChecker->get(); //TOD� - tT->start(100); + QTimer::singleShot(100, versionChecker, &HttpVersionChecker::get); conf.setLastVersionCheck(current); } @@ -1258,7 +1277,11 @@ void MainWindowViewer::setUpShortcutsManagement() << showFlowAction << toggleFullScreenAction << toggleToolbarsAction - << showEditShortcutsAction); + << showEditShortcutsAction +#ifdef Q_OS_MAC + << newInstanceAction +#endif + ); allActions << tmpList; diff --git a/YACReader/main_window_viewer.h b/YACReader/main_window_viewer.h index 6d230611d..21ad8cdd6 100644 --- a/YACReader/main_window_viewer.h +++ b/YACReader/main_window_viewer.h @@ -106,6 +106,9 @@ public slots: //! Actions QAction *openAction; +#ifdef Q_OS_MAC + QAction *newInstanceAction; //needed in macos +#endif QAction *openFolderAction; QAction *openLatestComicAction; QList recentFilesActionList; diff --git a/YACReader/options_dialog.cpp b/YACReader/options_dialog.cpp index 143408762..e69c727b6 100644 --- a/YACReader/options_dialog.cpp +++ b/YACReader/options_dialog.cpp @@ -55,18 +55,6 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(pathFindButton, SIGNAL(clicked()), this, SLOT(findFolder())); - //fitToWidthRatioLabel = new QLabel(tr("Page width stretch"),this); - /*QGroupBox *fitBox = new QGroupBox(tr("Page width stretch")); - fitToWidthRatioS = new QSlider(this); - fitToWidthRatioS->setMinimum(50); - fitToWidthRatioS->setMaximum(100); - fitToWidthRatioS->setPageStep(5); - fitToWidthRatioS->setOrientation(Qt::Horizontal); - //connect(fitToWidthRatioS,SIGNAL(valueChanged(int)),this,SLOT(fitToWidthRatio(int))); - QHBoxLayout * fitLayout = new QHBoxLayout; - fitLayout->addWidget(fitToWidthRatioS); - fitBox->setLayout(fitLayout);*/ - auto colorSelection = new QHBoxLayout; backgroundColor = new QLabel(); QPalette pal = backgroundColor->palette(); @@ -145,6 +133,32 @@ OptionsDialog::OptionsDialog(QWidget *parent) QGroupBox *imageBox = new QGroupBox(tr("Image options")); imageBox->setLayout(layoutImage); layoutImageV->addWidget(imageBox); + + auto scaleBox = new QGroupBox(tr("Fit options")); + auto scaleLayout = new QVBoxLayout(); + scaleCheckbox = new QCheckBox(tr("Enlarge images to fit width/height")); + connect(scaleCheckbox, &QCheckBox::clicked, + [=](bool checked) { + settings->setValue(ENLARGE_IMAGES, checked); + emit(changedImageOptions()); + }); + + scaleLayout->addWidget(scaleCheckbox); + scaleBox->setLayout(scaleLayout); + layoutImageV->addWidget(scaleBox); + + auto doublePageBox = new QGroupBox(tr("Double Page options")); + auto doublePageBoxLayout = new QVBoxLayout(); + coverSPCheckBox = new QCheckBox(tr("Show covers as single page")); + connect(coverSPCheckBox, &QCheckBox::clicked, + [=](bool checked) { + settings->setValue(COVER_IS_SP, checked); + emit(changedImageOptions()); + }); + + doublePageBoxLayout->addWidget(coverSPCheckBox); + doublePageBox->setLayout(doublePageBoxLayout); + layoutImageV->addWidget(doublePageBox); layoutImageV->addStretch(); pageGeneral->setLayout(layoutGeneral); @@ -233,6 +247,9 @@ void OptionsDialog::restoreOptions(QSettings *settings) brightnessS->setValue(settings->value(BRIGHTNESS, 0).toInt()); contrastS->setValue(settings->value(CONTRAST, 100).toInt()); gammaS->setValue(settings->value(GAMMA, 100).toInt()); + + scaleCheckbox->setChecked(settings->value(ENLARGE_IMAGES, true).toBool()); + coverSPCheckBox->setChecked(settings->value(COVER_IS_SP, true).toBool()); } void OptionsDialog::updateColor(const QColor &color) @@ -248,12 +265,6 @@ void OptionsDialog::updateColor(const QColor &color) emit(changedOptions()); } -/*void OptionsDialog::fitToWidthRatio(int value) -{ - Configuration::getConfiguration().setFitToWidthRatio(value/100.0); - emit(fitToWidthRatioChanged(value/100.0)); -}*/ - void OptionsDialog::brightnessChanged(int value) { QSettings settings(YACReader::getSettingsPath() + "/YACReader.ini", QSettings::IniFormat); diff --git a/YACReader/options_dialog.h b/YACReader/options_dialog.h index 32404a50b..3c278b742 100644 --- a/YACReader/options_dialog.h +++ b/YACReader/options_dialog.h @@ -25,6 +25,8 @@ class OptionsDialog : public YACReaderOptionsDialog QPushButton *pathFindButton; QCheckBox *quickNavi; QCheckBox *disableShowOnMouseOver; + QCheckBox *scaleCheckbox; + QCheckBox *coverSPCheckBox; QLabel *magGlassSizeLabel; diff --git a/YACReader/render.cpp b/YACReader/render.cpp index f89b69324..58501767e 100644 --- a/YACReader/render.cpp +++ b/YACReader/render.cpp @@ -11,6 +11,7 @@ #include "comic_db.h" #include "yacreader_global_gui.h" +#include "configuration.h" template inline const T &kClamp(const T &x, const T &low, const T &high) @@ -544,6 +545,9 @@ QPixmap *Render::getCurrentDoubleMangaPage() bool Render::currentPageIsDoublePage() { + if (currentIndex == 0 && Configuration::getConfiguration().getSettings()->value(COVER_IS_SP, true).toBool()) { + return false; + } if (buffer[currentPageBufferedIndex]->isNull() || buffer[currentPageBufferedIndex + 1]->isNull()) { return false; } @@ -583,6 +587,12 @@ bool Render::nextPageIsDoublePage() bool Render::previousPageIsDoublePage() { + qWarning("Previous page is doublepage!"); + qWarning("%d", currentIndex); + qWarning("%d", currentPageBufferedIndex); + if (currentIndex == 2 && Configuration::getConfiguration().getSettings()->value(COVER_IS_SP, true).toBool()) { + return false; + } if (buffer[currentPageBufferedIndex - 1]->isNull() || buffer[currentPageBufferedIndex - 2]->isNull()) { return false; } diff --git a/YACReader/viewer.cpp b/YACReader/viewer.cpp index c5e54f357..50dc09718 100644 --- a/YACReader/viewer.cpp +++ b/YACReader/viewer.cpp @@ -161,7 +161,7 @@ void Viewer::createConnections() connect(goToFlow, SIGNAL(goToPage(unsigned int)), this, SLOT(goTo(unsigned int))); //current time - auto t = new QTimer(); + auto t = new QTimer(this); connect(t, SIGNAL(timeout()), this, SLOT(updateInformation())); t->start(1000); @@ -206,10 +206,7 @@ void Viewer::prepareForOpening() verticalScrollBar()->setSliderPosition(verticalScrollBar()->minimum()); if (Configuration::getConfiguration().getShowInformation() && !information) { - auto timer = new QTimer(); - connect(timer, SIGNAL(timeout()), this, SLOT(informationSwitch())); - connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); - timer->start(); + QTimer::singleShot(0, this, &Viewer::informationSwitch); } informationLabel->setText("..."); @@ -319,24 +316,27 @@ void Viewer::updateContentSize() { //there is an image to resize if (currentPage != nullptr && !currentPage->isNull()) { - QSize pagefit; + QSize pagefit = currentPage->size(); + bool stretchImages = Configuration::getConfiguration().getSettings()->value(ENLARGE_IMAGES).toBool(); YACReader::FitMode fitmode = Configuration::getConfiguration().getFitMode(); switch (fitmode) { case YACReader::FitMode::FullRes: - pagefit = currentPage->size(); break; case YACReader::FitMode::ToWidth: - pagefit = currentPage->size(); + if (!stretchImages && width() > pagefit.width()) { + break; + } pagefit.scale(width(), 0, Qt::KeepAspectRatioByExpanding); break; case YACReader::FitMode::ToHeight: - pagefit = currentPage->size(); + if (!stretchImages && height() > pagefit.height()) { + break; + } pagefit.scale(0, height(), Qt::KeepAspectRatioByExpanding); break; //if everything fails showing the full page is a good idea case YACReader::FitMode::FullPage: default: - pagefit = currentPage->size(); pagefit.scale(size(), Qt::KeepAspectRatio); break; } diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index b39293fc3..2e6d6888e 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -107,6 +107,8 @@ HEADERS += comic_flow.h \ ../common/comic.h \ ../common/bookmarks.h \ ../common/pictureflow.h \ + ../common/release_acquire_atomic.h \ + ../common/worker_thread.h \ ../common/custom_widgets.h \ ../common/qnaturalsorting.h \ ../common/yacreader_global.h \ @@ -240,7 +242,7 @@ include(../compressed_archive/unarr/unarr-wrapper.pri) } include(./comic_vine/comic_vine.pri) -include(../QsLog/QsLog.pri) +include(../third_party/QsLog/QsLog.pri) include(../shortcuts_management/shortcuts_management.pri) RESOURCES += images.qrc files.qrc diff --git a/YACReaderLibrary/comic_flow.cpp b/YACReaderLibrary/comic_flow.cpp index 1bd5f32a3..f6bf38aeb 100644 --- a/YACReaderLibrary/comic_flow.cpp +++ b/YACReaderLibrary/comic_flow.cpp @@ -1,39 +1,26 @@ #include "comic_flow.h" -#include "qnaturalsorting.h" +#include "worker_thread.h" #include "yacreader_global.h" -#include - -#include -#include -#include - ComicFlow::ComicFlow(QWidget *parent, FlowType flowType) - : YACReaderFlow(parent, flowType) + : YACReaderFlow(parent, flowType), worker(new WorkerThread) { - updateTimer = new QTimer; - connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateImageData())); + resetWorkerIndex(); + connect(&updateTimer, SIGNAL(timeout()), this, SLOT(updateImageData())); - worker = new ImageLoader; connect(this, SIGNAL(centerIndexChanged(int)), this, SLOT(preload())); connect(this, SIGNAL(centerIndexChangedSilent(int)), this, SLOT(preload())); setReflectionEffect(PlainReflection); } -ComicFlow::~ComicFlow() -{ - worker->terminate(); - delete worker; - delete updateTimer; -} +ComicFlow::~ComicFlow() = default; void ComicFlow::setImagePaths(const QStringList &paths) { clear(); - //imagePath = path; imageFiles = paths; imagesLoaded.clear(); imagesLoaded.fill(false, imageFiles.size()); @@ -54,14 +41,15 @@ void ComicFlow::setImagePaths(const QStringList &paths) } setCenterIndex(0); - worker->reset(); + + resetWorkerIndex(); preload(); } void ComicFlow::preload() { if (numImagesLoaded < imagesLoaded.size()) - updateTimer->start(30); //TODO comprobar rendimiento, originalmente era 70 + updateTimer.start(30); //TODO comprobar rendimiento, originalmente era 70 } void ComicFlow::updateImageData() @@ -71,10 +59,11 @@ void ComicFlow::updateImageData() return; // set image of last one - int idx = worker->index(); - if (idx >= 0 && !worker->result().isNull()) { - if (!imagesSetted[idx]) { - setSlide(idx, worker->result()); + const int idx = workerIndex; + if (idx >= 0) { + const QImage result = worker->extractResult(); + if (!result.isNull() && !imagesSetted[idx]) { + setSlide(idx, result); imagesSetted[idx] = true; numImagesLoaded++; imagesLoaded[idx] = true; @@ -99,13 +88,14 @@ void ComicFlow::updateImageData() // schedule thumbnail generation QString fname = imageFiles[i]; - worker->generate(i, fname, slideSize()); + workerIndex = i; + worker->performTask([fname] { return QImage { fname }; }); return; } } // no need to generate anything? stop polling... - updateTimer->stop(); + updateTimer.stop(); } void ComicFlow::keyPressEvent(QKeyEvent *event) @@ -124,10 +114,6 @@ void ComicFlow::wheelEvent(QWheelEvent *event) void ComicFlow::removeSlide(int cover) { - worker->lock(); - - worker->reset(); - imageFiles.removeAt(cover); if (imagesLoaded[cover]) numImagesLoaded--; @@ -135,16 +121,13 @@ void ComicFlow::removeSlide(int cover) imagesSetted.remove(cover); YACReaderFlow::removeSlide(cover); - worker->unlock(); + resetWorkerIndex(); preload(); } void ComicFlow::resortCovers(QList newOrder) { - worker->lock(); - worker->reset(); - YACReaderFlow::resortCovers(newOrder); QStringList imageFilesNew; @@ -160,95 +143,5 @@ void ComicFlow::resortCovers(QList newOrder) imagesLoaded = imagesLoadedNew; imagesSetted = imagesSettedNew; - worker->unlock(); -} -//----------------------------------------------------------------------------- -//ImageLoader -//----------------------------------------------------------------------------- -static QImage loadImage(const QString &fileName) -{ - QImage image; - bool result = image.load(fileName); - - if (!result) - return QImage(); - - return image; -} - -ImageLoader::ImageLoader() - : QThread(), restart(false), working(false), idx(-1) -{ -} - -ImageLoader::~ImageLoader() -{ - mutex.lock(); - condition.wakeOne(); - mutex.unlock(); - wait(); -} - -bool ImageLoader::busy() const -{ - return isRunning() ? working : false; -} - -void ImageLoader::generate(int index, const QString &fileName, QSize size) -{ - mutex.lock(); - this->idx = index; - this->fileName = fileName; - this->size = size; - this->img = QImage(); - mutex.unlock(); - - if (!isRunning()) - start(); - else { - // already running, wake up whenever ready - restart = true; - condition.wakeOne(); - } -} - -void ImageLoader::lock() -{ - mutex.lock(); -} - -void ImageLoader::unlock() -{ - mutex.unlock(); -} - -void ImageLoader::run() -{ - for (;;) { - // copy necessary data - mutex.lock(); - this->working = true; - QString fileName = this->fileName; - mutex.unlock(); - - QImage image = loadImage(fileName); - - // let everyone knows it is ready - mutex.lock(); - this->working = false; - this->img = image; - mutex.unlock(); - - // put to sleep - mutex.lock(); - if (!this->restart) - condition.wait(&mutex); - restart = false; - mutex.unlock(); - } -} - -QImage ImageLoader::result() -{ - return img; + resetWorkerIndex(); } diff --git a/YACReaderLibrary/comic_flow.h b/YACReaderLibrary/comic_flow.h index 78b915828..a7f0627f7 100644 --- a/YACReaderLibrary/comic_flow.h +++ b/YACReaderLibrary/comic_flow.h @@ -4,21 +4,22 @@ #include "yacreader_flow.h" #include -#include -#include #include -#include -#include #include +#include #include -class ImageLoader; +#include + +template +class WorkerThread; + class ComicFlow : public YACReaderFlow { Q_OBJECT public: ComicFlow(QWidget *parent = nullptr, FlowType flowType = CoverFlowLike); - virtual ~ComicFlow(); + ~ComicFlow() override; void setImagePaths(const QStringList &paths); //bool eventFilter(QObject *target, QEvent *event); @@ -31,46 +32,16 @@ private slots: void updateImageData(); private: - //QString imagePath; + void resetWorkerIndex() { workerIndex = -1; } + QStringList imageFiles; QVector imagesLoaded; QVector imagesSetted; int numImagesLoaded; - QTimer *updateTimer; - ImageLoader *worker; + int workerIndex; + QTimer updateTimer; + std::unique_ptr> worker; virtual void wheelEvent(QWheelEvent *event); }; -//----------------------------------------------------------------------------- -// Source code of ImageLoader class was modified from http://code.google.com/p/photoflow/ -//------------------------------------------------------------------------------ -class ImageLoader : public QThread -{ -public: - ImageLoader(); - ~ImageLoader() override; - // returns FALSE if worker is still busy and can't take the task - bool busy() const; - void generate(int index, const QString &fileName, QSize size); - void reset() { idx = -1; }; - int index() const { return idx; }; - void lock(); - void unlock(); - QImage result(); - -protected: - void run() override; - -private: - QMutex mutex; - QWaitCondition condition; - - bool restart; - bool working; - int idx; - QString fileName; - QSize size; - QImage img; -}; - #endif diff --git a/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp b/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp index 40a025820..8047b4f37 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp +++ b/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp @@ -431,16 +431,18 @@ void ComicVineDialog::getComicsInfo(QList> &matchingInfo setLoadingMessage(tr("Retrieving tags for : %1").arg(p.first.getFileName())); } - - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); - db.open(); - db.transaction(); - foreach (ComicDB comic, comics) { - DBHelper::update(&(comic.info), db); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + db.open(); + db.transaction(); + foreach (ComicDB comic, comics) { + DBHelper::update(&(comic.info), db); + } + db.commit(); + connectionName = db.connectionName(); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); emit accepted(); } @@ -464,16 +466,18 @@ void ComicVineDialog::getComicInfo(const QString &comicId, int count, const QStr ComicDB comic = parseComicInfo(comics[currentIndex], result, count, publisher); //TODO check result error comic.info.comicVineID = comicId; setLoadingMessage(tr("Retrieving tags for : %1").arg(comics[currentIndex].getFileName())); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + db.open(); + db.transaction(); - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); - db.open(); - db.transaction(); - - DBHelper::update(&(comic.info), db); + DBHelper::update(&(comic.info), db); - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + db.commit(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); if (mode == SingleComic || currentIndex == (comics.count() - 1)) { emit accepted(); diff --git a/YACReaderLibrary/comic_vine/select_comic.cpp b/YACReaderLibrary/comic_vine/select_comic.cpp index ed0908661..681e1d20a 100644 --- a/YACReaderLibrary/comic_vine/select_comic.cpp +++ b/YACReaderLibrary/comic_vine/select_comic.cpp @@ -82,7 +82,7 @@ void SelectComic::load(const QString &json, const QString &searchString) ScraperSelector::load(json, searchString); } -SelectComic::~SelectComic() {} +SelectComic::~SelectComic() { } void SelectComic::loadComicInfo(const QModelIndex &mi) { diff --git a/YACReaderLibrary/comic_vine/select_volume.cpp b/YACReaderLibrary/comic_vine/select_volume.cpp index eb45cde6d..73edec07e 100644 --- a/YACReaderLibrary/comic_vine/select_volume.cpp +++ b/YACReaderLibrary/comic_vine/select_volume.cpp @@ -109,7 +109,7 @@ void SelectVolume::load(const QString &json, const QString &searchString) ScraperSelector::load(json, searchString); } -SelectVolume::~SelectVolume() {} +SelectVolume::~SelectVolume() { } void SelectVolume::loadVolumeInfo(const QModelIndex &omi) { diff --git a/YACReaderLibrary/comic_vine/sort_volume_comics.h b/YACReaderLibrary/comic_vine/sort_volume_comics.h index 8b09269b2..bacadcb1c 100644 --- a/YACReaderLibrary/comic_vine/sort_volume_comics.h +++ b/YACReaderLibrary/comic_vine/sort_volume_comics.h @@ -38,7 +38,7 @@ class ScrapperToolButton : public QPushButton return w; } void setAppearance(ScrapperToolButton::Appearance appearance) { this->appearance = appearance; } - virtual ~ScrapperToolButton() {} + virtual ~ScrapperToolButton() { } protected: void paintEvent(QPaintEvent *e) override diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index aa226790c..7fee8000a 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -152,23 +152,25 @@ bool ComicModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int foreach (ComicItem *item, _data) { allComicIds << item->data(Id).toULongLong(); } - - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - switch (mode) { - case Favorites: - DBHelper::reasignOrderToComicsInFavorites(allComicIds, db); - break; - case Label: - DBHelper::reasignOrderToComicsInLabel(sourceId, allComicIds, db); - break; - case ReadingList: - DBHelper::reasignOrderToComicsInReadingList(sourceId, allComicIds, db); - break; - default: - break; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + switch (mode) { + case Favorites: + DBHelper::reasignOrderToComicsInFavorites(allComicIds, db); + break; + case Label: + DBHelper::reasignOrderToComicsInLabel(sourceId, allComicIds, db); + break; + case ReadingList: + DBHelper::reasignOrderToComicsInReadingList(sourceId, allComicIds, db); + break; + default: + break; + } + connectionName = db.connectionName(); } - - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); //endMoveRows(); @@ -441,8 +443,9 @@ void ComicModel::setupFolderModelData(unsigned long long int folderId, const QSt _data.clear(); _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -450,13 +453,10 @@ void ComicModel::setupFolderModelData(unsigned long long int folderId, const QSt selectQuery.bindValue(":parentId", folderId); selectQuery.exec(); setupModelData(selectQuery); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); - - /*if(_data.length()==0) - emit isEmpty();*/ } void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QString &databasePath) @@ -470,8 +470,9 @@ void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QStri _data.clear(); _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -481,13 +482,10 @@ void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QStri selectQuery.bindValue(":parentLabelId", parentLabel); selectQuery.exec(); setupModelDataForList(selectQuery); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); - - /*if(_data.length()==0) - emit isEmpty();*/ } void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, const QString &databasePath) @@ -500,8 +498,9 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, _data.clear(); _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QList ids; ids << parentReadingList; @@ -535,9 +534,9 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, _data = tempData << _data; } + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); } @@ -551,8 +550,9 @@ void ComicModel::setupFavoritesModelData(const QString &databasePath) _data.clear(); _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -562,13 +562,10 @@ void ComicModel::setupFavoritesModelData(const QString &databasePath) selectQuery.bindValue(":parentDefaultListId", 1); selectQuery.exec(); setupModelDataForList(selectQuery); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); - - /*if(_data.length()==0) - emit isEmpty();*/ } void ComicModel::setupReadingModelData(const QString &databasePath) @@ -581,8 +578,9 @@ void ComicModel::setupReadingModelData(const QString &databasePath) _data.clear(); _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -591,32 +589,22 @@ void ComicModel::setupReadingModelData(const QString &databasePath) selectQuery.exec(); setupModelDataForList(selectQuery); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); - - /*if(_data.length()==0) - emit isEmpty();*/ } void ComicModel::setupModelData(const SearchModifiers modifier, const QString &filter, const QString &databasePath) { - //QFile f(QCoreApplication::applicationDirPath()+"/performance.txt"); - //f.open(QIODevice::Append); beginResetModel(); - //QElapsedTimer timer; - //timer.start(); qDeleteAll(_data); _data.clear(); - - //QTextStream txtS(&f); - //txtS << "TABLEMODEL: Tiempo de borrado: " << timer.elapsed() << "ms\r\n"; _databasePath = databasePath; - QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); + QString connectionName = ""; + { - //crear la consulta - //timer.restart(); + QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); QSqlQuery selectQuery(db); switch (modifier) { @@ -653,14 +641,10 @@ void ComicModel::setupModelData(const SearchModifiers modifier, const QString &f QLOG_DEBUG() << selectQuery.lastError() << "--"; - //txtS << "TABLEMODEL: Tiempo de consulta: " << timer.elapsed() << "ms\r\n"; - //timer.restart(); setupModelData(selectQuery); - //txtS << "TABLEMODEL: Tiempo de creaci�n del modelo: " << timer.elapsed() << "ms\r\n"; - //selectQuery.finish(); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); emit searchNumResults(_data.length()); @@ -715,20 +699,28 @@ void ComicModel::setupModelDataForList(QSqlQuery &sqlquery) ComicDB ComicModel::getComic(const QModelIndex &mi) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - ComicDB c = DBHelper::loadComic(_data.at(mi.row())->data(ComicModel::Id).toULongLong(), db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + ComicDB c; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + c = DBHelper::loadComic(_data.at(mi.row())->data(ComicModel::Id).toULongLong(), db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return c; } ComicDB ComicModel::_getComic(const QModelIndex &mi) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - ComicDB c = DBHelper::loadComic(_data.at(mi.row())->data(ComicModel::Id).toULongLong(), db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + ComicDB c; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + c = DBHelper::loadComic(_data.at(mi.row())->data(ComicModel::Id).toULongLong(), db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return c; } @@ -757,18 +749,21 @@ QVector ComicModel::setAllComicsRead(YACReaderComicRea QList ComicModel::getAllComics() { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - QList comics; - int numComics = _data.count(); - for (int i = 0; i < numComics; i++) { - comics.append(DBHelper::loadComic(_data.value(i)->data(ComicModel::Id).toULongLong(), db)); - } + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); + + int numComics = _data.count(); + for (int i = 0; i < numComics; i++) { + comics.append(DBHelper::loadComic(_data.value(i)->data(ComicModel::Id).toULongLong(), db)); + } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + db.commit(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return comics; } @@ -776,44 +771,41 @@ QList ComicModel::getAllComics() QList ComicModel::getComics(QList list) { QList comics; - - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - QList::const_iterator itr; - for (itr = list.constBegin(); itr != list.constEnd(); itr++) { + for (auto itr = list.constBegin(); itr != list.constEnd(); itr++) { comics.append(_getComic(*itr)); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); return comics; } //TODO QVector ComicModel::setComicsRead(QList list, YACReaderComicReadStatus read) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - foreach (QModelIndex mi, list) { - if (read == YACReader::Read) { - _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(true)); - ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); - c.info.read = true; - DBHelper::update(&(c.info), db); - } - if (read == YACReader::Unread) { - _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(false)); - _data.value(mi.row())->setData(ComicModel::CurrentPage, QVariant(1)); - _data.value(mi.row())->setData(ComicModel::HasBeenOpened, QVariant(false)); - ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); - c.info.read = false; - c.info.currentPage = 1; - c.info.hasBeenOpened = false; - DBHelper::update(&(c.info), db); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); + foreach (QModelIndex mi, list) { + if (read == YACReader::Read) { + _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(true)); + ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); + c.info.read = true; + DBHelper::update(&(c.info), db); + } + if (read == YACReader::Unread) { + _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(false)); + _data.value(mi.row())->setData(ComicModel::CurrentPage, QVariant(1)); + _data.value(mi.row())->setData(ComicModel::HasBeenOpened, QVariant(false)); + ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); + c.info.read = false; + c.info.currentPage = 1; + c.info.hasBeenOpened = false; + c.info.lastTimeOpened.setValue(QVariant()); + DBHelper::update(&(c.info), db); + } } + db.commit(); + connectionName = db.connectionName(); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); emit dataChanged(index(list.first().row(), ComicModel::ReadColumn), index(list.last().row(), ComicModel::HasBeenOpened), QVector() << ReadColumnRole << CurrentPageRole << HasBeenOpenedRole); @@ -821,23 +813,25 @@ QVector ComicModel::setComicsRead(QList l } qint64 ComicModel::asignNumbers(QList list, int startingNumber) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - qint64 idFirst = _data.value(list[0].row())->data(ComicModel::Id).toULongLong(); - int i = 0; - foreach (QModelIndex mi, list) { - ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); - c.info.number = startingNumber + i; - c.info.edited = true; - DBHelper::update(&(c.info), db); - i++; + qint64 idFirst; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); + idFirst = _data.value(list[0].row())->data(ComicModel::Id).toULongLong(); + int i = 0; + foreach (QModelIndex mi, list) { + ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db); + c.info.number = startingNumber + i; + c.info.edited = true; + DBHelper::update(&(c.info), db); + i++; + } + db.commit(); + connectionName = db.connectionName(); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); - - //emit dataChanged(index(0,ComicModel::Number),index(_data.count()-1,ComicModel::HasBeenOpened)); + QSqlDatabase::removeDatabase(connectionName); return idFirst; } @@ -867,19 +861,22 @@ QList ComicModel::getIndexesFromIds(const QList &comicI void ComicModel::startTransaction() { - dbTransaction = DataBaseManagement::loadDatabase(_databasePath); + auto dbTransaction = DataBaseManagement::loadDatabase(_databasePath); + _databaseConnection = dbTransaction.connectionName(); dbTransaction.transaction(); } void ComicModel::finishTransaction() { - dbTransaction.commit(); - dbTransaction.close(); - QSqlDatabase::removeDatabase(dbTransaction.connectionName()); + { + QSqlDatabase::database(_databaseConnection).commit(); + } + QSqlDatabase::removeDatabase(_databaseConnection); } void ComicModel::removeInTransaction(int row) { + auto dbTransaction = QSqlDatabase::database(_databaseConnection); ComicDB c = DBHelper::loadComic(_data.at(row)->data(ComicModel::Id).toULongLong(), dbTransaction); DBHelper::removeFromDB(&c, dbTransaction); @@ -890,27 +887,6 @@ void ComicModel::removeInTransaction(int row) endRemoveRows(); } -/* -void ComicModel::remove(ComicDB * comic, int row) -{ - beginRemoveRows(QModelIndex(),row,row); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::removeFromDB(comic,db); - - removeRow(row); - delete _data.at(row); - _data.removeAt(row); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); - endRemoveRows(); -} -*/ -/*ComicDB TableModel::getComic(int row) -{ - return getComic(index(row,0)); -}*/ void ComicModel::remove(int row) { @@ -938,17 +914,18 @@ void ComicModel::reload(const ComicDB &comic) void ComicModel::resetComicRating(const QModelIndex &mi) { ComicDB comic = getComic(mi); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - comic.info.rating = 0; - _data[mi.row()]->setData(ComicModel::Rating, 0); - DBHelper::update(&(comic.info), db); - - emit dataChanged(mi, mi); + comic.info.rating = 0; + _data[mi.row()]->setData(ComicModel::Rating, 0); + DBHelper::update(&(comic.info), db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + emit dataChanged(mi, mi); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } QUrl ComicModel::getCoverUrlPathForComicHash(const QString &hash) const @@ -964,13 +941,14 @@ void ComicModel::addComicsToFavorites(const QList &comicIds) void ComicModel::addComicsToFavorites(const QList &comicsList) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::insertComicsInFavorites(comics, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::insertComicsInFavorites(comics, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void ComicModel::addComicsToLabel(const QList &comicIds, qulonglong labelId) @@ -981,13 +959,14 @@ void ComicModel::addComicsToLabel(const QList &comicIds, qulonglong void ComicModel::addComicsToLabel(const QList &comicsList, qulonglong labelId) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::insertComicsInLabel(comics, labelId, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::insertComicsInLabel(comics, labelId, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void ComicModel::addComicsToReadingList(const QList &comicIds, qulonglong readingListId) @@ -998,25 +977,27 @@ void ComicModel::addComicsToReadingList(const QList &comicIds, qulon void ComicModel::addComicsToReadingList(const QList &comicsList, qulonglong readingListId) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::insertComicsInReadingList(comics, readingListId, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::insertComicsInReadingList(comics, readingListId, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void ComicModel::deleteComicsFromFavorites(const QList &comicsList) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::deleteComicsFromFavorites(comics, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::deleteComicsFromFavorites(comics, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); if (mode == Favorites) deleteComicsFromModel(comicsList); @@ -1025,13 +1006,14 @@ void ComicModel::deleteComicsFromFavorites(const QList &comicsList) void ComicModel::deleteComicsFromLabel(const QList &comicsList, qulonglong labelId) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::deleteComicsFromLabel(comics, labelId, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::deleteComicsFromLabel(comics, labelId, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); deleteComicsFromModel(comicsList); } @@ -1039,13 +1021,14 @@ void ComicModel::deleteComicsFromLabel(const QList &comicsList, qul void ComicModel::deleteComicsFromReadingList(const QList &comicsList, qulonglong readingListId) { QList comics = getComics(comicsList); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - DBHelper::deleteComicsFromReadingList(comics, readingListId, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::deleteComicsFromReadingList(comics, readingListId, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); deleteComicsFromModel(comicsList); } @@ -1068,13 +1051,14 @@ void ComicModel::deleteComicsFromModel(const QList &comicsList) bool ComicModel::isFavorite(const QModelIndex &index) { bool isFavorite; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - isFavorite = DBHelper::isFavoriteComic(_data[index.row()]->data(Id).toLongLong(), db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + isFavorite = DBHelper::isFavoriteComic(_data[index.row()]->data(Id).toLongLong(), db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return isFavorite; } @@ -1082,16 +1066,17 @@ bool ComicModel::isFavorite(const QModelIndex &index) void ComicModel::updateRating(int rating, QModelIndex mi) { ComicDB comic = getComic(mi); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + //TODO optimize update - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - //TODO optimize update - - comic.info.rating = rating; - _data[mi.row()]->setData(ComicModel::Rating, rating); - DBHelper::update(&(comic.info), db); - - emit dataChanged(mi, mi); + comic.info.rating = rating; + _data[mi.row()]->setData(ComicModel::Rating, rating); + DBHelper::update(&(comic.info), db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + emit dataChanged(mi, mi); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } diff --git a/YACReaderLibrary/db/comic_model.h b/YACReaderLibrary/db/comic_model.h index d3ee01e0b..263eaa43c 100644 --- a/YACReaderLibrary/db/comic_model.h +++ b/YACReaderLibrary/db/comic_model.h @@ -150,8 +150,7 @@ public slots: QList _data; QString _databasePath; - - QSqlDatabase dbTransaction; + QString _databaseConnection; bool enableResorting; Mode mode; diff --git a/YACReaderLibrary/db/data_base_management.cpp b/YACReaderLibrary/db/data_base_management.cpp index 74c1c085e..eb7606dee 100644 --- a/YACReaderLibrary/db/data_base_management.cpp +++ b/YACReaderLibrary/db/data_base_management.cpp @@ -97,13 +97,10 @@ QSqlDatabase DataBaseManagement::loadDatabase(QString path) QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", path + threadId); db.setDatabaseName(path + "/library.ydb"); if (!db.open()) { - //se devuelve una base de datos vacía e inválida - return QSqlDatabase(); } QSqlQuery pragma("PRAGMA foreign_keys = ON", db); - //pragma.finish(); - //devuelve la base de datos + return db; } @@ -118,11 +115,8 @@ QSqlDatabase DataBaseManagement::loadDatabaseFromFile(QString filePath) return QSqlDatabase(); } - { - QSqlQuery pragma("PRAGMA foreign_keys = ON", db); - } - //pragma.finish(); - //devuelve la base de datos + QSqlQuery pragma("PRAGMA foreign_keys = ON", db); + return db; } @@ -324,46 +318,34 @@ bool DataBaseManagement::createV8Tables(QSqlDatabase &database) void DataBaseManagement::exportComicsInfo(QString source, QString dest) { - //QSqlDatabase sourceDB = loadDatabase(source); - QSqlDatabase destDB = loadDatabaseFromFile(dest); - //sourceDB.open(); + QString connectionName = ""; { + QSqlDatabase destDB = loadDatabaseFromFile(dest); + QSqlQuery attach(destDB); attach.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(dest) + "' AS dest;"); - //attach.bindValue(":dest",QDir().toNativeSeparators(dest)); attach.exec(); - //attach.finish(); QSqlQuery attach2(destDB); attach2.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(source) + "' AS source;"); attach2.exec(); - //attach2.finish(); - //sourceDB.close(); QSqlQuery queryDBInfo(destDB); queryDBInfo.prepare("CREATE TABLE dest.db_info (version TEXT NOT NULL)"); queryDBInfo.exec(); - //queryDBInfo.finish(); - - /*QSqlQuery queryComicsInfo(sourceDB); - queryComicsInfo.prepare("CREATE TABLE dest.comic_info (id INTEGER PRIMARY KEY, hash TEXT NOT NULL, edited BOOLEAN DEFAULT FALSE, title TEXT, read BOOLEAN)"); - queryComicsInfo.exec();*/ QSqlQuery query("INSERT INTO dest.db_info (version) " "VALUES ('" VERSION "')", destDB); - //query.finish(); QSqlQuery exportData(destDB); exportData.prepare("create table dest.comic_info as select " + fields + " from source.comic_info where source.comic_info.edited = 1"); exportData.exec(); - //exportData.finish(); + connectionName = destDB.connectionName(); } - //sourceDB.close(); - destDB.close(); - QSqlDatabase::removeDatabase(dest); + QSqlDatabase::removeDatabase(connectionName); } bool DataBaseManagement::importComicsInfo(QString source, QString dest) @@ -374,10 +356,13 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest) bool b = false; - QSqlDatabase sourceDB = loadDatabaseFromFile(source); - QSqlDatabase destDB = loadDatabaseFromFile(dest); + QString sourceDBconnection = ""; + QString destDBconnection = ""; { + QSqlDatabase sourceDB = loadDatabaseFromFile(source); + QSqlDatabase destDB = loadDatabaseFromFile(dest); + QSqlQuery pragma("PRAGMA synchronous=OFF", destDB); QSqlQuery newInfo(sourceDB); @@ -538,31 +523,30 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest) insert.exec(); } - //update.finish(); - //insert.finish(); } - } - destDB.commit(); - QString hash; - foreach (hash, hashes) { - QSqlQuery getComic(destDB); - getComic.prepare("SELECT c.path,ci.coverPage FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) where ci.hash = :hash"); - getComic.bindValue(":hash", hash); - getComic.exec(); - if (getComic.next()) { - QString basePath = QString(dest).remove("/.yacreaderlibrary/library.ydb"); - QString path = basePath + getComic.record().value("path").toString(); - int coverPage = getComic.record().value("coverPage").toInt(); - ThumbnailCreator tc(path, basePath + "/.yacreaderlibrary/covers/" + hash + ".jpg", coverPage); - tc.create(); + destDB.commit(); + QString hash; + foreach (hash, hashes) { + QSqlQuery getComic(destDB); + getComic.prepare("SELECT c.path,ci.coverPage FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) where ci.hash = :hash"); + getComic.bindValue(":hash", hash); + getComic.exec(); + if (getComic.next()) { + QString basePath = QString(dest).remove("/.yacreaderlibrary/library.ydb"); + QString path = basePath + getComic.record().value("path").toString(); + int coverPage = getComic.record().value("coverPage").toInt(); + ThumbnailCreator tc(path, basePath + "/.yacreaderlibrary/covers/" + hash + ".jpg", coverPage); + tc.create(); + } } + sourceDBconnection = sourceDB.connectionName(); + destDBconnection = sourceDB.connectionName(); } - destDB.close(); - sourceDB.close(); - QSqlDatabase::removeDatabase(source); - QSqlDatabase::removeDatabase(dest); + QSqlDatabase::removeDatabase(sourceDBconnection); + QSqlDatabase::removeDatabase(destDBconnection); + return b; } //TODO fix these bindings @@ -666,19 +650,23 @@ void DataBaseManagement::bindDouble(const QString &name, const QSqlRecord &recor QString DataBaseManagement::checkValidDB(const QString &fullPath) { - QSqlDatabase db = loadDatabaseFromFile(fullPath); QString versionString = ""; - if (db.isValid() && db.isOpen()) { - QSqlQuery version(db); - version.prepare("SELECT * FROM db_info"); - version.exec(); + QString connectionName = ""; + { + QSqlDatabase db = loadDatabaseFromFile(fullPath); + + if (db.isValid() && db.isOpen()) { + QSqlQuery version(db); + version.prepare("SELECT * FROM db_info"); + version.exec(); - if (version.next()) - versionString = version.record().value("version").toString(); + if (version.next()) + versionString = version.record().value("version").toString(); + } + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return versionString; } @@ -731,116 +719,120 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path) if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.5.0") < 0) pre9_5 = true; - QSqlDatabase db = loadDatabaseFromFile(fullPath); + QString connectionName = ""; bool returnValue = false; - if (db.isValid() && db.isOpen()) { - QSqlQuery updateVersion(db); - updateVersion.prepare("UPDATE db_info SET " - "version = :version"); - updateVersion.bindValue(":version", VERSION); - updateVersion.exec(); - - if (updateVersion.numRowsAffected() > 0) - returnValue = true; - - if (pre7) //TODO: execute only if previous version was < 7.0 - { - //new 7.0 fields - QStringList columnDefs; - columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0" - << "rating INTEGER DEFAULT 0" - << "currentPage INTEGER DEFAULT 1" - << "bookmark1 INTEGER DEFAULT -1" - << "bookmark2 INTEGER DEFAULT -1" - << "bookmark3 INTEGER DEFAULT -1" - << "brightness INTEGER DEFAULT -1" - << "contrast INTEGER DEFAULT -1" - << "gamma INTEGER DEFAULT -1"; - - bool successAddingColumns = addColumns("comic_info", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } - //TODO update hasBeenOpened value - if (pre7_1) { + { + QSqlDatabase db = loadDatabaseFromFile(fullPath); + if (db.isValid() && db.isOpen()) { + QSqlQuery updateVersion(db); + updateVersion.prepare("UPDATE db_info SET " + "version = :version"); + updateVersion.bindValue(":version", VERSION); + updateVersion.exec(); + + if (updateVersion.numRowsAffected() > 0) + returnValue = true; + + if (pre7) //TODO: execute only if previous version was < 7.0 { + //new 7.0 fields QStringList columnDefs; - columnDefs << "finished BOOLEAN DEFAULT 0" - << "completed BOOLEAN DEFAULT 1"; - bool successAddingColumns = addColumns("folder", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } + columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0" + << "rating INTEGER DEFAULT 0" + << "currentPage INTEGER DEFAULT 1" + << "bookmark1 INTEGER DEFAULT -1" + << "bookmark2 INTEGER DEFAULT -1" + << "bookmark3 INTEGER DEFAULT -1" + << "brightness INTEGER DEFAULT -1" + << "contrast INTEGER DEFAULT -1" + << "gamma INTEGER DEFAULT -1"; - { //comic_info - QStringList columnDefs; - columnDefs << "comicVineID TEXT DEFAULT NULL"; bool successAddingColumns = addColumns("comic_info", columnDefs, db); returnValue = returnValue && successAddingColumns; } - } + //TODO update hasBeenOpened value + + if (pre7_1) { + { + QStringList columnDefs; + columnDefs << "finished BOOLEAN DEFAULT 0" + << "completed BOOLEAN DEFAULT 1"; + bool successAddingColumns = addColumns("folder", columnDefs, db); + returnValue = returnValue && successAddingColumns; + } - if (pre8) { - bool successCreatingNewTables = createV8Tables(db); - returnValue = returnValue && successCreatingNewTables; - } + { //comic_info + QStringList columnDefs; + columnDefs << "comicVineID TEXT DEFAULT NULL"; + bool successAddingColumns = addColumns("comic_info", columnDefs, db); + returnValue = returnValue && successAddingColumns; + } + } - if (pre9_5) { - { //folder - QStringList columnDefs; - //a full library update is needed after updating the table - columnDefs << "numChildren INTEGER"; - columnDefs << "firstChildHash TEXT"; - columnDefs << "customImage TEXT"; - bool successAddingColumns = addColumns("folder", columnDefs, db); - returnValue = returnValue && successAddingColumns; + if (pre8) { + bool successCreatingNewTables = createV8Tables(db); + returnValue = returnValue && successCreatingNewTables; } - { //comic_info - QStringList columnDefs; - columnDefs << "lastTimeOpened INTEGER"; - columnDefs << "coverSizeRatio REAL"; - columnDefs << "originalCoverSize TEXT"; - bool successAddingColumns = addColumns("comic_info", columnDefs, db); - returnValue = returnValue && successAddingColumns; + if (pre9_5) { + { //folder + QStringList columnDefs; + //a full library update is needed after updating the table + columnDefs << "numChildren INTEGER"; + columnDefs << "firstChildHash TEXT"; + columnDefs << "customImage TEXT"; + bool successAddingColumns = addColumns("folder", columnDefs, db); + returnValue = returnValue && successAddingColumns; + } - QSqlQuery queryIndexLastTimeOpened(db); - bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)"); - returnValue = returnValue && successCreatingIndex; - } + { //comic_info + QStringList columnDefs; + columnDefs << "lastTimeOpened INTEGER"; + columnDefs << "coverSizeRatio REAL"; + columnDefs << "originalCoverSize TEXT"; + bool successAddingColumns = addColumns("comic_info", columnDefs, db); + returnValue = returnValue && successAddingColumns; + + QSqlQuery queryIndexLastTimeOpened(db); + bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)"); + returnValue = returnValue && successCreatingIndex; + } - //update folders info - { - DBHelper::updateChildrenInfo(db); - } + //update folders info + { + DBHelper::updateChildrenInfo(db); + } - { - QSqlQuery selectQuery(db); - selectQuery.prepare("SELECT id, hash FROM comic_info"); - selectQuery.exec(); + { + QSqlQuery selectQuery(db); + selectQuery.prepare("SELECT id, hash FROM comic_info"); + selectQuery.exec(); - db.transaction(); + db.transaction(); - QSqlQuery updateCoverInfo(db); - updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id"); + QSqlQuery updateCoverInfo(db); + updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id"); - QImageReader thumbnail; - while (selectQuery.next()) { - thumbnail.setFileName(path % "/covers/" % selectQuery.value(1).toString() % ".jpg"); + QImageReader thumbnail; + while (selectQuery.next()) { + thumbnail.setFileName(path % "/covers/" % selectQuery.value(1).toString() % ".jpg"); - float coverSizeRatio = static_cast(thumbnail.size().width()) / thumbnail.size().height(); - updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio); - updateCoverInfo.bindValue(":id", selectQuery.value(0)); + float coverSizeRatio = static_cast(thumbnail.size().width()) / thumbnail.size().height(); + updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio); + updateCoverInfo.bindValue(":id", selectQuery.value(0)); - updateCoverInfo.exec(); - } + updateCoverInfo.exec(); + } - db.commit(); + db.commit(); + } } } + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return returnValue; } diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index a789c3b3c..640462d7a 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -291,16 +291,17 @@ void FolderModel::setupModelData(QString path) //cargar la base de datos _databasePath = path; - QSqlDatabase db = DataBaseManagement::loadDatabase(path); //crear la consulta + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(path); QSqlQuery selectQuery("select * from folder where id <> 1 order by parentId,name", db); setupModelData(selectQuery, rootItem); + connectionName = db.connectionName(); } //selectQuery.finish(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); } @@ -407,38 +408,44 @@ void FolderModel::resetFilter() void FolderModel::updateFolderCompletedStatus(const QModelIndexList &list, bool status) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - foreach (QModelIndex mi, list) { - auto item = static_cast(mi.internalPointer()); - item->setData(FolderModel::Completed, status); - - Folder f = DBHelper::loadFolder(item->id, db); - f.setCompleted(status); - DBHelper::update(f, db); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); + foreach (QModelIndex mi, list) { + auto item = static_cast(mi.internalPointer()); + item->setData(FolderModel::Completed, status); + + Folder f = DBHelper::loadFolder(item->id, db); + f.setCompleted(status); + DBHelper::update(f, db); + } + db.commit(); + connectionName = db.connectionName(); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Completed)); } void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool status) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - foreach (QModelIndex mi, list) { - auto item = static_cast(mi.internalPointer()); - item->setData(FolderModel::Finished, status); - - Folder f = DBHelper::loadFolder(item->id, db); - f.setFinished(status); - DBHelper::update(f, db); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); + foreach (QModelIndex mi, list) { + auto item = static_cast(mi.internalPointer()); + item->setData(FolderModel::Finished, status); + + Folder f = DBHelper::loadFolder(item->id, db); + f.setFinished(status); + DBHelper::update(f, db); + } + db.commit(); + connectionName = db.connectionName(); } - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Completed)); } @@ -451,15 +458,17 @@ QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi) auto item = static_cast(mi.internalPointer()); id = item->id; } + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + db.transaction(); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - - result = DBHelper::loadSubfoldersNames(id, db); + result = DBHelper::loadSubfoldersNames(id, db); - db.commit(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + db.commit(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); //TODO sort result)) qSort(result.begin(), result.end(), naturalSortLessThanCI); @@ -481,55 +490,57 @@ void FolderModel::fetchMoreFromDB(const QModelIndex &parent) endRemoveRows(); } - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QList items; - QList nextLevelItems; + QList items; + QList nextLevelItems; - QSqlQuery selectQuery(db); - selectQuery.prepare("select * from folder where id <> 1 and parentId = :parentId order by parentId,name"); + QSqlQuery selectQuery(db); + selectQuery.prepare("select * from folder where id <> 1 and parentId = :parentId order by parentId,name"); - items << item; - bool firstLevelUpdated = false; - while (items.size() > 0) { - nextLevelItems.clear(); - foreach (FolderItem *item, items) { - QLOG_DEBUG() << "ID " << item->id; - selectQuery.bindValue(":parentId", item->id); + items << item; + bool firstLevelUpdated = false; + while (items.size() > 0) { + nextLevelItems.clear(); + foreach (FolderItem *item, items) { + QLOG_DEBUG() << "ID " << item->id; + selectQuery.bindValue(":parentId", item->id); - selectQuery.exec(); + selectQuery.exec(); - if (!firstLevelUpdated) { - //NO size support - int numResults = 0; - while (selectQuery.next()) - numResults++; + if (!firstLevelUpdated) { + //NO size support + int numResults = 0; + while (selectQuery.next()) + numResults++; - if (!selectQuery.seek(-1)) - selectQuery.exec(); - //END no size support + if (!selectQuery.seek(-1)) + selectQuery.exec(); + //END no size support - beginInsertRows(parent, 0, numResults - 1); - } + beginInsertRows(parent, 0, numResults - 1); + } - updateFolderModelData(selectQuery, item); + updateFolderModelData(selectQuery, item); - if (!firstLevelUpdated) { - endInsertRows(); - firstLevelUpdated = true; + if (!firstLevelUpdated) { + endInsertRows(); + firstLevelUpdated = true; + } + + nextLevelItems << item->children(); } - nextLevelItems << item->children(); + items.clear(); + items = nextLevelItems; } - - items.clear(); - items = nextLevelItems; + connectionName = db.connectionName(); } - QLOG_DEBUG() << "item->childCount()-1" << item->childCount() - 1; - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); } QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QModelIndex &parent) @@ -545,11 +556,14 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod newFolder.name = folderName; newFolder.parentId = parentItem->id; newFolder.path = parentItem->data(1).toString() + "/" + folderName; - - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - newFolder.id = DBHelper::insert(&newFolder, db); - DBHelper::updateChildrenInfo(parentItem->id, db); - QSqlDatabase::removeDatabase(db.connectionName()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + newFolder.id = DBHelper::insert(&newFolder, db); + DBHelper::updateChildrenInfo(parentItem->id, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); int destRow = 0; @@ -585,19 +599,27 @@ void FolderModel::deleteFolder(const QModelIndex &mi) Folder f; f.setId(item->id); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - DBHelper::removeFromDB(&f, db); - DBHelper::updateChildrenInfo(item->parent()->id, db); - QSqlDatabase::removeDatabase(db.connectionName()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + DBHelper::removeFromDB(&f, db); + DBHelper::updateChildrenInfo(item->parent()->id, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); endRemoveRows(); } void FolderModel::updateFolderChildrenInfo(qulonglong folderId) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - DBHelper::updateChildrenInfo(folderId, db); - QSqlDatabase::removeDatabase(db.connectionName()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + DBHelper::updateChildrenInfo(folderId, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } //PROXY @@ -658,10 +680,10 @@ void FolderModelProxy::setupFilteredModelData() auto model = static_cast(sourceModel()); - //cargar la base de datos - QSqlDatabase db = DataBaseManagement::loadDatabase(model->_databasePath); - //crear la consulta + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(model->_databasePath); + QSqlQuery selectQuery(db); //TODO check if (!includeComics) { selectQuery.prepare("select * from folder where id <> 1 and upper(name) like upper(:filter) order by parentId,name "); @@ -700,10 +722,9 @@ void FolderModelProxy::setupFilteredModelData() selectQuery.exec(); setupFilteredModelData(selectQuery, rootItem); + connectionName = db.connectionName(); } - //selectQuery.finish(); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endResetModel(); } diff --git a/YACReaderLibrary/db/reading_list_item.h b/YACReaderLibrary/db/reading_list_item.h index 8745c2126..a6849afd6 100644 --- a/YACReaderLibrary/db/reading_list_item.h +++ b/YACReaderLibrary/db/reading_list_item.h @@ -17,7 +17,7 @@ class ListItem QVariant data(int column) const; virtual qulonglong getId() const; QList itemData; - virtual ~ListItem() {} + virtual ~ListItem() { } }; //------------------------------------------------------ diff --git a/YACReaderLibrary/db/reading_list_model.cpp b/YACReaderLibrary/db/reading_list_model.cpp index ee38a5ccb..b1991d4de 100644 --- a/YACReaderLibrary/db/reading_list_model.cpp +++ b/YACReaderLibrary/db/reading_list_model.cpp @@ -372,69 +372,68 @@ void ReadingListModel::setupReadingListsData(QString path) void ReadingListModel::addNewLabel(const QString &name, YACReader::LabelColors color) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - qulonglong id = DBHelper::insertLabel(name, color, db); - - int newPos = addLabelIntoList(new LabelItem(QList() << name << YACReader::colorToName(color) << id << color)); - beginInsertRows(QModelIndex(), specialLists.count() + 1 + newPos + 1, specialLists.count() + 1 + newPos + 1); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + qulonglong id = DBHelper::insertLabel(name, color, db); - endInsertRows(); + int newPos = addLabelIntoList(new LabelItem(QList() << name << YACReader::colorToName(color) << id << color)); + beginInsertRows(QModelIndex(), specialLists.count() + 1 + newPos + 1, specialLists.count() + 1 + newPos + 1); - QSqlDatabase::removeDatabase(db.connectionName()); + endInsertRows(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void ReadingListModel::addReadingList(const QString &name) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - beginInsertRows(QModelIndex(), 0, 0); //TODO calculate the right coordinates before inserting - - qulonglong id = DBHelper::insertReadingList(name, db); - ReadingListItem *newItem; - rootItem->appendChild(newItem = new ReadingListItem(QList() - << name - << id - << false - << true - << 0)); - - items.insert(id, newItem); - - /*int pos = rootItem->children().indexOf(newItem); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + beginInsertRows(QModelIndex(), 0, 0); //TODO calculate the right coordinates before inserting - pos += specialLists.count()+1+labels.count()+labels.count()>0?1:0;*/ + qulonglong id = DBHelper::insertReadingList(name, db); + ReadingListItem *newItem; + rootItem->appendChild(newItem = new ReadingListItem(QList() + << name + << id + << false + << true + << 0)); - endInsertRows(); + items.insert(id, newItem); - QSqlDatabase::removeDatabase(db.connectionName()); + endInsertRows(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void ReadingListModel::addReadingListAt(const QString &name, const QModelIndex &mi) { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - beginInsertRows(mi, 0, 0); //TODO calculate the right coordinates before inserting - - auto readingListParent = static_cast(mi.internalPointer()); - qulonglong id = DBHelper::insertReadingSubList(name, mi.data(IDRole).toULongLong(), readingListParent->childCount(), db); - ReadingListItem *newItem; - - readingListParent->appendChild(newItem = new ReadingListItem(QList() - << name - << id - << false - << true - << readingListParent->childCount())); - - items.insert(id, newItem); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - /*int pos = readingListParent->children().indexOf(newItem); + beginInsertRows(mi, 0, 0); //TODO calculate the right coordinates before inserting - pos += specialLists.count()+1+labels.count()+labels.count()>0?1:0;*/ + auto readingListParent = static_cast(mi.internalPointer()); + qulonglong id = DBHelper::insertReadingSubList(name, mi.data(IDRole).toULongLong(), readingListParent->childCount(), db); + ReadingListItem *newItem; - endInsertRows(); + readingListParent->appendChild(newItem = new ReadingListItem(QList() + << name + << id + << false + << true + << readingListParent->childCount())); - QSqlDatabase::removeDatabase(db.connectionName()); + items.insert(id, newItem); + endInsertRows(); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } bool ReadingListModel::isEditable(const QModelIndex &mi) @@ -477,29 +476,31 @@ void ReadingListModel::rename(const QModelIndex &mi, const QString &name) { if (!isEditable(mi)) return; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + auto item = static_cast(mi.internalPointer()); - auto item = static_cast(mi.internalPointer()); + if (typeid(*item) == typeid(ReadingListItem)) { + auto rli = static_cast(item); + rli->setName(name); + DBHelper::renameList(item->getId(), name, db); - if (typeid(*item) == typeid(ReadingListItem)) { - auto rli = static_cast(item); - rli->setName(name); - DBHelper::renameList(item->getId(), name, db); - - if (rli->parent->getId() != 0) { - //TODO - //move row depending on the name - } else + if (rli->parent->getId() != 0) { + //TODO + //move row depending on the name + } else + emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); + } else if (typeid(*item) == typeid(LabelItem)) { + auto li = static_cast(item); + li->setName(name); + DBHelper::renameLabel(item->getId(), name, db); emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); - } else if (typeid(*item) == typeid(LabelItem)) { - auto li = static_cast(item); - li->setName(name); - DBHelper::renameLabel(item->getId(), name, db); - emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); + } + connectionName = db.connectionName(); } - - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); } void ReadingListModel::deleteItem(const QModelIndex &mi) @@ -507,28 +508,30 @@ void ReadingListModel::deleteItem(const QModelIndex &mi) if (isEditable(mi)) { QLOG_DEBUG() << "parent row :" << mi.parent().data() << "-" << mi.row(); beginRemoveRows(mi.parent(), mi.row(), mi.row()); - - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - auto item = static_cast(mi.internalPointer()); - - if (typeid(*item) == typeid(ReadingListItem)) { - auto rli = static_cast(item); - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - rli->parent->removeChild(rli); - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - DBHelper::removeListFromDB(item->getId(), db); - if (rli->parent->getId() != 0) { - reorderingChildren(rli->parent->children()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + + auto item = static_cast(mi.internalPointer()); + + if (typeid(*item) == typeid(ReadingListItem)) { + auto rli = static_cast(item); + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + rli->parent->removeChild(rli); + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + DBHelper::removeListFromDB(item->getId(), db); + if (rli->parent->getId() != 0) { + reorderingChildren(rli->parent->children()); + } + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + } else if (typeid(*item) == typeid(LabelItem)) { + auto li = static_cast(item); + labels.removeOne(li); + DBHelper::removeLabelFromDB(item->getId(), db); } - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - } else if (typeid(*item) == typeid(LabelItem)) { - auto li = static_cast(item); - labels.removeOne(li); - DBHelper::removeLabelFromDB(item->getId(), db); + connectionName = db.connectionName(); } - - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); endRemoveRows(); } @@ -705,10 +708,13 @@ void ReadingListModel::reorderingChildren(QList children) item->setOrdering(i++); childrenIds << item->getId(); } - - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - DBHelper::reasignOrderToSublists(childrenIds, db); - QSqlDatabase::removeDatabase(db.connectionName()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + DBHelper::reasignOrderToSublists(childrenIds, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } bool ReadingListModel::rowIsSpecialList(int row, const QModelIndex &parent) const diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index 124cb67bb..47fdc68c6 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -35,12 +35,15 @@ YACReaderLibraries DBHelper::getLibraries() QList DBHelper::getFolderSubfoldersFromLibrary(qulonglong libraryId, qulonglong folderId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - QList list = DBHelper::getFoldersFromParent(folderId, db, false); + QString connectionName = ""; + QList list; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + list = DBHelper::getFoldersFromParent(folderId, db, false); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return list; } QList DBHelper::getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId) @@ -51,42 +54,43 @@ QList DBHelper::getFolderComicsFromLibrary(qulonglong libraryId, QList DBHelper::getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId, bool sort) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - QList list = DBHelper::getComicsFromParent(folderId, db, sort); + QString connectionName = ""; + QList list; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + list = DBHelper::getComicsFromParent(folderId, db, sort); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return list; } quint32 DBHelper::getNumChildrenFromFolder(qulonglong libraryId, qulonglong folderId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - quint32 result = 0; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QSqlQuery selectQuery(db); selectQuery.prepare("SELECT count(*) FROM folder WHERE parentId = :parentId and id <> 1"); selectQuery.bindValue(":parentId", folderId); selectQuery.exec(); result += selectQuery.record().value(0).toULongLong(); - } - { - QSqlQuery selectQuery(db); selectQuery.prepare("SELECT count(*) FROM comic c WHERE c.parentId = :parentId"); selectQuery.bindValue(":parentId", folderId); selectQuery.exec(); result += selectQuery.record().value(0).toULongLong(); + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return result; } @@ -94,45 +98,57 @@ quint32 DBHelper::getNumChildrenFromFolder(qulonglong libraryId, qulonglong fold qulonglong DBHelper::getParentFromComicFolderId(qulonglong libraryId, qulonglong id) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QString connectionName = ""; + Folder f; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - Folder f = DBHelper::loadFolder(id, db); + f = DBHelper::loadFolder(id, db); + connectionName = db.connectionName(); + } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return f.parentId; } ComicDB DBHelper::getComicInfo(qulonglong libraryId, qulonglong id) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - ComicDB comic = DBHelper::loadComic(id, db); + QString connectionName = ""; + ComicDB comic; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + comic = DBHelper::loadComic(id, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); return comic; } QList DBHelper::getSiblings(qulonglong libraryId, qulonglong parentId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QString connectionName = ""; + QList comics; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + comics = DBHelper::getSortedComicsFromParent(parentId, db); + connectionName = db.connectionName(); + } - QList comics = DBHelper::getSortedComicsFromParent(parentId, db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return comics; } QString DBHelper::getFolderName(qulonglong libraryId, qulonglong id) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QString name = ""; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QSqlQuery selectQuery(db); //TODO check selectQuery.prepare("SELECT name FROM folder WHERE id = :id"); selectQuery.bindValue(":id", id); @@ -141,10 +157,10 @@ QString DBHelper::getFolderName(qulonglong libraryId, qulonglong id) if (selectQuery.next()) { name = selectQuery.value(0).toString(); } + connectionName = db.connectionName(); } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return name; } QList DBHelper::getLibrariesNames() @@ -161,11 +177,12 @@ QString DBHelper::getLibraryName(int id) QList DBHelper::getLabelComics(qulonglong libraryId, qulonglong labelId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QList list; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT c.id,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -190,11 +207,9 @@ QList DBHelper::getLabelComics(qulonglong libraryId, qulonglong labelId list.append(comic); } - - db.close(); + connectionName = db.connectionName(); } - //TODO ? - //QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return list; } @@ -202,13 +217,13 @@ QList DBHelper::getLabelComics(qulonglong libraryId, qulonglong labelId QList DBHelper::getFavorites(qulonglong libraryId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - QList list; const int FAV_ID = 1; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT c.id,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -234,10 +249,10 @@ QList DBHelper::getFavorites(qulonglong libraryId) list.append(comic); } - db.close(); + connectionName = db.connectionName(); } //TODO ? - //QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return list; } @@ -245,11 +260,11 @@ QList DBHelper::getFavorites(qulonglong libraryId) QList DBHelper::getReading(qulonglong libraryId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - QList list; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QSqlQuery selectQuery(db); selectQuery.prepare("SELECT c.id,c.parentId,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " @@ -272,11 +287,10 @@ QList DBHelper::getReading(qulonglong libraryId) list.append(comic); } - - db.close(); + connectionName = db.connectionName(); } //TODO ? - //QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return list; } @@ -284,35 +298,38 @@ QList DBHelper::getReading(qulonglong libraryId) QList DBHelper::getReadingLists(qulonglong libraryId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - + QString connectionName = ""; QList list; - QSqlQuery selectQuery("SELECT * from reading_list WHERE parentId IS NULL ORDER BY name DESC", db); + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + + QSqlQuery selectQuery("SELECT * from reading_list WHERE parentId IS NULL ORDER BY name DESC", db); - selectQuery.exec(); + selectQuery.exec(); - QSqlRecord record = selectQuery.record(); + QSqlRecord record = selectQuery.record(); - int name = record.indexOf("name"); - int id = record.indexOf("id"); - int ordering = record.indexOf("ordering"); + int name = record.indexOf("name"); + int id = record.indexOf("id"); + int ordering = record.indexOf("ordering"); - while (selectQuery.next()) { - ReadingList item(selectQuery.value(name).toString(), selectQuery.value(id).toLongLong(), selectQuery.value(ordering).toInt()); + while (selectQuery.next()) { + ReadingList item(selectQuery.value(name).toString(), selectQuery.value(id).toLongLong(), selectQuery.value(ordering).toInt()); - if (list.isEmpty()) { - list.append(item); - } else { - int i = 0; - while (i < list.length() && naturalSortLessThanCI(list.at(i).getName(), item.getName())) - i++; - list.insert(i, item); + if (list.isEmpty()) { + list.append(item); + } else { + int i = 0; + while (i < list.length() && naturalSortLessThanCI(list.at(i).getName(), item.getName())) + i++; + list.insert(i, item); + } } + connectionName = db.connectionName(); } - //TODO ? - //QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return list; } @@ -320,11 +337,11 @@ QList DBHelper::getReadingLists(qulonglong libraryId) QList DBHelper::getReadingListFullContent(qulonglong libraryId, qulonglong readingListId) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - QList list; + QString connectionName = ""; { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QList ids; ids << readingListId; @@ -364,10 +381,11 @@ QList DBHelper::getReadingListFullContent(qulonglong libraryId, qulongl list.append(comic); } } + connectionName = db.connectionName(); } //TODO ? - //QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); return list; } @@ -476,12 +494,13 @@ void DBHelper::update(ComicDB *comic, QSqlDatabase &db) void DBHelper::update(qulonglong libraryId, ComicInfo &comicInfo) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - DBHelper::update(&comicInfo, db); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + DBHelper::update(&comicInfo, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) @@ -680,32 +699,38 @@ void DBHelper::updateChildrenInfo(QSqlDatabase &db) void DBHelper::updateProgress(qulonglong libraryId, const ComicInfo &comicInfo) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - ComicDB comic = DBHelper::loadComic(comicInfo.id, db); - comic.info.currentPage = comicInfo.currentPage; - comic.info.hasBeenOpened = comicInfo.currentPage > 0 || comic.info.hasBeenOpened; - comic.info.read = comic.info.read || comic.info.currentPage == comic.info.numPages; + ComicDB comic = DBHelper::loadComic(comicInfo.id, db); + comic.info.currentPage = comicInfo.currentPage; + comic.info.hasBeenOpened = comicInfo.currentPage > 0 || comic.info.hasBeenOpened; + comic.info.read = comic.info.read || comic.info.currentPage == comic.info.numPages; - DBHelper::updateReadingRemoteProgress(comic.info, db); + DBHelper::updateReadingRemoteProgress(comic.info, db); - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + connectionName = db.connectionName(); + } + + QSqlDatabase::removeDatabase(connectionName); } void DBHelper::setComicAsReading(qulonglong libraryId, const ComicInfo &comicInfo) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - ComicDB comic = DBHelper::loadComic(comicInfo.id, db); - comic.info.hasBeenOpened = true; - comic.info.read = comic.info.read || comic.info.currentPage == comic.info.numPages; + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - DBHelper::updateReadingRemoteProgress(comic.info, db); + ComicDB comic = DBHelper::loadComic(comicInfo.id, db); + comic.info.hasBeenOpened = true; + comic.info.read = comic.info.read || comic.info.currentPage == comic.info.numPages; - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::updateReadingRemoteProgress(comic.info, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } void DBHelper::updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatabase &db) @@ -733,31 +758,33 @@ void DBHelper::updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatab void DBHelper::updateFromRemoteClient(qulonglong libraryId, const ComicInfo &comicInfo) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - ComicDB comic = DBHelper::loadComic(comicInfo.id, db); + ComicDB comic = DBHelper::loadComic(comicInfo.id, db); - if (comic.info.hash == comicInfo.hash) { - if (comicInfo.currentPage > 0) { - comic.info.currentPage = comicInfo.currentPage; + if (comic.info.hash == comicInfo.hash) { + if (comicInfo.currentPage > 0) { + comic.info.currentPage = comicInfo.currentPage; - if (comic.info.currentPage == comic.info.numPages) - comic.info.read = true; + if (comic.info.currentPage == comic.info.numPages) + comic.info.read = true; - comic.info.hasBeenOpened = true; + comic.info.hasBeenOpened = true; - if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) - comic.info.lastTimeOpened = comicInfo.lastTimeOpened; - } + if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) + comic.info.lastTimeOpened = comicInfo.lastTimeOpened; + } - if (comicInfo.rating > 0) - comic.info.rating = comicInfo.rating; + if (comicInfo.rating > 0) + comic.info.rating = comicInfo.rating; - DBHelper::updateReadingRemoteProgress(comic.info, db); + DBHelper::updateReadingRemoteProgress(comic.info, db); + } + connectionName = db.connectionName(); } - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); } void DBHelper::updateFromRemoteClientWithHash(const ComicInfo &comicInfo) @@ -765,91 +792,121 @@ void DBHelper::updateFromRemoteClientWithHash(const ComicInfo &comicInfo) YACReaderLibraries libraries = DBHelper::getLibraries(); QStringList names = libraries.getNames(); + QString connectionName = ""; foreach (QString name, names) { QString libraryPath = DBHelper::getLibraries().getPath(libraries.getId(name)); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - ComicInfo info = loadComicInfo(comicInfo.hash, db); - - if (!info.existOnDb) { - continue; - } + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + ComicInfo info = loadComicInfo(comicInfo.hash, db); - if (comicInfo.currentPage > 0) { - info.currentPage = comicInfo.currentPage; + if (!info.existOnDb) { + continue; + } - if (info.currentPage == info.numPages) - info.read = true; + if (comicInfo.currentPage > 0) { + info.currentPage = comicInfo.currentPage; - info.hasBeenOpened = true; + if (info.currentPage == info.numPages) + info.read = true; - if (info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) - info.lastTimeOpened = comicInfo.lastTimeOpened; - } + info.hasBeenOpened = true; - if (comicInfo.rating > 0) - info.rating = comicInfo.rating; + if (info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) + info.lastTimeOpened = comicInfo.lastTimeOpened; + } - DBHelper::update(&info, db); + if (comicInfo.rating > 0) + info.rating = comicInfo.rating; - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + DBHelper::update(&info, db); + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); } } -void DBHelper::updateFromRemoteClient(const QMap> &comics) +QMap> DBHelper::updateFromRemoteClient(const QMap> &comics) { + QMap> moreRecentComics; + foreach (qulonglong libraryId, comics.keys()) { + QList libraryMoreRecentComics; + QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - db.transaction(); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - QSqlQuery updateComicInfo(db); - updateComicInfo.prepare("UPDATE comic_info SET " - "read = :read, " - "currentPage = :currentPage, " - "hasBeenOpened = :hasBeenOpened, " - "lastTimeOpened = :lastTimeOpened, " - "rating = :rating" - " WHERE id = :id "); + db.transaction(); - foreach (ComicInfo comicInfo, comics[libraryId]) { - ComicDB comic = DBHelper::loadComic(comicInfo.id, db); + QSqlQuery updateComicInfo(db); + updateComicInfo.prepare("UPDATE comic_info SET " + "read = :read, " + "currentPage = :currentPage, " + "hasBeenOpened = :hasBeenOpened, " + "lastTimeOpened = :lastTimeOpened, " + "rating = :rating" + " WHERE id = :id "); - if (comic.info.hash == comicInfo.hash) { - if (comicInfo.currentPage > 0) { - comic.info.currentPage = comicInfo.currentPage; + foreach (ComicInfo comicInfo, comics[libraryId]) { + ComicDB comic = DBHelper::loadComic(comicInfo.id, db); + + if (comic.info.hash == comicInfo.hash) { + bool isMoreRecent = false; + + //completion takes precedence over lastTimeOpened, if we just want to synchronize the lastest status we should use only lastTimeOpened + if ((comic.info.currentPage > 1 && comic.info.currentPage > comicInfo.currentPage) || comic.info.hasBeenOpened || (comic.info.read && !comicInfo.read)) { + isMoreRecent = true; + } + + if (comic.info.lastTimeOpened.toULongLong() > 0 && comicInfo.lastTimeOpened.toULongLong() == 0) { + isMoreRecent = true; + } + + comic.info.currentPage = qMax(comic.info.currentPage, comicInfo.currentPage); if (comic.info.currentPage == comic.info.numPages) comic.info.read = true; - comic.info.hasBeenOpened = true; + comic.info.read = comic.info.read || comicInfo.read; - if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) + comic.info.hasBeenOpened = comic.info.hasBeenOpened || comicInfo.currentPage > 0; + + if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong() && comicInfo.lastTimeOpened.toULongLong() > 0) comic.info.lastTimeOpened = comicInfo.lastTimeOpened; - } - if (comicInfo.rating > 0) - comic.info.rating = comicInfo.rating; + if (comicInfo.rating > 0) + comic.info.rating = comicInfo.rating; - updateComicInfo.bindValue(":read", comic.info.read ? 1 : 0); - updateComicInfo.bindValue(":currentPage", comic.info.currentPage); - updateComicInfo.bindValue(":hasBeenOpened", comic.info.hasBeenOpened ? 1 : 0); - updateComicInfo.bindValue(":lastTimeOpened", QDateTime::currentMSecsSinceEpoch() / 1000); - updateComicInfo.bindValue(":id", comic.info.id); - updateComicInfo.bindValue(":rating", comic.info.rating); - updateComicInfo.exec(); + updateComicInfo.bindValue(":read", comic.info.read ? 1 : 0); + updateComicInfo.bindValue(":currentPage", comic.info.currentPage); + updateComicInfo.bindValue(":hasBeenOpened", comic.info.hasBeenOpened ? 1 : 0); + updateComicInfo.bindValue(":lastTimeOpened", comic.info.lastTimeOpened); + updateComicInfo.bindValue(":id", comic.info.id); + updateComicInfo.bindValue(":rating", comic.info.rating); + updateComicInfo.exec(); + + if (isMoreRecent) { + libraryMoreRecentComics.append(comic); + } + } } - } - db.commit(); + if (!libraryMoreRecentComics.isEmpty()) { + moreRecentComics[libraryId] = libraryMoreRecentComics; + } + + db.commit(); + connectionName = db.connectionName(); + } - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); } + + return moreRecentComics; } void DBHelper::updateFromRemoteClientWithHash(const QList &comics) @@ -860,56 +917,57 @@ void DBHelper::updateFromRemoteClientWithHash(const QList &comics) foreach (QString name, names) { QString libraryPath = DBHelper::getLibraries().getPath(libraries.getId(name)); + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + + db.transaction(); + + QSqlQuery updateComicInfo(db); + updateComicInfo.prepare("UPDATE comic_info SET " + "read = :read, " + "currentPage = :currentPage, " + "hasBeenOpened = :hasBeenOpened, " + "lastTimeOpened = :lastTimeOpened, " + "rating = :rating" + " WHERE id = :id "); + + foreach (ComicInfo comicInfo, comics) { + ComicInfo info = loadComicInfo(comicInfo.hash, db); + + if (!info.existOnDb) { + continue; + } - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - - db.transaction(); - - QSqlQuery updateComicInfo(db); - updateComicInfo.prepare("UPDATE comic_info SET " - "read = :read, " - "currentPage = :currentPage, " - "hasBeenOpened = :hasBeenOpened, " - "lastTimeOpened = :lastTimeOpened, " - "rating = :rating" - " WHERE id = :id "); - - foreach (ComicInfo comicInfo, comics) { - ComicInfo info = loadComicInfo(comicInfo.hash, db); - - if (!info.existOnDb) { - continue; - } + if (comicInfo.currentPage > 0) { + info.currentPage = comicInfo.currentPage; - if (comicInfo.currentPage > 0) { - info.currentPage = comicInfo.currentPage; + if (info.currentPage == info.numPages) + info.read = true; - if (info.currentPage == info.numPages) - info.read = true; + info.hasBeenOpened = true; - info.hasBeenOpened = true; + if (info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) + info.lastTimeOpened = comicInfo.lastTimeOpened; + } - if (info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) - info.lastTimeOpened = comicInfo.lastTimeOpened; - } + if (comicInfo.rating > 0) { + info.rating = comicInfo.rating; + } - if (comicInfo.rating > 0) { - info.rating = comicInfo.rating; + updateComicInfo.bindValue(":read", info.read ? 1 : 0); + updateComicInfo.bindValue(":currentPage", info.currentPage); + updateComicInfo.bindValue(":hasBeenOpened", info.hasBeenOpened ? 1 : 0); + updateComicInfo.bindValue(":lastTimeOpened", QDateTime::currentMSecsSinceEpoch() / 1000); + updateComicInfo.bindValue(":id", info.id); + updateComicInfo.bindValue(":rating", info.rating); + updateComicInfo.exec(); } - updateComicInfo.bindValue(":read", info.read ? 1 : 0); - updateComicInfo.bindValue(":currentPage", info.currentPage); - updateComicInfo.bindValue(":hasBeenOpened", info.hasBeenOpened ? 1 : 0); - updateComicInfo.bindValue(":lastTimeOpened", QDateTime::currentMSecsSinceEpoch() / 1000); - updateComicInfo.bindValue(":id", info.id); - updateComicInfo.bindValue(":rating", info.rating); - updateComicInfo.exec(); + db.commit(); + connectionName = db.connectionName(); } - - db.commit(); - - db.close(); - QSqlDatabase::removeDatabase(db.connectionName()); + QSqlDatabase::removeDatabase(connectionName); } } @@ -1405,47 +1463,48 @@ QList DBHelper::getComicsFromParent(qulonglong parentId, QSqlData QList