Merge lp:~mzanetti/reminders-app/two-job-queues into lp:reminders-app

Proposed by Michael Zanetti
Status: Merged
Approved by: Riccardo Padovani
Approved revision: 388
Merged at revision: 380
Proposed branch: lp:~mzanetti/reminders-app/two-job-queues
Merge into: lp:reminders-app
Prerequisite: lp:~mzanetti/reminders-app/cleanup-debug
Diff against target: 887 lines (+298/-127)
15 files modified
src/app/qml/reminders.qml (+2/-0)
src/app/qml/ui/NotesPage.qml (+4/-0)
src/libqtevernote/evernoteconnection.cpp (+107/-30)
src/libqtevernote/evernoteconnection.h (+19/-2)
src/libqtevernote/jobs/evernotejob.cpp (+10/-3)
src/libqtevernote/jobs/evernotejob.h (+8/-3)
src/libqtevernote/jobs/fetchnotesjob.cpp (+3/-1)
src/libqtevernote/note.cpp (+38/-44)
src/libqtevernote/note.h (+7/-5)
src/libqtevernote/notesstore.cpp (+29/-21)
src/libqtevernote/resource.cpp (+20/-9)
src/libqtevernote/resource.h (+3/-1)
src/libqtevernote/resourceimageprovider.cpp (+44/-8)
src/libqtevernote/resourceimageprovider.h (+3/-0)
src/libqtevernote/utils/enmldocument.cpp (+1/-0)
To merge this branch: bzr merge lp:~mzanetti/reminders-app/two-job-queues
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Riccardo Padovani Approve
Review via email: mp+252175@code.launchpad.net

This proposal supersedes a proposal from 2015-03-04.

Commit message

Further improve the jobqueue by splitting it up into high, medium and low priority queues and optimizing the reply rate.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote : Posted in a previous version of this proposal

Looks good to me, but I left a couple of comments, just to be sure changes you made are wanted :-)

review: Needs Information
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

Thanks for those comments. While I think this branch is ok, I found an issue with the attachToDuplicate() mechanism. I will fix that in another branch, as that issue is not introduced by this branch.

Revision history for this message
Michael Zanetti (mzanetti) wrote :

Ok. I've fixed the attachToDuplicate issue too and rebased it on cleanup-debug as they were conflicting. Please give this a good portion of testing.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Tested, looks good to me, just 3 small inline comments

review: Needs Fixing
387. By Michael Zanetti

fix issues from reviews

Revision history for this message
Michael Zanetti (mzanetti) wrote :

> Tested, looks good to me, just 3 small inline comments

Very good catches. All fixed.

388. By Michael Zanetti

use qCDebug

Revision history for this message
Riccardo Padovani (rpadovani) wrote :

Now looks perfect :-)

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== 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-09 10:03:17 +0000
@@ -111,6 +111,7 @@
111111
112 function displayNote(note) {112 function displayNote(note) {
113 print("displayNote:", note.guid)113 print("displayNote:", note.guid)
114 note.load(true);
114 if (root.narrowMode) {115 if (root.narrowMode) {
115 print("creating noteview");116 print("creating noteview");
116 var component = Qt.createComponent(Qt.resolvedUrl("ui/NotePage.qml"));117 var component = Qt.createComponent(Qt.resolvedUrl("ui/NotePage.qml"));
@@ -127,6 +128,7 @@
127 }128 }
128129
129 function switchToEditMode(note) {130 function switchToEditMode(note) {
131 note.load(true)
130 if (root.narrowMode) {132 if (root.narrowMode) {
131 if (pagestack.depth > 1) {133 if (pagestack.depth > 1) {
132 pagestack.pop();134 pagestack.pop();
133135
=== 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-09 10:03:17 +0000
@@ -177,6 +177,10 @@
177 syncError: model.syncError177 syncError: model.syncError
178 conflicting: model.conflicting178 conflicting: model.conflicting
179179
180 Component.onCompleted: {
181 notes.note(model.guid).load(false);
182 }
183
180 onItemClicked: {184 onItemClicked: {
181 if (!model.conflicting) {185 if (!model.conflicting) {
182 root.selectedNote = NotesStore.note(guid);186 root.selectedNote = NotesStore.note(guid);
183187
=== modified file 'src/libqtevernote/evernoteconnection.cpp'
--- src/libqtevernote/evernoteconnection.cpp 2015-03-06 00:47:45 +0000
+++ src/libqtevernote/evernoteconnection.cpp 2015-03-09 10:03:17 +0000
@@ -153,11 +153,23 @@
153 return;153 return;
154 }154 }
155155
156 foreach (EvernoteJob *job, m_jobQueue) {156 foreach (EvernoteJob *job, m_highPriorityJobQueue) {
157 job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");157 job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
158 job->deleteLater();158 job->deleteLater();
159 }159 }
160 m_jobQueue.clear();160 m_highPriorityJobQueue.clear();
161
162 foreach (EvernoteJob *job, m_mediumPriorityJobQueue) {
163 job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
164 job->deleteLater();
165 }
166 m_mediumPriorityJobQueue.clear();
167
168 foreach (EvernoteJob *job, m_lowPriorityJobQueue) {
169 job->emitJobDone(EvernoteConnection::ErrorCodeConnectionLost, "Disconnected from Evernote");
170 job->deleteLater();
171 }
172 m_lowPriorityJobQueue.clear();
161173
162 m_errorMessage.clear();174 m_errorMessage.clear();
163 emit errorChanged();175 emit errorChanged();
@@ -340,11 +352,38 @@
340 return false;352 return false;
341}353}
342354
343EvernoteJob* EvernoteConnection::findDuplicate(EvernoteJob *job)355void EvernoteConnection::attachDuplicate(EvernoteJob *original, EvernoteJob *duplicate)
344{356{
345 foreach (EvernoteJob *queuedJob, m_jobQueue) {357 if (duplicate->originatingObject() && duplicate->originatingObject() != original->originatingObject()) {
346 // explicitly use custom operator==()358 duplicate->attachToDuplicate(m_currentJob);
347 if (job->operator ==(queuedJob)) {359 }
360 connect(original, &EvernoteJob::jobFinished, duplicate, &EvernoteJob::deleteLater);
361}
362
363EvernoteJob* EvernoteConnection::findExistingDuplicate(EvernoteJob *job)
364{
365 qCDebug(dcJobQueue) << "Length:"
366 << m_highPriorityJobQueue.count() + m_mediumPriorityJobQueue.count() + m_lowPriorityJobQueue.count()
367 << "(High:" << m_highPriorityJobQueue.count() << "Medium:" << m_mediumPriorityJobQueue.count() << "Low:" << m_lowPriorityJobQueue.count() << ")";
368
369 foreach (EvernoteJob *queuedJob, m_highPriorityJobQueue) {
370 // explicitly use custom operator==()
371 if (job->operator ==(queuedJob)) {
372 qCDebug(dcJobQueue) << "Found duplicate in high priority queue";
373 return queuedJob;
374 }
375 }
376 foreach (EvernoteJob *queuedJob, m_mediumPriorityJobQueue) {
377 // explicitly use custom operator==()
378 if (job->operator ==(queuedJob)) {
379 qCDebug(dcJobQueue) << "Found duplicate in medium priority queue";
380 return queuedJob;
381 }
382 }
383 foreach (EvernoteJob *queuedJob, m_lowPriorityJobQueue) {
384 // explicitly use custom operator==()
385 if (job->operator ==(queuedJob)) {
386 qCDebug(dcJobQueue) << "Found duplicate in low priority queue";
348 return queuedJob;387 return queuedJob;
349 }388 }
350 }389 }
@@ -359,26 +398,56 @@
359 job->deleteLater();398 job->deleteLater();
360 return;399 return;
361 }400 }
362 EvernoteJob *duplicate = findDuplicate(job);401 if (m_currentJob && m_currentJob->operator ==(job)) {
363 if (duplicate) {402 qCDebug(dcJobQueue) << "Duplicate of new job request already running:" << job->toString();
364 job->attachToDuplicate(duplicate);403 if (m_currentJob->isFinished()) {
365 connect(duplicate, &EvernoteJob::finished, job, &EvernoteJob::deleteLater);404 qCWarning(dcJobQueue) << "Job seems to be stuck in a loop. Deleting it:" << job->toString();
405 job->deleteLater();
406 } else {
407 attachDuplicate(m_currentJob, job);
408 }
409 return;
410 }
411 EvernoteJob *existingJob = findExistingDuplicate(job);
412 if (existingJob) {
413 qCDebug(dcJobQueue) << "Duplicate job already queued:" << job->toString();
414 attachDuplicate(existingJob, job);
366 // reprioritze the repeated request415 // reprioritze the repeated request
367 qCDebug(dcJobQueue) << "Duplicate job already queued:" << job->toString();
368 if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {416 if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {
369 qCDebug(dcJobQueue) << "Reprioritising duplicate job:" << job->toString();417 qCDebug(dcJobQueue) << "Reprioritising duplicate job in high priority queue:" << job->toString();
370 duplicate->setJobPriority(job->jobPriority());418 existingJob->setJobPriority(job->jobPriority());
371 m_jobQueue.prepend(m_jobQueue.takeAt(m_jobQueue.indexOf(duplicate)));419 if (m_highPriorityJobQueue.contains(existingJob)) {
420 m_highPriorityJobQueue.prepend(m_highPriorityJobQueue.takeAt(m_highPriorityJobQueue.indexOf(existingJob)));
421 } else if (m_mediumPriorityJobQueue.contains(existingJob)){
422 m_highPriorityJobQueue.prepend(m_mediumPriorityJobQueue.takeAt(m_mediumPriorityJobQueue.indexOf(existingJob)));
423 } else {
424 m_highPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
425 }
426 } else if (job->jobPriority() == EvernoteJob::JobPriorityMedium){
427 if (m_mediumPriorityJobQueue.contains(existingJob)) {
428 qCDebug(dcJobQueue) << "Reprioritising duplicate job in medium priority queue:" << job->toString();
429 m_mediumPriorityJobQueue.prepend(m_mediumPriorityJobQueue.takeAt(m_mediumPriorityJobQueue.indexOf(existingJob)));
430 } else if (m_lowPriorityJobQueue.contains(existingJob)) {
431 m_mediumPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
432 }
433 } else if (job->jobPriority() == EvernoteJob::JobPriorityLow) {
434 if (m_lowPriorityJobQueue.contains(existingJob)) {
435 qCDebug(dcJobQueue) << "Reprioritising duplicate job in low priority queue:" << job->toString();
436 m_lowPriorityJobQueue.prepend(m_lowPriorityJobQueue.takeAt(m_lowPriorityJobQueue.indexOf(existingJob)));
437 }
372 }438 }
373 } else {439 } else {
374 connect(job, &EvernoteJob::finished, job, &EvernoteJob::deleteLater);440 connect(job, &EvernoteJob::jobFinished, job, &EvernoteJob::deleteLater);
375 connect(job, &EvernoteJob::finished, this, &EvernoteConnection::startNextJob);441 connect(job, &EvernoteJob::jobFinished, this, &EvernoteConnection::startNextJob);
376 if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {442 if (job->jobPriority() == EvernoteJob::JobPriorityHigh) {
377 qCDebug(dcJobQueue) << "Prepending high priority job request:" << job->toString();443 qCDebug(dcJobQueue) << "Adding high priority job request:" << job->toString();
378 m_jobQueue.prepend(job);444 m_highPriorityJobQueue.prepend(job);
445 } else if (job->jobPriority() == EvernoteJob::JobPriorityMedium){
446 qCDebug(dcJobQueue) << "Adding medium priority job request:" << job->toString();
447 m_mediumPriorityJobQueue.prepend(job);
379 } else {448 } else {
380 qCDebug(dcJobQueue) << "Appending low priority job request:" << job->toString();449 qCDebug(dcJobQueue) << "Adding low priority job request:" << job->toString();
381 m_jobQueue.append(job);450 m_lowPriorityJobQueue.prepend(job);
382 }451 }
383 startJobQueue();452 startJobQueue();
384 }453 }
@@ -401,16 +470,24 @@
401470
402void EvernoteConnection::startJobQueue()471void EvernoteConnection::startJobQueue()
403{472{
404 if (m_jobQueue.isEmpty()) {
405 return;
406 }
407
408 if (m_currentJob) {473 if (m_currentJob) {
409 return;474 return;
410 }475 }
411476
412 m_currentJob = m_jobQueue.takeFirst();477 if (!m_highPriorityJobQueue.isEmpty()) {
413 qCDebug(dcJobQueue) << "Starting job:" << m_currentJob->toString();478 m_currentJob = m_highPriorityJobQueue.takeFirst();
479 } else if (!m_mediumPriorityJobQueue.isEmpty()){
480 m_currentJob = m_mediumPriorityJobQueue.takeFirst();
481 } else if (!m_lowPriorityJobQueue.isEmpty()){
482 m_currentJob = m_lowPriorityJobQueue.takeFirst();
483 }
484
485 if (!m_currentJob) {
486 qCDebug(dcJobQueue) << "Queue empty. Nothing to do.";
487 return;
488 }
489
490 qCDebug(dcJobQueue) << QString("Starting job (Priority: %1):").arg(m_currentJob->jobPriority()) << m_currentJob->toString();
414 m_currentJob->start();491 m_currentJob->start();
415}492}
416493
417494
=== modified file 'src/libqtevernote/evernoteconnection.h'
--- src/libqtevernote/evernoteconnection.h 2015-02-26 22:47:10 +0000
+++ src/libqtevernote/evernoteconnection.h 2015-03-09 10:03:17 +0000
@@ -73,6 +73,18 @@
73 QString token() const;73 QString token() const;
74 void setToken(const QString &token);74 void setToken(const QString &token);
7575
76 // This will add the job to the job queue. The job queue will take ownership of the object
77 // and manage it's lifetime.
78 // * If there is an identical job already existing in the queue, the duplicate will be
79 // attached to original job and not actually fetched a second time from the network in
80 // order to reduce network traffic.
81 // * If the new job has a higher priority than the existing one, the existing one will
82 // reprioritized to the higher priorty.
83 // * If the jobs have different originatingObjects, each job will emit the jobDone signal,
84 // if instead the originatingObject is the same in both jobs, only one of them will emit
85 // a jobDone signal. This is useful if you want to reschedule a job with higher priority
86 // without having to track previously queued jobs and avoid invoking the connected slot
87 // multiple times.
76 void enqueue(EvernoteJob *job);88 void enqueue(EvernoteJob *job);
7789
78 bool isConnected() const;90 bool isConnected() const;
@@ -104,7 +116,10 @@
104 bool connectUserStore();116 bool connectUserStore();
105 bool connectNotesStore();117 bool connectNotesStore();
106118
107 EvernoteJob* findDuplicate(EvernoteJob *job);119 EvernoteJob* findExistingDuplicate(EvernoteJob *job);
120
121 // "duplicate" will be attached to "original"
122 void attachDuplicate(EvernoteJob *original, EvernoteJob *duplicate);
108123
109 bool m_useSSL;124 bool m_useSSL;
110 bool m_isConnected;125 bool m_isConnected;
@@ -115,7 +130,9 @@
115130
116 // There must be only one job running at a time131 // There must be only one job running at a time
117 // Do not start jobs other than with startJobQueue()132 // Do not start jobs other than with startJobQueue()
118 QList<EvernoteJob*> m_jobQueue;133 QList<EvernoteJob*> m_highPriorityJobQueue;
134 QList<EvernoteJob*> m_mediumPriorityJobQueue;
135 QList<EvernoteJob*> m_lowPriorityJobQueue;
119 EvernoteJob *m_currentJob;136 EvernoteJob *m_currentJob;
120137
121 // Those need to be mutexed138 // Those need to be mutexed
122139
=== 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-09 10:03:17 +0000
@@ -38,11 +38,13 @@
38using namespace apache::thrift::protocol;38using namespace apache::thrift::protocol;
39using namespace apache::thrift::transport;39using namespace apache::thrift::transport;
4040
41EvernoteJob::EvernoteJob(QObject *parent, JobPriority jobPriority) :41EvernoteJob::EvernoteJob(QObject *originatingObject, JobPriority jobPriority) :
42 QThread(parent),42 QThread(nullptr),
43 m_token(EvernoteConnection::instance()->token()),43 m_token(EvernoteConnection::instance()->token()),
44 m_jobPriority(jobPriority)44 m_jobPriority(jobPriority),
45 m_originatingObject(originatingObject)
45{46{
47 connect(this, &QThread::finished, this, &EvernoteJob::jobFinished);
46}48}
4749
48EvernoteJob::~EvernoteJob()50EvernoteJob::~EvernoteJob()
@@ -198,6 +200,11 @@
198 return metaObject()->className();200 return metaObject()->className();
199}201}
200202
203QObject *EvernoteJob::originatingObject() const
204{
205 return m_originatingObject;
206}
207
201QString EvernoteJob::token()208QString EvernoteJob::token()
202{209{
203 return m_token;210 return m_token;
204211
=== 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-09 10:03:17 +0000
@@ -37,8 +37,7 @@
37 * your job won't be executed but you should instead forward the other's job results.37 * your job won't be executed but you should instead forward the other's job results.
38 *38 *
39 * Jobs can be enqueue()d in NotesStore.39 * Jobs can be enqueue()d in NotesStore.
40 * They will destroy themselves when finished.40 * The jobqueue will take care about starting them and deleting them.
41 * The jobqueue will take care about starting them.
42 */41 */
43class EvernoteJob : public QThread42class EvernoteJob : public QThread
44{43{
@@ -46,10 +45,11 @@
46public:45public:
47 enum JobPriority {46 enum JobPriority {
48 JobPriorityHigh,47 JobPriorityHigh,
48 JobPriorityMedium,
49 JobPriorityLow49 JobPriorityLow
50 };50 };
5151
52 explicit EvernoteJob(QObject *parent = 0, JobPriority jobPriority = JobPriorityHigh);52 explicit EvernoteJob(QObject *originatingObject = 0, JobPriority jobPriority = JobPriorityHigh);
53 virtual ~EvernoteJob();53 virtual ~EvernoteJob();
5454
55 JobPriority jobPriority() const;55 JobPriority jobPriority() const;
@@ -63,9 +63,13 @@
6363
64 virtual QString toString() const;64 virtual QString toString() const;
6565
66 QObject* originatingObject() const;
67
66signals:68signals:
67 void connectionLost(const QString &errorMessage);69 void connectionLost(const QString &errorMessage);
6870
71 void jobFinished();
72
69protected:73protected:
70 virtual void resetConnection() = 0;74 virtual void resetConnection() = 0;
71 virtual void startJob() = 0;75 virtual void startJob() = 0;
@@ -76,6 +80,7 @@
76private:80private:
77 QString m_token;81 QString m_token;
78 JobPriority m_jobPriority;82 JobPriority m_jobPriority;
83 QObject *m_originatingObject;
7984
80 friend class EvernoteConnection;85 friend class EvernoteConnection;
81};86};
8287
=== 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-09 10:03:17 +0000
@@ -41,7 +41,9 @@
41 return false;41 return false;
42 }42 }
43 return this->m_filterNotebookGuid == otherJob->m_filterNotebookGuid43 return this->m_filterNotebookGuid == otherJob->m_filterNotebookGuid
44 && this->m_searchWords == otherJob->m_searchWords;44 && this->m_searchWords == otherJob->m_searchWords
45 && this->m_startIndex == otherJob->m_startIndex
46 && this->m_chunkSize == otherJob->m_chunkSize;
45}47}
4648
47void FetchNotesJob::attachToDuplicate(const EvernoteJob *other)49void FetchNotesJob::attachToDuplicate(const EvernoteJob *other)
4850
=== modified file 'src/libqtevernote/note.cpp'
--- src/libqtevernote/note.cpp 2015-03-08 16:01:23 +0000
+++ src/libqtevernote/note.cpp 2015-03-09 10:03:17 +0000
@@ -38,7 +38,6 @@
38 m_isSearchResult(false),38 m_isSearchResult(false),
39 m_updateSequenceNumber(updateSequenceNumber),39 m_updateSequenceNumber(updateSequenceNumber),
40 m_loading(false),40 m_loading(false),
41 m_loadingHighPriority(false),
42 m_loaded(false),41 m_loaded(false),
43 m_needsContentSync(false),42 m_needsContentSync(false),
44 m_syncError(false),43 m_syncError(false),
@@ -64,15 +63,9 @@
6463
65 infoFile.beginGroup("resources");64 infoFile.beginGroup("resources");
66 foreach (const QString &hash, infoFile.childGroups()) {65 foreach (const QString &hash, infoFile.childGroups()) {
67 if (Resource::isCached(hash)) {66 infoFile.beginGroup(hash);
68 infoFile.beginGroup(hash);67 addResource(hash, infoFile.value("fileName").toString(), infoFile.value("type").toString());
69 // Assuming the resource is already cached...68 infoFile.endGroup();
70 addResource(QByteArray(), hash, infoFile.value("fileName").toString(), infoFile.value("type").toString());
71 infoFile.endGroup();
72 } else {
73 // uh oh... have a resource description without file... reset sequence number to indicate we need a sync
74 qCWarning(dcNotesStore) << "Have a resource description but no resource file for it";
75 }
76 }69 }
77 infoFile.endGroup();70 infoFile.endGroup();
7871
@@ -243,7 +236,6 @@
243236
244QString Note::enmlContent() const237QString Note::enmlContent() const
245{238{
246 load();
247 return m_content.enml();239 return m_content.enml();
248}240}
249241
@@ -263,13 +255,11 @@
263255
264QString Note::htmlContent() const256QString Note::htmlContent() const
265{257{
266 load();
267 return m_content.toHtml(m_guid);258 return m_content.toHtml(m_guid);
268}259}
269260
270QString Note::richTextContent() const261QString Note::richTextContent() const
271{262{
272 load();
273 return m_content.toRichText(m_guid);263 return m_content.toRichText(m_guid);
274}264}
275265
@@ -286,15 +276,11 @@
286276
287QString Note::plaintextContent() const277QString Note::plaintextContent() const
288{278{
289 load();
290 return m_content.toPlaintext().trimmed();279 return m_content.toPlaintext().trimmed();
291}280}
292281
293QString Note::tagline() const282QString Note::tagline() const
294{283{
295 if (m_tagline.isEmpty()) {
296 load(false);
297 }
298 return m_tagline;284 return m_tagline;
299}285}
300286
@@ -488,11 +474,12 @@
488QStringList Note::resourceUrls() const474QStringList Note::resourceUrls() const
489{475{
490 QList<QString> ret;476 QList<QString> ret;
491 foreach (const QString &hash, m_resources.keys()) {477 foreach (Resource *resource, m_resources) {
492 QUrl url("image://resource/" + m_resources.value(hash)->type());478 QUrl url("image://resource/" + resource->type());
493 QUrlQuery arguments;479 QUrlQuery arguments;
494 arguments.addQueryItem("noteGuid", m_guid);480 arguments.addQueryItem("noteGuid", m_guid);
495 arguments.addQueryItem("hash", hash);481 arguments.addQueryItem("hash", resource->hash());
482 arguments.addQueryItem("loaded", resource->isCached() ? "true" : "false");
496 url.setQuery(arguments);483 url.setQuery(arguments);
497 ret << url.toString();484 ret << url.toString();
498 }485 }
@@ -505,25 +492,29 @@
505}492}
506493
507494
508Resource* Note::addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type)495Resource* Note::addResource(const QString &hash, const QString &fileName, const QString &type, const QByteArray &data)
509{496{
497 Resource *resource;
510 if (m_resources.contains(hash)) {498 if (m_resources.contains(hash)) {
511 return m_resources.value(hash);499 resource = m_resources.value(hash);
500 if (!data.isEmpty()) {
501 resource->setData(data);
502 }
503 } else {
504 resource = new Resource(data, hash, fileName, type, this);
505 m_resources.insert(hash, resource);
506 QSettings infoFile(m_infoFile, QSettings::IniFormat);
507 infoFile.beginGroup("resources");
508 infoFile.beginGroup(hash);
509 infoFile.setValue("fileName", fileName);
510 infoFile.setValue("type", type);
511 infoFile.endGroup();
512 infoFile.endGroup();
512 }513 }
513514
514 Resource *resource = new Resource(data, hash, fileName, type, this);
515 m_resources.insert(hash, resource);
516 emit resourcesChanged();515 emit resourcesChanged();
517 emit contentChanged();516 emit contentChanged();
518517
519 QSettings infoFile(m_infoFile, QSettings::IniFormat);
520 infoFile.beginGroup("resources");
521 infoFile.beginGroup(hash);
522 infoFile.setValue("fileName", fileName);
523 infoFile.setValue("type", type);
524 infoFile.endGroup();
525 infoFile.endGroup();
526
527 return resource;518 return resource;
528}519}
529520
@@ -593,7 +584,7 @@
593 note->setUpdateSequenceNumber(m_updateSequenceNumber);584 note->setUpdateSequenceNumber(m_updateSequenceNumber);
594 note->setDeleted(m_deleted);585 note->setDeleted(m_deleted);
595 foreach (Resource *resource, m_resources) {586 foreach (Resource *resource, m_resources) {
596 note->addResource(resource->data(), resource->hash(), resource->fileName(), resource->type());587 note->addResource(resource->hash(), resource->fileName(), resource->type(), resource->data());
597 }588 }
598 note->m_needsContentSync = m_needsContentSync;589 note->m_needsContentSync = m_needsContentSync;
599590
@@ -620,17 +611,11 @@
620 NotesStore::instance()->deleteNote(m_guid);611 NotesStore::instance()->deleteNote(m_guid);
621}612}
622613
623void Note::setLoading(bool loading, bool highPriority)614void Note::setLoading(bool loading)
624{615{
625 if (m_loading != loading) {616 if (m_loading != loading) {
626 m_loading = loading;617 m_loading = loading;
627 emit loadingChanged();618 emit loadingChanged();
628
629 if (!m_loading) {
630 m_loadingHighPriority = false;
631 } else {
632 m_loadingHighPriority = highPriority;
633 }
634 }619 }
635}620}
636621
@@ -670,13 +655,22 @@
670 }655 }
671}656}
672657
673void Note::load(bool priorityHigh) const658void Note::load(bool priorityHigh)
674{659{
675 if (!m_loaded && isCached()) {660 if (!m_loaded && isCached()) {
676 loadFromCacheFile();661 loadFromCacheFile();
677 } else if (!m_loaded) {662 }
678 if (!m_loading || (priorityHigh && !m_loadingHighPriority)) {663
679 NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadContent, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityLow);664 if (!m_loaded) {
665 NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadContent, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityMedium);
666 return;
667 }
668
669 // Check if resources are loaded
670 foreach (Resource *resource, m_resources) {
671 if (!resource->isCached()) {
672 NotesStore::instance()->refreshNoteContent(m_guid, FetchNoteJob::LoadResources, priorityHigh ? EvernoteJob::JobPriorityHigh : EvernoteJob::JobPriorityLow);
673 break;
680 }674 }
681 }675 }
682}676}
683677
=== modified file 'src/libqtevernote/note.h'
--- src/libqtevernote/note.h 2015-03-08 16:01:23 +0000
+++ src/libqtevernote/note.h 2015-03-09 10:03:17 +0000
@@ -157,7 +157,7 @@
157 QStringList resourceUrls() const;157 QStringList resourceUrls() const;
158 Q_INVOKABLE Resource* resource(const QString &hash);158 Q_INVOKABLE Resource* resource(const QString &hash);
159 QList<Resource*> resources() const;159 QList<Resource*> resources() const;
160 Resource *addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type);160
161161
162 Q_INVOKABLE void markTodo(const QString &todoId, bool checked);162 Q_INVOKABLE void markTodo(const QString &todoId, bool checked);
163 Q_INVOKABLE void attachFile(int position, const QUrl &fileName);163 Q_INVOKABLE void attachFile(int position, const QUrl &fileName);
@@ -167,6 +167,8 @@
167 int renderWidth() const;167 int renderWidth() const;
168 void setRenderWidth(int renderWidth);168 void setRenderWidth(int renderWidth);
169169
170 Q_INVOKABLE void load(bool highPriority = false);
171
170public slots:172public slots:
171 void save();173 void save();
172 void remove();174 void remove();
@@ -201,7 +203,7 @@
201203
202private:204private:
203 // Those should only be called from NotesStore, which is a friend205 // Those should only be called from NotesStore, which is a friend
204 void setLoading(bool loading, bool highPriority = false);206 void setLoading(bool loading);
205 void setSyncError(bool syncError);207 void setSyncError(bool syncError);
206 void setDeleted(bool deleted);208 void setDeleted(bool deleted);
207 void syncToCacheFile();209 void syncToCacheFile();
@@ -210,9 +212,10 @@
210 void setUpdateSequenceNumber(qint32 updateSequenceNumber);212 void setUpdateSequenceNumber(qint32 updateSequenceNumber);
211 void setLastSyncedSequenceNumber(qint32 lastSyncedSequenceNumber);213 void setLastSyncedSequenceNumber(qint32 lastSyncedSequenceNumber);
212 void setConflicting(bool conflicting);214 void setConflicting(bool conflicting);
215 Resource *addResource(const QString &hash, const QString &fileName, const QString &type, const QByteArray &data = QByteArray());
216 void addMissingResource();
217 void setMissingResources(int missingResources);
213218
214 // const because we want to load on demand in getters. Keep this private!
215 void load(bool priorityHigh = true) const;
216 void loadFromCacheFile() const;219 void loadFromCacheFile() const;
217220
218private:221private:
@@ -236,7 +239,6 @@
236 QString m_infoFile;239 QString m_infoFile;
237240
238 bool m_loading;241 bool m_loading;
239 bool m_loadingHighPriority;
240 mutable bool m_loaded;242 mutable bool m_loaded;
241 bool m_synced;243 bool m_synced;
242 bool m_needsContentSync;244 bool m_needsContentSync;
243245
=== modified file 'src/libqtevernote/notesstore.cpp'
--- src/libqtevernote/notesstore.cpp 2015-03-08 16:01:23 +0000
+++ src/libqtevernote/notesstore.cpp 2015-03-09 10:03:17 +0000
@@ -677,7 +677,7 @@
677 if (note->updateSequenceNumber() < result.updateSequenceNum) {677 if (note->updateSequenceNumber() < result.updateSequenceNum) {
678 qCDebug(dcSync) << "refreshing note from network. suequence number changed: " << note->updateSequenceNumber() << "->" << result.updateSequenceNum;678 qCDebug(dcSync) << "refreshing note from network. suequence number changed: " << note->updateSequenceNumber() << "->" << result.updateSequenceNum;
679 changedRoles = updateFromEDAM(result, note);679 changedRoles = updateFromEDAM(result, note);
680 refreshNoteContent(note->guid(), FetchNoteJob::LoadContent, EvernoteJob::JobPriorityLow);680 refreshNoteContent(note->guid(), FetchNoteJob::LoadContent, EvernoteJob::JobPriorityMedium);
681 syncToCacheFile(note);681 syncToCacheFile(note);
682 }682 }
683 } else {683 } else {
@@ -798,15 +798,17 @@
798 return;798 return;
799 }799 }
800 if (EvernoteConnection::instance()->isConnected()) {800 if (EvernoteConnection::instance()->isConnected()) {
801 qCDebug(dcNotesStore) << "Fetching note content from network for note" << guid << (what == FetchNoteJob::LoadContent ? "content" : "image");801 qCDebug(dcNotesStore) << "Fetching note content from network for note" << guid << (what == FetchNoteJob::LoadContent ? "Content" : "Resource") << "Priority:" << priority;
802 FetchNoteJob *job = new FetchNoteJob(guid, what, this);802 FetchNoteJob *job = new FetchNoteJob(guid, what, this);
803 job->setJobPriority(priority);803 job->setJobPriority(priority);
804 connect(job, &FetchNoteJob::resultReady, this, &NotesStore::fetchNoteJobDone);804 connect(job, &FetchNoteJob::resultReady, this, &NotesStore::fetchNoteJobDone);
805 EvernoteConnection::instance()->enqueue(job);805 EvernoteConnection::instance()->enqueue(job);
806806
807 note->setLoading(true, priority == EvernoteJob::JobPriorityHigh);807 if (!note->loading()) {
808 int idx = m_notes.indexOf(note);808 note->setLoading(true);
809 emit dataChanged(index(idx), index(idx), QVector<int>() << RoleLoading);809 int idx = m_notes.indexOf(note);
810 emit dataChanged(index(idx), index(idx), QVector<int>() << RoleLoading);
811 }
810 }812 }
811}813}
812814
@@ -818,16 +820,13 @@
818 qCWarning(dcSync) << "can't find note for this update... ignoring...";820 qCWarning(dcSync) << "can't find note for this update... ignoring...";
819 return;821 return;
820 }822 }
823
821 QModelIndex noteIndex = index(m_notes.indexOf(note));824 QModelIndex noteIndex = index(m_notes.indexOf(note));
822 QVector<int> roles;825 QVector<int> roles;
823826
824 note->setLoading(false);
825 roles << RoleLoading;
826
827 switch (errorCode) {827 switch (errorCode) {
828 case EvernoteConnection::ErrorCodeNoError:828 case EvernoteConnection::ErrorCodeNoError:
829 // All is well829 // All is well
830 emit dataChanged(noteIndex, noteIndex, roles);
831 break;830 break;
832 case EvernoteConnection::ErrorCodeUserException:831 case EvernoteConnection::ErrorCodeUserException:
833 qCWarning(dcSync) << "FetchNoteJobDone: EDAMUserException:" << errorMessage;832 qCWarning(dcSync) << "FetchNoteJobDone: EDAMUserException:" << errorMessage;
@@ -877,15 +876,17 @@
877 QString mime = QString::fromStdString(resource.mime);876 QString mime = QString::fromStdString(resource.mime);
878877
879 if (what == FetchNoteJob::LoadResources) {878 if (what == FetchNoteJob::LoadResources) {
880 qCDebug(dcSync) << "Resource fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;879 qCDebug(dcSync) << "Resource content fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
881 QByteArray resourceData = QByteArray(resource.data.body.data(), resource.data.size);880 QByteArray resourceData = QByteArray(resource.data.body.data(), resource.data.size);
882 note->addResource(resourceData, hash, fileName, mime);881 note->addResource(hash, fileName, mime, resourceData);
883 } else if (Resource::isCached(hash)) {
884 qCDebug(dcSync) << "Resource already cached for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
885 note->addResource(QByteArray(), hash, fileName, mime);
886 } else {882 } else {
887 qCDebug(dcSync) << "Resource not yet fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;883 qCDebug(dcSync) << "Adding resource info to note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
888 refreshWithResourceData = true;884 Resource *resource = note->addResource(hash, fileName, mime);
885
886 if (!resource->isCached()) {
887 qCDebug(dcSync) << "Resource not yet fetched for note:" << note->guid() << "Filename:" << fileName << "Mimetype:" << mime << "Hash:" << hash;
888 refreshWithResourceData = true;
889 }
889 }890 }
890 roles << RoleHtmlContent << RoleEnmlContent << RoleResourceUrls;891 roles << RoleHtmlContent << RoleEnmlContent << RoleResourceUrls;
891 }892 }
@@ -915,17 +916,20 @@
915 note->setReminderDoneTime(reminderDoneTime);916 note->setReminderDoneTime(reminderDoneTime);
916 roles << RoleReminderDone << RoleReminderDoneTime;917 roles << RoleReminderDone << RoleReminderDoneTime;
917 }918 }
919
920 note->setLoading(false);
921 roles << RoleLoading;
922
918 emit noteChanged(note->guid(), note->notebookGuid());923 emit noteChanged(note->guid(), note->notebookGuid());
919
920 emit dataChanged(noteIndex, noteIndex, roles);924 emit dataChanged(noteIndex, noteIndex, roles);
921925
922 if (refreshWithResourceData) {926 if (refreshWithResourceData) {
923 qCDebug(dcSync) << "Fetching Note resources:" << note->guid();927 qCDebug(dcSync) << "Fetching Note resources:" << note->guid();
924 refreshNoteContent(note->guid(), FetchNoteJob::LoadResources, job->jobPriority());928 EvernoteJob::JobPriority newPriority = job->jobPriority() == EvernoteJob::JobPriorityMedium ? EvernoteJob::JobPriorityLow : job->jobPriority();
925 } else {929 refreshNoteContent(note->guid(), FetchNoteJob::LoadResources, newPriority);
926 syncToCacheFile(note); // Syncs into the list cache
927 note->syncToCacheFile(); // Syncs note's content into notes cache
928 }930 }
931 syncToCacheFile(note); // Syncs into the list cache
932 note->syncToCacheFile(); // Syncs note's content into notes cache
929}933}
930934
931void NotesStore::refreshNotebooks()935void NotesStore::refreshNotebooks()
@@ -1004,6 +1008,8 @@
1004 }1008 }
1005 }1009 }
10061010
1011 qCDebug(dcSync) << "Remote notebooks merged into storage. Merging local changes to server.";
1012
1007 foreach (Notebook *notebook, unhandledNotebooks) {1013 foreach (Notebook *notebook, unhandledNotebooks) {
1008 if (notebook->lastSyncedSequenceNumber() == 0) {1014 if (notebook->lastSyncedSequenceNumber() == 0) {
1009 qCDebug(dcSync) << "Have a local notebook that doesn't exist on Evernote. Creating on server:" << notebook->guid();1015 qCDebug(dcSync) << "Have a local notebook that doesn't exist on Evernote. Creating on server:" << notebook->guid();
@@ -1027,6 +1033,8 @@
1027 notebook->deleteLater();1033 notebook->deleteLater();
1028 }1034 }
1029 }1035 }
1036
1037 qCDebug(dcSync) << "Notebooks merged.";
1030}1038}
10311039
1032void NotesStore::refreshTags()1040void NotesStore::refreshTags()
10331041
=== modified file 'src/libqtevernote/resource.cpp'
--- src/libqtevernote/resource.cpp 2015-03-06 00:47:45 +0000
+++ src/libqtevernote/resource.cpp 2015-03-09 10:03:17 +0000
@@ -52,15 +52,16 @@
52 }52 }
53}53}
5454
55bool Resource::isCached(const QString &hash)55Resource::Resource(const QString &hash, const QString &fileName, const QString &type, QObject *parent):
56{56 Resource(QByteArray(), hash, fileName, type, parent)
57 QDir cacheDir(NotesStore::instance()->storageLocation());57{
58 foreach (const QString fi, cacheDir.entryList()) {58
59 if (fi.contains(hash)) {59}
60 return true;60
61 }61bool Resource::isCached()
62 }62{
63 return false;63 QFileInfo fi(m_filePath);
64 return fi.exists();
64}65}
6566
66Resource::Resource(const QString &path, QObject *parent):67Resource::Resource(const QString &path, QObject *parent):
@@ -159,3 +160,13 @@
159 }160 }
160 return QByteArray();161 return QByteArray();
161}162}
163
164void Resource::setData(const QByteArray &data)
165{
166 QFile file(m_filePath);
167 if (file.open(QFile::WriteOnly | QFile::Truncate)) {
168 file.write(data);
169 } else {
170 qCDebug(dcNotesStore) << "Error saving data for resource:" << m_hash;
171 }
172}
162173
=== modified file 'src/libqtevernote/resource.h'
--- src/libqtevernote/resource.h 2015-02-16 21:57:16 +0000
+++ src/libqtevernote/resource.h 2015-03-09 10:03:17 +0000
@@ -37,10 +37,12 @@
37public:37public:
38 Resource(const QString &path, QObject *parent = 0);38 Resource(const QString &path, QObject *parent = 0);
39 Resource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0);39 Resource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0);
40 Resource(const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0);
4041
41 static bool isCached(const QString &hash);42 bool isCached();
4243
43 QByteArray data() const;44 QByteArray data() const;
45 void setData(const QByteArray &data);
44 QString hash() const;46 QString hash() const;
45 QString fileName() const;47 QString fileName() const;
46 QString type() const;48 QString type() const;
4749
=== modified file 'src/libqtevernote/resourceimageprovider.cpp'
--- src/libqtevernote/resourceimageprovider.cpp 2015-03-06 00:47:45 +0000
+++ src/libqtevernote/resourceimageprovider.cpp 2015-03-09 10:03:17 +0000
@@ -5,11 +5,13 @@
5#include <note.h>5#include <note.h>
66
7#include <QUrlQuery>7#include <QUrlQuery>
8#include <QFileInfo>
9#include <QStandardPaths>
10#include <QDir>
811
9ResourceImageProvider::ResourceImageProvider():12ResourceImageProvider::ResourceImageProvider():
10 QQuickImageProvider(QQuickImageProvider::Image)13 QQuickImageProvider(QQuickImageProvider::Image)
11{14{
12
13}15}
1416
15QImage ResourceImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)17QImage ResourceImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
@@ -18,6 +20,7 @@
18 QUrlQuery arguments(id.split('?').last());20 QUrlQuery arguments(id.split('?').last());
19 QString noteGuid = arguments.queryItemValue("noteGuid");21 QString noteGuid = arguments.queryItemValue("noteGuid");
20 QString resourceHash = arguments.queryItemValue("hash");22 QString resourceHash = arguments.queryItemValue("hash");
23 bool isLoaded = arguments.queryItemValue("loaded") == "true";
21 Note *note = NotesStore::instance()->note(noteGuid);24 Note *note = NotesStore::instance()->note(noteGuid);
22 if (!note) {25 if (!note) {
23 qCWarning(dcNotesStore) << "Unable to find note for resource:" << id;26 qCWarning(dcNotesStore) << "Unable to find note for resource:" << id;
@@ -26,19 +29,52 @@
2629
27 QImage image;30 QImage image;
28 if (mediaType.startsWith("image")) {31 if (mediaType.startsWith("image")) {
29 QSize tmpSize = requestedSize;32 if (isLoaded) {
30 if (!requestedSize.isValid() || requestedSize.width() > 1024 || requestedSize.height() > 1024) {33 QSize tmpSize = requestedSize;
31 tmpSize = QSize(1024, 1024);34 if (!requestedSize.isValid() || requestedSize.width() > 1024 || requestedSize.height() > 1024) {
35 tmpSize = QSize(1024, 1024);
36 }
37 image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->imageData(tmpSize));
38 } else {
39 image = loadIcon("image-x-generic-symbolic", requestedSize);
32 }40 }
33 image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->imageData(tmpSize));
34 } else if (mediaType.startsWith("audio")) {41 } else if (mediaType.startsWith("audio")) {
35 image.load("/usr/share/icons/suru/mimetypes/scalable/audio-x-generic-symbolic.svg");42 image = loadIcon("audio-x-generic-symbolic", requestedSize);
36 } else if (mediaType == "application/pdf") {43 } else if (mediaType == "application/pdf") {
37 image.load("/usr/share/icons/suru/mimetypes/scalable/application-pdf-symbolic.svg");44 image = loadIcon("application-pdf-symbolic", requestedSize);
38 } else {45 } else {
39 image.load("/usr/share/icons/suru/mimetypes/scalable/empty-symbolic.svg");46 image = loadIcon("empty-symbolic", requestedSize);
40 }47 }
4148
42 *size = image.size();49 *size = image.size();
43 return image;50 return image;
44}51}
52
53QImage ResourceImageProvider::loadIcon(const QString &name, const QSize &size)
54{
55 QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first();
56 QString path = QString(cachePath + "/%1_%2x%3.png").arg(name).arg(size.width()).arg(size.height());
57 QFileInfo fi(path);
58 if (fi.exists()) {
59 QImage image;
60 image.load(path);
61 return image;
62 }
63
64 QString svgPath = "/usr/share/icons/suru/mimetypes/scalable/" + name + ".svg";
65 QImage image;
66 image.load(svgPath);
67 if (size.height() > 0 && size.width() > 0) {
68 image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
69 } else if (size.height() > 0) {
70 image = image.scaledToHeight(size.height(), Qt::SmoothTransformation);
71 } else if (size.width() > 0) {
72 image = image.scaledToWidth(size.width(), Qt::SmoothTransformation);
73 }
74 QDir dir(cachePath);
75 if (!dir.exists()) {
76 dir.mkpath(cachePath);
77 }
78 image.save(path);
79 return image;
80}
4581
=== modified file 'src/libqtevernote/resourceimageprovider.h'
--- src/libqtevernote/resourceimageprovider.h 2014-10-23 21:27:46 +0000
+++ src/libqtevernote/resourceimageprovider.h 2015-03-09 10:03:17 +0000
@@ -9,6 +9,9 @@
9 explicit ResourceImageProvider();9 explicit ResourceImageProvider();
1010
11 QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);11 QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
12
13 void scale(QImage &image, const QSize &size);
14 QImage loadIcon(const QString &name, const QSize &size);
12};15};
1316
14#endif // RESOURCEIMAGEPROVIDER_H17#endif // RESOURCEIMAGEPROVIDER_H
1518
=== 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-09 10:03:17 +0000
@@ -296,6 +296,7 @@
296 QUrlQuery arguments;296 QUrlQuery arguments;
297 arguments.addQueryItem("noteGuid", noteGuid);297 arguments.addQueryItem("noteGuid", noteGuid);
298 arguments.addQueryItem("hash", hash);298 arguments.addQueryItem("hash", hash);
299 arguments.addQueryItem("loaded", NotesStore::instance()->note(noteGuid)->resource(hash)->isCached() ? "true" : "false");
299 url.setQuery(arguments);300 url.setQuery(arguments);
300 return url.toString();301 return url.toString();
301}302}

Subscribers

People subscribed via source and target branches