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