Merge lp:~renatofilho/address-book-app/fix-1469005 into lp:address-book-app

Proposed by Renato Araujo Oliveira Filho
Status: Superseded
Proposed branch: lp:~renatofilho/address-book-app/fix-1469005
Merge into: lp:address-book-app
Diff against target: 352 lines (+100/-48)
9 files modified
src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml (+1/-4)
src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml (+24/-3)
src/imports/Ubuntu/Contacts/contacts.cpp (+10/-21)
src/imports/Ubuntu/Contacts/contacts.h (+2/-1)
src/imports/Ubuntu/Contacts/imagescalethread.cpp (+25/-11)
src/imports/Ubuntu/Contacts/imagescalethread.h (+7/-5)
tests/autopilot/address_book_app/__init__.py (+2/-1)
tests/autopilot/address_book_app/pages/__init__.py (+1/-2)
tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py (+28/-0)
To merge this branch: bzr merge lp:~renatofilho/address-book-app/fix-1469005
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Ubuntu Phablet Team Pending
Review via email: mp+274938@code.launchpad.net

This proposal has been superseded by a proposal from 2015-10-28.

Commit message

Use Runnable implementation instead of thread to avoid overload cpu usage.
Implement async copyImage support.

To post a comment you must log in.
484. By Renato Araujo Oliveira Filho

Use Runnable implementation instead of thread to avoid overload cpu usage.
Implement async copyImage support.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
485. By Renato Araujo Oliveira Filho

Trunk merged.

486. By Renato Araujo Oliveira Filho

Merged: ~renatofilho/address-book-app/update-autopilot-with-new-bottom-edge

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml'
2--- src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml 2015-10-26 13:18:11 +0000
3+++ src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml 2015-10-28 19:43:31 +0000
4@@ -59,7 +59,6 @@
5 id: peerPicker
6
7 anchors.fill: parent
8- visible: dialogue.done
9 contentType: ContentType.Pictures
10 handler: ContentHandler.Source
11
12@@ -77,13 +76,11 @@
13 Connections {
14 id: signalConnections
15
16- target: dialogue.activeTransfer
17 onStateChanged: {
18 var done = ((dialogue.activeTransfer.state === ContentTransfer.Charged) ||
19 (dialogue.activeTransfer.state === ContentTransfer.Aborted))
20
21 if (dialogue.activeTransfer.state === ContentTransfer.Charged) {
22- dialogue.hide()
23 if (dialogue.activeTransfer.items.length > 0) {
24 root.avatarReceived(dialogue.activeTransfer.items[0].url)
25 }
26@@ -108,7 +105,7 @@
27 repeat: true
28 running: false
29 onTriggered: {
30- if(Qt.application.active) {
31+ if(Qt.application.state === Qt.ApplicationActive) {
32 PopupUtils.close(root.importDialog)
33 }
34 }
35
36=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml'
37--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-10-26 13:18:11 +0000
38+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-10-28 19:43:31 +0000
39@@ -27,6 +27,8 @@
40
41 readonly property alias busy: activityIndicator.running
42 readonly property string defaultAvatar: "image://theme/add"
43+ property string temporaryAvatar: ""
44+ property string temporaryAvatarId: ""
45
46 function isEmpty() {
47 return false;
48@@ -101,7 +103,7 @@
49 id: activityIndicator
50
51 anchors.centerIn: avatar
52- running: (avatarImport.importDialog != null)
53+ running: (avatarImport.importDialog != null) || (root.temporaryAvatarId != "")
54 visible: running
55 }
56
57@@ -109,12 +111,25 @@
58 id: avatarImport
59
60 onAvatarReceived: {
61+ Contacts.removeFile(root.temporaryAvatar)
62+
63 // remove the previous image, this is nessary to make sure that the new image
64 // get updated otherwise if the new image has the same name the image will not
65 // be updated
66 avatarImage.source = ""
67- // Update with the new value
68- avatarImage.source = Contacts.copyImage(root.contact, avatarUrl);
69+ // copy and resize image
70+ root.temporaryAvatarId = Contacts.copyImage(avatarUrl, null);
71+ }
72+ }
73+
74+ Connections {
75+ target: Contacts
76+ onImageCopyDone: {
77+ if (root.temporaryAvatarId === id) {
78+ root.temporaryAvatar = fileName
79+ avatarImage.source = fileName
80+ root.temporaryAvatarId = ""
81+ }
82 }
83 }
84
85@@ -126,6 +141,12 @@
86 avatarImport.requestNewAvatar()
87 }
88 }
89+
90+ Component.onDestruction: {
91+ console.debug("Delete temporary avatar image:" + root.temporaryAvatar)
92+ Contacts.removeFile("file:///" + root.temporaryAvatar)
93+ root.temporaryAvatar = ""
94+ }
95 }
96
97
98
99=== modified file 'src/imports/Ubuntu/Contacts/contacts.cpp'
100--- src/imports/Ubuntu/Contacts/contacts.cpp 2015-10-14 22:53:35 +0000
101+++ src/imports/Ubuntu/Contacts/contacts.cpp 2015-10-28 19:43:31 +0000
102@@ -23,6 +23,7 @@
103 #include <QtCore/QDir>
104 #include <QtCore/QUrl>
105 #include <QtCore/QLockFile>
106+#include <QtCore/QThreadPool>
107
108 #include "config.h"
109
110@@ -77,27 +78,11 @@
111 return out;
112 }
113
114-QUrl UbuntuContacts::copyImage(QObject *contact, const QUrl &imageUrl)
115+QString UbuntuContacts::copyImage(const QUrl &imageUrl)
116 {
117- // keep track of threads to avoid memory leeak
118- ImageScaleThread *imgThread;
119- QVariant oldThread = contact->property("IMAGE_SCALE_THREAD");
120- if (!oldThread.isNull()) {
121- imgThread = oldThread.value<ImageScaleThread *>();
122- imgThread->updateImageUrl(imageUrl);
123- } else {
124- imgThread = new ImageScaleThread(imageUrl, contact);
125- contact->setProperty("IMAGE_SCALE_THREAD", QVariant::fromValue<ImageScaleThread*>(imgThread));
126- }
127-
128- imgThread->start();
129-
130- // FIXME: implement this as async function
131- while(imgThread->isRunning()) {
132- QCoreApplication::processEvents(QEventLoop::AllEvents, 3000);
133- }
134-
135- return imgThread->outputFile();
136+ ImageScaleThread *imgThread = new ImageScaleThread(imageUrl, this);
137+ QThreadPool::globalInstance()->start(imgThread);
138+ return imgThread->id();
139 }
140
141 bool UbuntuContacts::containsLetters(const QString &value)
142@@ -112,7 +97,11 @@
143
144 bool UbuntuContacts::removeFile(const QUrl &file)
145 {
146- return QFile::remove(file.toLocalFile());
147+ QString localFile = file.toLocalFile();
148+ if (!localFile.isEmpty() && QFile::exists(localFile)) {
149+ return QFile::remove(localFile);
150+ }
151+ return false;
152 }
153
154 bool UbuntuContacts::updateIsRunning() const
155
156=== modified file 'src/imports/Ubuntu/Contacts/contacts.h'
157--- src/imports/Ubuntu/Contacts/contacts.h 2015-10-13 12:50:14 +0000
158+++ src/imports/Ubuntu/Contacts/contacts.h 2015-10-28 19:43:31 +0000
159@@ -36,12 +36,13 @@
160
161 Q_INVOKABLE QString contactInitialsFromString(const QString &value);
162 Q_INVOKABLE QString normalized(const QString &value);
163- Q_INVOKABLE QUrl copyImage(QObject *contact, const QUrl &imageUrl);
164+ Q_INVOKABLE QString copyImage(const QUrl &imageUrl);
165 Q_INVOKABLE bool containsLetters(const QString &value);
166 Q_INVOKABLE bool removeFile(const QUrl &file);
167 Q_INVOKABLE bool updateIsRunning() const;
168
169 Q_SIGNALS:
170+ void imageCopyDone(const QString &id, const QString &fileName);
171 void updateIsRunningChanged();
172
173 private:
174
175=== modified file 'src/imports/Ubuntu/Contacts/imagescalethread.cpp'
176--- src/imports/Ubuntu/Contacts/imagescalethread.cpp 2015-05-07 17:27:16 +0000
177+++ src/imports/Ubuntu/Contacts/imagescalethread.cpp 2015-10-28 19:43:31 +0000
178@@ -20,39 +20,46 @@
179 #include <QImageReader>
180 #include <QFile>
181 #include <QDir>
182+#include <QUuid>
183 #include <QDebug>
184
185-ImageScaleThread::ImageScaleThread(const QUrl &imageUrl, QObject *parent)
186- : QThread(parent),
187- m_imageUrl(imageUrl),
188- m_tmpFile(0)
189+ImageScaleThread::ImageScaleThread(const QUrl &imageUrl, QObject *listener)
190+ : m_imageUrl(imageUrl),
191+ m_id(QUuid::createUuid().toString()),
192+ m_listener(listener),
193+ m_tmpFile(0)
194 {
195 }
196
197 ImageScaleThread::~ImageScaleThread()
198 {
199 if (m_tmpFile) {
200- delete m_tmpFile;
201+ m_tmpFile->setAutoRemove(false);
202+ m_tmpFile->deleteLater();
203+ m_tmpFile = 0;
204 }
205 }
206
207-void ImageScaleThread::updateImageUrl(const QUrl &imageUrl)
208+QString ImageScaleThread::id()
209 {
210- if (isRunning()) {
211- wait();
212- }
213- m_imageUrl = imageUrl;
214+ return m_id;
215 }
216
217 QString ImageScaleThread::outputFile() const
218 {
219- return m_tmpFile->fileName();
220+ if (m_tmpFile) {
221+ return m_tmpFile->fileName();
222+ } else {
223+ return QString();
224+ }
225 }
226
227 void ImageScaleThread::run()
228 {
229 // make sure that the old image get deleted
230 if (m_tmpFile) {
231+ qDebug() << "Delete previous avatar" << m_tmpFile->fileName();
232+ m_tmpFile->setAutoRemove(true);
233 m_tmpFile->close();
234 delete m_tmpFile;
235 }
236@@ -60,6 +67,7 @@
237 // Create the temporary file
238 m_tmpFile = new QTemporaryFile(QString("%1/avatar_XXXXXX.png").arg(QDir::tempPath()));
239 if (!m_tmpFile->open()) {
240+ qWarning() << "Fail to create avatar temporary file";
241 return;
242 }
243
244@@ -91,5 +99,11 @@
245 if (!scaledAvatar.isNull()) {
246 scaledAvatar.save(m_tmpFile, "png");
247 }
248+
249 m_tmpFile->close();
250+
251+ if (m_listener) {
252+ QMetaObject::invokeMethod(m_listener, "imageCopyDone",
253+ Q_ARG(QString, m_id), Q_ARG(QString, m_tmpFile->fileName()));
254+ }
255 }
256
257=== modified file 'src/imports/Ubuntu/Contacts/imagescalethread.h'
258--- src/imports/Ubuntu/Contacts/imagescalethread.h 2015-05-07 17:27:16 +0000
259+++ src/imports/Ubuntu/Contacts/imagescalethread.h 2015-10-28 19:43:31 +0000
260@@ -18,18 +18,18 @@
261 #define IMAGESCALETHREAD_H
262
263 #include <QObject>
264-#include <QThread>
265+#include <QRunnable>
266 #include <QUrl>
267+#include <QPointer>
268 #include <QTemporaryFile>
269
270-class ImageScaleThread : public QThread
271+class ImageScaleThread : public QRunnable
272 {
273- Q_OBJECT
274 public:
275- ImageScaleThread(const QUrl &imageUrl, QObject *parent=0);
276+ ImageScaleThread(const QUrl &imageUrl, QObject *listener);
277 ~ImageScaleThread();
278
279- void updateImageUrl(const QUrl &imageUrl);
280+ QString id();
281 QString outputFile() const;
282
283 protected:
284@@ -37,6 +37,8 @@
285
286 private:
287 QUrl m_imageUrl;
288+ QString m_id;
289+ QPointer<QObject> m_listener;
290 QTemporaryFile *m_tmpFile;
291 };
292
293
294=== modified file 'tests/autopilot/address_book_app/__init__.py'
295--- tests/autopilot/address_book_app/__init__.py 2015-10-20 03:38:07 +0000
296+++ tests/autopilot/address_book_app/__init__.py 2015-10-28 19:43:31 +0000
297@@ -70,7 +70,8 @@
298 def get_contact_edit_page(self):
299 # We can have two contact editor page because of bottom edge page
300 # but we will return only the active one
301- return self.wait_select_single(objectName="contactEditorPage", active=True)
302+ return self.wait_select_single(pages.ABContactEditorPage,
303+ objectName="contactEditorPage", active=True)
304
305 def get_contact_view_page(self):
306 return self.wait_select_single(pages.ABContactViewPage,
307
308=== modified file 'tests/autopilot/address_book_app/pages/__init__.py'
309--- tests/autopilot/address_book_app/pages/__init__.py 2015-05-11 14:21:03 +0000
310+++ tests/autopilot/address_book_app/pages/__init__.py 2015-10-28 19:43:31 +0000
311@@ -20,7 +20,6 @@
312 'ABContactViewPage'
313 ]
314
315-from address_book_app.address_book \
316- import ContactEditorPage as ABContactEditorPage
317+from address_book_app.pages._ab_contact_editor_page import ABContactEditorPage
318 from address_book_app.pages._ab_contact_view_page import ABContactViewPage
319 from address_book_app.pages._ab_contact_list_page import ABContactListPage
320
321=== added file 'tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py'
322--- tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py 1970-01-01 00:00:00 +0000
323+++ tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py 2015-10-28 19:43:31 +0000
324@@ -0,0 +1,28 @@
325+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
326+#
327+# Copyright (C) 2014 Canonical Ltd.
328+#
329+# This program is free software; you can redistribute it and/or modify
330+# it under the terms of the GNU General Public License version 3, as published
331+# by the Free Software Foundation.
332+#
333+# This program is distributed in the hope that it will be useful,
334+# but WITHOUT ANY WARRANTY; without even the implied warranty of
335+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
336+# GNU General Public License for more details.
337+#
338+# You should have received a copy of the GNU General Public License
339+# along with this program. If not, see <http://www.gnu.org/licenses/>.
340+
341+""" ContactEditorPage emulator for Addressbook App tests """
342+
343+import logging
344+import time
345+
346+import autopilot.logging
347+import ubuntuuitoolkit
348+
349+from address_book_app import address_book
350+
351+class ABContactEditorPage(address_book.ContactEditorPage):
352+ """Autopilot helper for the Contact Editor page."""

Subscribers

People subscribed via source and target branches