ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #00588
Re: [Merge] lp:~mzanetti/reminders-app/two-job-queues into lp:reminders-app
Review: Needs Fixing
Tested, looks good to me, just 3 small inline comments
Diff comments:
> === modified file 'src/app/qml/reminders.qml'
> --- src/app/qml/reminders.qml 2015-03-06 12:16:37 +0000
> +++ src/app/qml/reminders.qml 2015-03-08 21:00:47 +0000
> @@ -111,6 +111,7 @@
>
> function displayNote(note) {
> print("displayNote:", note.guid)
> + note.load(true);
> if (root.narrowMode) {
> print("creating noteview");
> var component = Qt.createComponent(Qt.resolvedUrl("ui/NotePage.qml"));
> @@ -127,6 +128,7 @@
> }
>
> function switchToEditMode(note) {
> + note.load(true)
> if (root.narrowMode) {
> if (pagestack.depth > 1) {
> pagestack.pop();
>
> === modified file 'src/app/qml/ui/NotesPage.qml'
> --- src/app/qml/ui/NotesPage.qml 2015-03-01 22:32:41 +0000
> +++ src/app/qml/ui/NotesPage.qml 2015-03-08 21:00:47 +0000
> @@ -177,6 +177,10 @@
> syncError: model.syncError
> conflicting: model.conflicting
>
> + Component.onCompleted: {
> + notes.note(model.guid).load(false);
> + }
> +
> onItemClicked: {
> if (!model.conflicting) {
> root.selectedNote = NotesStore.note(guid);
>
> === modified file 'src/libqtevernote/evernoteconnection.cpp'
> --- src/libqtevernote/evernoteconnection.cpp 2015-03-06 00:47:45 +0000
> +++ src/libqtevernote/evernoteconnection.cpp 2015-03-08 21:00:47 +0000
> @@ -153,11 +153,23 @@
> return;
> }
>
> - foreach (EvernoteJob *job, m_jobQueue) {
> - job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
> - job->deleteLater();
> - }
> - m_jobQueue.clear();
> + foreach (EvernoteJob *job, m_highPriorityJobQueue) {
> + job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
> + job->deleteLater();
> + }
> + m_highPriorityJobQueue.clear();
> +
> + foreach (EvernoteJob *job, m_mediumPriorityJobQueue) {
> + job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
> + job->deleteLater();
> + }
> + m_mediumPriorityJobQueue.clear();
> +
> + foreach (EvernoteJob *job, m_lowPriorityJobQueue) {
> + job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
> + job->deleteLater();
> + }
> + m_lowPriorityJobQueue.clear();
>
> m_errorMessage.clear();
> emit errorChanged();
> @@ -340,11 +352,38 @@
> return false;
> }
>
> -EvernoteJob* EvernoteConnection::findDuplicate(EvernoteJob *job)
> -{
> - foreach (EvernoteJob *queuedJob, m_jobQueue) {
> - // explicitly use custom operator==()
> - if (job->operator ==(queuedJob)) {
> +void EvernoteConnection::attachDuplicate(EvernoteJob *original, EvernoteJob *duplicate)
> +{
> + if (duplicate->originatingObject() && duplicate->originatingObject() != original->originatingObject()) {
> + duplicate->attachToDuplicate(m_currentJob);
> + }
> + connect(original, &EvernoteJob::jobFinished, duplicate, &EvernoteJob::deleteLater);
> +}
> +
> +EvernoteJob* EvernoteConnection::findExistingDuplicate(EvernoteJob *job)
> +{
> + qWarning(dcJobQueue) << "Length:"
Shouldn't be qCWarning?
> + << m_highPriorityJobQueue.count() + m_mediumPriorityJobQueue.count() + m_lowPriorityJobQueue.count()
> + << "(High:" << m_highPriorityJobQueue.count() << "Medium:" << m_mediumPriorityJobQueue.count() << "Low:" << m_lowPriorityJobQueue.count() << ")";
> +
> + foreach (EvernoteJob *queuedJob, m_highPriorityJobQueue) {
> + // explicitly use custom operator==()
> + if (job->operator ==(queuedJob)) {
> + qCDebug(dcJobQueue) << "Found duplicate in high priority queue";
> + return queuedJob;
> + }
> + }
> + foreach (EvernoteJob *queuedJob, m_mediumPriorityJobQueue) {
> + // explicitly use custom operator==()
> + if (job->operator ==(queuedJob)) {
> + qCDebug(dcJobQueue) << "Found duplicate in medium priority queue";
> + return queuedJob;
> + }
> + }
> + foreach (EvernoteJob *queuedJob, m_lowPriorityJobQueue) {
> + // explicitly use custom operator==()
> + if (job->operator ==(queuedJob)) {
> + qCDebug(dcJobQueue) << "Found duplicate in low priority queue";
> return queuedJob;
> }
> }
> @@ -359,26 +398,56 @@
> job->deleteLater();
> return;
> }
> - EvernoteJob *duplicate = findDuplicate(job);
> - if (duplicate) {
> - job->attachToDuplicate(duplicate);
> - connect(duplicate, &EvernoteJob::finished, job, &EvernoteJob::deleteLater);
> + if (m_currentJob && m_currentJob->operator ==(job)) {
> + qCDebug(dcJobQueue) << "Duplicate of new job request already running:" << job->toString();
> + if (m_currentJob->isFinished()) {
> + qCWarning(dcJobQueue) << "Job seems to be stuck in a loop. Deleting it:" << job->toString();
> + job->deleteLater();
> + } else {
> + attachDuplicate(m_currentJob, job);
> + }
> + return;
> + }
> + EvernoteJob *existingJob = findExistingDuplicate(job);
> + if (existingJob) {
> + qCDebug(dcJobQueue) << "Duplicate job already queued:" << job->toString();
> + attachDuplicate(existingJob, job);
> // reprioritze the repeated request
> - qCDebug(dcJobQueue) << "Duplicate job already queued:" << job->toString();
> if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {
> - qCDebug(dcJobQueue) << "Reprioritising duplicate job:" << job->toString();
> - duplicate->setJobPriority(job->jobPriority());
> - m_jobQueue.prepend(m_jobQueue.takeAt(m_jobQueue.indexOf(duplicate)));
> + qCDebug(dcJobQueue) << "Reprioritising duplicate job in high priority queue:" << job->toString();
> + existingJob->setJobPriority(job->jobPriority());
> + if (m_highPriorityJobQueue.contains(existingJob)) {
> + m_highPriorityJobQueue.prepend(m_highPriorityJobQueue.takeAt(m_highPriorityJobQueue.indexOf(existingJob)));
> + } else if (m_mediumPriorityJobQueue.contains(existingJob)){
> + m_highPriorityJobQueue.prepend(m_mediumPriorityJobQueue.takeAt(m_mediumPriorityJobQueue.indexOf(existingJob)));
> + } else {
> + m_highPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
> + }
> + } else if (job->jobPriority() == EvernoteJob::JobPriorityMedium){
> + if (m_mediumPriorityJobQueue.contains(existingJob)) {
> + qCDebug(dcJobQueue) << "Reprioritising duplicate job in medium priority queue:" << job->toString();
> + m_mediumPriorityJobQueue.prepend(m_mediumPriorityJobQueue.takeAt(m_mediumPriorityJobQueue.indexOf(existingJob)));
> + } else if (m_lowPriorityJobQueue.contains(existingJob)) {
> + m_mediumPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
> + }
> + } else if (job->jobPriority() == EvernoteJob::JobPriorityLow) {
> + if (m_lowPriorityJobQueue.contains(existingJob)) {
> + qCDebug(dcJobQueue) << "Reprioritising duplicate job in low priority queue:" << job->toString();
> + m_lowPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
> + }
> }
> } else {
> - connect(job, &EvernoteJob::finished, job, &EvernoteJob::deleteLater);
> - connect(job, &EvernoteJob::finished, this, &EvernoteConnection::startNextJob);
> + connect(job, &EvernoteJob::jobFinished, job, &EvernoteJob::deleteLater);
> + connect(job, &EvernoteJob::jobFinished, this, &EvernoteConnection::startNextJob);
> if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {
> - qCDebug(dcJobQueue) << "Prepending high priority job request:" << job->toString();
> - m_jobQueue.prepend(job);
> + qCDebug(dcJobQueue) << "Adding high priority job request:" << job->toString();
> + m_highPriorityJobQueue.prepend(job);
> + } else if (job->jobPriority() == EvernoteJob::JobPriorityMedium){
> + qCDebug(dcJobQueue) << "Adding medium priority job request:" << job->toString();
> + m_mediumPriorityJobQueue.prepend(job);
> } else {
> - qCDebug(dcJobQueue) << "Appending low priority job request:" << job->toString();
> - m_jobQueue.append(job);
> + qCDebug(dcJobQueue) << "Adding low priority job request:" << job->toString();
> + m_lowPriorityJobQueue.prepend(job);
> }
> startJobQueue();
> }
> @@ -401,16 +470,24 @@
>
> void EvernoteConnection::startJobQueue()
> {
> - if (m_jobQueue.isEmpty()) {
> - return;
> - }
> -
> if (m_currentJob) {
> return;
> }
>
> - m_currentJob = m_jobQueue.takeFirst();
> - qCDebug(dcJobQueue) << "Starting job:" << m_currentJob->toString();
> + if (!m_highPriorityJobQueue.isEmpty()) {
> + m_currentJob = m_highPriorityJobQueue.takeFirst();
> + } else if (!m_mediumPriorityJobQueue.isEmpty()){
> + m_currentJob = m_mediumPriorityJobQueue.takeFirst();
> + } else if (!m_lowPriorityJobQueue.isEmpty()){
> + m_currentJob = m_lowPriorityJobQueue.takeFirst();
> + }
> +
> + if (!m_currentJob) {
> + qCDebug(dcJobQueue) << "Queue empty. Nothing to do.";
> + return;
> + }
> +
> + qCDebug(dcJobQueue) << QString("Starting job (Priority: %1):").arg(m_currentJob->jobPriority()) << m_currentJob->toString();
> m_currentJob->start();
> }
>
>
> === modified file 'src/libqtevernote/evernoteconnection.h'
> --- src/libqtevernote/evernoteconnection.h 2015-02-26 22:47:10 +0000
> +++ src/libqtevernote/evernoteconnection.h 2015-03-08 21:00:47 +0000
> @@ -73,6 +73,18 @@
> QString token() const;
> void setToken(const QString &token);
>
> + // This will add the job to the job queue. The job queue will take ownership of the object
> + // and manage it's lifetime.
> + // * If there is an identical job already existing in the queue, the duplicate will be
> + // attached to original job and not actually fetched a second time from the network in
> + // order to reduce network traffic.
> + // * If the new job has a higher priority than the existing one, the existing one will
> + // reprioritized to the higher priorty.
> + // * If the jobs have different originatingObjects, each job will emit the jobDone signal,
> + // if instead the originatingObject is the same in both jobs, only one of them will emit
> + // a jobDone signal. This is useful if you want to reschedule a job with higher priority
> + // without having to track previously queued jobs and avoid invoking the connected slot
> + // multiple times.
> void enqueue(EvernoteJob *job);
>
> bool isConnected() const;
> @@ -104,7 +116,10 @@
> bool connectUserStore();
> bool connectNotesStore();
>
> - EvernoteJob* findDuplicate(EvernoteJob *job);
> + EvernoteJob* findExistingDuplicate(EvernoteJob *job);
> +
> + // "duplicate" will be attached to "original"
> + void attachDuplicate(EvernoteJob *original, EvernoteJob *duplicate);
>
> bool m_useSSL;
> bool m_isConnected;
> @@ -115,7 +130,9 @@
>
> // There must be only one job running at a time
> // Do not start jobs other than with startJobQueue()
> - QList<EvernoteJob*> m_jobQueue;
> + QList<EvernoteJob*> m_highPriorityJobQueue;
> + QList<EvernoteJob*> m_mediumPriorityJobQueue;
> + QList<EvernoteJob*> m_lowPriorityJobQueue;
> EvernoteJob *m_currentJob;
>
> // Those need to be mutexed
>
> === modified file 'src/libqtevernote/jobs/evernotejob.cpp'
> --- src/libqtevernote/jobs/evernotejob.cpp 2015-03-06 00:42:42 +0000
> +++ src/libqtevernote/jobs/evernotejob.cpp 2015-03-08 21:00:47 +0000
> @@ -38,11 +38,13 @@
> using namespace apache::thrift::protocol;
> using namespace apache::thrift::transport;
>
> -EvernoteJob::EvernoteJob(QObject *parent, JobPriority jobPriority) :
> - QThread(parent),
> +EvernoteJob::EvernoteJob(QObject *originatingObject, JobPriority jobPriority) :
> + QThread(nullptr),
> m_token(EvernoteConnection::instance()->token()),
> - m_jobPriority(jobPriority)
> + m_jobPriority(jobPriority),
> + m_originatingObject(originatingObject)
> {
> + connect(this, &QThread::finished, this, &EvernoteJob::jobFinished);
> }
>
> EvernoteJob::~EvernoteJob()
> @@ -198,6 +200,11 @@
> return metaObject()->className();
> }
>
> +QObject *EvernoteJob::originatingObject() const
> +{
> + return m_originatingObject;
> +}
> +
> QString EvernoteJob::token()
> {
> return m_token;
>
> === modified file 'src/libqtevernote/jobs/evernotejob.h'
> --- src/libqtevernote/jobs/evernotejob.h 2015-02-26 22:47:10 +0000
> +++ src/libqtevernote/jobs/evernotejob.h 2015-03-08 21:00:47 +0000
> @@ -37,8 +37,7 @@
> * your job won't be executed but you should instead forward the other's job results.
> *
> * Jobs can be enqueue()d in NotesStore.
> - * They will destroy themselves when finished.
> - * The jobqueue will take care about starting them.
> + * The jobqueue will take care about starting them and deleting them.
> */
> class EvernoteJob : public QThread
> {
> @@ -46,10 +45,11 @@
> public:
> enum JobPriority {
> JobPriorityHigh,
> + JobPriorityMedium,
> JobPriorityLow
> };
>
> - explicit EvernoteJob(QObject *parent = 0, JobPriority jobPriority = JobPriorityHigh);
> + explicit EvernoteJob(QObject *originatingObject = 0, JobPriority jobPriority = JobPriorityHigh);
> virtual ~EvernoteJob();
>
> JobPriority jobPriority() const;
> @@ -63,9 +63,13 @@
>
> virtual QString toString() const;
>
> + QObject* originatingObject() const;
> +
> signals:
> void connectionLost(const QString &errorMessage);
>
> + void jobFinished();
> +
> protected:
> virtual void resetConnection() = 0;
> virtual void startJob() = 0;
> @@ -76,6 +80,7 @@
> private:
> QString m_token;
> JobPriority m_jobPriority;
> + QObject *m_originatingObject;
>
> friend class EvernoteConnection;
> };
>
> === modified file 'src/libqtevernote/jobs/fetchnotesjob.cpp'
> --- src/libqtevernote/jobs/fetchnotesjob.cpp 2015-03-06 00:47:45 +0000
> +++ src/libqtevernote/jobs/fetchnotesjob.cpp 2015-03-08 21:00:47 +0000
> @@ -41,7 +41,9 @@
> return false;
> }
> return this->m_filterNotebookGuid == otherJob->m_filterNotebookGuid
> - && this->m_searchWords == otherJob->m_searchWords;
> + && this->m_searchWords == otherJob->m_searchWords
> + && this->m_startIndex == otherJob->m_startIndex
> + && this->m_chunkSize == otherJob->m_chunkSize;
> }
>
> void FetchNotesJob::attachToDuplicate(const EvernoteJob *other)
>
> === modified file 'src/libqtevernote/note.cpp'
> --- src/libqtevernote/note.cpp 2015-03-08 16:01:23 +0000
> +++ src/libqtevernote/note.cpp 2015-03-08 21:00:47 +0000
> @@ -38,7 +38,6 @@
> m_isSearchResult(false),
> m_updateSequenceNumber(updateSequenceNumber),
> m_loading(false),
> - m_loadingHighPriority(false),
> m_loaded(false),
> m_needsContentSync(false),
> m_syncError(false),
> @@ -64,15 +63,9 @@
>
> infoFile.beginGroup("resources");
> foreach (const QString &hash, infoFile.childGroups()) {
> - if (Resource::isCached(hash)) {
> - infoFile.beginGroup(hash);
> - // Assuming the resource is already cached...
> - addResource(QByteArray(), hash, infoFile.value("fileName").toString(), infoFile.value("type").toString());
> - infoFile.endGroup();
> - } else {
> - // uh oh... have a resource description without file... reset sequence number to indicate we need a sync
> - qCWarning(dcNotesStore) << "Have a resource description but no resource file for it";
> - }
> + infoFile.beginGroup(hash);
> + addResource(hash, infoFile.value("fileName").toString(), infoFile.value("type").toString());
> + infoFile.endGroup();
> }
> infoFile.endGroup();
>
> @@ -243,7 +236,6 @@
>
> QString Note::enmlContent() const
> {
> - load();
> return m_content.enml();
> }
>
> @@ -263,13 +255,11 @@
>
> QString Note::htmlContent() const
> {
> - load();
> return m_content.toHtml(m_guid);
> }
>
> QString Note::richTextContent() const
> {
> - load();
> return m_content.toRichText(m_guid);
> }
>
> @@ -286,15 +276,11 @@
>
> QString Note::plaintextContent() const
> {
> - load();
> return m_content.toPlaintext().trimmed();
> }
>
> QString Note::tagline() const
> {
> - if (m_tagline.isEmpty()) {
> - load(false);
> - }
> return m_tagline;
> }
>
> @@ -488,11 +474,12 @@
> QStringList Note::resourceUrls() const
> {
> QList<QString> ret;
> - foreach (const QString &hash, m_resources.keys()) {
> - QUrl url("image://resource/" + m_resources.value(hash)->type());
> + foreach (Resource *resource, m_resources) {
> + QUrl url("image://resource/" + resource->type());
> QUrlQuery arguments;
> arguments.addQueryItem("noteGuid", m_guid);
> - arguments.addQueryItem("hash", hash);
> + arguments.addQueryItem("hash", resource->hash());
> + arguments.addQueryItem("loaded", resource->isCached() ? "true" : "false");
> url.setQuery(arguments);
> ret << url.toString();
> }
> @@ -505,25 +492,29 @@
> }
>
>
> -Resource* Note::addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type)
> +Resource* Note::addResource(const QString &hash, const QString &fileName, const QString &type, const QByteArray &data)
> {
> + Resource *resource;
> if (m_resources.contains(hash)) {
> - return m_resources.value(hash);
> + resource = m_resources.value(hash);
> + if (!data.isEmpty()) {
> + resource->setData(data);
> + }
> + } else {
> + resource = new Resource(data, hash, fileName, type, this);
> + m_resources.insert(hash, resource);
> + QSettings infoFile(m_infoFile, QSettings::IniFormat);
> + infoFile.beginGroup("resources");
> + infoFile.beginGroup(hash);
> + infoFile.setValue("fileName", fileName);
> + infoFile.setValue("type", type);
> + infoFile.endGroup();
> + infoFile.endGroup();
> }
>
> - Resource *resource = new Resource(data, hash, fileName, type, this);
> - m_resources.insert(hash, resource);
> emit resourcesChanged();
> emit contentChanged();
>
> - QSettings infoFile(m_infoFile, QSettings::IniFormat);
> - infoFile.beginGroup("resources");
> - infoFile.beginGroup(hash);
> - infoFile.setValue("fileName", fileName);
> - infoFile.setValue("type", type);
> - infoFile.endGroup();
> - infoFile.endGroup();
> -
> return resource;
> }
>
> @@ -593,7 +584,7 @@
> note->setUpdateSequenceNumber(m_updateSequenceNumber);
> note->setDeleted(m_deleted);
> foreach (Resource *resource, m_resources) {
> - note->addResource(resource->data(), resource->hash(), resource->fileName(), resource->type());
> + note->addResource(resource->hash(), resource->fileName(), resource->type(), resource->data());
> }
> note->m_needsContentSync = m_needsContentSync;
>
> @@ -625,12 +616,6 @@
> if (m_loading != loading) {
> m_loading = loading;
> emit loadingChanged();
> -
> - if (!m_loading) {
> - m_loadingHighPriority = false;
> - } else {
> - m_loadingHighPriority = highPriority;
/home/rpadovani/Documents/ubuntu/touch/coreapps/reminders/two-job-queues/src/libqtevernote/note.cpp:614:42: warning: unused parameter ‘highPriority’ [-Wunused-parameter]
> - }
> }
> }
>
> @@ -670,13 +655,22 @@
> }
> }
>
> -void Note::load(bool priorityHigh) const
> +void Note::load(bool priorityHigh)
> {
> if (!m_loaded && isCached()) {
> loadFromCacheFile();
> - } else if (!m_loaded) {
> - if (!m_loading || (priorityHigh && !m_loadingHighPriority)) {
> - NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadContent, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityLow);
> + }
> +
> + if (!m_loaded) {
> + NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadContent, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityMedium);
> + return;
> + }
> +
> + // Check if resources are loaded
> + foreach (Resource *resource, m_resources) {
> + if (!resource->isCached()) {
> + NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadResources, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityLow);
> + break;
> }
> }
> }
>
> === modified file 'src/libqtevernote/note.h'
> --- src/libqtevernote/note.h 2015-03-08 16:01:23 +0000
> +++ src/libqtevernote/note.h 2015-03-08 21:00:47 +0000
> @@ -157,7 +157,7 @@
> QStringList resourceUrls() const;
> Q_INVOKABLE Resource* resource(const QString &hash);
> QList<Resource*> resources() const;
> - Resource *addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type);
> +
>
> Q_INVOKABLE void markTodo(const QString &todoId, bool checked);
> Q_INVOKABLE void attachFile(int position, const QUrl &fileName);
> @@ -167,6 +167,8 @@
> int renderWidth() const;
> void setRenderWidth(int renderWidth);
>
> + Q_INVOKABLE void load(bool highPriority = false);
> +
> public slots:
> void save();
> void remove();
> @@ -210,9 +212,10 @@
> void setUpdateSequenceNumber(qint32 updateSequenceNumber);
> void setLastSyncedSequenceNumber(qint32 lastSyncedSequenceNumber);
> void setConflicting(bool conflicting);
> + Resource *addResource(const QString &hash, const QString &fileName, const QString &type, const QByteArray &data = QByteArray());
> + void addMissingResource();
> + void setMissingResources(int missingResources);
>
> - // const because we want to load on demand in getters. Keep this private!
> - void load(bool priorityHigh = true) const;
> void loadFromCacheFile() const;
>
> private:
> @@ -236,7 +239,6 @@
> QString m_infoFile;
>
> bool m_loading;
> - bool m_loadingHighPriority;
> mutable bool m_loaded;
> bool m_synced;
> bool m_needsContentSync;
>
> === modified file 'src/libqtevernote/notesstore.cpp'
> --- src/libqtevernote/notesstore.cpp 2015-03-08 16:01:23 +0000
> +++ src/libqtevernote/notesstore.cpp 2015-03-08 21:00:47 +0000
> @@ -677,7 +677,7 @@
> if (note->updateSequenceNumber() < result.updateSequenceNum) {
> qCDebug(dcSync) << "refreshing note from network. suequence number changed: " << note->updateSequenceNumber() << "->" << result.updateSequenceNum;
> changedRoles = updateFromEDAM(result, note);
> - refreshNoteContent(note->guid(), FetchNoteJob::LoadContent, EvernoteJob::JobPriorityLow);
> + refreshNoteContent(note->guid(), FetchNoteJob::LoadContent, EvernoteJob::JobPriorityMedium);
> syncToCacheFile(note);
> }
> } else {
> @@ -798,15 +798,18 @@
> return;
> }
> if (EvernoteConnection::instance()->isConnected()) {
> - qCDebug(dcNotesStore) << "Fetching note content from network for note" << guid << (what == FetchNoteJob::LoadContent ? "content" : "image");
> + qCDebug(dcNotesStore) << "Fetching note content from network for note" << guid << (what == FetchNoteJob::LoadContent ? "Content" : "Resource") << "Priority:" << priority;
> FetchNoteJob *job = new FetchNoteJob(guid, what, this);
> job->setJobPriority(priority);
> connect(job, &FetchNoteJob::resultReady, this, &NotesStore::fetchNoteJobDone);
> EvernoteConnection::instance()->enqueue(job);
>
> + bool wasLoading = note->loading();
> note->setLoading(true, priority == EvernoteJob::JobPriorityHigh);
> - int idx = m_notes.indexOf(note);
> - emit dataChanged(index(idx), index(idx), QVector<int>() << RoleLoading);
> + if (!wasLoading) {
> + int idx = m_notes.indexOf(note);
> + emit dataChanged(index(idx), index(idx), QVector<int>() << RoleLoading);
> + }
> }
> }
>
> @@ -818,16 +821,13 @@
> qCWarning(dcSync) << "can't find note for this update... ignoring...";
> return;
> }
> +
> QModelIndex noteIndex = index(m_notes.indexOf(note));
> QVector<int> roles;
>
> - note->setLoading(false);
> - roles << RoleLoading;
> -
> switch (errorCode) {
> case EvernoteConnection::ErrorCodeNoError:
> // All is well
> - emit dataChanged(noteIndex, noteIndex, roles);
> break;
> case EvernoteConnection::ErrorCodeUserException:
> qCWarning(dcSync) << "FetchNoteJobDone: EDAMUserException:" << errorMessage;
> @@ -877,15 +877,17 @@
> QString mime = QString::fromStdString(resource.mime);
>
> if (what == FetchNoteJob::LoadResources) {
> - qCDebug(dcSync) << "Resource fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> + qCDebug(dcSync) << "Resource content fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> QByteArray resourceData = QByteArray(resource.data.body.data(), resource.data.size);
> - note->addResource(resourceData, hash, fileName, mime);
> - } else if (Resource::isCached(hash)) {
> - qCDebug(dcSync) << "Resource already cached for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> - note->addResource(QByteArray(), hash, fileName, mime);
> + note->addResource(hash, fileName, mime, resourceData);
> } else {
> - qCDebug(dcSync) << "Resource not yet fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> - refreshWithResourceData = true;
> + qCDebug(dcSync) << "Adding resource info to note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> + Resource *resource = note->addResource(hash, fileName, mime);
> +
> + if (!resource->isCached()) {
> + qCDebug(dcSync) << "Resource not yet fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
> + refreshWithResourceData = true;
> + }
> }
> roles << RoleHtmlContent << RoleEnmlContent << RoleResourceUrls;
> }
> @@ -915,17 +917,20 @@
> note->setReminderDoneTime(reminderDoneTime);
> roles << RoleReminderDone << RoleReminderDoneTime;
> }
> +
> + note->setLoading(false);
> + roles << RoleLoading;
> +
> emit noteChanged(note->guid(), note->notebookGuid());
> -
> emit dataChanged(noteIndex, noteIndex, roles);
>
> if (refreshWithResourceData) {
> qCDebug(dcSync) << "Fetching Note resources:" << note->guid();
> - refreshNoteContent(note->guid(), FetchNoteJob::LoadResources, job->jobPriority());
> - } else {
> - syncToCacheFile(note); // Syncs into the list cache
> - note->syncToCacheFile(); // Syncs note's content into notes cache
> + EvernoteJob::JobPriority newPriority = job->jobPriority() == EvernoteJob::JobPriorityMedium ? EvernoteJob::JobPriorityLow : job->jobPriority();
> + refreshNoteContent(note->guid(), FetchNoteJob::LoadResources, newPriority);
> }
> + syncToCacheFile(note); // Syncs into the list cache
> + note->syncToCacheFile(); // Syncs note's content into notes cache
> }
>
> void NotesStore::refreshNotebooks()
> @@ -1004,6 +1009,8 @@
> }
> }
>
> + qCDebug(dcSync) << "Remote notebooks merged into storage. Merging local changes to server.";
> +
> foreach (Notebook *notebook, unhandledNotebooks) {
> if (notebook->lastSyncedSequenceNumber() == 0) {
> qCDebug(dcSync) << "Have a local notebook that doesn't exist on Evernote. Creating on server:" << notebook->guid();
> @@ -1027,6 +1034,8 @@
> notebook->deleteLater();
> }
> }
> +
> + qCDebug(dcSync) << "Notebooks merged.";
> }
>
> void NotesStore::refreshTags()
>
> === modified file 'src/libqtevernote/resource.cpp'
> --- src/libqtevernote/resource.cpp 2015-03-06 00:47:45 +0000
> +++ src/libqtevernote/resource.cpp 2015-03-08 21:00:47 +0000
> @@ -52,15 +52,16 @@
> }
> }
>
> -bool Resource::isCached(const QString &hash)
> -{
> - QDir cacheDir(NotesStore::instance()->storageLocation());
> - foreach (const QString fi, cacheDir.entryList()) {
> - if (fi.contains(hash)) {
> - return true;
> - }
> - }
> - return false;
> +Resource::Resource(const QString &hash, const QString &fileName, const QString &type, QObject *parent):
> + Resource(QByteArray(), hash, fileName, type, parent)
> +{
> +
> +}
> +
> +bool Resource::isCached()
> +{
> + QFileInfo fi(m_filePath);
> + return fi.exists();
> }
>
> Resource::Resource(const QString &path, QObject *parent):
> @@ -159,3 +160,13 @@
> }
> return QByteArray();
> }
> +
> +void Resource::setData(const QByteArray &data)
> +{
> + QFile file(m_filePath);
> + if (file.open(QFile::WriteOnly | QFile::Truncate)) {
> + file.write(data);
> + } else {
> + qCDebug(dcNotesStore) << "Error saving data for resource:" << m_hash;
> + }
> +}
>
> === modified file 'src/libqtevernote/resource.h'
> --- src/libqtevernote/resource.h 2015-02-16 21:57:16 +0000
> +++ src/libqtevernote/resource.h 2015-03-08 21:00:47 +0000
> @@ -37,10 +37,12 @@
> public:
> Resource(const QString &path, QObject *parent = 0);
> Resource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0);
> + Resource(const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0);
>
> - static bool isCached(const QString &hash);
> + bool isCached();
>
> QByteArray data() const;
> + void setData(const QByteArray &data);
> QString hash() const;
> QString fileName() const;
> QString type() const;
>
> === modified file 'src/libqtevernote/resourceimageprovider.cpp'
> --- src/libqtevernote/resourceimageprovider.cpp 2015-03-06 00:47:45 +0000
> +++ src/libqtevernote/resourceimageprovider.cpp 2015-03-08 21:00:47 +0000
> @@ -5,6 +5,7 @@
> #include <note.h>
>
> #include <QUrlQuery>
> +#include <QFileInfo>
>
> ResourceImageProvider::ResourceImageProvider():
> QQuickImageProvider(QQuickImageProvider::Image)
> @@ -18,6 +19,7 @@
> QUrlQuery arguments(id.split('?').last());
> QString noteGuid = arguments.queryItemValue("noteGuid");
> QString resourceHash = arguments.queryItemValue("hash");
> + bool isLoaded = arguments.queryItemValue("loaded") == "true";
> Note *note = NotesStore::instance()->note(noteGuid);
> if (!note) {
> qCWarning(dcNotesStore) << "Unable to find note for resource:" << id;
> @@ -26,19 +28,47 @@
>
> QImage image;
> if (mediaType.startsWith("image")) {
> - QSize tmpSize = requestedSize;
> - if (!requestedSize.isValid() || requestedSize.width() > 1024 || requestedSize.height() > 1024) {
> - tmpSize = QSize(1024, 1024);
> + if (isLoaded) {
> + QSize tmpSize = requestedSize;
> + if (!requestedSize.isValid() || requestedSize.width() > 1024 || requestedSize.height() > 1024) {
> + tmpSize = QSize(1024, 1024);
> + }
> + image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->imageData(tmpSize));
> + } else {
> + image = loadIcon("image-x-generic-symbolic", requestedSize);
> }
> - image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->imageData(tmpSize));
> } else if (mediaType.startsWith("audio")) {
> - image.load("/usr/share/icons/suru/mimetypes/scalable/audio-x-generic-symbolic.svg");
> + image = loadIcon("audio-x-generic-symbolic", requestedSize);
> } else if (mediaType == "application/pdf") {
> - image.load("/usr/share/icons/suru/mimetypes/scalable/application-pdf-symbolic.svg");
> + image = loadIcon("application-pdf-symbolic", requestedSize);
> } else {
> - image.load("/usr/share/icons/suru/mimetypes/scalable/empty-symbolic.svg");
> + image = loadIcon("empty-symbolic", requestedSize);
> }
>
> *size = image.size();
> return image;
> }
> +
> +QImage ResourceImageProvider::loadIcon(const QString &name, const QSize &size)
> +{
> + QString path = QString("/home/phablet/.cache/com.ubuntu.reminders/%1_%2x%3.png").arg(name).arg(size.width()).arg(size.height());
Shouldn't better to use QStandardPaths::CacheLocation, so in a future, when the system will support multiuser, every user could use his home folder?
Also, this break compatibility with destkop if username != phablet
> + QFileInfo fi(path);
> + if (fi.exists()) {
> + QImage image;
> + image.load(path);
> + return image;
> + }
> +
> + QString svgPath = "/usr/share/icons/suru/mimetypes/scalable/" + name + ".svg";
> + QImage image;
> + image.load(svgPath);
> + if (size.height() > 0 && size.width() > 0) {
> + image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
> + } else if (size.height() > 0) {
> + image = image.scaledToHeight(size.height(), Qt::SmoothTransformation);
> + } else if (size.width() > 0) {
> + image = image.scaledToWidth(size.width(), Qt::SmoothTransformation);
> + }
> + image.save(path);
> + return image;
> +}
>
> === modified file 'src/libqtevernote/resourceimageprovider.h'
> --- src/libqtevernote/resourceimageprovider.h 2014-10-23 21:27:46 +0000
> +++ src/libqtevernote/resourceimageprovider.h 2015-03-08 21:00:47 +0000
> @@ -9,6 +9,9 @@
> explicit ResourceImageProvider();
>
> QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
> +
> + void scale(QImage &image, const QSize &size);
> + QImage loadIcon(const QString &name, const QSize &size);
> };
>
> #endif // RESOURCEIMAGEPROVIDER_H
>
> === modified file 'src/libqtevernote/utils/enmldocument.cpp'
> --- src/libqtevernote/utils/enmldocument.cpp 2015-03-08 16:01:23 +0000
> +++ src/libqtevernote/utils/enmldocument.cpp 2015-03-08 21:00:47 +0000
> @@ -296,6 +296,7 @@
> QUrlQuery arguments;
> arguments.addQueryItem("noteGuid", noteGuid);
> arguments.addQueryItem("hash", hash);
> + arguments.addQueryItem("loaded", NotesStore::instance()->note(noteGuid)->resource(hash)->isCached() ? "true" : "false");
> url.setQuery(arguments);
> return url.toString();
> }
>
--
https://code.launchpad.net/~mzanetti/reminders-app/two-job-queues/+merge/252175
Your team Ubuntu Reminders app developers is subscribed to branch lp:reminders-app.
Follow ups
References