Merge lp:~mzanetti/reminders-app/enable-attaching-images into lp:reminders-app
- enable-attaching-images
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | David Planella |
Approved revision: | 46 |
Merged at revision: | 31 |
Proposed branch: | lp:~mzanetti/reminders-app/enable-attaching-images |
Merge into: | lp:reminders-app |
Diff against target: |
757 lines (+341/-50) 18 files modified
run_on_ubuntu_touch.sh (+1/-1) src/app/qml/reminders-app.qml (+12/-0) src/app/qml/ui/EditNotePage.qml (+31/-3) src/app/qml/ui/NotesPage.qml (+2/-2) src/plugin/Evernote/CMakeLists.txt (+1/-0) src/plugin/Evernote/evernoteplugin.cpp (+2/-0) src/plugin/Evernote/jobs/createnotejob.cpp (+10/-6) src/plugin/Evernote/jobs/createnotejob.h (+1/-1) src/plugin/Evernote/jobs/savenotejob.cpp (+27/-0) src/plugin/Evernote/note.cpp (+35/-12) src/plugin/Evernote/note.h (+10/-8) src/plugin/Evernote/notesstore.cpp (+6/-9) src/plugin/Evernote/notesstore.h (+3/-2) src/plugin/Evernote/resource.cpp (+92/-0) src/plugin/Evernote/resource.h (+52/-0) src/plugin/Evernote/resourceimageprovider.cpp (+1/-1) src/plugin/Evernote/utils/enmldocument.cpp (+52/-4) src/plugin/Evernote/utils/enmldocument.h (+3/-1) |
To merge this branch: | bzr merge lp:~mzanetti/reminders-app/enable-attaching-images |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Planella | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+202817@code.launchpad.net |
Commit message
Enable attaching and uploading images
Description of the change
- 46. By Michael Zanetti
-
cleanup
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
David Planella (dpm) wrote : | # |
Here's what I did:
1. Create a new note
2. Change the note's title
3. Add some text to the note
4. Press the attach button to attach an image
5. Pick an image from the device after the Content Hub brings up the gallery app
6. I'm now back to the note, although there is no visual feedback that the note has an attached image
7. I press save
8. On the list of notes, my new note is called Untitled, regardless of the fact that I did give it a name
9. When I click on the note to view it, the title is then as expected, and I can see the image in the note's body
10. However, when I go to sandbox.
Here's the debug output that I got when I performed these steps:
http://
David Planella (dpm) wrote : | # |
I forgot to say: after these steps have been followed, the 'add note' button no longer works.
David Planella (dpm) wrote : | # |
More feedback:
- If I create a note and save it, and then go back to it and attach the image, then it all works: the note contains the image and that note + image appear in sandbox.
However, the fact that after adding an image the 'add note' button no longer works still remains.
Michael Zanetti (mzanetti) wrote : | # |
I can't reproduce it... the steps you described seem to work fine here.
David Planella (dpm) wrote : | # |
LGTM, works now after having upgraded to the latest image.
David Planella (dpm) : | # |
Preview Diff
1 | === modified file 'run_on_ubuntu_touch.sh' |
2 | --- run_on_ubuntu_touch.sh 2014-01-07 12:21:44 +0000 |
3 | +++ run_on_ubuntu_touch.sh 2014-01-23 09:46:22 +0000 |
4 | @@ -79,7 +79,7 @@ |
5 | } |
6 | |
7 | run() { |
8 | - exec_with_ssh "cd $CODE_DIR/$BUILD_DIR/src/app/ && ./$BINARY --desktop_file_hint=$CODE_DIR/reminders-app.desktop" |
9 | + exec_with_ssh "cd $CODE_DIR/$BUILD_DIR/src/app/ && ./$BINARY --desktop_file_hint=/home/phablet/$CODE_DIR/reminders-app.desktop" |
10 | } |
11 | |
12 | set -- `getopt -n$0 -u -a --longoptions="setup,gdb,click,help" "sgch" "$@"` |
13 | |
14 | === modified file 'src/app/qml/reminders-app.qml' |
15 | --- src/app/qml/reminders-app.qml 2013-12-14 23:59:04 +0000 |
16 | +++ src/app/qml/reminders-app.qml 2014-01-23 09:46:22 +0000 |
17 | @@ -59,6 +59,18 @@ |
18 | } |
19 | } |
20 | |
21 | + Connections { |
22 | + target: NotesStore |
23 | + onNoteCreated: { |
24 | + var note = NotesStore.note(guid); |
25 | + print("note created:", note.guid); |
26 | + var component = Qt.createComponent(Qt.resolvedUrl("ui/EditNotePage.qml")); |
27 | + var page = component.createObject(pageStack) |
28 | + page.note = note; |
29 | + pagestack.push(page); |
30 | + } |
31 | + } |
32 | + |
33 | PageStack { |
34 | id: pagestack |
35 | |
36 | |
37 | === modified file 'src/app/qml/ui/EditNotePage.qml' |
38 | --- src/app/qml/ui/EditNotePage.qml 2013-12-17 23:19:58 +0000 |
39 | +++ src/app/qml/ui/EditNotePage.qml 2014-01-23 09:46:22 +0000 |
40 | @@ -19,6 +19,7 @@ |
41 | import QtQuick 2.0 |
42 | import Ubuntu.Components 0.1 |
43 | import Ubuntu.Components.ListItems 0.1 |
44 | +import Ubuntu.Content 0.1 |
45 | import Evernote 0.1 |
46 | import "../components" |
47 | |
48 | @@ -51,6 +52,14 @@ |
49 | |
50 | ToolbarButton { |
51 | text: "attach" |
52 | + onTriggered: { |
53 | + priv.insertPosition = noteTextArea.cursorPosition; |
54 | + note.richTextContent = noteTextArea.text; |
55 | + |
56 | + priv.activeTransfer = ContentHub.importContent(ContentType.Pictures); |
57 | + priv.activeTransfer.selectionType = ContentTransfer.Single; |
58 | + priv.activeTransfer.start(); |
59 | + } |
60 | } |
61 | ToolbarButton { |
62 | text: "camera" |
63 | @@ -59,8 +68,28 @@ |
64 | ToolbarButton { |
65 | text: "rtf" |
66 | } |
67 | - |
68 | - } |
69 | + } |
70 | + |
71 | + QtObject { |
72 | + id: priv |
73 | + property int insertPosition |
74 | + property var activeTransfer |
75 | + } |
76 | + |
77 | + ContentImportHint { |
78 | + id: importHint |
79 | + anchors.fill: parent |
80 | + activeTransfer: root.activeTransfer |
81 | + } |
82 | + Connections { |
83 | + target: priv.activeTransfer ? priv.activeTransfer : null |
84 | + onStateChanged: { |
85 | + if (priv.activeTransfer.state === ContentTransfer.Charged) { |
86 | + print("attaching", priv.activeTransfer.items[0].url.toString()) |
87 | + note.attachFile(priv.insertPosition, priv.activeTransfer.items[0].url.toString()) |
88 | + } |
89 | + } |
90 | + } |
91 | |
92 | Column { |
93 | anchors.fill: parent |
94 | @@ -99,7 +128,6 @@ |
95 | |
96 | textFormat: TextEdit.RichText |
97 | text: root.note ? root.note.richTextContent : "" |
98 | - |
99 | } |
100 | } |
101 | } |
102 | |
103 | === modified file 'src/app/qml/ui/NotesPage.qml' |
104 | --- src/app/qml/ui/NotesPage.qml 2013-12-15 01:57:25 +0000 |
105 | +++ src/app/qml/ui/NotesPage.qml 2014-01-23 09:46:22 +0000 |
106 | @@ -49,7 +49,7 @@ |
107 | text: "add note" |
108 | iconName: "add" |
109 | onTriggered: { |
110 | - pagestack.push(Qt.resolvedUrl("EditNotePage.qml")); |
111 | + NotesStore.createNote("Untitled"); |
112 | } |
113 | } |
114 | } |
115 | @@ -68,7 +68,7 @@ |
116 | title: model.title |
117 | creationDate: model.created |
118 | content: model.plaintextContent |
119 | - resource: model.resources.length > 0 ? model.resources[0] : "" |
120 | + resource: model.resourceUrls.length > 0 ? model.resourceUrls[0] : "" |
121 | |
122 | onClicked: { |
123 | pageStack.push(Qt.resolvedUrl("NotePage.qml"), {note: NotesStore.note(guid)}) |
124 | |
125 | === modified file 'src/plugin/Evernote/CMakeLists.txt' |
126 | --- src/plugin/Evernote/CMakeLists.txt 2014-01-19 13:59:12 +0000 |
127 | +++ src/plugin/Evernote/CMakeLists.txt 2014-01-23 09:46:22 +0000 |
128 | @@ -11,6 +11,7 @@ |
129 | notebooks.cpp |
130 | notes.cpp |
131 | note.cpp |
132 | + resource.cpp |
133 | notebook.cpp |
134 | jobs/fetchnotesjob.cpp |
135 | jobs/fetchnotebooksjob.cpp |
136 | |
137 | === modified file 'src/plugin/Evernote/evernoteplugin.cpp' |
138 | --- src/plugin/Evernote/evernoteplugin.cpp 2013-12-15 01:57:25 +0000 |
139 | +++ src/plugin/Evernote/evernoteplugin.cpp 2014-01-23 09:46:22 +0000 |
140 | @@ -26,6 +26,7 @@ |
141 | #include "notes.h" |
142 | #include "notebooks.h" |
143 | #include "note.h" |
144 | +#include "resource.h" |
145 | #include "notebook.h" |
146 | #include "resourceimageprovider.h" |
147 | |
148 | @@ -56,6 +57,7 @@ |
149 | qmlRegisterType<Notebooks>("Evernote", 0, 1, "Notebooks"); |
150 | qmlRegisterUncreatableType<Note>("Evernote", 0, 1, "Note", "Cannot create Notes in QML. Use NotesStore.createNote() instead."); |
151 | qmlRegisterUncreatableType<Notebook>("Evernote", 0, 1, "Notebook", "Cannot create Notes in QML. Use NotesStore.createNotebook() instead."); |
152 | + qmlRegisterUncreatableType<Resource>("Evernote", 0, 1, "Resource", "Cannot create Resources. Use Note.attachFile() instead."); |
153 | } |
154 | |
155 | void EvernotePlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
156 | |
157 | === modified file 'src/plugin/Evernote/jobs/createnotejob.cpp' |
158 | --- src/plugin/Evernote/jobs/createnotejob.cpp 2013-11-28 00:39:33 +0000 |
159 | +++ src/plugin/Evernote/jobs/createnotejob.cpp 2014-01-23 09:46:22 +0000 |
160 | @@ -35,12 +35,16 @@ |
161 | evernote::edam::Note input; |
162 | input.title = m_title.toStdString(); |
163 | input.__isset.title = true; |
164 | - input.notebookGuid = m_notebookGuid.toStdString(); |
165 | - input.__isset.notebookGuid = true; |
166 | - input.content = m_content.toStdString(); |
167 | - input.__isset.content = true; |
168 | - input.contentLength = m_content.length(); |
169 | - input.__isset.contentLength = true; |
170 | + if (!m_notebookGuid.isEmpty()) { |
171 | + input.notebookGuid = m_notebookGuid.toStdString(); |
172 | + input.__isset.notebookGuid = true; |
173 | + } |
174 | + if (!m_content.isEmpty()) { |
175 | + input.content = m_content.toStdString(); |
176 | + input.__isset.content = true; |
177 | + input.contentLength = m_content.length(); |
178 | + input.__isset.contentLength = true; |
179 | + } |
180 | |
181 | client()->createNote(m_resultNote, token().toStdString(), input); |
182 | } |
183 | |
184 | === modified file 'src/plugin/Evernote/jobs/createnotejob.h' |
185 | --- src/plugin/Evernote/jobs/createnotejob.h 2013-11-29 20:58:04 +0000 |
186 | +++ src/plugin/Evernote/jobs/createnotejob.h 2014-01-23 09:46:22 +0000 |
187 | @@ -27,7 +27,7 @@ |
188 | { |
189 | Q_OBJECT |
190 | public: |
191 | - explicit CreateNoteJob(const QString &title, const QString ¬ebookGuid, const QString &content, QObject *parent = 0); |
192 | + explicit CreateNoteJob(const QString &title, const QString ¬ebookGuid = QString(), const QString &content = QString(), QObject *parent = 0); |
193 | |
194 | signals: |
195 | void jobDone(EvernoteConnection::ErrorCode errorCode, const QString &errorMessage, evernote::edam::Note note); |
196 | |
197 | === modified file 'src/plugin/Evernote/jobs/savenotejob.cpp' |
198 | --- src/plugin/Evernote/jobs/savenotejob.cpp 2013-12-14 22:38:57 +0000 |
199 | +++ src/plugin/Evernote/jobs/savenotejob.cpp 2014-01-23 09:46:22 +0000 |
200 | @@ -54,6 +54,33 @@ |
201 | note.attributes.reminderDoneTime = m_note->reminderDoneTime().toMSecsSinceEpoch(); |
202 | note.attributes.__isset.reminderDoneTime = true; |
203 | |
204 | + note.resources.clear(); |
205 | + foreach (Resource *resource, m_note->resources()) { |
206 | + evernote::edam::Resource evResource; |
207 | + evResource.noteGuid = m_note->guid().toStdString(); |
208 | + evResource.__isset.noteGuid = true; |
209 | + evResource.mime = resource->type().toStdString(); |
210 | + evResource.__isset.mime = true; |
211 | + |
212 | + evResource.data.bodyHash = resource->hash().toStdString(); |
213 | + evResource.data.__isset.bodyHash = true; |
214 | + |
215 | + QByteArray data = resource->data(); |
216 | + evResource.data.body.assign(data.data(), data.length()); |
217 | + evResource.data.__isset.body = true; |
218 | + |
219 | + evResource.data.size = data.length(); |
220 | + evResource.data.__isset.size = true; |
221 | + evResource.__isset.data = true; |
222 | + |
223 | + evResource.attributes.fileName = resource->fileName().toStdString(); |
224 | + evResource.attributes.__isset.fileName = true; |
225 | + evResource.__isset.attributes = true; |
226 | + |
227 | + note.resources.push_back(evResource); |
228 | + } |
229 | + note.__isset.resources = true; |
230 | + |
231 | client()->updateNote(m_resultNote, token().toStdString(), note); |
232 | } |
233 | |
234 | |
235 | === modified file 'src/plugin/Evernote/note.cpp' |
236 | --- src/plugin/Evernote/note.cpp 2013-12-18 22:35:03 +0000 |
237 | +++ src/plugin/Evernote/note.cpp 2014-01-23 09:46:22 +0000 |
238 | @@ -27,6 +27,8 @@ |
239 | #include <QUrlQuery> |
240 | #include <QStandardPaths> |
241 | #include <QDebug> |
242 | +#include <QCryptographicHash> |
243 | +#include <QFile> |
244 | |
245 | Note::Note(const QString &guid, const QDateTime &created, QObject *parent) : |
246 | QObject(parent), |
247 | @@ -36,6 +38,11 @@ |
248 | { |
249 | } |
250 | |
251 | +Note::~Note() |
252 | +{ |
253 | + qDeleteAll(m_resources.values()); |
254 | +} |
255 | + |
256 | QString Note::guid() const |
257 | { |
258 | return m_guid; |
259 | @@ -189,11 +196,16 @@ |
260 | } |
261 | } |
262 | |
263 | -QStringList Note::resources() const |
264 | +QList<Resource*> Note::resources() const |
265 | +{ |
266 | + return m_resources.values(); |
267 | +} |
268 | + |
269 | +QStringList Note::resourceUrls() const |
270 | { |
271 | QList<QString> ret; |
272 | foreach (const QString &hash, m_resources.keys()) { |
273 | - QUrl url("image://resource/" + m_resourceTypes.value(hash)); |
274 | + QUrl url("image://resource/" + m_resources.value(hash)->type()); |
275 | QUrlQuery arguments; |
276 | arguments.addQueryItem("noteGuid", m_guid); |
277 | arguments.addQueryItem("hash", hash); |
278 | @@ -203,24 +215,24 @@ |
279 | return ret; |
280 | } |
281 | |
282 | -QImage Note::resource(const QString &hash) |
283 | +Resource* Note::resource(const QString &hash) |
284 | { |
285 | return m_resources.value(hash); |
286 | } |
287 | |
288 | -QString Note::resourceName(const QString &hash) |
289 | + |
290 | +Resource* Note::addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type) |
291 | { |
292 | - return m_resourceNames.value(hash); |
293 | + Resource *resource = new Resource(data, hash, fileName, type, this); |
294 | + m_resources.insert(hash, resource); |
295 | + return resource; |
296 | } |
297 | |
298 | -void Note::addResource(const QString &hash, const QString &fileName, const QString &type, const QImage &image) |
299 | +Resource *Note::addResource(const QString &fileName) |
300 | { |
301 | - image.save(QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + hash + "." + type.split('/').last()); |
302 | - if (!image.isNull()) { |
303 | - m_resources.insert(hash, image); |
304 | - } |
305 | - m_resourceTypes.insert(hash, type); |
306 | - m_resourceNames.insert(hash, fileName); |
307 | + Resource *resource = new Resource(fileName); |
308 | + m_resources.insert(resource->hash(), resource); |
309 | + return resource; |
310 | } |
311 | |
312 | void Note::markTodo(const QString &todoId, bool checked) |
313 | @@ -228,6 +240,13 @@ |
314 | m_content.markTodo(todoId, checked); |
315 | } |
316 | |
317 | +void Note::attachFile(int position, const QUrl &fileName) |
318 | +{ |
319 | + Resource *resource = addResource(fileName.path()); |
320 | + m_content.attachFile(position, fileName.path(), resource->hash(), resource->type()); |
321 | + emit contentChanged(); |
322 | +} |
323 | + |
324 | Note *Note::clone() |
325 | { |
326 | Note *note = new Note(m_guid, m_created); |
327 | @@ -238,6 +257,10 @@ |
328 | note->setReminderTime(m_reminderTime); |
329 | note->setReminderDoneTime(m_reminderDoneTime); |
330 | note->setIsSearchResult(m_isSearchResult); |
331 | + foreach (Resource *resource, m_resources) { |
332 | + note->addResource(resource->data(), resource->hash(), resource->fileName(), resource->type()); |
333 | + } |
334 | + |
335 | return note; |
336 | } |
337 | |
338 | |
339 | === modified file 'src/plugin/Evernote/note.h' |
340 | --- src/plugin/Evernote/note.h 2014-01-10 12:00:26 +0000 |
341 | +++ src/plugin/Evernote/note.h 2014-01-23 09:46:22 +0000 |
342 | @@ -22,6 +22,7 @@ |
343 | #define NOTE_H |
344 | |
345 | #include "utils/enmldocument.h" |
346 | +#include "resource.h" |
347 | |
348 | #include <QObject> |
349 | #include <QDateTime> |
350 | @@ -41,7 +42,7 @@ |
351 | Q_PROPERTY(QString richTextContent READ richTextContent WRITE setRichTextContent NOTIFY contentChanged) |
352 | Q_PROPERTY(QString enmlContent READ enmlContent WRITE setEnmlContent NOTIFY contentChanged) |
353 | Q_PROPERTY(QString plaintextContent READ plaintextContent NOTIFY contentChanged) |
354 | - Q_PROPERTY(QList<QString> resources READ resources NOTIFY contentChanged) |
355 | + Q_PROPERTY(QStringList resourceUrls READ resourceUrls NOTIFY contentChanged) |
356 | Q_PROPERTY(bool reminder READ reminder WRITE setReminder NOTIFY reminderChanged) |
357 | Q_PROPERTY(QDateTime reminderTime READ reminderTime WRITE setReminderTime NOTIFY reminderTimeChanged) |
358 | Q_PROPERTY(bool reminderDone READ reminderDone WRITE setReminderDone NOTIFY reminderDoneChanged) |
359 | @@ -51,6 +52,7 @@ |
360 | |
361 | public: |
362 | explicit Note(const QString &guid, const QDateTime &created, QObject *parent = 0); |
363 | + ~Note(); |
364 | |
365 | QString guid() const; |
366 | |
367 | @@ -96,12 +98,14 @@ |
368 | bool isSearchResult() const; |
369 | void setIsSearchResult(bool isSearchResult); |
370 | |
371 | - QStringList resources() const; |
372 | - QImage resource(const QString &hash); |
373 | - QString resourceName(const QString &hash); |
374 | - void addResource(const QString &hash, const QString &fileName, const QString &type, const QImage &image = QImage()); |
375 | + QStringList resourceUrls() const; |
376 | + Resource* resource(const QString &hash); |
377 | + QList<Resource*> resources() const; |
378 | + Resource *addResource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type); |
379 | + Resource *addResource(const QString &fileName); |
380 | |
381 | Q_INVOKABLE void markTodo(const QString &todoId, bool checked); |
382 | + Q_INVOKABLE void attachFile(int position, const QUrl &fileName); |
383 | |
384 | Note* clone(); |
385 | |
386 | @@ -128,9 +132,7 @@ |
387 | QDateTime m_reminderTime; |
388 | QDateTime m_reminderDoneTime; |
389 | bool m_isSearchResult; |
390 | - QHash<QString, QImage> m_resources; |
391 | - QHash<QString, QString> m_resourceTypes; |
392 | - QHash<QString, QString> m_resourceNames; |
393 | + QHash<QString, Resource*> m_resources; |
394 | }; |
395 | |
396 | #endif // NOTE_H |
397 | |
398 | === modified file 'src/plugin/Evernote/notesstore.cpp' |
399 | --- src/plugin/Evernote/notesstore.cpp 2013-12-18 22:35:03 +0000 |
400 | +++ src/plugin/Evernote/notesstore.cpp 2014-01-23 09:46:22 +0000 |
401 | @@ -93,8 +93,8 @@ |
402 | return m_notes.at(index.row())->richTextContent(); |
403 | case RolePlaintextContent: |
404 | return m_notes.at(index.row())->plaintextContent(); |
405 | - case RoleResources: |
406 | - return m_notes.at(index.row())->resources(); |
407 | + case RoleResourceUrls: |
408 | + return m_notes.at(index.row())->resourceUrls(); |
409 | } |
410 | return QVariant(); |
411 | } |
412 | @@ -114,7 +114,7 @@ |
413 | roles.insert(RoleRichTextContent, "richTextContent"); |
414 | roles.insert(RoleHtmlContent, "htmlContent"); |
415 | roles.insert(RolePlaintextContent, "plaintextContent"); |
416 | - roles.insert(RoleResources, "resources"); |
417 | + roles.insert(RoleResourceUrls, "resourceUrls"); |
418 | return roles; |
419 | } |
420 | |
421 | @@ -235,12 +235,8 @@ |
422 | QString fileName = QString::fromStdString(resource.attributes.fileName); |
423 | QString mime = QString::fromStdString(resource.mime); |
424 | |
425 | - if (mime.startsWith("image/")) { |
426 | - QImage image = QImage::fromData((const uchar*)resource.data.body.data(), resource.data.size); |
427 | - note->addResource(hash, fileName, mime, image); |
428 | - } else { |
429 | - note->addResource(hash, fileName, mime); |
430 | - } |
431 | + QByteArray resourceData = QByteArray(resource.data.body.data(), resource.data.size); |
432 | + note->addResource(resourceData, hash, fileName, mime); |
433 | } |
434 | |
435 | note->setEnmlContent(QString::fromStdString(result.content)); |
436 | @@ -324,6 +320,7 @@ |
437 | endInsertRows(); |
438 | |
439 | emit noteAdded(note->guid(), note->notebookGuid()); |
440 | + emit noteCreated(note->guid(), note->notebookGuid()); |
441 | } |
442 | |
443 | void NotesStore::saveNote(const QString &guid) |
444 | |
445 | === modified file 'src/plugin/Evernote/notesstore.h' |
446 | --- src/plugin/Evernote/notesstore.h 2014-01-10 12:00:26 +0000 |
447 | +++ src/plugin/Evernote/notesstore.h 2014-01-23 09:46:22 +0000 |
448 | @@ -63,7 +63,7 @@ |
449 | RoleHtmlContent, |
450 | RoleRichTextContent, |
451 | RolePlaintextContent, |
452 | - RoleResources |
453 | + RoleResourceUrls |
454 | }; |
455 | |
456 | ~NotesStore(); |
457 | @@ -77,7 +77,7 @@ |
458 | QList<Note*> notes() const; |
459 | |
460 | Q_INVOKABLE Note* note(const QString &guid); |
461 | - Q_INVOKABLE void createNote(const QString &title, const QString ¬ebookGuid, const QString &richTextContent); |
462 | + Q_INVOKABLE void createNote(const QString &title, const QString ¬ebookGuid = QString(), const QString &richTextContent = QString()); |
463 | void createNote(const QString &title, const QString ¬ebookGuid, const EnmlDocument &content); |
464 | Q_INVOKABLE void saveNote(const QString &guid); |
465 | Q_INVOKABLE void deleteNote(const QString &guid); |
466 | @@ -96,6 +96,7 @@ |
467 | signals: |
468 | void tokenChanged(); |
469 | |
470 | + void noteCreated(const QString &guid, const QString ¬ebookGuid); |
471 | void noteAdded(const QString &guid, const QString ¬ebookGuid); |
472 | void noteChanged(const QString &guid, const QString ¬ebookGuid); |
473 | void noteRemoved(const QString &guid, const QString ¬ebookGuid); |
474 | |
475 | === added file 'src/plugin/Evernote/resource.cpp' |
476 | --- src/plugin/Evernote/resource.cpp 1970-01-01 00:00:00 +0000 |
477 | +++ src/plugin/Evernote/resource.cpp 2014-01-23 09:46:22 +0000 |
478 | @@ -0,0 +1,92 @@ |
479 | +/* |
480 | + * Copyright: 2013 Canonical, Ltd |
481 | + * |
482 | + * This file is part of reminders-app |
483 | + * |
484 | + * reminders-app is free software: you can redistribute it and/or modify |
485 | + * it under the terms of the GNU General Public License as published by |
486 | + * the Free Software Foundation; version 3. |
487 | + * |
488 | + * reminders-app is distributed in the hope that it will be useful, |
489 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
490 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
491 | + * GNU General Public License for more details. |
492 | + * |
493 | + * You should have received a copy of the GNU General Public License |
494 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
495 | + * |
496 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
497 | + */ |
498 | + |
499 | +#include "resource.h" |
500 | + |
501 | +#include <QFile> |
502 | +#include <QStandardPaths> |
503 | +#include <QDebug> |
504 | +#include <QCryptographicHash> |
505 | + |
506 | +Resource::Resource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type, QObject *parent): |
507 | + m_hash(hash), |
508 | + m_fileName(fileName), |
509 | + m_type(type) |
510 | +{ |
511 | + |
512 | + m_filePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first() + "/" + hash + "." + type.split('/').last(); |
513 | + |
514 | + QFile file(m_filePath); |
515 | + if (!file.exists()) { |
516 | + |
517 | + if (!file.open(QFile::WriteOnly)) { |
518 | + qWarning() << "error writing file" << m_filePath; |
519 | + return; |
520 | + } |
521 | + file.write(data); |
522 | + file.close(); |
523 | + } |
524 | +} |
525 | + |
526 | +Resource::Resource(const QString &path, QObject *parent): |
527 | + m_filePath(path) |
528 | +{ |
529 | + QFile file(path); |
530 | + if (!file.open(QFile::ReadOnly)) { |
531 | + qWarning() << "Cannot open file for reading..."; |
532 | + return; |
533 | + } |
534 | + |
535 | + QByteArray fileContent = file.readAll(); |
536 | + m_hash = QCryptographicHash::hash(fileContent, QCryptographicHash::Md5).toHex(); |
537 | + |
538 | + m_fileName = path.split('/').last(); |
539 | + if (m_fileName.endsWith(".png")) { |
540 | + m_type = "image/png"; |
541 | + } else if (m_fileName.endsWith(".jpg") || m_fileName.endsWith(".jpeg")) { |
542 | + m_type = "image/jpeg"; |
543 | + } else { |
544 | + qWarning() << "cannot determine mime type of file" << m_fileName; |
545 | + } |
546 | +} |
547 | + |
548 | +QString Resource::hash() const |
549 | +{ |
550 | + return m_hash; |
551 | +} |
552 | + |
553 | +QString Resource::type() const |
554 | +{ |
555 | + return m_type; |
556 | +} |
557 | + |
558 | +QString Resource::fileName() const |
559 | +{ |
560 | + return m_fileName; |
561 | +} |
562 | + |
563 | +QByteArray Resource::data() const |
564 | +{ |
565 | + QFile file(m_filePath); |
566 | + if (file.open(QFile::ReadOnly)) { |
567 | + return file.readAll(); |
568 | + } |
569 | + return QByteArray(); |
570 | +} |
571 | |
572 | === added file 'src/plugin/Evernote/resource.h' |
573 | --- src/plugin/Evernote/resource.h 1970-01-01 00:00:00 +0000 |
574 | +++ src/plugin/Evernote/resource.h 2014-01-23 09:46:22 +0000 |
575 | @@ -0,0 +1,52 @@ |
576 | +/* |
577 | + * Copyright: 2013 Canonical, Ltd |
578 | + * |
579 | + * This file is part of reminders-app |
580 | + * |
581 | + * reminders-app is free software: you can redistribute it and/or modify |
582 | + * it under the terms of the GNU General Public License as published by |
583 | + * the Free Software Foundation; version 3. |
584 | + * |
585 | + * reminders-app is distributed in the hope that it will be useful, |
586 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
587 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
588 | + * GNU General Public License for more details. |
589 | + * |
590 | + * You should have received a copy of the GNU General Public License |
591 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
592 | + * |
593 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
594 | + */ |
595 | + |
596 | +#ifndef RESOURCE_H |
597 | +#define RESOURCE_H |
598 | + |
599 | +#include <QObject> |
600 | +#include <QString> |
601 | +#include <QImage> |
602 | + |
603 | +class Resource: public QObject |
604 | +{ |
605 | + Q_OBJECT |
606 | + Q_PROPERTY(QByteArray data READ data CONSTANT) |
607 | + Q_PROPERTY(QString hash READ hash CONSTANT) |
608 | + Q_PROPERTY(QString fileName READ fileName CONSTANT) |
609 | + Q_PROPERTY(QString type READ type CONSTANT) |
610 | + |
611 | +public: |
612 | + Resource(const QString &path, QObject *parent = 0); |
613 | + Resource(const QByteArray &data, const QString &hash, const QString &fileName, const QString &type, QObject *parent = 0); |
614 | + |
615 | + QByteArray data() const; |
616 | + QString hash() const; |
617 | + QString fileName() const; |
618 | + QString type() const; |
619 | + |
620 | +private: |
621 | + QString m_hash; |
622 | + QString m_fileName; |
623 | + QString m_filePath; |
624 | + QString m_type; |
625 | +}; |
626 | + |
627 | +#endif |
628 | |
629 | === modified file 'src/plugin/Evernote/resourceimageprovider.cpp' |
630 | --- src/plugin/Evernote/resourceimageprovider.cpp 2013-12-18 22:35:03 +0000 |
631 | +++ src/plugin/Evernote/resourceimageprovider.cpp 2014-01-23 09:46:22 +0000 |
632 | @@ -26,7 +26,7 @@ |
633 | |
634 | QImage image; |
635 | if (mediaType.startsWith("image")) { |
636 | - image = NotesStore::instance()->note(noteGuid)->resource(resourceHash); |
637 | + image = QImage::fromData(NotesStore::instance()->note(noteGuid)->resource(resourceHash)->data()); |
638 | } else if (mediaType.startsWith("audio")) { |
639 | image.load("/usr/share/icons/ubuntu-mobile/actions/scalable/media-playback-start.svg"); |
640 | } else { |
641 | |
642 | === modified file 'src/plugin/Evernote/utils/enmldocument.cpp' |
643 | --- src/plugin/Evernote/utils/enmldocument.cpp 2014-01-10 12:00:26 +0000 |
644 | +++ src/plugin/Evernote/utils/enmldocument.cpp 2014-01-23 09:46:22 +0000 |
645 | @@ -156,7 +156,7 @@ |
646 | } else if (type == TypeHtml) { |
647 | QString imagePath = "file:///usr/share/icons/ubuntu-mobile/actions/scalable/media-playback-start.svg"; |
648 | writer.writeAttribute("src", imagePath); |
649 | - writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resourceName(hash)); |
650 | + writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName()); |
651 | } |
652 | } else { |
653 | if (type == TypeRichText) { |
654 | @@ -169,7 +169,7 @@ |
655 | } else if (type == TypeHtml) { |
656 | QString imagePath = "file:///usr/share/icons/ubuntu-mobile/actions/scalable/help.svg"; |
657 | writer.writeAttribute("src", imagePath); |
658 | - writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resourceName(hash)); |
659 | + writer.writeCharacters(NotesStore::instance()->note(noteGuid)->resource(hash)->fileName()); |
660 | } |
661 | } |
662 | } |
663 | @@ -234,16 +234,22 @@ |
664 | return html; |
665 | } |
666 | |
667 | -void EnmlDocument::setRichText(const QString &html) |
668 | +void EnmlDocument::setRichText(const QString &richText) |
669 | { |
670 | // output |
671 | m_enml.clear(); |
672 | + |
673 | QXmlStreamWriter writer(&m_enml); |
674 | writer.writeStartDocument(); |
675 | writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">"); |
676 | |
677 | + if (richText.isEmpty()) { |
678 | + writer.writeStartElement("en-note"); |
679 | + writer.writeEndElement(); |
680 | + } |
681 | + |
682 | // input |
683 | - QXmlStreamReader reader(html); |
684 | + QXmlStreamReader reader(richText); |
685 | |
686 | // state |
687 | bool isBody = false; |
688 | @@ -363,6 +369,48 @@ |
689 | m_enml = output; |
690 | } |
691 | |
692 | +void EnmlDocument::attachFile(int position, const QString &file, const QString &hash, const QString &type) |
693 | +{ |
694 | + QXmlStreamReader reader(m_enml); |
695 | + |
696 | + QString output; |
697 | + QXmlStreamWriter writer(&output); |
698 | + writer.writeStartDocument(); |
699 | + writer.writeDTD("<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">"); |
700 | + |
701 | + int textPos = 0; |
702 | + |
703 | + while (!reader.atEnd() && !reader.hasError()) { |
704 | + QXmlStreamReader::TokenType token = reader.readNext(); |
705 | + |
706 | + if (token == QXmlStreamReader::StartElement) { |
707 | + writer.writeStartElement(reader.name().toString()); |
708 | + writer.writeAttributes(reader.attributes()); |
709 | + } |
710 | + |
711 | + if (token == QXmlStreamReader::Characters) { |
712 | + QString textString = reader.text().toString(); |
713 | + if (textPos <= position && textPos + textString.length() > position) { |
714 | + writer.writeCharacters(textString.left(position - textPos)); |
715 | + |
716 | + writer.writeStartElement("en-media"); |
717 | + writer.writeAttribute("hash", hash); |
718 | + writer.writeAttribute("type", type); |
719 | + writer.writeEndElement(); |
720 | + |
721 | + writer.writeCharacters(textString.right(textString.length() - (position - textPos))); |
722 | + } else { |
723 | + writer.writeCharacters(reader.text().toString()); |
724 | + } |
725 | + textPos += textString.length(); |
726 | + } |
727 | + if (token == QXmlStreamReader::EndElement) { |
728 | + writer.writeEndElement(); |
729 | + } |
730 | + } |
731 | + m_enml = output; |
732 | +} |
733 | + |
734 | QString EnmlDocument::toPlaintext() const |
735 | { |
736 | // output |
737 | |
738 | === modified file 'src/plugin/Evernote/utils/enmldocument.h' |
739 | --- src/plugin/Evernote/utils/enmldocument.h 2014-01-10 12:00:26 +0000 |
740 | +++ src/plugin/Evernote/utils/enmldocument.h 2014-01-23 09:46:22 +0000 |
741 | @@ -38,6 +38,9 @@ |
742 | |
743 | void setRichText(const QString &richText); |
744 | |
745 | + // Will insert the file at position in the plaintext string |
746 | + void attachFile(int position, const QString &file, const QString &hash, const QString &type); |
747 | + |
748 | void markTodo(const QString &todoId, bool checked); |
749 | |
750 | private: |
751 | @@ -47,7 +50,6 @@ |
752 | }; |
753 | |
754 | QString convert(const QString ¬eGuid, Type type) const; |
755 | - |
756 | private: |
757 | QString m_enml; |
758 |
PASSED: Continuous integration, rev:46 91.189. 93.70:8080/ job/reminders- app-ci/ 68/ 91.189. 93.70:8080/ job/generic- mediumtests- trusty/ 768 91.189. 93.70:8080/ job/reminders- app-saucy- amd64-ci/ 68 91.189. 93.70:8080/ job/reminders- app-trusty- amd64-ci/ 68
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/reminders- app-ci/ 68/rebuild
http://