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
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/AvatarImport.qml 2015-10-28 19:43:31 +0000
@@ -59,7 +59,6 @@
59 id: peerPicker59 id: peerPicker
6060
61 anchors.fill: parent61 anchors.fill: parent
62 visible: dialogue.done
63 contentType: ContentType.Pictures62 contentType: ContentType.Pictures
64 handler: ContentHandler.Source63 handler: ContentHandler.Source
6564
@@ -77,13 +76,11 @@
77 Connections {76 Connections {
78 id: signalConnections77 id: signalConnections
7978
80 target: dialogue.activeTransfer
81 onStateChanged: {79 onStateChanged: {
82 var done = ((dialogue.activeTransfer.state === ContentTransfer.Charged) ||80 var done = ((dialogue.activeTransfer.state === ContentTransfer.Charged) ||
83 (dialogue.activeTransfer.state === ContentTransfer.Aborted))81 (dialogue.activeTransfer.state === ContentTransfer.Aborted))
8482
85 if (dialogue.activeTransfer.state === ContentTransfer.Charged) {83 if (dialogue.activeTransfer.state === ContentTransfer.Charged) {
86 dialogue.hide()
87 if (dialogue.activeTransfer.items.length > 0) {84 if (dialogue.activeTransfer.items.length > 0) {
88 root.avatarReceived(dialogue.activeTransfer.items[0].url)85 root.avatarReceived(dialogue.activeTransfer.items[0].url)
89 }86 }
@@ -108,7 +105,7 @@
108 repeat: true105 repeat: true
109 running: false106 running: false
110 onTriggered: {107 onTriggered: {
111 if(Qt.application.active) {108 if(Qt.application.state === Qt.ApplicationActive) {
112 PopupUtils.close(root.importDialog)109 PopupUtils.close(root.importDialog)
113 }110 }
114 }111 }
115112
=== modified file 'src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml'
--- src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-10-26 13:18:11 +0000
+++ src/imports/Ubuntu/AddressBook/ContactEditor/ContactDetailAvatarEditor.qml 2015-10-28 19:43:31 +0000
@@ -27,6 +27,8 @@
2727
28 readonly property alias busy: activityIndicator.running28 readonly property alias busy: activityIndicator.running
29 readonly property string defaultAvatar: "image://theme/add"29 readonly property string defaultAvatar: "image://theme/add"
30 property string temporaryAvatar: ""
31 property string temporaryAvatarId: ""
3032
31 function isEmpty() {33 function isEmpty() {
32 return false;34 return false;
@@ -101,7 +103,7 @@
101 id: activityIndicator103 id: activityIndicator
102104
103 anchors.centerIn: avatar105 anchors.centerIn: avatar
104 running: (avatarImport.importDialog != null)106 running: (avatarImport.importDialog != null) || (root.temporaryAvatarId != "")
105 visible: running107 visible: running
106 }108 }
107109
@@ -109,12 +111,25 @@
109 id: avatarImport111 id: avatarImport
110112
111 onAvatarReceived: {113 onAvatarReceived: {
114 Contacts.removeFile(root.temporaryAvatar)
115
112 // remove the previous image, this is nessary to make sure that the new image116 // remove the previous image, this is nessary to make sure that the new image
113 // get updated otherwise if the new image has the same name the image will not117 // get updated otherwise if the new image has the same name the image will not
114 // be updated118 // be updated
115 avatarImage.source = ""119 avatarImage.source = ""
116 // Update with the new value120 // copy and resize image
117 avatarImage.source = Contacts.copyImage(root.contact, avatarUrl);121 root.temporaryAvatarId = Contacts.copyImage(avatarUrl, null);
122 }
123 }
124
125 Connections {
126 target: Contacts
127 onImageCopyDone: {
128 if (root.temporaryAvatarId === id) {
129 root.temporaryAvatar = fileName
130 avatarImage.source = fileName
131 root.temporaryAvatarId = ""
132 }
118 }133 }
119 }134 }
120135
@@ -126,6 +141,12 @@
126 avatarImport.requestNewAvatar()141 avatarImport.requestNewAvatar()
127 }142 }
128 }143 }
144
145 Component.onDestruction: {
146 console.debug("Delete temporary avatar image:" + root.temporaryAvatar)
147 Contacts.removeFile("file:///" + root.temporaryAvatar)
148 root.temporaryAvatar = ""
149 }
129}150}
130151
131152
132153
=== modified file 'src/imports/Ubuntu/Contacts/contacts.cpp'
--- src/imports/Ubuntu/Contacts/contacts.cpp 2015-10-14 22:53:35 +0000
+++ src/imports/Ubuntu/Contacts/contacts.cpp 2015-10-28 19:43:31 +0000
@@ -23,6 +23,7 @@
23#include <QtCore/QDir>23#include <QtCore/QDir>
24#include <QtCore/QUrl>24#include <QtCore/QUrl>
25#include <QtCore/QLockFile>25#include <QtCore/QLockFile>
26#include <QtCore/QThreadPool>
2627
27#include "config.h"28#include "config.h"
2829
@@ -77,27 +78,11 @@
77 return out;78 return out;
78}79}
7980
80QUrl UbuntuContacts::copyImage(QObject *contact, const QUrl &imageUrl)81QString UbuntuContacts::copyImage(const QUrl &imageUrl)
81{82{
82 // keep track of threads to avoid memory leeak83 ImageScaleThread *imgThread = new ImageScaleThread(imageUrl, this);
83 ImageScaleThread *imgThread;84 QThreadPool::globalInstance()->start(imgThread);
84 QVariant oldThread = contact->property("IMAGE_SCALE_THREAD");85 return imgThread->id();
85 if (!oldThread.isNull()) {
86 imgThread = oldThread.value<ImageScaleThread *>();
87 imgThread->updateImageUrl(imageUrl);
88 } else {
89 imgThread = new ImageScaleThread(imageUrl, contact);
90 contact->setProperty("IMAGE_SCALE_THREAD", QVariant::fromValue<ImageScaleThread*>(imgThread));
91 }
92
93 imgThread->start();
94
95 // FIXME: implement this as async function
96 while(imgThread->isRunning()) {
97 QCoreApplication::processEvents(QEventLoop::AllEvents, 3000);
98 }
99
100 return imgThread->outputFile();
101}86}
10287
103bool UbuntuContacts::containsLetters(const QString &value)88bool UbuntuContacts::containsLetters(const QString &value)
@@ -112,7 +97,11 @@
11297
113bool UbuntuContacts::removeFile(const QUrl &file)98bool UbuntuContacts::removeFile(const QUrl &file)
114{99{
115 return QFile::remove(file.toLocalFile());100 QString localFile = file.toLocalFile();
101 if (!localFile.isEmpty() && QFile::exists(localFile)) {
102 return QFile::remove(localFile);
103 }
104 return false;
116}105}
117106
118bool UbuntuContacts::updateIsRunning() const107bool UbuntuContacts::updateIsRunning() const
119108
=== modified file 'src/imports/Ubuntu/Contacts/contacts.h'
--- src/imports/Ubuntu/Contacts/contacts.h 2015-10-13 12:50:14 +0000
+++ src/imports/Ubuntu/Contacts/contacts.h 2015-10-28 19:43:31 +0000
@@ -36,12 +36,13 @@
3636
37 Q_INVOKABLE QString contactInitialsFromString(const QString &value);37 Q_INVOKABLE QString contactInitialsFromString(const QString &value);
38 Q_INVOKABLE QString normalized(const QString &value);38 Q_INVOKABLE QString normalized(const QString &value);
39 Q_INVOKABLE QUrl copyImage(QObject *contact, const QUrl &imageUrl);39 Q_INVOKABLE QString copyImage(const QUrl &imageUrl);
40 Q_INVOKABLE bool containsLetters(const QString &value);40 Q_INVOKABLE bool containsLetters(const QString &value);
41 Q_INVOKABLE bool removeFile(const QUrl &file);41 Q_INVOKABLE bool removeFile(const QUrl &file);
42 Q_INVOKABLE bool updateIsRunning() const;42 Q_INVOKABLE bool updateIsRunning() const;
4343
44Q_SIGNALS:44Q_SIGNALS:
45 void imageCopyDone(const QString &id, const QString &fileName);
45 void updateIsRunningChanged();46 void updateIsRunningChanged();
4647
47private:48private:
4849
=== modified file 'src/imports/Ubuntu/Contacts/imagescalethread.cpp'
--- src/imports/Ubuntu/Contacts/imagescalethread.cpp 2015-05-07 17:27:16 +0000
+++ src/imports/Ubuntu/Contacts/imagescalethread.cpp 2015-10-28 19:43:31 +0000
@@ -20,39 +20,46 @@
20#include <QImageReader>20#include <QImageReader>
21#include <QFile>21#include <QFile>
22#include <QDir>22#include <QDir>
23#include <QUuid>
23#include <QDebug>24#include <QDebug>
2425
25ImageScaleThread::ImageScaleThread(const QUrl &imageUrl, QObject *parent)26ImageScaleThread::ImageScaleThread(const QUrl &imageUrl, QObject *listener)
26 : QThread(parent),27 : m_imageUrl(imageUrl),
27 m_imageUrl(imageUrl),28 m_id(QUuid::createUuid().toString()),
28 m_tmpFile(0)29 m_listener(listener),
30 m_tmpFile(0)
29{31{
30}32}
3133
32ImageScaleThread::~ImageScaleThread()34ImageScaleThread::~ImageScaleThread()
33{35{
34 if (m_tmpFile) {36 if (m_tmpFile) {
35 delete m_tmpFile;37 m_tmpFile->setAutoRemove(false);
38 m_tmpFile->deleteLater();
39 m_tmpFile = 0;
36 }40 }
37}41}
3842
39void ImageScaleThread::updateImageUrl(const QUrl &imageUrl)43QString ImageScaleThread::id()
40{44{
41 if (isRunning()) {45 return m_id;
42 wait();
43 }
44 m_imageUrl = imageUrl;
45}46}
4647
47QString ImageScaleThread::outputFile() const48QString ImageScaleThread::outputFile() const
48{49{
49 return m_tmpFile->fileName();50 if (m_tmpFile) {
51 return m_tmpFile->fileName();
52 } else {
53 return QString();
54 }
50}55}
5156
52void ImageScaleThread::run()57void ImageScaleThread::run()
53{58{
54 // make sure that the old image get deleted59 // make sure that the old image get deleted
55 if (m_tmpFile) {60 if (m_tmpFile) {
61 qDebug() << "Delete previous avatar" << m_tmpFile->fileName();
62 m_tmpFile->setAutoRemove(true);
56 m_tmpFile->close();63 m_tmpFile->close();
57 delete m_tmpFile;64 delete m_tmpFile;
58 }65 }
@@ -60,6 +67,7 @@
60 // Create the temporary file67 // Create the temporary file
61 m_tmpFile = new QTemporaryFile(QString("%1/avatar_XXXXXX.png").arg(QDir::tempPath()));68 m_tmpFile = new QTemporaryFile(QString("%1/avatar_XXXXXX.png").arg(QDir::tempPath()));
62 if (!m_tmpFile->open()) {69 if (!m_tmpFile->open()) {
70 qWarning() << "Fail to create avatar temporary file";
63 return;71 return;
64 }72 }
6573
@@ -91,5 +99,11 @@
91 if (!scaledAvatar.isNull()) {99 if (!scaledAvatar.isNull()) {
92 scaledAvatar.save(m_tmpFile, "png");100 scaledAvatar.save(m_tmpFile, "png");
93 }101 }
102
94 m_tmpFile->close();103 m_tmpFile->close();
104
105 if (m_listener) {
106 QMetaObject::invokeMethod(m_listener, "imageCopyDone",
107 Q_ARG(QString, m_id), Q_ARG(QString, m_tmpFile->fileName()));
108 }
95}109}
96110
=== modified file 'src/imports/Ubuntu/Contacts/imagescalethread.h'
--- src/imports/Ubuntu/Contacts/imagescalethread.h 2015-05-07 17:27:16 +0000
+++ src/imports/Ubuntu/Contacts/imagescalethread.h 2015-10-28 19:43:31 +0000
@@ -18,18 +18,18 @@
18#define IMAGESCALETHREAD_H18#define IMAGESCALETHREAD_H
1919
20#include <QObject>20#include <QObject>
21#include <QThread>21#include <QRunnable>
22#include <QUrl>22#include <QUrl>
23#include <QPointer>
23#include <QTemporaryFile>24#include <QTemporaryFile>
2425
25class ImageScaleThread : public QThread26class ImageScaleThread : public QRunnable
26{27{
27 Q_OBJECT
28public:28public:
29 ImageScaleThread(const QUrl &imageUrl, QObject *parent=0);29 ImageScaleThread(const QUrl &imageUrl, QObject *listener);
30 ~ImageScaleThread();30 ~ImageScaleThread();
3131
32 void updateImageUrl(const QUrl &imageUrl);32 QString id();
33 QString outputFile() const;33 QString outputFile() const;
3434
35protected:35protected:
@@ -37,6 +37,8 @@
3737
38private:38private:
39 QUrl m_imageUrl;39 QUrl m_imageUrl;
40 QString m_id;
41 QPointer<QObject> m_listener;
40 QTemporaryFile *m_tmpFile;42 QTemporaryFile *m_tmpFile;
41};43};
4244
4345
=== modified file 'tests/autopilot/address_book_app/__init__.py'
--- tests/autopilot/address_book_app/__init__.py 2015-10-20 03:38:07 +0000
+++ tests/autopilot/address_book_app/__init__.py 2015-10-28 19:43:31 +0000
@@ -70,7 +70,8 @@
70 def get_contact_edit_page(self):70 def get_contact_edit_page(self):
71 # We can have two contact editor page because of bottom edge page71 # We can have two contact editor page because of bottom edge page
72 # but we will return only the active one72 # but we will return only the active one
73 return self.wait_select_single(objectName="contactEditorPage", active=True)73 return self.wait_select_single(pages.ABContactEditorPage,
74 objectName="contactEditorPage", active=True)
7475
75 def get_contact_view_page(self):76 def get_contact_view_page(self):
76 return self.wait_select_single(pages.ABContactViewPage,77 return self.wait_select_single(pages.ABContactViewPage,
7778
=== modified file 'tests/autopilot/address_book_app/pages/__init__.py'
--- tests/autopilot/address_book_app/pages/__init__.py 2015-05-11 14:21:03 +0000
+++ tests/autopilot/address_book_app/pages/__init__.py 2015-10-28 19:43:31 +0000
@@ -20,7 +20,6 @@
20 'ABContactViewPage'20 'ABContactViewPage'
21]21]
2222
23from address_book_app.address_book \23from address_book_app.pages._ab_contact_editor_page import ABContactEditorPage
24 import ContactEditorPage as ABContactEditorPage
25from address_book_app.pages._ab_contact_view_page import ABContactViewPage24from address_book_app.pages._ab_contact_view_page import ABContactViewPage
26from address_book_app.pages._ab_contact_list_page import ABContactListPage25from address_book_app.pages._ab_contact_list_page import ABContactListPage
2726
=== added file 'tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py'
--- tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/address_book_app/pages/_ab_contact_editor_page.py 2015-10-28 19:43:31 +0000
@@ -0,0 +1,28 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2014 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17""" ContactEditorPage emulator for Addressbook App tests """
18
19import logging
20import time
21
22import autopilot.logging
23import ubuntuuitoolkit
24
25from address_book_app import address_book
26
27class ABContactEditorPage(address_book.ContactEditorPage):
28 """Autopilot helper for the Contact Editor page."""

Subscribers

People subscribed via source and target branches