From c95bb79aa21129834e82a8d44ce9f65ceb91a96c Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Sat, 12 Dec 2015 11:36:22 +0300 Subject: [PATCH] [app] Tweaking book copy --- app/qml/BooksShelfItem.qml | 14 +++- app/src/BooksBook.cpp | 138 +++++++++++++++++++---------------- app/src/BooksBook.h | 12 ++- app/src/BooksBookModel.cpp | 2 +- app/src/BooksCoverWidget.cpp | 43 +++++++++-- app/src/BooksCoverWidget.h | 13 +++- app/src/BooksImportModel.cpp | 2 +- app/src/BooksItem.h | 4 +- app/src/BooksPageWidget.cpp | 2 +- app/src/BooksShelf.cpp | 39 ++++++---- app/src/BooksShelf.h | 8 +- app/src/BooksTaskQueue.cpp | 63 +++++++++++----- app/src/BooksTaskQueue.h | 7 +- 13 files changed, 230 insertions(+), 117 deletions(-) diff --git a/app/qml/BooksShelfItem.qml b/app/qml/BooksShelfItem.qml index 85be990..ca1578b 100644 --- a/app/qml/BooksShelfItem.qml +++ b/app/qml/BooksShelfItem.qml @@ -138,14 +138,24 @@ Item { ProgressCircle { id: progressIndicator - width: parent.width/2 + width: busyIndicator.width height: width - anchors.centerIn: parent + anchors.centerIn: busyIndicator opacity: (copying && !longCopyTimer.running && value > 0 && value < 1) ? 1 : 0 visible: opacity > 0 Behavior on opacity { FadeAnimation {} } } + BusyIndicator { + id: busyIndicator + size: BusyIndicatorSize.Medium + x: cover.x + cover.centerX - width/2 + y: cover.y + cover.centerY - height/2 + visible: opacity > 0 + running: copying && !longCopyTimer.running && (progressIndicator.value <= 0 || progressIndicator.value >= 1) + Behavior on opacity { enabled: false } + } + function withinDeleteButton(x, y) { return x >= deleteButton.x - deleteButton.margin && x < deleteButton.x + deleteButton.width + deleteButton.margin && diff --git a/app/src/BooksBook.cpp b/app/src/BooksBook.cpp index a2994e2..1835ec8 100644 --- a/app/src/BooksBook.cpp +++ b/app/src/BooksBook.cpp @@ -37,6 +37,7 @@ #include "BooksTextView.h" #include "BooksTextStyle.h" #include "BooksPaintContext.h" +#include "BooksUtil.h" #include "HarbourJson.h" #include "HarbourDebug.h" @@ -46,6 +47,7 @@ #include "bookmodel/BookModel.h" #include "library/Author.h" +#include #include #include #include @@ -132,15 +134,16 @@ bool BooksBook::CoverPaintContext::gotIt() const class BooksBook::CoverTask : public BooksTask { public: - CoverTask(QString aStateDir, shared_ptr aBook) : - iStateDir(aStateDir), iBook(aBook), iCoverMissing(false) {} + CoverTask(QString aStateDir, shared_ptr aBook, QString aImagePath) : + iStateDir(aStateDir), iBook(aBook), iImagePath(aImagePath), + iCoverMissing(false) {} bool hasImage() const; - QString cachedImagePath() const; public: QString iStateDir; shared_ptr iBook; + QString iImagePath; QImage iCoverImage; bool iCoverMissing; }; @@ -150,16 +153,6 @@ inline bool BooksBook::CoverTask::hasImage() const return iCoverImage.width() > 0 && iCoverImage.height() > 0; } -QString BooksBook::CoverTask::cachedImagePath() const -{ - if (!iStateDir.isEmpty()) { - return iStateDir + "/" + - QString::fromStdString(iBook->file().name(false)) + - BOOK_COVER_SUFFIX + "jpg"; - } - return QString(); -} - // ========================================================================== // BooksBook::LoadCoverTask // ========================================================================== @@ -168,8 +161,8 @@ class BooksBook::LoadCoverTask : public BooksBook::CoverTask { public: LoadCoverTask(QString aStateDir, shared_ptr aBook, - shared_ptr aFormatPlugin) : - BooksBook::CoverTask(aStateDir, aBook), + shared_ptr aFormatPlugin, QString aImagePath) : + BooksBook::CoverTask(aStateDir, aBook, aImagePath), iFormatPlugin(aFormatPlugin) {} virtual void performTask(); @@ -234,8 +227,8 @@ void BooksBook::LoadCoverTask::performTask() class BooksBook::GuessCoverTask : public BooksBook::CoverTask { public: - GuessCoverTask(QString aStateDir, shared_ptr aBook) : - BooksBook::CoverTask(aStateDir, aBook) {} + GuessCoverTask(QString aStateDir, shared_ptr aBook, QString aImagePath) : + BooksBook::CoverTask(aStateDir, aBook, aImagePath) {} virtual void performTask(); }; @@ -264,17 +257,16 @@ void BooksBook::GuessCoverTask::performTask() iCoverImage.width() << "as cover for" << iBook->title().c_str()); // Save the extracted image - QString coverPath(cachedImagePath()); - if (!coverPath.isEmpty()) { - QFileInfo file(coverPath); + if (!iImagePath.isEmpty()) { + QFileInfo file(iImagePath); QDir dir(file.dir()); if (!dir.mkpath(dir.absolutePath())) { HWARN("failed to create" << qPrintable(dir.absolutePath())); } - if (iCoverImage.save(coverPath)) { - HDEBUG("saved cover to" << qPrintable(coverPath)); + if (iCoverImage.save(iImagePath)) { + HDEBUG("saved cover to" << qPrintable(iImagePath)); } else { - HWARN("failed to save" << qPrintable(coverPath)); + HWARN("failed to save" << qPrintable(iImagePath)); } } } else if (isCanceled()) { @@ -285,12 +277,11 @@ void BooksBook::GuessCoverTask::performTask() // Create empty file. Guessing the cover image is an expensive task, // we don't want to do it every time the application is started. - QString coverPath(cachedImagePath()); - if (!coverPath.isEmpty() && + if (!iImagePath.isEmpty() && // Check if the book file still exists - the failure could've // been caused by the SD-card removal. QFile::exists(QString::fromStdString(iBook->file().path()))) { - QFile(coverPath).open(QIODevice::WriteOnly); + QFile(iImagePath).open(QIODevice::WriteOnly); } } } @@ -313,7 +304,7 @@ BooksBook::BooksBook(const BooksStorage& aStorage, QString aRelativePath, iRef(1), iStorage(aStorage), iBook(aBook), - iTaskQueue(BooksTaskQueue::instance()) + iTaskQueue(BooksTaskQueue::defaultQueue()) { init(); HASSERT(!iBook.isNull()); @@ -328,8 +319,10 @@ BooksBook::BooksBook(const BooksStorage& aStorage, QString aRelativePath, iAuthors += QString::fromStdString(authors[i]->name()); } if (iStorage.isValid()) { - iStateDir = iStorage.configDir().path() + "/" + aRelativePath; - iStateFilePath = iStateDir + "/" + iFileName + BOOKS_STATE_FILE_SUFFIX; + iStateDir = QDir::cleanPath(iStorage.configDir().path() + + QDir::separator() + aRelativePath); + iStateFilePath = QDir::cleanPath(iStateDir + + QDir::separator() + iFileName + BOOKS_STATE_FILE_SUFFIX); // Load the state QVariantMap state; if (HarbourJson::load(iStateFilePath, state)) { @@ -430,11 +423,6 @@ void BooksBook::setCopyingOut(bool aValue) } } -QImage BooksBook::coverImage() -{ - return iCoverImage; -} - bool BooksBook::hasCoverImage() const { return iCoverImage.width() > 0 && iCoverImage.height() > 0; @@ -453,7 +441,8 @@ bool BooksBook::requestCoverImage() if (!iBook.isNull() && !iFormatPlugin.isNull() && !iCoverTasksDone && !iCoverTask) { HDEBUG(iTitle); - iCoverTask = new LoadCoverTask(iStateDir, iBook, iFormatPlugin); + iCoverTask = new LoadCoverTask(iStateDir, iBook, iFormatPlugin, + cachedImagePath()); connect(iCoverTask, SIGNAL(done()), SLOT(onLoadCoverTaskDone())); iTaskQueue->submit(iCoverTask); Q_EMIT loadingCoverChanged(); @@ -492,7 +481,7 @@ void BooksBook::onLoadCoverTaskDone() iCoverTasksDone = true; Q_EMIT loadingCoverChanged(); } else { - iCoverTask = new GuessCoverTask(iStateDir, iBook); + iCoverTask = new GuessCoverTask(iStateDir, iBook, cachedImagePath()); connect(iCoverTask, SIGNAL(done()), SLOT(onGuessCoverTaskDone())); iTaskQueue->submit(iCoverTask); } @@ -501,22 +490,21 @@ void BooksBook::onLoadCoverTaskDone() void BooksBook::onGuessCoverTaskDone() { HDEBUG(iTitle); - - if (iCoverTask->iCoverMissing && !iCoverImage.isNull()) { - // This may happen after the book with custom cover has been moved - // between SD-card and the internal storage. Store the custom cover - // so that it doesn't get lost. This is a fairly rare situation. - QString coverPath(iCoverTask->cachedImagePath()); - if (!coverPath.isEmpty() && iCoverImage.save(coverPath)) { - HDEBUG("saved custom cover to" << qPrintable(coverPath)); - } - } - coverTaskDone(); iCoverTasksDone = true; Q_EMIT loadingCoverChanged(); } +QString BooksBook::cachedImagePath() const +{ + if (!iStateDir.isEmpty() && !iBook.isNull()) { + return QDir::cleanPath(iStateDir + QDir::separator() + + QString::fromStdString(iBook->file().name(false)) + + BOOK_COVER_SUFFIX "jpg"); + } + return QString(); +} + void BooksBook::saveState() { if (!iStateFilePath.isEmpty()) { @@ -551,6 +539,21 @@ void BooksBook::deleteFiles() } } +BooksBook* BooksBook::newBook(const BooksStorage& aStorage, QString aRelPath, + QString aFileName) +{ + shared_ptr ref = BooksUtil::bookFromFile( + QFileInfo(QDir(aStorage.fullPath(aRelPath)), aFileName). + absoluteFilePath()); + if (!ref.isNull()) { + BooksBook* book = new BooksBook(aStorage, aRelPath, ref); + book->moveToThread(qApp->thread()); + return book; + } else { + return NULL; + } +} + // NOTE: below methods are invoked on the worker thread bool BooksBook::makeLink(QString aDestPath) { @@ -574,21 +577,24 @@ bool BooksBook::makeLink(QString aDestPath) return false; } -bool BooksBook::copyTo(QDir aDestDir, CopyOperation* aOperation) +BooksItem* BooksBook::copyTo(const BooksStorage& aStorage, QString aRelPath, + CopyOperation* aOperation) { - QString destPath(QFileInfo(aDestDir, iFileName).absoluteFilePath()); - aDestDir.mkpath(aDestDir.path()); - if (!isCanceled(aOperation) && makeLink(destPath)) { - return true; + QDir destDir(aStorage.fullPath(aRelPath)); + destDir.mkpath(destDir.path()); + const QString absDestPath(QFileInfo(QDir(aStorage.fullPath(aRelPath)), + iFileName).absoluteFilePath()); + if (!isCanceled(aOperation) && makeLink(absDestPath)) { + return newBook(aStorage, aRelPath, iFileName); } else if (isCanceled(aOperation)) { - return true; + return NULL; } else { - bool success = false; + BooksBook* copy = NULL; QFile src(iPath); const qint64 total = src.size(); qint64 copied = 0; if (src.open(QIODevice::ReadOnly)) { - QFile dest(destPath); + QFile dest(absDestPath); if (dest.open(QIODevice::WriteOnly)) { QDateTime lastTime; const qint64 bufsiz = 0x1000; @@ -614,32 +620,40 @@ bool BooksBook::copyTo(QDir aDestDir, CopyOperation* aOperation) } } } - aOperation->copyProgressChanged(PROGRESS_PRECISION); delete [] buf; dest.close(); + aOperation->copyProgressChanged(PROGRESS_PRECISION); if (copied == total) { dest.setPermissions(BOOKS_FILE_PERMISSIONS); - success = true; HDEBUG(total << "bytes copied from"<< qPrintable(iPath) << - "to" << qPrintable(destPath)); + "to" << qPrintable(absDestPath)); + copy = newBook(aStorage, aRelPath, iFileName); + + // Copy cover image too + if (copy && !iCoverImage.isNull()) { + QString cover(copy->cachedImagePath()); + if (!cover.isEmpty() && iCoverImage.save(cover)) { + HDEBUG("copied cover to" << qPrintable(cover)); + } + } } else { if (isCanceled(aOperation)) { HDEBUG("copy" << qPrintable(iPath) << "to" << - qPrintable(destPath) << "cancelled"); + qPrintable(absDestPath) << "cancelled"); } else { HWARN(copied << "out of" << total << "bytes copied from" << qPrintable(iPath) << - "to" << qPrintable(destPath)); + "to" << qPrintable(absDestPath)); } dest.remove(); } } else { - HWARN("failed to open" << qPrintable(destPath)); + HWARN("failed to open" << qPrintable(absDestPath)); } src.close(); } else { HWARN("failed to open" << qPrintable(iPath)); } - return success; + return copy; } } diff --git a/app/src/BooksBook.h b/app/src/BooksBook.h index e334a5e..a1dc0a8 100644 --- a/app/src/BooksBook.h +++ b/app/src/BooksBook.h @@ -70,6 +70,9 @@ public: shared_ptr aBook); ~BooksBook(); + static BooksBook* newBook(const BooksStorage& aStorage, QString aRelPath, + QString aFileName); + QString title() const { return iTitle; } QString authors() const { return iAuthors; } BooksPos lastPos() const { return iLastPos; } @@ -82,8 +85,7 @@ public: bool requestCoverImage(); void cancelCoverRequest(); void setCoverImage(QImage aImage); - QImage coverImage(); - + QImage coverImage() const; void setCopyingOut(bool aValue); // BooksItem @@ -97,7 +99,8 @@ public: virtual QString path() const; virtual bool accessible() const; virtual void deleteFiles(); - virtual bool copyTo(QDir aDestDir, CopyOperation* aObserver); + virtual BooksItem* copyTo(const BooksStorage& aStorage, QString aRelPath, + CopyOperation* aObserver); Q_SIGNALS: void coverImageChanged(); @@ -115,6 +118,7 @@ private: void init(); bool coverTaskDone(); bool makeLink(QString aDestPath); + QString cachedImagePath() const; static bool isCanceled(CopyOperation* aOperation); private: @@ -141,5 +145,7 @@ QML_DECLARE_TYPE(BooksBook) inline bool BooksBook::isCanceled(CopyOperation* aObserver) { return aObserver && aObserver->isCanceled(); } +inline QImage BooksBook::coverImage() const + { return iCoverImage; } #endif // BOOKS_BOOK_H diff --git a/app/src/BooksBookModel.cpp b/app/src/BooksBookModel.cpp index eabfdb0..b6e363f 100644 --- a/app/src/BooksBookModel.cpp +++ b/app/src/BooksBookModel.cpp @@ -210,7 +210,7 @@ BooksBookModel::BooksBookModel(QObject* aParent) : iTask(NULL), iData(NULL), iData2(NULL), - iTaskQueue(BooksTaskQueue::instance()), + iTaskQueue(BooksTaskQueue::defaultQueue()), iTextStyle(BooksTextStyle::defaults()) { HDEBUG("created"); diff --git a/app/src/BooksCoverWidget.cpp b/app/src/BooksCoverWidget.cpp index ef00634..9a23380 100644 --- a/app/src/BooksCoverWidget.cpp +++ b/app/src/BooksCoverWidget.cpp @@ -198,7 +198,7 @@ void BooksCoverWidget::DefaultImage::release(QImage* aImage) BooksCoverWidget::BooksCoverWidget(QQuickItem* aParent) : QQuickPaintedItem(aParent), - iTaskQueue(BooksTaskQueue::instance()), + iTaskQueue(BooksTaskQueue::scaleQueue()), iScaleTask(NULL), iBook(NULL), iDefaultImage(NULL), @@ -234,7 +234,6 @@ void BooksCoverWidget::setBook(BooksBook* aBook) if (aBook) { (iBook = aBook)->retain(); iBook->requestCoverImage(); - iBookRef = iBook->bookRef(); iCoverImage = iBook->coverImage(); iTitle = iBook->title(); connect(iBook, @@ -246,7 +245,6 @@ void BooksCoverWidget::setBook(BooksBook* aBook) HDEBUG(iTitle); } else { iBook = NULL; - iBookRef.reset(); iCoverImage = QImage(); iTitle.clear(); HDEBUG(""); @@ -333,7 +331,7 @@ void BooksCoverWidget::onSizeChanged() bool BooksCoverWidget::empty() const { - return !iBook || !iBook->hasCoverImage() || iScaledImage.isNull(); + return iScaledImage.isNull(); } bool BooksCoverWidget::loading() const @@ -358,6 +356,7 @@ void BooksCoverWidget::scaleImage(bool aWasEmpty) HWARN("Failed to load" << qPrintable(path)); } } + if (iCoverImage.isNull()) { if (!iDefaultImage) iDefaultImage = DefaultImage::retain(); if (iDefaultImage) iCoverImage = *iDefaultImage; @@ -380,6 +379,8 @@ void BooksCoverWidget::scaleImage(bool aWasEmpty) iScaledImage = QImage(); } + updateCenter(); + if (aWasEmpty != empty()) { Q_EMIT emptyChanged(); } @@ -393,6 +394,7 @@ void BooksCoverWidget::onScaleTaskDone() iScaleTask->release(this); iScaleTask = NULL; update(); + updateCenter(); if (wasEmpty != empty()) { Q_EMIT emptyChanged(); } @@ -404,6 +406,8 @@ void BooksCoverWidget::paint(QPainter* aPainter) const qreal h = height(); if (w > 0 && h > 0) { qreal sw, sh; + + // This has to be consistent with updateCenter() if (!iScaledImage.isNull()) { sw = iScaledImage.width(); sh = iScaledImage.height(); @@ -412,7 +416,7 @@ void BooksCoverWidget::paint(QPainter* aPainter) sh = h; } - const int x = (w - sw)/2; + const int x = floor((w - sw)/2); const int y = h - sh; QPainterPath path; @@ -424,7 +428,7 @@ void BooksCoverWidget::paint(QPainter* aPainter) const qreal d = 2*iBorderRadius; w1 = qMin(w, qMax(sw, 2*d)) - iBorderWidth; h1 = qMin(h, qMax(sh, 3*d)) - iBorderWidth; - x1 = (w - w1)/2; + x1 = floor((w - w1)/2); y1 = h - h1 - iBorderWidth/2; const qreal x2 = x1 + w1 - d; @@ -439,7 +443,7 @@ void BooksCoverWidget::paint(QPainter* aPainter) } else { w1 = sw - iBorderWidth; h1 = sh - iBorderWidth; - x1 = (w - w1)/2; + x1 = floor((w - w1)/2); y1 = h - h1 - iBorderWidth/2; } @@ -461,3 +465,28 @@ void BooksCoverWidget::paint(QPainter* aPainter) } } } + +void BooksCoverWidget::updateCenter() +{ + const QPoint oldCenter(iCenter); + const qreal w = width(); + const qreal h = height(); + + // This has to be consistent with paint() + iCenter.setX(floor(w/2)); + if (iScaledImage.isNull()) { + iCenter.setY(floor(h/2)); + } else { + iCenter.setY(floor(h - iScaledImage.height()/2)); + } + + if (iCenter != oldCenter) { + Q_EMIT centerChanged(); + if (iCenter.x() != oldCenter.x()) { + Q_EMIT centerXChanged(); + } + if (iCenter.y() != oldCenter.y()) { + Q_EMIT centerYChanged(); + } + } +} diff --git a/app/src/BooksCoverWidget.h b/app/src/BooksCoverWidget.h index bc9529e..63ce0d4 100644 --- a/app/src/BooksCoverWidget.h +++ b/app/src/BooksCoverWidget.h @@ -57,6 +57,9 @@ class BooksCoverWidget: public QQuickPaintedItem Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged) Q_PROPERTY(QUrl defaultCover READ defaultCover WRITE setDefaultCover NOTIFY defaultCoverChanged) Q_PROPERTY(BooksBook* book READ book WRITE setBook NOTIFY bookChanged) + Q_PROPERTY(qreal centerX READ centerX NOTIFY centerXChanged) + Q_PROPERTY(qreal centerY READ centerY NOTIFY centerYChanged) + Q_PROPERTY(QPoint center READ center NOTIFY centerChanged) public: BooksCoverWidget(QQuickItem* aParent = NULL); @@ -86,6 +89,10 @@ public: bool synchronous() const { return iSynchronous; } void setSynchronous(bool aValue); + qreal centerX() const { return iCenter.x(); } + qreal centerY() const { return iCenter.y(); } + QPoint center() const { return iCenter; } + Q_SIGNALS: void bookChanged(); void emptyChanged(); @@ -96,6 +103,9 @@ Q_SIGNALS: void borderRadiusChanged(); void borderColorChanged(); void defaultCoverChanged(); + void centerXChanged(); + void centerYChanged(); + void centerChanged(); private Q_SLOTS: void onCoverImageChanged(); @@ -106,6 +116,7 @@ private: void paint(QPainter *painter); void scaleImage(bool aWasEmpty); void scaleImage() { scaleImage(empty()); } + void updateCenter(); private: class ScaleTask; @@ -114,7 +125,6 @@ private: ScaleTask* iScaleTask; QImage iScaledImage; QImage iCoverImage; - shared_ptr iBookRef; BooksBook* iBook; QImage* iDefaultImage; qreal iBorderWidth; @@ -122,6 +132,7 @@ private: QColor iBorderColor; QUrl iDefaultCover; QString iTitle; + QPoint iCenter; bool iStretch; bool iSynchronous; }; diff --git a/app/src/BooksImportModel.cpp b/app/src/BooksImportModel.cpp index 16b3e88..63b1ca4 100644 --- a/app/src/BooksImportModel.cpp +++ b/app/src/BooksImportModel.cpp @@ -278,7 +278,7 @@ BooksImportModel::BooksImportModel(QObject* aParent) : iProgress(0), iSelectedCount(0), iAutoRefresh(false), - iTaskQueue(BooksTaskQueue::instance()), + iTaskQueue(BooksTaskQueue::defaultQueue()), iTask(NULL) { iSelectedRole.append(BooksImportRoleSelected); diff --git a/app/src/BooksItem.h b/app/src/BooksItem.h index 1625d96..a78053b 100644 --- a/app/src/BooksItem.h +++ b/app/src/BooksItem.h @@ -35,6 +35,7 @@ #define BOOKS_ITEM_H #include "BooksTypes.h" +#include "BooksStorage.h" #include @@ -65,7 +66,8 @@ public: virtual QString path() const = 0; virtual bool accessible() const = 0; virtual void deleteFiles() = 0; - virtual bool copyTo(QDir aDestDir, CopyOperation* aOperation = NULL) = 0; + virtual BooksItem* copyTo(const BooksStorage& aStorage, QString aRelPath, + CopyOperation* aOperation = NULL) = 0; }; #endif // BOOKS_ITEM_H diff --git a/app/src/BooksPageWidget.cpp b/app/src/BooksPageWidget.cpp index 7ecf47d..6e9d5b0 100644 --- a/app/src/BooksPageWidget.cpp +++ b/app/src/BooksPageWidget.cpp @@ -158,7 +158,7 @@ void BooksPageWidget::RenderTask::performTask() BooksPageWidget::BooksPageWidget(QQuickItem* aParent) : QQuickPaintedItem(aParent), - iTaskQueue(BooksTaskQueue::instance()), + iTaskQueue(BooksTaskQueue::defaultQueue()), iTextStyle(BooksTextStyle::defaults()), iResizeTimer(new QTimer(this)), iModel(NULL), diff --git a/app/src/BooksShelf.cpp b/app/src/BooksShelf.cpp index b57fb9b..eee1a32 100644 --- a/app/src/BooksShelf.cpp +++ b/app/src/BooksShelf.cpp @@ -77,9 +77,12 @@ Q_SIGNALS: public: BooksShelf::Data* iDestData; + BooksStorage iDestStorage; + QString iDestRelPath; + QString iDestAbsPath; BooksItem* iSrcItem; + BooksItem* iDestItem; int iCopyProgress; - bool iSuccess; }; // ========================================================================== @@ -323,9 +326,12 @@ inline bool BooksShelf::Data::copyingOut() BooksShelf::CopyTask::CopyTask(BooksShelf::Data* aDestData, BooksItem* aSrcItem) : iDestData(aDestData), + iDestStorage(aDestData->iShelf->storage()), + iDestRelPath(aDestData->iShelf->relativePath()), + iDestAbsPath(iDestStorage.fullPath(iDestRelPath + "/" + aSrcItem->fileName())), iSrcItem(aSrcItem->retain()), - iCopyProgress(0), - iSuccess(false) + iDestItem(NULL), + iCopyProgress(0) { if (iDestData->iCopyTask) { iDestData->iCopyTask->release(iDestData->iShelf); @@ -341,6 +347,7 @@ BooksShelf::CopyTask::~CopyTask() { HASSERT(!iDestData); iSrcItem->release(); + if (iDestItem) iDestItem->release(); } inline QString BooksShelf::CopyTask::srcPath() const @@ -350,13 +357,12 @@ inline QString BooksShelf::CopyTask::srcPath() const inline QString BooksShelf::CopyTask::destPath() const { - return QFileInfo(iDestData->iShelf->path(), - iSrcItem->fileName()).absoluteFilePath(); + return iDestAbsPath; } void BooksShelf::CopyTask::performTask() { - iSuccess = iSrcItem->copyTo(QDir(iDestData->iShelf->path()), this); + iDestItem = iSrcItem->copyTo(iDestStorage, iDestRelPath, this); } bool BooksShelf::CopyTask::isCanceled() const @@ -470,7 +476,7 @@ BooksShelf::BooksShelf(QObject* aParent) : iEditMode(false), iRef(-1), iSaveTimer(new BooksSaveTimer(this)), - iTaskQueue(BooksTaskQueue::instance()) + iTaskQueue(BooksTaskQueue::defaultQueue()) { init(); connect(iSaveTimer, SIGNAL(save()), SLOT(saveState())); @@ -485,7 +491,7 @@ BooksShelf::BooksShelf(BooksStorage aStorage, QString aRelativePath) : iEditMode(false), iRef(1), iSaveTimer(NULL), - iTaskQueue(BooksTaskQueue::instance()) + iTaskQueue(BooksTaskQueue::defaultQueue()) { init(); // Refcounted BooksShelf objects are managed by C++ code @@ -1088,7 +1094,7 @@ void BooksShelf::onCopyTaskDone() if (task) { QString dest = task->destPath(); HDEBUG(qPrintable(task->srcPath()) << "->" << qPrintable(dest) << - "copy" << (task->iSuccess ? "done" : "FAILED")); + "copy" << (task->iDestItem ? "done" : "FAILED")); Data* data = task->iDestData; const int row = iList.indexOf(data); @@ -1099,15 +1105,15 @@ void BooksShelf::onCopyTaskDone() HASSERT(src); if (src) { src->retain(); - if (task->iSuccess) { - shared_ptr book = BooksUtil::bookFromFile(dest); - if (!book.isNull()) { - copy = new BooksBook(iStorage, iRelativePath, book); + if (task->iDestItem) { + copy = task->iDestItem->book(); + if (copy) { + copy->retain(); copy->setLastPos(src->lastPos()); copy->setCoverImage(src->coverImage()); copy->requestCoverImage(); } else { - HWARN("can't open copied book" << qPrintable(dest)); + HWARN("not a book:" << qPrintable(dest)); } } } @@ -1167,10 +1173,11 @@ void BooksShelf::deleteFiles() } } -bool BooksShelf::copyTo(QDir aDestDir, CopyOperation* aOperation) +BooksItem* BooksShelf::copyTo(const BooksStorage& aStorage, QString aRelPath, + CopyOperation* aObserver) { HWARN("copying folders is not implemented!!"); - return false; + return NULL; } QHash BooksShelf::roleNames() const diff --git a/app/src/BooksShelf.h b/app/src/BooksShelf.h index b7c2bc8..c7ddfc6 100644 --- a/app/src/BooksShelf.h +++ b/app/src/BooksShelf.h @@ -65,7 +65,7 @@ class BooksShelf: public QAbstractListModel, public BooksItem, public BooksLoadi Q_PROPERTY(int dummyItemIndex READ dummyItemIndex WRITE setDummyItemIndex NOTIFY dummyItemIndexChanged) Q_PROPERTY(BooksBook* book READ book CONSTANT) Q_PROPERTY(BooksShelf* shelf READ shelf CONSTANT) - Q_PROPERTY(QObject* storage READ storage CONSTANT) + Q_PROPERTY(QObject* storage READ storageObject CONSTANT) public: explicit BooksShelf(QObject* aParent = NULL); @@ -89,7 +89,8 @@ public: QString relativePath() const { return iRelativePath; } void setRelativePath(QString aPath); BooksBook* bookAt(int aIndex) const; - QObject* storage() { return &iStorage; } + QObject* storageObject() { return &iStorage; } + const BooksStorage& storage() const { return iStorage; } void setName(QString aName); bool editMode() const { return iEditMode; } @@ -120,7 +121,8 @@ public: virtual QString path() const; virtual bool accessible() const; virtual void deleteFiles(); - virtual bool copyTo(QDir aDestDir, CopyOperation* aOperation); + virtual BooksItem* copyTo(const BooksStorage& aStorage, QString aRelPath, + CopyOperation* aObserver); Q_SIGNALS: void loadingChanged(); diff --git a/app/src/BooksTaskQueue.cpp b/app/src/BooksTaskQueue.cpp index 0c9b277..53fb279 100644 --- a/app/src/BooksTaskQueue.cpp +++ b/app/src/BooksTaskQueue.cpp @@ -36,32 +36,61 @@ #include "HarbourDebug.h" -static weak_ptr booksTaskQueueInstance; +class BooksTaskQueue::Private { +public: + static weak_ptr gDefaultQueue; + static weak_ptr gScaleQueue; -shared_ptr BooksTaskQueue::instance() -{ - shared_ptr worker; - if (booksTaskQueueInstance.isNull()) { - booksTaskQueueInstance = (worker = new BooksTaskQueue()); - } else { - worker = booksTaskQueueInstance; + static BooksTaskQueue* newDefaultQueue() { return new BooksTaskQueue(1); } + static BooksTaskQueue* newScaleQueue() { return new BooksTaskQueue(2); } + + static void waitForDone(shared_ptr aQueue, int aMsecs) { + if (!aQueue.isNull()) { + aQueue->iPool->waitForDone(aMsecs); + } } - return worker; + + static void waitForDone(int aMsecs) { + waitForDone(gDefaultQueue, aMsecs); + waitForDone(gScaleQueue, aMsecs); + } + + static shared_ptr get(weak_ptr* aQueue, + BooksTaskQueue* (*aNewFunc)()) + { + shared_ptr queue; + if (aQueue->isNull()) { + *aQueue = (queue = aNewFunc()); + } else { + queue = *aQueue; + } + return queue; + } +}; + +weak_ptr BooksTaskQueue::Private::gDefaultQueue; +weak_ptr BooksTaskQueue::Private::gScaleQueue; + +shared_ptr BooksTaskQueue::defaultQueue() +{ + return Private::get(&Private::gDefaultQueue, Private::newDefaultQueue); } -BooksTaskQueue::BooksTaskQueue() : - iPool(new QThreadPool) +shared_ptr BooksTaskQueue::scaleQueue() { - HDEBUG("created"); - iPool->setMaxThreadCount(1); + return Private::get(&Private::gScaleQueue, Private::newScaleQueue); } void BooksTaskQueue::waitForDone(int aMsecs) { - shared_ptr worker = booksTaskQueueInstance; - if (!worker.isNull()) { - worker->iPool->waitForDone(aMsecs); - } + Private::waitForDone(aMsecs); +} + +BooksTaskQueue::BooksTaskQueue(int aMaxThreadCount) : + iPool(new QThreadPool) +{ + HDEBUG("created"); + iPool->setMaxThreadCount(aMaxThreadCount); } BooksTaskQueue::~BooksTaskQueue() diff --git a/app/src/BooksTaskQueue.h b/app/src/BooksTaskQueue.h index 9160f89..6c3f5a2 100644 --- a/app/src/BooksTaskQueue.h +++ b/app/src/BooksTaskQueue.h @@ -45,17 +45,20 @@ class BooksTaskQueue friend class shared_ptr_storage; public: - static shared_ptr instance(); + static shared_ptr defaultQueue(); + static shared_ptr scaleQueue(); static void waitForDone(int aMsecs = -1); void submit(BooksTask* aTask); void submit(BooksTask* aTask, QObject* aTarget, const char* aSlot); private: - BooksTaskQueue(); + BooksTaskQueue(int aMaxThreadCount); ~BooksTaskQueue(); private: + class Private; + friend class Private; QThreadPool* iPool; };