[app] Tweaking book copy
This commit is contained in:
parent
84b9b77523
commit
c95bb79aa2
13 changed files with 230 additions and 117 deletions
|
@ -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 &&
|
||||
|
|
|
@ -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 <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QDirIterator>
|
||||
|
@ -132,15 +134,16 @@ bool BooksBook::CoverPaintContext::gotIt() const
|
|||
class BooksBook::CoverTask : public BooksTask
|
||||
{
|
||||
public:
|
||||
CoverTask(QString aStateDir, shared_ptr<Book> aBook) :
|
||||
iStateDir(aStateDir), iBook(aBook), iCoverMissing(false) {}
|
||||
CoverTask(QString aStateDir, shared_ptr<Book> aBook, QString aImagePath) :
|
||||
iStateDir(aStateDir), iBook(aBook), iImagePath(aImagePath),
|
||||
iCoverMissing(false) {}
|
||||
|
||||
bool hasImage() const;
|
||||
QString cachedImagePath() const;
|
||||
|
||||
public:
|
||||
QString iStateDir;
|
||||
shared_ptr<Book> 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<Book> aBook,
|
||||
shared_ptr<FormatPlugin> aFormatPlugin) :
|
||||
BooksBook::CoverTask(aStateDir, aBook),
|
||||
shared_ptr<FormatPlugin> 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<Book> aBook) :
|
||||
BooksBook::CoverTask(aStateDir, aBook) {}
|
||||
GuessCoverTask(QString aStateDir, shared_ptr<Book> 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<Book> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@ public:
|
|||
shared_ptr<Book> 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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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("<none>");
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Book> iBookRef;
|
||||
BooksBook* iBook;
|
||||
QImage* iDefaultImage;
|
||||
qreal iBorderWidth;
|
||||
|
@ -122,6 +132,7 @@ private:
|
|||
QColor iBorderColor;
|
||||
QUrl iDefaultCover;
|
||||
QString iTitle;
|
||||
QPoint iCenter;
|
||||
bool iStretch;
|
||||
bool iSynchronous;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#define BOOKS_ITEM_H
|
||||
|
||||
#include "BooksTypes.h"
|
||||
#include "BooksStorage.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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> 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<int,QByteArray> BooksShelf::roleNames() const
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -36,32 +36,61 @@
|
|||
|
||||
#include "HarbourDebug.h"
|
||||
|
||||
static weak_ptr<BooksTaskQueue> booksTaskQueueInstance;
|
||||
class BooksTaskQueue::Private {
|
||||
public:
|
||||
static weak_ptr<BooksTaskQueue> gDefaultQueue;
|
||||
static weak_ptr<BooksTaskQueue> gScaleQueue;
|
||||
|
||||
shared_ptr<BooksTaskQueue> BooksTaskQueue::instance()
|
||||
{
|
||||
shared_ptr<BooksTaskQueue> 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<BooksTaskQueue> 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<BooksTaskQueue> get(weak_ptr<BooksTaskQueue>* aQueue,
|
||||
BooksTaskQueue* (*aNewFunc)())
|
||||
{
|
||||
shared_ptr<BooksTaskQueue> queue;
|
||||
if (aQueue->isNull()) {
|
||||
*aQueue = (queue = aNewFunc());
|
||||
} else {
|
||||
queue = *aQueue;
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
};
|
||||
|
||||
weak_ptr<BooksTaskQueue> BooksTaskQueue::Private::gDefaultQueue;
|
||||
weak_ptr<BooksTaskQueue> BooksTaskQueue::Private::gScaleQueue;
|
||||
|
||||
shared_ptr<BooksTaskQueue> BooksTaskQueue::defaultQueue()
|
||||
{
|
||||
return Private::get(&Private::gDefaultQueue, Private::newDefaultQueue);
|
||||
}
|
||||
|
||||
BooksTaskQueue::BooksTaskQueue() :
|
||||
iPool(new QThreadPool)
|
||||
shared_ptr<BooksTaskQueue> BooksTaskQueue::scaleQueue()
|
||||
{
|
||||
HDEBUG("created");
|
||||
iPool->setMaxThreadCount(1);
|
||||
return Private::get(&Private::gScaleQueue, Private::newScaleQueue);
|
||||
}
|
||||
|
||||
void BooksTaskQueue::waitForDone(int aMsecs)
|
||||
{
|
||||
shared_ptr<BooksTaskQueue> 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()
|
||||
|
|
|
@ -45,17 +45,20 @@ class BooksTaskQueue
|
|||
friend class shared_ptr_storage<BooksTaskQueue>;
|
||||
|
||||
public:
|
||||
static shared_ptr<BooksTaskQueue> instance();
|
||||
static shared_ptr<BooksTaskQueue> defaultQueue();
|
||||
static shared_ptr<BooksTaskQueue> 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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue