Merge lp:camera-app/staging into lp:camera-app
- staging
- Merge into trunk
Status: | Merged | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Florian Boucault | ||||||||||||||||||||||||||||||||
Approved revision: | 658 | ||||||||||||||||||||||||||||||||
Merged at revision: | 636 | ||||||||||||||||||||||||||||||||
Proposed branch: | lp:camera-app/staging | ||||||||||||||||||||||||||||||||
Merge into: | lp:camera-app | ||||||||||||||||||||||||||||||||
Diff against target: |
2752 lines (+657/-1424) 31 files modified
BottomEdgeIndicators.qml (+1/-1) CameraApp/CMakeLists.txt (+2/-4) CameraApp/advancedcamerasettings.cpp (+3/-3) CameraApp/components.cpp (+9/-0) CameraApp/qstorageinfo.cpp (+0/-378) CameraApp/qstorageinfo.h (+0/-102) CameraApp/qstorageinfo_p.h (+0/-84) CameraApp/qstorageinfo_unix.cpp (+0/-442) CameraApp/storagelocations.cpp (+121/-0) CameraApp/storagelocations.h (+50/-0) CameraApp/storagemonitor.cpp (+34/-1) CameraApp/storagemonitor.h (+5/-0) GalleryView.qml (+3/-3) GalleryViewHeader.qml (+3/-3) PictureReview.qml (+46/-0) ProcessingFeedback.qml (+43/-0) SharePopover.qml (+1/-9) Snapshot.qml (+0/-98) ViewFinderExportConfirmation.qml (+40/-21) ViewFinderOverlay.qml (+103/-40) ViewFinderOverlayLoader.qml (+4/-1) ViewFinderView.qml (+112/-65) cameraapplication.cpp (+0/-106) cameraapplication.h (+0/-15) debian/rules (+0/-4) manifest.json.in (+1/-1) run_tests.sh (+0/-13) tests/autopilot/camera_app/tests/test_focus.py (+32/-28) tests/autopilot/camera_app/tests/test_options.py (+27/-0) tests/unittests/CMakeLists.txt (+1/-0) tests/unittests/qstorageinfo_stub.cpp (+16/-2) |
||||||||||||||||||||||||||||||||
To merge this branch: | bzr merge lp:camera-app/staging | ||||||||||||||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+284427@code.launchpad.net |
Commit message
New release:
- Allow tap to focus up to the left/right edge of the screen
- Query the manual focus support to enable/disable tap-to-focus as the backend supports it
- Do not crash if no QCameraExposure
- Before setting a photo capture resolution, always checks it is included in the possible resolution options
- Fix bottom edge mouse handling: ensure that clicks on the bottom edge open it and that any click outside of option buttons dismiss the bottom edge
- Various performance improvements to minimize the time between shots and between pressing the shutter button and the actual capture
- When the GPS fix is accurate to less than 100m display the GPS icon in red and don't save location
- Display error messages when disk write fails and when SD card is not writeable when switching to it
- Disable record/shuttle button while PhotoRoll hint is visible
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:643
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:651
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:656
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:658
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 659. By Florian Boucault
-
Add flake8 tests to unit tests
Preview Diff
1 | === modified file 'BottomEdgeIndicators.qml' |
2 | --- BottomEdgeIndicators.qml 2015-11-17 15:25:03 +0000 |
3 | +++ BottomEdgeIndicators.qml 2016-02-26 17:17:00 +0000 |
4 | @@ -83,7 +83,7 @@ |
5 | Icon { |
6 | id: indicatorIcon |
7 | anchors.fill: parent |
8 | - color: "white" |
9 | + color: modelData.colorize ? "red" : "white" |
10 | name: modelData && modelData.isToggle ? modelData.icon : (modelData.get(model.selectedIndex) ? modelData.get(model.selectedIndex).icon : "") |
11 | source: name ? "image://theme/%1".arg(name) : (modelData.iconSource || "") |
12 | visible: source != "" |
13 | |
14 | === modified file 'CameraApp/CMakeLists.txt' |
15 | --- CameraApp/CMakeLists.txt 2015-11-18 06:44:35 +0000 |
16 | +++ CameraApp/CMakeLists.txt 2016-02-26 17:17:00 +0000 |
17 | @@ -7,8 +7,7 @@ |
18 | fileoperations.cpp |
19 | foldersmodel.cpp |
20 | storagemonitor.cpp |
21 | - qstorageinfo.cpp |
22 | - qstorageinfo_unix.cpp |
23 | + storagelocations.cpp |
24 | ) |
25 | |
26 | set(plugin_HDRS |
27 | @@ -17,8 +16,7 @@ |
28 | fileoperations.h |
29 | foldersmodel.h |
30 | storagemonitor.h |
31 | - qstorageinfo.h |
32 | - qstorageinfo_p.h |
33 | + storagelocations.h |
34 | ) |
35 | |
36 | add_library(camera-qml SHARED ${plugin_SRCS} ${plugin_HDRS}) |
37 | |
38 | === modified file 'CameraApp/advancedcamerasettings.cpp' |
39 | --- CameraApp/advancedcamerasettings.cpp 2016-01-05 13:08:28 +0000 |
40 | +++ CameraApp/advancedcamerasettings.cpp 2016-02-26 17:17:00 +0000 |
41 | @@ -237,11 +237,11 @@ |
42 | |
43 | m_cameraFlashControl = flashControlFromCamera(m_camera); |
44 | m_cameraExposureControl = exposureControlFromCamera(m_camera); |
45 | - QVariant exposureMode = m_hdrEnabled ? QVariant::fromValue(ExposureHdr) |
46 | - : QVariant::fromValue(QCameraExposure::ExposureAuto); |
47 | - m_cameraExposureControl->setValue(QCameraExposureControl::ExposureMode, exposureMode); |
48 | |
49 | if (m_cameraExposureControl) { |
50 | + QVariant exposureMode = m_hdrEnabled ? QVariant::fromValue(ExposureHdr) |
51 | + : QVariant::fromValue(QCameraExposure::ExposureAuto); |
52 | + m_cameraExposureControl->setValue(QCameraExposureControl::ExposureMode, exposureMode); |
53 | QObject::connect(m_cameraExposureControl, |
54 | SIGNAL(actualValueChanged(int)), |
55 | this, SLOT(onExposureValueChanged(int))); |
56 | |
57 | === modified file 'CameraApp/components.cpp' |
58 | --- CameraApp/components.cpp 2015-01-22 16:15:08 +0000 |
59 | +++ CameraApp/components.cpp 2016-02-26 17:17:00 +0000 |
60 | @@ -24,6 +24,14 @@ |
61 | #include "fileoperations.h" |
62 | #include "foldersmodel.h" |
63 | #include "storagemonitor.h" |
64 | +#include "storagelocations.h" |
65 | + |
66 | +static QObject* StorageLocations_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) |
67 | +{ |
68 | + Q_UNUSED(engine); |
69 | + Q_UNUSED(scriptEngine); |
70 | + return new StorageLocations(); |
71 | +} |
72 | |
73 | void Components::registerTypes(const char *uri) |
74 | { |
75 | @@ -34,6 +42,7 @@ |
76 | qmlRegisterType<FileOperations>(uri, 0, 1, "FileOperations"); |
77 | qmlRegisterType<FoldersModel>(uri, 0, 1, "FoldersModel"); |
78 | qmlRegisterType<StorageMonitor>(uri, 0, 1, "StorageMonitor"); |
79 | + qmlRegisterSingletonType<StorageLocations>(uri, 0, 1, "StorageLocations", StorageLocations_singleton_factory); |
80 | } |
81 | |
82 | void Components::initializeEngine(QQmlEngine *engine, const char *uri) |
83 | |
84 | === removed file 'CameraApp/qstorageinfo.cpp' |
85 | --- CameraApp/qstorageinfo.cpp 2015-01-27 14:34:31 +0000 |
86 | +++ CameraApp/qstorageinfo.cpp 1970-01-01 00:00:00 +0000 |
87 | @@ -1,378 +0,0 @@ |
88 | -/**************************************************************************** |
89 | -** |
90 | -** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> |
91 | -** Contact: http://www.qt-project.org/legal |
92 | -** |
93 | -** This file is part of the QtCore module of the Qt Toolkit. |
94 | -** |
95 | -** This program is free software; you can redistribute it and/or modify |
96 | -** it under the terms of the GNU General Public License as published by |
97 | -** the Free Software Foundation; version 3. |
98 | -** |
99 | -** This program is distributed in the hope that it will be useful, |
100 | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
101 | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
102 | -** GNU General Public License for more details. |
103 | -** |
104 | -** You should have received a copy of the GNU General Public License |
105 | -** along with this program. If not, see <http://www.gnu.org/licenses/>. |
106 | -** |
107 | -****************************************************************************/ |
108 | - |
109 | -#include "qstorageinfo.h" |
110 | -#include "qstorageinfo_p.h" |
111 | - |
112 | -QT_BEGIN_NAMESPACE |
113 | - |
114 | -/*! |
115 | - \class QStorageInfo |
116 | - \inmodule QtCore |
117 | - \since 5.4 |
118 | - \brief Provides information about currently mounted storage and drives. |
119 | - |
120 | - \ingroup io |
121 | - \ingroup shared |
122 | - |
123 | - Allows retrieving information about the volume's space, its mount point, |
124 | - label, and filesystem name. |
125 | - |
126 | - You can create an instance of QStorageInfo by passing the path to the |
127 | - volume's mount point as a constructor parameter, or you can set it using |
128 | - the setPath() method. The static mountedVolumes() method can be used to get the |
129 | - list of all mounted filesystems. |
130 | - |
131 | - QStorageInfo always caches the retrieved information, but you can call |
132 | - refresh() to invalidate the cache. |
133 | - |
134 | - The following example retrieves the most common information about the root |
135 | - volume of the system, and prints information about it. |
136 | - |
137 | - \snippet code/src_corelib_io_qstorageinfo.cpp 2 |
138 | -*/ |
139 | - |
140 | -/*! |
141 | - Constructs an empty QStorageInfo object. |
142 | - |
143 | - Objects created with the default constructor will be invalid and therefore |
144 | - not ready for use. |
145 | - |
146 | - \sa setPath(), isReady(), isValid() |
147 | -*/ |
148 | -QStorageInfo::QStorageInfo() |
149 | - : d(new QStorageInfoPrivate) |
150 | -{ |
151 | -} |
152 | - |
153 | -/*! |
154 | - Constructs a new QStorageInfo object that gives information about the volume |
155 | - mounted at \a path. |
156 | - |
157 | - If you pass a directory or file, the QStorageInfo object will refer to the |
158 | - volume where this directory or file is located. |
159 | - You can check if the created object is correct using the isValid() method. |
160 | - |
161 | - The following example shows how to get the volume on which the application is |
162 | - located. It is recommended to always check that the volume is ready and valid. |
163 | - |
164 | - \snippet code/src_corelib_io_qstorageinfo.cpp 0 |
165 | - |
166 | - \sa setPath() |
167 | -*/ |
168 | -QStorageInfo::QStorageInfo(const QString &path) |
169 | - : d(new QStorageInfoPrivate) |
170 | -{ |
171 | - setPath(path); |
172 | -} |
173 | - |
174 | -/*! |
175 | - Constructs a new QStorageInfo object that gives information about the volume |
176 | - containing the \a dir folder. |
177 | -*/ |
178 | -QStorageInfo::QStorageInfo(const QDir &dir) |
179 | - : d(new QStorageInfoPrivate) |
180 | -{ |
181 | - setPath(dir.absolutePath()); |
182 | -} |
183 | - |
184 | -/*! |
185 | - Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object. |
186 | -*/ |
187 | -QStorageInfo::QStorageInfo(const QStorageInfo &other) |
188 | - : d(other.d) |
189 | -{ |
190 | -} |
191 | - |
192 | -/*! |
193 | - Destroys the QStorageInfo object and frees its resources. |
194 | -*/ |
195 | -QStorageInfo::~QStorageInfo() |
196 | -{ |
197 | -} |
198 | - |
199 | -/*! |
200 | - Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object. |
201 | -*/ |
202 | -QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other) |
203 | -{ |
204 | - d = other.d; |
205 | - return *this; |
206 | -} |
207 | - |
208 | -/*! |
209 | - \fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other) |
210 | - |
211 | - Assigns \a other to this QStorageInfo instance. |
212 | -*/ |
213 | - |
214 | -/*! |
215 | - \fn void QStorageInfo::swap(QStorageInfo &other) |
216 | - |
217 | - Swaps this volume info with \a other. This function is very fast and |
218 | - never fails. |
219 | -*/ |
220 | - |
221 | -/*! |
222 | - Sets this QStorageInfo object to the filesystem mounted where \a path is located. |
223 | - |
224 | - \a path can either be a root path of the filesystem, a directory, or a file |
225 | - within that filesystem. |
226 | - |
227 | - \sa rootPath() |
228 | -*/ |
229 | -void QStorageInfo::setPath(const QString &path) |
230 | -{ |
231 | - if (d->rootPath == path) |
232 | - return; |
233 | - d.detach(); |
234 | - d->rootPath = path; |
235 | - d->doStat(); |
236 | -} |
237 | - |
238 | -/*! |
239 | - Returns the mount point of the filesystem this QStorageInfo object |
240 | - represents. |
241 | - |
242 | - On Windows, it returns the volume letter in case the volume is not mounted to |
243 | - a directory. |
244 | - |
245 | - Note that the value returned by rootPath() is the real mount point of a |
246 | - volume, and may not be equal to the value passed to the constructor or setPath() |
247 | - method. For example, if you have only the root volume in the system, and |
248 | - pass '/directory' to setPath(), then this method will return '/'. |
249 | - |
250 | - \sa setPath(), device() |
251 | -*/ |
252 | -QString QStorageInfo::rootPath() const |
253 | -{ |
254 | - return d->rootPath; |
255 | -} |
256 | - |
257 | -/*! |
258 | - Returns the size (in bytes) available for the current user. It returns |
259 | - the total size available if the user is the root user or a system administrator. |
260 | - |
261 | - This size can be less than or equal to the free size returned by |
262 | - bytesFree() function. |
263 | - |
264 | - \sa bytesTotal(), bytesFree() |
265 | -*/ |
266 | -qint64 QStorageInfo::bytesAvailable() const |
267 | -{ |
268 | - return d->bytesAvailable; |
269 | -} |
270 | - |
271 | -/*! |
272 | - Returns the number of free bytes in a volume. Note that if there are |
273 | - quotas on the filesystem, this value can be larger than the value |
274 | - returned by bytesAvailable(). |
275 | - |
276 | - \sa bytesTotal(), bytesAvailable() |
277 | -*/ |
278 | -qint64 QStorageInfo::bytesFree() const |
279 | -{ |
280 | - return d->bytesFree; |
281 | -} |
282 | - |
283 | -/*! |
284 | - Returns the total volume size in bytes. |
285 | - |
286 | - \sa bytesFree(), bytesAvailable() |
287 | -*/ |
288 | -qint64 QStorageInfo::bytesTotal() const |
289 | -{ |
290 | - return d->bytesTotal; |
291 | -} |
292 | - |
293 | -/*! |
294 | - Returns the type name of the filesystem. |
295 | - |
296 | - This is a platform-dependent function, and filesystem names can vary |
297 | - between different operating systems. For example, on Windows filesystems |
298 | - they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk. |
299 | - |
300 | - \sa name() |
301 | -*/ |
302 | -QByteArray QStorageInfo::fileSystemType() const |
303 | -{ |
304 | - return d->fileSystemType; |
305 | -} |
306 | - |
307 | -/*! |
308 | - Returns the device for this volume. |
309 | - |
310 | - For example, on Unix filesystems (including OS X), this returns the |
311 | - devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC |
312 | - path starting with \c \\\\?\\ for local storages (in other words, the volume GUID). |
313 | - |
314 | - \sa rootPath() |
315 | -*/ |
316 | -QByteArray QStorageInfo::device() const |
317 | -{ |
318 | - return d->device; |
319 | -} |
320 | - |
321 | -/*! |
322 | - Returns the human-readable name of a filesystem, usually called \c label. |
323 | - |
324 | - Not all filesystems support this feature. In this case, the value returned by |
325 | - this method could be empty. An empty string is returned if the file system |
326 | - does not support labels, or if no label is set. |
327 | - |
328 | - On Linux, retrieving the volume's label requires \c udev to be present in the |
329 | - system. |
330 | - |
331 | - \sa fileSystemType() |
332 | -*/ |
333 | -QString QStorageInfo::name() const |
334 | -{ |
335 | - return d->name; |
336 | -} |
337 | - |
338 | -/*! |
339 | - Returns the volume's name, if available, or the root path if not. |
340 | -*/ |
341 | -QString QStorageInfo::displayName() const |
342 | -{ |
343 | - if (!d->name.isEmpty()) |
344 | - return d->name; |
345 | - return d->rootPath; |
346 | -} |
347 | - |
348 | -/*! |
349 | - \fn bool QStorageInfo::isRoot() const |
350 | - |
351 | - Returns true if this QStorageInfo represents the system root volume; false |
352 | - otherwise. |
353 | - |
354 | - On Unix filesystems, the root volume is a volume mounted on \c /. On Windows, |
355 | - the root volume is the volume where the OS is installed. |
356 | - |
357 | - \sa root() |
358 | -*/ |
359 | - |
360 | -/*! |
361 | - Returns true if the current filesystem is protected from writing; false |
362 | - otherwise. |
363 | -*/ |
364 | -bool QStorageInfo::isReadOnly() const |
365 | -{ |
366 | - return d->readOnly; |
367 | -} |
368 | - |
369 | -/*! |
370 | - Returns true if the current filesystem is ready to work; false otherwise. For |
371 | - example, false is returned if the CD volume is not inserted. |
372 | - |
373 | - Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and |
374 | - bytesAvailable() will return invalid data until the volume is ready. |
375 | - |
376 | - \sa isValid() |
377 | -*/ |
378 | -bool QStorageInfo::isReady() const |
379 | -{ |
380 | - return d->ready; |
381 | -} |
382 | - |
383 | -/*! |
384 | - Returns true if the QStorageInfo specified by rootPath exists and is mounted |
385 | - correctly. |
386 | - |
387 | - \sa isReady() |
388 | -*/ |
389 | -bool QStorageInfo::isValid() const |
390 | -{ |
391 | - return d->valid; |
392 | -} |
393 | - |
394 | -/*! |
395 | - Resets QStorageInfo's internal cache. |
396 | - |
397 | - QStorageInfo caches information about storage to speed up performance. |
398 | - QStorageInfo retrieves information during object construction and/or when calling |
399 | - the setPath() method. You have to manually reset the cache by calling this |
400 | - function to update storage information. |
401 | -*/ |
402 | -void QStorageInfo::refresh() |
403 | -{ |
404 | - d.detach(); |
405 | - d->doStat(); |
406 | -} |
407 | - |
408 | -/*! |
409 | - Returns the list of QStorageInfo objects that corresponds to the list of currently |
410 | - mounted filesystems. |
411 | - |
412 | - On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix |
413 | - operating systems, it returns the list of all mounted filesystems (except for |
414 | - pseudo filesystems). |
415 | - |
416 | - Returns all currently mounted filesystems by default. |
417 | - |
418 | - The example shows how to retrieve all available filesystems, skipping read-only ones. |
419 | - |
420 | - \snippet code/src_corelib_io_qstorageinfo.cpp 1 |
421 | - |
422 | - \sa root() |
423 | -*/ |
424 | -QList<QStorageInfo> QStorageInfo::mountedVolumes() |
425 | -{ |
426 | - return QStorageInfoPrivate::mountedVolumes(); |
427 | -} |
428 | - |
429 | -Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root())) |
430 | - |
431 | -/*! |
432 | - Returns a QStorageInfo object that represents the system root volume. |
433 | - |
434 | - On Unix systems this call returns the root ('/') volume; in Windows the volume where |
435 | - the operating system is installed. |
436 | - |
437 | - \sa isRoot() |
438 | -*/ |
439 | -QStorageInfo QStorageInfo::root() |
440 | -{ |
441 | - return *getRoot(); |
442 | -} |
443 | - |
444 | -/*! |
445 | - \fn inline bool operator==(const QStorageInfo &first, const QStorageInfo &second) |
446 | - |
447 | - \relates QStorageInfo |
448 | - |
449 | - Returns true if the \a first QStorageInfo object refers to the same drive or volume |
450 | - as the \a second; otherwise it returns false. |
451 | - |
452 | - Note that the result of comparing two invalid QStorageInfo objects is always |
453 | - positive. |
454 | -*/ |
455 | - |
456 | -/*! |
457 | - \fn inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second) |
458 | - |
459 | - \relates QStorageInfo |
460 | - |
461 | - Returns true if the \a first QStorageInfo object refers to a different drive or |
462 | - volume than the \a second; otherwise returns false. |
463 | -*/ |
464 | - |
465 | -QT_END_NAMESPACE |
466 | |
467 | === removed file 'CameraApp/qstorageinfo.h' |
468 | --- CameraApp/qstorageinfo.h 2015-01-27 14:34:31 +0000 |
469 | +++ CameraApp/qstorageinfo.h 1970-01-01 00:00:00 +0000 |
470 | @@ -1,102 +0,0 @@ |
471 | -/**************************************************************************** |
472 | -** |
473 | -** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> |
474 | -** Contact: http://www.qt-project.org/legal |
475 | -** |
476 | -** This file is part of the QtCore module of the Qt Toolkit. |
477 | -** |
478 | -** This program is free software; you can redistribute it and/or modify |
479 | -** it under the terms of the GNU General Public License as published by |
480 | -** the Free Software Foundation; version 3. |
481 | -** |
482 | -** This program is distributed in the hope that it will be useful, |
483 | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
484 | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
485 | -** GNU General Public License for more details. |
486 | -** |
487 | -** You should have received a copy of the GNU General Public License |
488 | -** along with this program. If not, see <http://www.gnu.org/licenses/>. |
489 | -** |
490 | -****************************************************************************/ |
491 | - |
492 | -#ifndef QSTORAGEINFO_H |
493 | -#define QSTORAGEINFO_H |
494 | - |
495 | -#include <QtCore/qbytearray.h> |
496 | -#include <QtCore/qdir.h> |
497 | -#include <QtCore/qlist.h> |
498 | -#include <QtCore/qmetatype.h> |
499 | -#include <QtCore/qstring.h> |
500 | -#include <QtCore/qshareddata.h> |
501 | - |
502 | -QT_BEGIN_NAMESPACE |
503 | - |
504 | -class QStorageInfoPrivate; |
505 | -class Q_CORE_EXPORT QStorageInfo |
506 | -{ |
507 | -public: |
508 | - QStorageInfo(); |
509 | - explicit QStorageInfo(const QString &path); |
510 | - explicit QStorageInfo(const QDir &dir); |
511 | - QStorageInfo(const QStorageInfo &other); |
512 | - ~QStorageInfo(); |
513 | - |
514 | - QStorageInfo &operator=(const QStorageInfo &other); |
515 | -#ifdef Q_COMPILER_RVALUE_REFS |
516 | - inline QStorageInfo &operator=(QStorageInfo &&other) |
517 | - { qSwap(d, other.d); return *this; } |
518 | -#endif |
519 | - |
520 | - inline void swap(QStorageInfo &other) |
521 | - { qSwap(d, other.d); } |
522 | - |
523 | - void setPath(const QString &path); |
524 | - |
525 | - QString rootPath() const; |
526 | - QByteArray device() const; |
527 | - QByteArray fileSystemType() const; |
528 | - QString name() const; |
529 | - QString displayName() const; |
530 | - |
531 | - qint64 bytesTotal() const; |
532 | - qint64 bytesFree() const; |
533 | - qint64 bytesAvailable() const; |
534 | - |
535 | - inline bool isRoot() const; |
536 | - bool isReadOnly() const; |
537 | - bool isReady() const; |
538 | - bool isValid() const; |
539 | - |
540 | - void refresh(); |
541 | - |
542 | - static QList<QStorageInfo> mountedVolumes(); |
543 | - static QStorageInfo root(); |
544 | - |
545 | -private: |
546 | - friend class QStorageInfoPrivate; |
547 | - friend bool operator==(const QStorageInfo &first, const QStorageInfo &second); |
548 | - QExplicitlySharedDataPointer<QStorageInfoPrivate> d; |
549 | -}; |
550 | - |
551 | -inline bool operator==(const QStorageInfo &first, const QStorageInfo &second) |
552 | -{ |
553 | - if (first.d == second.d) |
554 | - return true; |
555 | - return first.device() == second.device(); |
556 | -} |
557 | - |
558 | -inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second) |
559 | -{ |
560 | - return !(first == second); |
561 | -} |
562 | - |
563 | -inline bool QStorageInfo::isRoot() const |
564 | -{ return *this == QStorageInfo::root(); } |
565 | - |
566 | -Q_DECLARE_SHARED(QStorageInfo) |
567 | - |
568 | -QT_END_NAMESPACE |
569 | - |
570 | -Q_DECLARE_METATYPE(QStorageInfo) |
571 | - |
572 | -#endif // QSTORAGEINFO_H |
573 | |
574 | === removed file 'CameraApp/qstorageinfo_p.h' |
575 | --- CameraApp/qstorageinfo_p.h 2015-01-27 14:34:31 +0000 |
576 | +++ CameraApp/qstorageinfo_p.h 1970-01-01 00:00:00 +0000 |
577 | @@ -1,84 +0,0 @@ |
578 | -/**************************************************************************** |
579 | -** |
580 | -** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> |
581 | -** Contact: http://www.qt-project.org/legal |
582 | -** |
583 | -** |
584 | -** This file is part of the QtCore module of the Qt Toolkit. |
585 | -** |
586 | -** This program is free software; you can redistribute it and/or modify |
587 | -** it under the terms of the GNU General Public License as published by |
588 | -** the Free Software Foundation; version 3. |
589 | -** |
590 | -** This program is distributed in the hope that it will be useful, |
591 | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
592 | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
593 | -** GNU General Public License for more details. |
594 | -** |
595 | -** You should have received a copy of the GNU General Public License |
596 | -** along with this program. If not, see <http://www.gnu.org/licenses/>. |
597 | -** |
598 | -****************************************************************************/ |
599 | - |
600 | -#ifndef QSTORAGEINFO_P_H |
601 | -#define QSTORAGEINFO_P_H |
602 | - |
603 | -// |
604 | -// W A R N I N G |
605 | -// ------------- |
606 | -// |
607 | -// This file is not part of the Qt API. It exists purely as an |
608 | -// implementation detail. This header file may change from version to |
609 | -// version without notice, or even be removed. |
610 | -// |
611 | -// We mean it. |
612 | -// |
613 | - |
614 | -#include "qstorageinfo.h" |
615 | - |
616 | -QT_BEGIN_NAMESPACE |
617 | - |
618 | -class QStorageInfoPrivate : public QSharedData |
619 | -{ |
620 | -public: |
621 | - inline QStorageInfoPrivate() : QSharedData(), |
622 | - bytesTotal(0), bytesFree(0), bytesAvailable(0), |
623 | - readOnly(false), ready(false), valid(false) |
624 | - {} |
625 | - |
626 | - void initRootPath(); |
627 | - void doStat(); |
628 | - |
629 | - static QList<QStorageInfo> mountedVolumes(); |
630 | - static QStorageInfo root(); |
631 | - |
632 | -protected: |
633 | -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) |
634 | - void retreiveVolumeInfo(); |
635 | - void retreiveDiskFreeSpace(); |
636 | -#elif defined(Q_OS_MAC) |
637 | - void retrievePosixInfo(); |
638 | - void retrieveUrlProperties(bool initRootPath = false); |
639 | - void retrieveLabel(); |
640 | -#elif defined(Q_OS_UNIX) |
641 | - void retreiveVolumeInfo(); |
642 | -#endif |
643 | - |
644 | -public: |
645 | - QString rootPath; |
646 | - QByteArray device; |
647 | - QByteArray fileSystemType; |
648 | - QString name; |
649 | - |
650 | - qint64 bytesTotal; |
651 | - qint64 bytesFree; |
652 | - qint64 bytesAvailable; |
653 | - |
654 | - bool readOnly; |
655 | - bool ready; |
656 | - bool valid; |
657 | -}; |
658 | - |
659 | -QT_END_NAMESPACE |
660 | - |
661 | -#endif // QSTORAGEINFO_P_H |
662 | |
663 | === removed file 'CameraApp/qstorageinfo_unix.cpp' |
664 | --- CameraApp/qstorageinfo_unix.cpp 2015-01-27 14:34:31 +0000 |
665 | +++ CameraApp/qstorageinfo_unix.cpp 1970-01-01 00:00:00 +0000 |
666 | @@ -1,442 +0,0 @@ |
667 | -/**************************************************************************** |
668 | -** |
669 | -** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com> |
670 | -** Contact: http://www.qt-project.org/legal |
671 | -** |
672 | -** This file is part of the QtCore module of the Qt Toolkit. |
673 | -** |
674 | -** This program is free software; you can redistribute it and/or modify |
675 | -** it under the terms of the GNU General Public License as published by |
676 | -** the Free Software Foundation; version 3. |
677 | -** |
678 | -** This program is distributed in the hope that it will be useful, |
679 | -** but WITHOUT ANY WARRANTY; without even the implied warranty of |
680 | -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
681 | -** GNU General Public License for more details. |
682 | -** |
683 | -** You should have received a copy of the GNU General Public License |
684 | -** along with this program. If not, see <http://www.gnu.org/licenses/>. |
685 | -** |
686 | -****************************************************************************/ |
687 | - |
688 | -#include "qstorageinfo_p.h" |
689 | - |
690 | -#include <QtCore/qdiriterator.h> |
691 | -#include <QtCore/qfileinfo.h> |
692 | -#include <QtCore/qtextstream.h> |
693 | - |
694 | -// Copy this definition directly instead of importing the whole file which |
695 | -// would pull in more dependencies we don't need. |
696 | -//#include <QtCore/private/qcore_unix_p.h> |
697 | -#define EINTR_LOOP(var, cmd) \ |
698 | - do { \ |
699 | - var = cmd; \ |
700 | - } while (var == -1 && errno == EINTR) |
701 | - |
702 | -#include <errno.h> |
703 | -#include <sys/stat.h> |
704 | - |
705 | -#if defined(Q_OS_BSD4) |
706 | -# include <sys/mount.h> |
707 | -# include <sys/statvfs.h> |
708 | -#elif defined(Q_OS_ANDROID) |
709 | -# include <sys/mount.h> |
710 | -# include <sys/vfs.h> |
711 | -# include <mntent.h> |
712 | -#elif defined(Q_OS_LINUX) |
713 | -# include <mntent.h> |
714 | -# include <sys/statvfs.h> |
715 | -#elif defined(Q_OS_SOLARIS) |
716 | -# include <sys/mnttab.h> |
717 | -#else |
718 | -# include <sys/statvfs.h> |
719 | -#endif |
720 | - |
721 | -#if defined(Q_OS_BSD4) |
722 | -# define QT_STATFSBUF struct statvfs |
723 | -# define QT_STATFS ::statvfs |
724 | -#elif defined(Q_OS_ANDROID) |
725 | -# define QT_STATFS ::statfs |
726 | -# define QT_STATFSBUF struct statfs |
727 | -# if !defined(ST_RDONLY) |
728 | -# define ST_RDONLY 1 // hack for missing define on Android |
729 | -# endif |
730 | -#else |
731 | -# if defined(QT_LARGEFILE_SUPPORT) |
732 | -# define QT_STATFSBUF struct statvfs64 |
733 | -# define QT_STATFS ::statvfs64 |
734 | -# else |
735 | -# define QT_STATFSBUF struct statvfs |
736 | -# define QT_STATFS ::statvfs |
737 | -# endif // QT_LARGEFILE_SUPPORT |
738 | -#endif // Q_OS_BSD4 |
739 | - |
740 | -QT_BEGIN_NAMESPACE |
741 | - |
742 | -static bool isPseudoFs(const QString &mountDir, const QByteArray &type) |
743 | -{ |
744 | - if (mountDir.startsWith(QLatin1String("/dev")) |
745 | - || mountDir.startsWith(QLatin1String("/proc")) |
746 | - || mountDir.startsWith(QLatin1String("/sys")) |
747 | - || mountDir.startsWith(QLatin1String("/var/run")) |
748 | - || mountDir.startsWith(QLatin1String("/var/lock"))) { |
749 | - return true; |
750 | - } |
751 | - if (type == "tmpfs") |
752 | - return true; |
753 | -#if defined(Q_OS_LINUX) |
754 | - if (type == "rootfs" || type == "rpc_pipefs") |
755 | - return true; |
756 | -#endif |
757 | - |
758 | - return false; |
759 | -} |
760 | - |
761 | -class QStorageIterator |
762 | -{ |
763 | -public: |
764 | - QStorageIterator(); |
765 | - ~QStorageIterator(); |
766 | - |
767 | - inline bool isValid() const; |
768 | - inline bool next(); |
769 | - inline QString rootPath() const; |
770 | - inline QByteArray fileSystemType() const; |
771 | - inline QByteArray device() const; |
772 | -private: |
773 | -#if defined(Q_OS_BSD4) |
774 | - struct statfs *stat_buf; |
775 | - int entryCount; |
776 | - int currentIndex; |
777 | -#elif defined(Q_OS_SOLARIS) |
778 | - FILE *fp; |
779 | - mnttab mnt; |
780 | -#elif defined(Q_OS_ANDROID) |
781 | - QFile file; |
782 | - QByteArray m_rootPath; |
783 | - QByteArray m_fileSystemType; |
784 | - QByteArray m_device; |
785 | -#elif defined(Q_OS_LINUX) |
786 | - FILE *fp; |
787 | - mntent mnt; |
788 | - QByteArray buffer; |
789 | -#endif |
790 | -}; |
791 | - |
792 | -#if defined(Q_OS_BSD4) |
793 | - |
794 | -inline QStorageIterator::QStorageIterator() |
795 | - : entryCount(::getmntinfo(&stat_buf, 0)), |
796 | - currentIndex(-1) |
797 | -{ |
798 | -} |
799 | - |
800 | -inline QStorageIterator::~QStorageIterator() |
801 | -{ |
802 | -} |
803 | - |
804 | -inline bool QStorageIterator::isValid() const |
805 | -{ |
806 | - return entryCount != -1; |
807 | -} |
808 | - |
809 | -inline bool QStorageIterator::next() |
810 | -{ |
811 | - return ++currentIndex < entryCount; |
812 | -} |
813 | - |
814 | -inline QString QStorageIterator::rootPath() const |
815 | -{ |
816 | - return QFile::decodeName(stat_buf[currentIndex].f_mntonname); |
817 | -} |
818 | - |
819 | -inline QByteArray QStorageIterator::fileSystemType() const |
820 | -{ |
821 | - return QByteArray(stat_buf[currentIndex].f_fstypename); |
822 | -} |
823 | - |
824 | -inline QByteArray QStorageIterator::device() const |
825 | -{ |
826 | - return QByteArray(stat_buf[currentIndex].f_mntfromname); |
827 | -} |
828 | - |
829 | -#elif defined(Q_OS_SOLARIS) |
830 | - |
831 | -static const char pathMounted[] = "/etc/mnttab"; |
832 | - |
833 | -inline QStorageIterator::QStorageIterator() |
834 | -{ |
835 | - const int fd = qt_safe_open(pathMounted, O_RDONLY); |
836 | - fp = ::fdopen(fd, "r"); |
837 | -} |
838 | - |
839 | -inline QStorageIterator::~QStorageIterator() |
840 | -{ |
841 | - if (fp) |
842 | - ::fclose(fp); |
843 | -} |
844 | - |
845 | -inline bool QStorageIterator::isValid() const |
846 | -{ |
847 | - return fp != Q_NULLPTR; |
848 | -} |
849 | - |
850 | -inline bool QStorageIterator::next() |
851 | -{ |
852 | - return ::getmntent(fp, &mnt) == Q_NULLPTR; |
853 | -} |
854 | - |
855 | -inline QString QStorageIterator::rootPath() const |
856 | -{ |
857 | - return QFile::decodeName(mnt->mnt_mountp); |
858 | -} |
859 | - |
860 | -inline QByteArray QStorageIterator::fileSystemType() const |
861 | -{ |
862 | - return QByteArray(mnt->mnt_fstype); |
863 | -} |
864 | - |
865 | -inline QByteArray QStorageIterator::device() const |
866 | -{ |
867 | - return QByteArray(mnt->mnt_mntopts); |
868 | -} |
869 | - |
870 | -#elif defined(Q_OS_ANDROID) |
871 | - |
872 | -static const char pathMounted[] = "/proc/mounts"; |
873 | - |
874 | -inline QStorageIterator::QStorageIterator() |
875 | -{ |
876 | - file.setFileName(pathMounted); |
877 | - file.open(QIODevice::ReadOnly | QIODevice::Text); |
878 | -} |
879 | - |
880 | -inline QStorageIterator::~QStorageIterator() |
881 | -{ |
882 | -} |
883 | - |
884 | -inline bool QStorageIterator::isValid() const |
885 | -{ |
886 | - return file.isOpen(); |
887 | -} |
888 | - |
889 | -inline bool QStorageIterator::next() |
890 | -{ |
891 | - QList<QByteArray> data; |
892 | - do { |
893 | - const QByteArray line = file.readLine(); |
894 | - data = line.split(' '); |
895 | - } while (data.count() < 3 && !file.atEnd()); |
896 | - |
897 | - if (file.atEnd()) |
898 | - return false; |
899 | - m_device = data.at(0); |
900 | - m_rootPath = data.at(1); |
901 | - m_fileSystemType = data.at(2); |
902 | - |
903 | - return true; |
904 | -} |
905 | - |
906 | -inline QString QStorageIterator::rootPath() const |
907 | -{ |
908 | - return QFile::decodeName(m_rootPath); |
909 | -} |
910 | - |
911 | -inline QByteArray QStorageIterator::fileSystemType() const |
912 | -{ |
913 | - return m_fileSystemType; |
914 | -} |
915 | - |
916 | -inline QByteArray QStorageIterator::device() const |
917 | -{ |
918 | - return m_device; |
919 | -} |
920 | - |
921 | -#elif defined(Q_OS_LINUX) |
922 | - |
923 | -static const char pathMounted[] = "/etc/mtab"; |
924 | -static const int bufferSize = 3*PATH_MAX; // 2 paths (mount point+device) and metainfo |
925 | - |
926 | -inline QStorageIterator::QStorageIterator() : |
927 | - buffer(QByteArray(bufferSize, 0)) |
928 | -{ |
929 | - fp = ::setmntent(pathMounted, "r"); |
930 | -} |
931 | - |
932 | -inline QStorageIterator::~QStorageIterator() |
933 | -{ |
934 | - if (fp) |
935 | - ::endmntent(fp); |
936 | -} |
937 | - |
938 | -inline bool QStorageIterator::isValid() const |
939 | -{ |
940 | - return fp != Q_NULLPTR; |
941 | -} |
942 | - |
943 | -inline bool QStorageIterator::next() |
944 | -{ |
945 | - return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != Q_NULLPTR; |
946 | -} |
947 | - |
948 | -inline QString QStorageIterator::rootPath() const |
949 | -{ |
950 | - return QFile::decodeName(mnt.mnt_dir); |
951 | -} |
952 | - |
953 | -inline QByteArray QStorageIterator::fileSystemType() const |
954 | -{ |
955 | - return QByteArray(mnt.mnt_type); |
956 | -} |
957 | - |
958 | -inline QByteArray QStorageIterator::device() const |
959 | -{ |
960 | - return QByteArray(mnt.mnt_fsname); |
961 | -} |
962 | - |
963 | -#else |
964 | - |
965 | -inline QStorageIterator::QStorageIterator() |
966 | -{ |
967 | -} |
968 | - |
969 | -inline QStorageIterator::~QStorageIterator() |
970 | -{ |
971 | -} |
972 | - |
973 | -inline bool QStorageIterator::isValid() const |
974 | -{ |
975 | - return false; |
976 | -} |
977 | - |
978 | -inline bool QStorageIterator::next() |
979 | -{ |
980 | - return false; |
981 | -} |
982 | - |
983 | -inline QString QStorageIterator::rootPath() const |
984 | -{ |
985 | - return QString(); |
986 | -} |
987 | - |
988 | -inline QByteArray QStorageIterator::fileSystemType() const |
989 | -{ |
990 | - return QByteArray(); |
991 | -} |
992 | - |
993 | -inline QByteArray QStorageIterator::device() const |
994 | -{ |
995 | - return QByteArray(); |
996 | -} |
997 | - |
998 | -#endif |
999 | - |
1000 | -void QStorageInfoPrivate::initRootPath() |
1001 | -{ |
1002 | - rootPath = QFileInfo(rootPath).canonicalFilePath(); |
1003 | - |
1004 | - if (rootPath.isEmpty()) |
1005 | - return; |
1006 | - |
1007 | - QStorageIterator it; |
1008 | - if (!it.isValid()) { |
1009 | - rootPath = QStringLiteral("/"); |
1010 | - return; |
1011 | - } |
1012 | - |
1013 | - int maxLength = 0; |
1014 | - const QString oldRootPath = rootPath; |
1015 | - rootPath.clear(); |
1016 | - |
1017 | - while (it.next()) { |
1018 | - const QString mountDir = it.rootPath(); |
1019 | - const QByteArray fsName = it.fileSystemType(); |
1020 | - if (isPseudoFs(mountDir, fsName)) |
1021 | - continue; |
1022 | - // we try to find most suitable entry |
1023 | - if (oldRootPath.startsWith(mountDir) && maxLength < mountDir.length()) { |
1024 | - maxLength = mountDir.length(); |
1025 | - rootPath = mountDir; |
1026 | - device = it.device(); |
1027 | - fileSystemType = fsName; |
1028 | - } |
1029 | - } |
1030 | -} |
1031 | - |
1032 | -static inline QString retrieveLabel(const QByteArray &device) |
1033 | -{ |
1034 | -#ifdef Q_OS_LINUX |
1035 | - static const char pathDiskByLabel[] = "/dev/disk/by-label"; |
1036 | - |
1037 | - QDirIterator it(QLatin1String(pathDiskByLabel), QDir::NoDotAndDotDot); |
1038 | - while (it.hasNext()) { |
1039 | - it.next(); |
1040 | - QFileInfo fileInfo(it.fileInfo()); |
1041 | - if (fileInfo.isSymLink() && fileInfo.symLinkTarget().toLocal8Bit() == device) |
1042 | - return fileInfo.fileName(); |
1043 | - } |
1044 | -#else |
1045 | - Q_UNUSED(device); |
1046 | -#endif |
1047 | - |
1048 | - return QString(); |
1049 | -} |
1050 | - |
1051 | -void QStorageInfoPrivate::doStat() |
1052 | -{ |
1053 | - initRootPath(); |
1054 | - if (rootPath.isEmpty()) |
1055 | - return; |
1056 | - |
1057 | - retreiveVolumeInfo(); |
1058 | - name = retrieveLabel(device); |
1059 | -} |
1060 | - |
1061 | -void QStorageInfoPrivate::retreiveVolumeInfo() |
1062 | -{ |
1063 | - QT_STATFSBUF statfs_buf; |
1064 | - int result; |
1065 | - EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf)); |
1066 | - if (result == 0) { |
1067 | - valid = true; |
1068 | - ready = true; |
1069 | - |
1070 | - bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize; |
1071 | - bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; |
1072 | - bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize; |
1073 | -#if defined(Q_OS_ANDROID) |
1074 | -#if defined(_STATFS_F_FLAGS) |
1075 | - readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0; |
1076 | -#endif |
1077 | -#else |
1078 | - readOnly = (statfs_buf.f_flag & ST_RDONLY) != 0; |
1079 | -#endif |
1080 | - } |
1081 | -} |
1082 | - |
1083 | -QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() |
1084 | -{ |
1085 | - QStorageIterator it; |
1086 | - if (!it.isValid()) |
1087 | - return QList<QStorageInfo>() << root(); |
1088 | - |
1089 | - QList<QStorageInfo> volumes; |
1090 | - |
1091 | - while (it.next()) { |
1092 | - const QString mountDir = it.rootPath(); |
1093 | - const QByteArray fsName = it.fileSystemType(); |
1094 | - if (isPseudoFs(mountDir, fsName)) |
1095 | - continue; |
1096 | - |
1097 | - volumes.append(QStorageInfo(mountDir)); |
1098 | - } |
1099 | - |
1100 | - return volumes; |
1101 | -} |
1102 | - |
1103 | -QStorageInfo QStorageInfoPrivate::root() |
1104 | -{ |
1105 | - return QStorageInfo(QStringLiteral("/")); |
1106 | -} |
1107 | - |
1108 | -QT_END_NAMESPACE |
1109 | |
1110 | === added file 'CameraApp/storagelocations.cpp' |
1111 | --- CameraApp/storagelocations.cpp 1970-01-01 00:00:00 +0000 |
1112 | +++ CameraApp/storagelocations.cpp 2016-02-26 17:17:00 +0000 |
1113 | @@ -0,0 +1,121 @@ |
1114 | +/* |
1115 | + * Copyright (C) 2016 Canonical, Ltd. |
1116 | + * |
1117 | + * This program is free software; you can redistribute it and/or modify |
1118 | + * it under the terms of the GNU General Public License as published by |
1119 | + * the Free Software Foundation; version 3. |
1120 | + * |
1121 | + * This program is distributed in the hope that it will be useful, |
1122 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1123 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1124 | + * GNU General Public License for more details. |
1125 | + * |
1126 | + * You should have received a copy of the GNU General Public License |
1127 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1128 | + */ |
1129 | + |
1130 | +#include "storagelocations.h" |
1131 | + |
1132 | +#include <QCoreApplication> |
1133 | +#include <QStandardPaths> |
1134 | +#include <QStorageInfo> |
1135 | + |
1136 | +StorageLocations::StorageLocations(QObject *parent) : QObject(parent) |
1137 | +{ |
1138 | +} |
1139 | + |
1140 | +QString StorageLocations::picturesLocation() const |
1141 | +{ |
1142 | + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); |
1143 | + if (locations.isEmpty()) { |
1144 | + return QString(); |
1145 | + } |
1146 | + QString location = locations.at(0) + "/" + QCoreApplication::applicationName(); |
1147 | + QDir dir; |
1148 | + // Transition from old directory 'camera' to new one; see bug #1363112 |
1149 | + // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1363112 |
1150 | + dir.rename(locations.at(0) + "/" + "camera", location); |
1151 | + dir.mkpath(location); |
1152 | + return location; |
1153 | +} |
1154 | + |
1155 | +QString StorageLocations::videosLocation() const |
1156 | +{ |
1157 | + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation); |
1158 | + if (locations.isEmpty()) { |
1159 | + return QString(); |
1160 | + } |
1161 | + QString location = locations.at(0) + "/" + QCoreApplication::applicationName(); |
1162 | + QDir dir; |
1163 | + // Transition from old directory 'camera' to new one; see bug #1363112 |
1164 | + // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1363112 |
1165 | + dir.rename(locations.at(0) + "/" + "camera", location); |
1166 | + dir.mkpath(location); |
1167 | + return location; |
1168 | +} |
1169 | + |
1170 | +QString StorageLocations::temporaryLocation() const |
1171 | +{ |
1172 | + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::TempLocation); |
1173 | + if (locations.isEmpty()) { |
1174 | + return QString(); |
1175 | + } |
1176 | + QString location = locations.at(0); |
1177 | + QDir dir; |
1178 | + dir.mkpath(location); |
1179 | + return location; |
1180 | +} |
1181 | + |
1182 | +QString StorageLocations::removableStorageLocation() const |
1183 | +{ |
1184 | + QString mediaRoot("/media/" + qgetenv("USER")); |
1185 | + Q_FOREACH(QStorageInfo volume, QStorageInfo::mountedVolumes()) { |
1186 | + if (volume.rootPath().startsWith(mediaRoot) && |
1187 | + volume.isValid() && volume.isReady()) { |
1188 | + return volume.rootPath(); |
1189 | + } |
1190 | + } |
1191 | + |
1192 | + return QString(); |
1193 | +} |
1194 | + |
1195 | +QString StorageLocations::removableStoragePicturesLocation() const |
1196 | +{ |
1197 | + QString storageLocation = removableStorageLocation(); |
1198 | + if (storageLocation.isEmpty()) { |
1199 | + return QString(); |
1200 | + } |
1201 | + |
1202 | + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); |
1203 | + QString pictureDir = QString(locations.at(0)).split("/").value(3); |
1204 | + if (pictureDir.isEmpty()){ |
1205 | + return QString(); |
1206 | + } |
1207 | + QString location = storageLocation + "/" + pictureDir + "/" + QCoreApplication::applicationName(); |
1208 | + QDir dir; |
1209 | + dir.mkpath(location); |
1210 | + return location; |
1211 | +} |
1212 | + |
1213 | +QString StorageLocations::removableStorageVideosLocation() const |
1214 | +{ |
1215 | + QString storageLocation = removableStorageLocation(); |
1216 | + if (storageLocation.isEmpty()) { |
1217 | + return QString(); |
1218 | + } |
1219 | + |
1220 | + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation); |
1221 | + QString movieDir = QString(locations.at(0)).split("/").value(3); |
1222 | + if (movieDir.isEmpty()){ |
1223 | + return QString(); |
1224 | + } |
1225 | + QString location = storageLocation + "/" + movieDir + "/" + QCoreApplication::applicationName(); |
1226 | + QDir dir; |
1227 | + dir.mkpath(location); |
1228 | + return location; |
1229 | +} |
1230 | + |
1231 | +bool StorageLocations::removableStoragePresent() const |
1232 | +{ |
1233 | + return !removableStorageLocation().isEmpty(); |
1234 | +} |
1235 | |
1236 | === added file 'CameraApp/storagelocations.h' |
1237 | --- CameraApp/storagelocations.h 1970-01-01 00:00:00 +0000 |
1238 | +++ CameraApp/storagelocations.h 2016-02-26 17:17:00 +0000 |
1239 | @@ -0,0 +1,50 @@ |
1240 | +/* |
1241 | + * Copyright (C) 2016 Canonical, Ltd. |
1242 | + * |
1243 | + * This program is free software; you can redistribute it and/or modify |
1244 | + * it under the terms of the GNU General Public License as published by |
1245 | + * the Free Software Foundation; version 3. |
1246 | + * |
1247 | + * This program is distributed in the hope that it will be useful, |
1248 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1249 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1250 | + * GNU General Public License for more details. |
1251 | + * |
1252 | + * You should have received a copy of the GNU General Public License |
1253 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1254 | + */ |
1255 | + |
1256 | +#ifndef STORAGELOCATIONS_H |
1257 | +#define STORAGELOCATIONS_H |
1258 | + |
1259 | +#include <QObject> |
1260 | + |
1261 | +class StorageLocations : public QObject |
1262 | +{ |
1263 | + Q_OBJECT |
1264 | + |
1265 | + Q_PROPERTY(QString picturesLocation READ picturesLocation CONSTANT) |
1266 | + Q_PROPERTY(QString videosLocation READ videosLocation CONSTANT) |
1267 | + Q_PROPERTY(QString temporaryLocation READ temporaryLocation CONSTANT) |
1268 | + Q_PROPERTY(QString removableStorageLocation READ removableStorageLocation CONSTANT) |
1269 | + Q_PROPERTY(QString removableStoragePicturesLocation READ removableStoragePicturesLocation CONSTANT) |
1270 | + Q_PROPERTY(QString removableStorageVideosLocation READ removableStorageVideosLocation CONSTANT) |
1271 | + Q_PROPERTY(bool removableStoragePresent READ removableStoragePresent NOTIFY removableStoragePresentChanged) |
1272 | + |
1273 | +public: |
1274 | + explicit StorageLocations(QObject *parent = 0); |
1275 | + |
1276 | + QString picturesLocation() const; |
1277 | + QString videosLocation() const; |
1278 | + QString temporaryLocation() const; |
1279 | + QString removableStorageLocation() const; |
1280 | + QString removableStoragePicturesLocation() const; |
1281 | + QString removableStorageVideosLocation() const; |
1282 | + |
1283 | + bool removableStoragePresent() const; |
1284 | + |
1285 | +Q_SIGNALS: |
1286 | + void removableStoragePresentChanged(); |
1287 | +}; |
1288 | + |
1289 | +#endif // STORAGELOCATIONS_H |
1290 | |
1291 | === modified file 'CameraApp/storagemonitor.cpp' |
1292 | --- CameraApp/storagemonitor.cpp 2015-01-23 19:28:44 +0000 |
1293 | +++ CameraApp/storagemonitor.cpp 2016-02-26 17:17:00 +0000 |
1294 | @@ -15,9 +15,10 @@ |
1295 | */ |
1296 | |
1297 | #include "storagemonitor.h" |
1298 | +#include "storagelocations.h" |
1299 | |
1300 | StorageMonitor::StorageMonitor(QObject *parent) : |
1301 | - QObject(parent), m_low(false), m_criticallyLow(false) |
1302 | + QObject(parent), m_low(false), m_criticallyLow(false), m_writeable(true) |
1303 | { |
1304 | m_timer.setInterval(POLL_INTERVAL); |
1305 | m_timer.setSingleShot(false); |
1306 | @@ -54,6 +55,32 @@ |
1307 | } |
1308 | } |
1309 | |
1310 | +void StorageMonitor::checkWriteable() |
1311 | +{ |
1312 | + bool writeable = true; |
1313 | + |
1314 | + QString mediaRoot("/media/" + qgetenv("USER")); |
1315 | + if (m_storage.rootPath().startsWith(mediaRoot)) { |
1316 | + // check only for external media, assume internal media is always writeable |
1317 | + if (m_storage.isReadOnly()) { |
1318 | + writeable = false; |
1319 | + } else { |
1320 | + StorageLocations locations; |
1321 | + QDir storageRoot(locations.removableStoragePicturesLocation()); |
1322 | + QFile testFile(storageRoot.absoluteFilePath(".write_test")); |
1323 | + bool opened = testFile.open(QIODevice::WriteOnly | QIODevice::Unbuffered); |
1324 | + if (!opened || testFile.write("x", 1) != 1) writeable = false; |
1325 | + testFile.close(); |
1326 | + testFile.remove(); |
1327 | + } |
1328 | + } |
1329 | + |
1330 | + if (m_writeable != writeable) { |
1331 | + m_writeable = writeable; |
1332 | + Q_EMIT isWriteableChanged(); |
1333 | + } |
1334 | +} |
1335 | + |
1336 | void StorageMonitor::setLocation(QString location) |
1337 | { |
1338 | if (location != m_location) { |
1339 | @@ -62,6 +89,7 @@ |
1340 | |
1341 | m_storage.setPath(m_location); |
1342 | checkDiskSpace(); |
1343 | + checkWriteable(); |
1344 | if (m_storage.isValid()) { |
1345 | m_timer.start(); |
1346 | } |
1347 | @@ -84,3 +112,8 @@ |
1348 | { |
1349 | return m_criticallyLow; |
1350 | } |
1351 | + |
1352 | +bool StorageMonitor::isWriteable() const |
1353 | +{ |
1354 | + return m_writeable; |
1355 | +} |
1356 | |
1357 | === modified file 'CameraApp/storagemonitor.h' |
1358 | --- CameraApp/storagemonitor.h 2015-01-23 19:29:03 +0000 |
1359 | +++ CameraApp/storagemonitor.h 2016-02-26 17:17:00 +0000 |
1360 | @@ -34,6 +34,7 @@ |
1361 | Q_PROPERTY(QString location READ location WRITE setLocation NOTIFY locationChanged) |
1362 | Q_PROPERTY(bool diskSpaceLow READ diskSpaceLow NOTIFY diskSpaceLowChanged) |
1363 | Q_PROPERTY(bool diskSpaceCriticallyLow READ diskSpaceCriticallyLow NOTIFY diskSpaceCriticallyLowChanged) |
1364 | + Q_PROPERTY(bool isWriteable READ isWriteable NOTIFY isWriteableChanged) |
1365 | |
1366 | public: |
1367 | explicit StorageMonitor(QObject *parent = 0); |
1368 | @@ -42,21 +43,25 @@ |
1369 | void setLocation(QString location); |
1370 | bool diskSpaceLow() const; |
1371 | bool diskSpaceCriticallyLow() const; |
1372 | + bool isWriteable() const; |
1373 | |
1374 | Q_SIGNALS: |
1375 | void locationChanged(); |
1376 | void diskSpaceLowChanged(); |
1377 | void diskSpaceCriticallyLowChanged(); |
1378 | + void isWriteableChanged(); |
1379 | |
1380 | private Q_SLOTS: |
1381 | void refresh(); |
1382 | |
1383 | private: |
1384 | void checkDiskSpace(); |
1385 | + void checkWriteable(); |
1386 | |
1387 | private: |
1388 | bool m_low; |
1389 | bool m_criticallyLow; |
1390 | + bool m_writeable; |
1391 | QTimer m_timer; |
1392 | QString m_location; |
1393 | QStorageInfo m_storage; |
1394 | |
1395 | === modified file 'GalleryView.qml' |
1396 | --- GalleryView.qml 2015-11-26 11:29:18 +0000 |
1397 | +++ GalleryView.qml 2016-02-26 17:17:00 +0000 |
1398 | @@ -30,9 +30,9 @@ |
1399 | property bool userSelectionMode: false |
1400 | property Item currentView: state == "GRID" ? photogridView : slideshowView |
1401 | property var model: FoldersModel { |
1402 | - folders: [application.picturesLocation, application.videosLocation, |
1403 | - application.removableStoragePicturesLocation, |
1404 | - application.removableStorageVideosLocation] |
1405 | + folders: [StorageLocations.picturesLocation, StorageLocations.videosLocation, |
1406 | + StorageLocations.removableStoragePicturesLocation, |
1407 | + StorageLocations.removableStorageVideosLocation] |
1408 | typeFilters: !main.contentExportMode ? [ "image", "video" ] |
1409 | : [MimeTypeMapper.contentTypeToMimeType(main.transferContentType)] |
1410 | singleSelectionOnly: main.transfer.selectionType === ContentTransfer.Single |
1411 | |
1412 | === modified file 'GalleryViewHeader.qml' |
1413 | --- GalleryViewHeader.qml 2015-10-30 15:01:10 +0000 |
1414 | +++ GalleryViewHeader.qml 2016-02-26 17:17:00 +0000 |
1415 | @@ -73,7 +73,7 @@ |
1416 | } |
1417 | width: units.gu(8) |
1418 | iconName: "back" |
1419 | - iconColor: theme.palette.normal.foregroundText |
1420 | + iconColor: "white" |
1421 | onClicked: editMode ? header.exitEditor() : header.exit() |
1422 | } |
1423 | |
1424 | @@ -81,7 +81,7 @@ |
1425 | text: main.contentExportMode || userSelectionMode ? i18n.tr("Select") : |
1426 | (editMode ? i18n.tr("Edit Photo") : i18n.tr("Photo Roll")) |
1427 | fontSize: "x-large" |
1428 | - color: theme.palette.normal.foregroundText |
1429 | + color: "white" |
1430 | elide: Text.ElideRight |
1431 | Layout.fillWidth: true |
1432 | } |
1433 | @@ -228,7 +228,7 @@ |
1434 | } |
1435 | text: model.text |
1436 | elide: Text.ElideRight |
1437 | - color: action.enabled ? theme.palette.normal.foregroundText : Qt.darker(theme.palette.normal.foregroundText, 2.0) |
1438 | + color: action.enabled ? "white" : Qt.darker("white", 2.0) |
1439 | } |
1440 | |
1441 | Icon { |
1442 | |
1443 | === added file 'PictureReview.qml' |
1444 | --- PictureReview.qml 1970-01-01 00:00:00 +0000 |
1445 | +++ PictureReview.qml 2016-02-26 17:17:00 +0000 |
1446 | @@ -0,0 +1,46 @@ |
1447 | +/* |
1448 | + * Copyright (C) 2016 Canonical, Ltd. |
1449 | + * |
1450 | + * This program is free software; you can redistribute it and/or modify |
1451 | + * it under the terms of the GNU General Public License as published by |
1452 | + * the Free Software Foundation; version 3. |
1453 | + * |
1454 | + * This program is distributed in the hope that it will be useful, |
1455 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1456 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1457 | + * GNU General Public License for more details. |
1458 | + * |
1459 | + * You should have received a copy of the GNU General Public License |
1460 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1461 | + */ |
1462 | + |
1463 | +import QtQuick 2.4 |
1464 | +import QtQuick.Window 2.2 |
1465 | + |
1466 | +Item { |
1467 | + id: snapshotRoot |
1468 | + property alias source: image.source |
1469 | + property ViewFinderGeometry geometry |
1470 | + property bool loaded: image.status == Image.Ready |
1471 | + |
1472 | + // Rotation is locked at the moment the picture is shoot |
1473 | + // (in case processing is long, such as with HDR) |
1474 | + function lockOrientation() { |
1475 | + image.rotation = Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) |
1476 | + } |
1477 | + |
1478 | + Image { |
1479 | + id: image |
1480 | + anchors.centerIn: parent |
1481 | + anchors.verticalCenterOffset: -geometry.y |
1482 | + |
1483 | + asynchronous: true |
1484 | + cache: false |
1485 | + fillMode: Image.PreserveAspectFit |
1486 | + smooth: false |
1487 | + width: rotation == 0 ? geometry.width : geometry.height |
1488 | + height: rotation == 0 ? geometry.height : geometry.width |
1489 | + sourceSize.width: width |
1490 | + sourceSize.height: height |
1491 | + } |
1492 | +} |
1493 | |
1494 | === added file 'ProcessingFeedback.qml' |
1495 | --- ProcessingFeedback.qml 1970-01-01 00:00:00 +0000 |
1496 | +++ ProcessingFeedback.qml 2016-02-26 17:17:00 +0000 |
1497 | @@ -0,0 +1,43 @@ |
1498 | +/* |
1499 | + * Copyright 2016 Canonical Ltd. |
1500 | + * |
1501 | + * This program is free software; you can redistribute it and/or modify |
1502 | + * it under the terms of the GNU General Public License as published by |
1503 | + * the Free Software Foundation; version 3. |
1504 | + * |
1505 | + * This program is distributed in the hope that it will be useful, |
1506 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1507 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1508 | + * GNU General Public License for more details. |
1509 | + * |
1510 | + * You should have received a copy of the GNU General Public License |
1511 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1512 | + */ |
1513 | + |
1514 | +import QtQuick 2.4 |
1515 | +import Ubuntu.Components 1.3 |
1516 | + |
1517 | +Item { |
1518 | + id: processingFeedback |
1519 | + |
1520 | + property bool processing: false |
1521 | + |
1522 | + Timer { |
1523 | + interval: 2000 |
1524 | + running: processing |
1525 | + onTriggered: spinner.running = true |
1526 | + } |
1527 | + |
1528 | + onProcessingChanged: if (!processing) spinner.running = false |
1529 | + |
1530 | + ActivityIndicator { |
1531 | + id: spinner |
1532 | + opacity: running ? 1.0 : 0.0 |
1533 | + Behavior on opacity { |
1534 | + OpacityAnimator { |
1535 | + duration: UbuntuAnimation.SnapDuration |
1536 | + easing: UbuntuAnimation.StandardEasing |
1537 | + } |
1538 | + } |
1539 | + } |
1540 | +} |
1541 | |
1542 | === modified file 'SharePopover.qml' |
1543 | --- SharePopover.qml 2015-10-22 12:46:34 +0000 |
1544 | +++ SharePopover.qml 2016-02-26 17:17:00 +0000 |
1545 | @@ -17,7 +17,7 @@ |
1546 | import QtQuick 2.4 |
1547 | import Ubuntu.Components 1.3 |
1548 | import Ubuntu.Components.Popups 1.3 |
1549 | -import Ubuntu.Content 0.1 |
1550 | +import Ubuntu.Content 1.3 |
1551 | |
1552 | PopupBase { |
1553 | property var transferContentType |
1554 | @@ -31,17 +31,9 @@ |
1555 | contentPeerPicker.peerSelected.connect(contentPeerSelected); |
1556 | } |
1557 | |
1558 | - // FIXME: ContentPeerPicker should either have a background or not, not half of one |
1559 | - Rectangle { |
1560 | - anchors.fill: parent |
1561 | - color: theme.palette.normal.overlay |
1562 | - } |
1563 | - |
1564 | ContentPeerPicker { |
1565 | id: contentPeerPicker |
1566 | // FIXME: ContentPeerPicker should define an implicit size and not refer to its parent |
1567 | - // FIXME: ContentPeerPicker should not be visible: false by default |
1568 | - visible: true |
1569 | Component.onCompleted: { |
1570 | contentType = parent.transferContentType; |
1571 | } |
1572 | |
1573 | === removed file 'Snapshot.qml' |
1574 | --- Snapshot.qml 2015-10-22 12:21:14 +0000 |
1575 | +++ Snapshot.qml 1970-01-01 00:00:00 +0000 |
1576 | @@ -1,98 +0,0 @@ |
1577 | -/* |
1578 | - * Copyright (C) 2012 Canonical, Ltd. |
1579 | - * |
1580 | - * This program is free software; you can redistribute it and/or modify |
1581 | - * it under the terms of the GNU General Public License as published by |
1582 | - * the Free Software Foundation; version 3. |
1583 | - * |
1584 | - * This program is distributed in the hope that it will be useful, |
1585 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1586 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1587 | - * GNU General Public License for more details. |
1588 | - * |
1589 | - * You should have received a copy of the GNU General Public License |
1590 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1591 | - */ |
1592 | - |
1593 | -import QtQuick 2.4 |
1594 | -import QtQuick.Window 2.2 |
1595 | -import Ubuntu.Components 1.3 |
1596 | - |
1597 | -Item { |
1598 | - id: snapshotRoot |
1599 | - property alias source: snapshot.source |
1600 | - property alias sliding: shoot.running |
1601 | - property int orientation |
1602 | - property ViewFinderGeometry geometry |
1603 | - property bool deviceDefaultIsPortrait: true |
1604 | - property bool loading: snapshot.status == Image.Loading |
1605 | - |
1606 | - function startOutAnimation() { |
1607 | - shoot.restart() |
1608 | - } |
1609 | - |
1610 | - visible: false |
1611 | - |
1612 | - Item { |
1613 | - id: container |
1614 | - width: parent.width |
1615 | - height: parent.height |
1616 | - |
1617 | - Image { |
1618 | - id: snapshot |
1619 | - anchors.centerIn: parent |
1620 | - anchors.verticalCenterOffset: -geometry.y |
1621 | - rotation: snapshotRoot.orientation * -1 |
1622 | - |
1623 | - asynchronous: true |
1624 | - cache: false |
1625 | - fillMode: Image.PreserveAspectFit |
1626 | - smooth: false |
1627 | - width: deviceDefaultIsPortrait ? geometry.height : geometry.width |
1628 | - height: deviceDefaultIsPortrait ? geometry.width : geometry.height |
1629 | - sourceSize.width: width |
1630 | - sourceSize.height: height |
1631 | - } |
1632 | - |
1633 | - Image { |
1634 | - id: shadow |
1635 | - |
1636 | - property bool rotated: (snapshot.rotation % 180) != 0 |
1637 | - height: rotated ? snapshot.width : snapshot.height |
1638 | - width: units.gu(2) |
1639 | - x: (container.width - (rotated ? snapshot.height : snapshot.width)) / 2 - width |
1640 | - source: "assets/shadow.png" |
1641 | - fillMode: Image.Stretch |
1642 | - asynchronous: true |
1643 | - cache: false |
1644 | - } |
1645 | - } |
1646 | - property int orientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) |
1647 | - property var angleToOrientation: {0: "PORTRAIT", |
1648 | - 90: "LANDSCAPE", |
1649 | - 270: "INVERTED_LANDSCAPE"} |
1650 | - |
1651 | - SequentialAnimation { |
1652 | - id: shoot |
1653 | - |
1654 | - PropertyAction { target: snapshotRoot; property: "visible"; value: true } |
1655 | - PauseAnimation { duration: 150 } |
1656 | - XAnimator { |
1657 | - target: container |
1658 | - to: angleToOrientation[orientationAngle] == "PORTRAIT" ? container.width + shadow.width : 0 |
1659 | - duration: UbuntuAnimation.BriskDuration |
1660 | - easing: UbuntuAnimation.StandardEasing |
1661 | - } |
1662 | - YAnimator { |
1663 | - target: container |
1664 | - to: angleToOrientation[orientationAngle] == "LANDSCAPE" ? container.height + shadow.width : |
1665 | - angleToOrientation[orientationAngle] == "INVERTED_LANDSCAPE" ? -(container.height + shadow.width) : 0 |
1666 | - duration: UbuntuAnimation.BriskDuration |
1667 | - easing: UbuntuAnimation.StandardEasing |
1668 | - } |
1669 | - PropertyAction { target: snapshot; property: "source"; value: ""} |
1670 | - PropertyAction { target: snapshotRoot; property: "visible"; value: false } |
1671 | - PropertyAction { target: container; property: "x"; value: 0 } |
1672 | - PropertyAction { target: container; property: "y"; value: 0 } |
1673 | - } |
1674 | -} |
1675 | |
1676 | === modified file 'ViewFinderExportConfirmation.qml' |
1677 | --- ViewFinderExportConfirmation.qml 2015-12-10 12:17:49 +0000 |
1678 | +++ ViewFinderExportConfirmation.qml 2016-02-26 17:17:00 +0000 |
1679 | @@ -22,39 +22,56 @@ |
1680 | |
1681 | property bool isVideo |
1682 | property string mediaPath |
1683 | - property Snapshot snapshot |
1684 | - |
1685 | - function confirmExport(path) { |
1686 | - viewFinder.visible = false; |
1687 | - viewFinderOverlay.visible = false; |
1688 | - mediaPath = path; |
1689 | - if (!isVideo) snapshot.visible = true; |
1690 | - visible = true; |
1691 | - } |
1692 | - |
1693 | - function hide() { |
1694 | - viewFinder.visible = true; |
1695 | - viewFinderOverlay.visible = true; |
1696 | - snapshot.source = ""; |
1697 | - snapshot.visible = false; |
1698 | - visible = false; |
1699 | - } |
1700 | + property bool waitingForPictureCapture: false |
1701 | + |
1702 | + signal hideRequested() |
1703 | + signal showRequested() |
1704 | + property ViewFinderGeometry viewFinderGeometry |
1705 | |
1706 | visible: false |
1707 | |
1708 | + // For videos show immediately without waiting for the preview to load, |
1709 | + // since we will show a progress indicator instead of the preview |
1710 | + onMediaPathChanged: if (mediaPath && isVideo) showRequested() |
1711 | + |
1712 | + function photoCaptureStarted() { |
1713 | + controls.item.lockPictureOrientation() |
1714 | + waitingForPictureCapture = true |
1715 | + } |
1716 | + |
1717 | Loader { |
1718 | + id: controls |
1719 | anchors.fill: parent |
1720 | asynchronous: true |
1721 | sourceComponent: Component { |
1722 | Item { |
1723 | + function lockPictureOrientation() { pictureReview.lockOrientation() } |
1724 | + |
1725 | VideoReview { |
1726 | id: videoReview |
1727 | anchors.fill: parent |
1728 | bottomMargin: buttons.height |
1729 | - videoPath: mediaPath |
1730 | + videoPath: isVideo ? mediaPath : "" |
1731 | visible: isVideo |
1732 | } |
1733 | |
1734 | + PictureReview { |
1735 | + id: pictureReview |
1736 | + anchors.fill: parent |
1737 | + visible: !isVideo |
1738 | + geometry: viewFinderGeometry |
1739 | + source: !isVideo ? mediaPath : "" |
1740 | + |
1741 | + // Show export confirmation only when the snapshot is loaded to prevent the |
1742 | + // screen being black while the image loads |
1743 | + onLoadedChanged: { |
1744 | + if (loaded) { |
1745 | + viewFinderExportConfirmation.showRequested() |
1746 | + waitingForPictureCapture = false |
1747 | + } |
1748 | + } |
1749 | + } |
1750 | + |
1751 | Item { |
1752 | id: buttons |
1753 | anchors.bottom: parent.bottom |
1754 | @@ -74,7 +91,7 @@ |
1755 | } |
1756 | |
1757 | iconName: "reload" |
1758 | - onClicked: viewFinderExportConfirmation.hide() |
1759 | + onClicked: hideRequested() |
1760 | } |
1761 | |
1762 | CircleButton { |
1763 | @@ -90,8 +107,9 @@ |
1764 | |
1765 | iconName: "ok" |
1766 | onClicked: { |
1767 | - viewFinderExportConfirmation.hide(); |
1768 | + hideRequested(); |
1769 | main.exportContent([mediaPath]); |
1770 | + mediaPath = ""; |
1771 | } |
1772 | } |
1773 | |
1774 | @@ -108,8 +126,9 @@ |
1775 | |
1776 | iconName: "close" |
1777 | onClicked: { |
1778 | - viewFinderExportConfirmation.hide(); |
1779 | + hideRequested(); |
1780 | main.cancelExport(); |
1781 | + mediaPath = ""; |
1782 | } |
1783 | } |
1784 | } |
1785 | |
1786 | === modified file 'ViewFinderOverlay.qml' |
1787 | --- ViewFinderOverlay.qml 2016-01-11 15:07:58 +0000 |
1788 | +++ ViewFinderOverlay.qml 2016-02-26 17:17:00 +0000 |
1789 | @@ -32,6 +32,7 @@ |
1790 | property real revealProgress: noSpaceHint.visible ? 1.0 : bottomEdge.progress |
1791 | property var controls: controls |
1792 | property var settings: settings |
1793 | + property bool readyForCapture |
1794 | |
1795 | function showFocusRing(x, y) { |
1796 | focusRing.center = Qt.point(x, y); |
1797 | @@ -217,12 +218,31 @@ |
1798 | photoResolutionOptionsModel.insert(1, optionFitting); |
1799 | } |
1800 | |
1801 | + // If resolution setting is not supported select the resolution automatically |
1802 | var photoResolution = settings["photoResolution" + camera.advanced.activeCameraIndex]; |
1803 | - // If resolution setting chosen is not supported select the fitting resolution |
1804 | - if (photoResolution != optionFitting.value && |
1805 | - photoResolution != optionMaximum.value) { |
1806 | - settings["photoResolution" + camera.advanced.activeCameraIndex] = optionFitting.value; |
1807 | - } |
1808 | + if (!isResolutionAnOption(photoResolution)) { |
1809 | + settings["photoResolution" + camera.advanced.activeCameraIndex] = getAutomaticResolution(); |
1810 | + } |
1811 | + } |
1812 | + |
1813 | + function getAutomaticResolution() { |
1814 | + var fittingResolution = sizeToString(camera.advanced.fittingResolution); |
1815 | + var maximumResolution = sizeToString(camera.advanced.maximumResolution); |
1816 | + if (isResolutionAnOption(fittingResolution)) { |
1817 | + return fittingResolution; |
1818 | + } else { |
1819 | + return maximumResolution; |
1820 | + } |
1821 | + } |
1822 | + |
1823 | + function isResolutionAnOption(resolution) { |
1824 | + for (var i=0; i<photoResolutionOptionsModel.count; i++) { |
1825 | + var option = photoResolutionOptionsModel.get(i); |
1826 | + if (option.value == resolution) { |
1827 | + return true; |
1828 | + } |
1829 | + } |
1830 | + return false; |
1831 | } |
1832 | |
1833 | function updateResolutionOptions() { |
1834 | @@ -249,9 +269,9 @@ |
1835 | settings.videoResolution = sizeToString(camera.advanced.videoRecorderResolution); |
1836 | updateResolutionOptions(); |
1837 | |
1838 | - // If no resolution has ever been chosen, select the one that fits the screen |
1839 | + // If no resolution has ever been chosen, select one automatically |
1840 | if (!hasPhotoResolutionSetting) { |
1841 | - settings["photoResolution" + camera.advanced.activeCameraIndex] = sizeToString(camera.advanced.fittingResolution); |
1842 | + settings["photoResolution" + camera.advanced.activeCameraIndex] = getAutomaticResolution(); |
1843 | } |
1844 | } |
1845 | } |
1846 | @@ -288,16 +308,6 @@ |
1847 | && !camera.photoCaptureInProgress |
1848 | opacity: enabled ? 1.0 : 0.3 |
1849 | |
1850 | - Item { |
1851 | - /* Use the 'trigger' feature of Panel so that tapping on the Panel |
1852 | - has the same effect as tapping outside of it (bottomEdgeClose) */ |
1853 | - id: clickReceiver |
1854 | - anchors.fill: parent |
1855 | - function trigger() { |
1856 | - optionsOverlayClose(); |
1857 | - } |
1858 | - } |
1859 | - |
1860 | /* At startup, opened is false and 'bottomEdge.height' is 0 until |
1861 | optionsOverlayLoader has finished loading. When that happens |
1862 | 'bottomEdge.height' becomes non 0 and 'bottomEdge.position' which |
1863 | @@ -321,6 +331,7 @@ |
1864 | property bool available: true |
1865 | property bool visible: true |
1866 | property bool showInIndicators: true |
1867 | + property bool colorize: !positionSource.isPrecise |
1868 | |
1869 | ListElement { |
1870 | icon: "" |
1871 | @@ -492,7 +503,7 @@ |
1872 | property string label: i18n.tr("SD") |
1873 | property bool isToggle: true |
1874 | property int selectedIndex: bottomEdge.indexForValue(removableStorageOptionsModel, settings.preferRemovableStorage) |
1875 | - property bool available: application.removableStoragePresent |
1876 | + property bool available: StorageLocations.removableStoragePresent |
1877 | property bool visible: available |
1878 | |
1879 | ListElement { |
1880 | @@ -555,12 +566,12 @@ |
1881 | } |
1882 | ] |
1883 | |
1884 | - /* FIXME: application.removableStoragePresent is not updated dynamically. |
1885 | + /* FIXME: StorageLocations.removableStoragePresent is not updated dynamically. |
1886 | Workaround that by reading it when the bottom edge is opened/closed. |
1887 | */ |
1888 | Connections { |
1889 | target: bottomEdge |
1890 | - onOpenedChanged: removableStorageOptionsModel.available = application.removableStoragePresent |
1891 | + onOpenedChanged: removableStorageOptionsModel.available = StorageLocations.removableStoragePresent |
1892 | } |
1893 | |
1894 | function indexForValue(model, value) { |
1895 | @@ -601,6 +612,24 @@ |
1896 | } |
1897 | } |
1898 | } |
1899 | + |
1900 | + triggerSize: units.gu(3) |
1901 | + |
1902 | + Item { |
1903 | + /* Use the 'trigger' feature of Panel so that tapping on the Panel |
1904 | + can be acted upon */ |
1905 | + id: clickReceiver |
1906 | + anchors.fill: parent |
1907 | + anchors.topMargin: -bottomEdge.triggerSize |
1908 | + |
1909 | + function trigger() { |
1910 | + if (bottomEdge.opened) { |
1911 | + optionsOverlayClose(); |
1912 | + } else { |
1913 | + bottomEdge.open(); |
1914 | + } |
1915 | + } |
1916 | + } |
1917 | } |
1918 | } |
1919 | |
1920 | @@ -669,11 +698,11 @@ |
1921 | |
1922 | if (camera.captureMode == Camera.CaptureVideo) { |
1923 | if (main.contentExportMode) { |
1924 | - camera.videoRecorder.outputLocation = application.temporaryLocation; |
1925 | - } else if (application.removableStoragePresent && settings.preferRemovableStorage) { |
1926 | - camera.videoRecorder.outputLocation = application.removableStorageVideosLocation; |
1927 | + camera.videoRecorder.outputLocation = StorageLocations.temporaryLocation; |
1928 | + } else if (StorageLocations.removableStoragePresent && settings.preferRemovableStorage) { |
1929 | + camera.videoRecorder.outputLocation = StorageLocations.removableStorageVideosLocation; |
1930 | } else { |
1931 | - camera.videoRecorder.outputLocation = application.videosLocation; |
1932 | + camera.videoRecorder.outputLocation = StorageLocations.videosLocation; |
1933 | } |
1934 | |
1935 | if (camera.videoRecorder.recorderState == CameraRecorder.StoppedState) { |
1936 | @@ -684,11 +713,10 @@ |
1937 | if (!main.contentExportMode) { |
1938 | shootFeedback.start(); |
1939 | } |
1940 | + camera.photoCaptureInProgress = true; |
1941 | camera.imageCapture.setMetadata("Orientation", orientation); |
1942 | var position = positionSource.position; |
1943 | - if (settings.gpsEnabled && positionSource.valid |
1944 | - && position.latitudeValid |
1945 | - && position.longitudeValid) { |
1946 | + if (settings.gpsEnabled && positionSource.isPrecise) { |
1947 | camera.imageCapture.setMetadata("GPSLatitude", position.coordinate.latitude); |
1948 | camera.imageCapture.setMetadata("GPSLongitude", position.coordinate.longitude); |
1949 | camera.imageCapture.setMetadata("GPSTimeStamp", position.timestamp); |
1950 | @@ -698,13 +726,12 @@ |
1951 | } |
1952 | } |
1953 | |
1954 | - camera.photoCaptureInProgress = true; |
1955 | if (main.contentExportMode) { |
1956 | - camera.imageCapture.captureToLocation(application.temporaryLocation); |
1957 | - } else if (application.removableStoragePresent && settings.preferRemovableStorage) { |
1958 | - camera.imageCapture.captureToLocation(application.removableStoragePicturesLocation); |
1959 | + camera.imageCapture.captureToLocation(StorageLocations.temporaryLocation); |
1960 | + } else if (StorageLocations.removableStoragePresent && settings.preferRemovableStorage) { |
1961 | + camera.imageCapture.captureToLocation(StorageLocations.removableStoragePicturesLocation); |
1962 | } else { |
1963 | - camera.imageCapture.captureToLocation(application.picturesLocation); |
1964 | + camera.imageCapture.captureToLocation(StorageLocations.picturesLocation); |
1965 | } |
1966 | } |
1967 | } |
1968 | @@ -760,6 +787,11 @@ |
1969 | id: positionSource |
1970 | updateInterval: 1000 |
1971 | active: settings.gpsEnabled |
1972 | + property bool isPrecise: valid |
1973 | + && position.latitudeValid |
1974 | + && position.longitudeValid |
1975 | + && (!position.horizontalAccuracyValid || |
1976 | + position.horizontalAccuracy <= 100) |
1977 | } |
1978 | |
1979 | Connections { |
1980 | @@ -800,7 +832,7 @@ |
1981 | horizontalCenter: parent.horizontalCenter |
1982 | } |
1983 | |
1984 | - enabled: camera.imageCapture.ready && !storageMonitor.diskSpaceCriticallyLow |
1985 | + enabled: viewFinderOverlay.readyForCapture && !storageMonitor.diskSpaceCriticallyLow |
1986 | state: (camera.captureMode == Camera.CaptureVideo) ? |
1987 | ((camera.videoRecorder.recorderState == CameraRecorder.StoppedState) ? "record_off" : "record_on") : |
1988 | "camera" |
1989 | @@ -878,15 +910,19 @@ |
1990 | |
1991 | MouseArea { |
1992 | id: manualFocusMouseArea |
1993 | - anchors.fill: parent |
1994 | - enabled: !camera.photoCaptureInProgress |
1995 | + anchors { |
1996 | + fill: parent |
1997 | + // Pinch gestures need more clearance at the edges of the screen, but |
1998 | + // tap to focus should be safe all the way to the edges themselves instead. |
1999 | + leftMargin: -bottomEdgeIndicators.height |
2000 | + rightMargin: -bottomEdgeIndicators.height |
2001 | + } |
2002 | + enabled: camera.focus.isFocusPointModeSupported(Camera.FocusPointCustom) && |
2003 | + !camera.photoCaptureInProgress |
2004 | onClicked: { |
2005 | camera.manualFocus(mouse.x, mouse.y); |
2006 | mouse.accepted = false; |
2007 | } |
2008 | - // FIXME: calling 'isFocusPointModeSupported' fails with |
2009 | - // "Error: Unknown method parameter type: QDeclarativeCamera::FocusPointMode" |
2010 | - //enabled: camera.focus.isFocusPointModeSupported(Camera.FocusPointCustom) |
2011 | } |
2012 | } |
2013 | |
2014 | @@ -941,16 +977,29 @@ |
2015 | } |
2016 | } |
2017 | |
2018 | + ProcessingFeedback { |
2019 | + anchors { |
2020 | + top: parent.top |
2021 | + topMargin: units.gu(2) |
2022 | + left: parent.left |
2023 | + leftMargin: units.gu(2) |
2024 | + } |
2025 | + processing: camera.photoCaptureInProgress |
2026 | + } |
2027 | + |
2028 | StorageMonitor { |
2029 | id: storageMonitor |
2030 | - location: (application.removableStoragePresent && settings.preferRemovableStorage) ? |
2031 | - application.removableStorageLocation : application.videosLocation |
2032 | + location: (StorageLocations.removableStoragePresent && settings.preferRemovableStorage) ? |
2033 | + StorageLocations.removableStorageLocation : StorageLocations.videosLocation |
2034 | onDiskSpaceLowChanged: if (storageMonitor.diskSpaceLow && !storageMonitor.diskSpaceCriticallyLow) { |
2035 | PopupUtils.open(freeSpaceLowDialogComponent); |
2036 | } |
2037 | onDiskSpaceCriticallyLowChanged: if (storageMonitor.diskSpaceCriticallyLow) { |
2038 | camera.videoRecorder.stop(); |
2039 | } |
2040 | + onIsWriteableChanged: if (!isWriteable && !diskSpaceLow && !main.contentExportMode) { |
2041 | + PopupUtils.open(readOnlyMediaDialogComponent); |
2042 | + } |
2043 | } |
2044 | |
2045 | NoSpaceHint { |
2046 | @@ -974,6 +1023,20 @@ |
2047 | } |
2048 | } |
2049 | |
2050 | + Component { |
2051 | + id: readOnlyMediaDialogComponent |
2052 | + Dialog { |
2053 | + id: readOnlyMediaDialog |
2054 | + objectName: "readOnlyMediaDialog" |
2055 | + title: i18n.tr("External storage not writeable") |
2056 | + text: i18n.tr("It does not seem possible to write to your external storage media. Trying to eject and insert it again might solve the issue, or you might need to format it.") |
2057 | + Button { |
2058 | + text: i18n.tr("Cancel") |
2059 | + onClicked: PopupUtils.close(readOnlyMediaDialog) |
2060 | + } |
2061 | + } |
2062 | + } |
2063 | + |
2064 | Connections { |
2065 | id: permissionErrorMonitor |
2066 | property var currentPermissionsDialog: null |
2067 | |
2068 | === modified file 'ViewFinderOverlayLoader.qml' |
2069 | --- ViewFinderOverlayLoader.qml 2016-01-07 08:03:57 +0000 |
2070 | +++ ViewFinderOverlayLoader.qml 2016-02-26 17:17:00 +0000 |
2071 | @@ -24,6 +24,7 @@ |
2072 | property real revealProgress: loader.item ? loader.item.revealProgress : 0 |
2073 | property var controls: loader.item ? loader.item.controls : null |
2074 | property var settings: loader.item.settings |
2075 | + property bool readyForCapture |
2076 | |
2077 | function showFocusRing(x, y) { |
2078 | loader.item.showFocusRing(x, y); |
2079 | @@ -35,6 +36,8 @@ |
2080 | |
2081 | asynchronous: true |
2082 | Component.onCompleted: { |
2083 | - loader.setSource("ViewFinderOverlay.qml", { "camera": loader.camera }); |
2084 | + loader.setSource("ViewFinderOverlay.qml", { "camera": loader.camera, |
2085 | + "readyForCapture": Qt.binding(function() { return loader.readyForCapture}) |
2086 | + }); |
2087 | } |
2088 | } |
2089 | |
2090 | === modified file 'ViewFinderView.qml' |
2091 | --- ViewFinderView.qml 2016-01-14 15:55:52 +0000 |
2092 | +++ ViewFinderView.qml 2016-02-26 17:17:00 +0000 |
2093 | @@ -17,6 +17,7 @@ |
2094 | import QtQuick 2.4 |
2095 | import QtQuick.Window 2.2 |
2096 | import Ubuntu.Components 1.3 |
2097 | +import Ubuntu.Components.Popups 1.3 |
2098 | import QtMultimedia 5.0 |
2099 | import CameraApp 0.1 |
2100 | import QtGraphicalEffects 1.0 |
2101 | @@ -96,36 +97,41 @@ |
2102 | property bool switchInProgress: false |
2103 | property bool photoCaptureInProgress: false |
2104 | |
2105 | + onPhotoCaptureInProgressChanged: { |
2106 | + if (main.contentExportMode && camera.photoCaptureInProgress) { |
2107 | + viewFinderExportConfirmation.photoCaptureStarted(); |
2108 | + } |
2109 | + } |
2110 | + |
2111 | imageCapture { |
2112 | onReadyChanged: { |
2113 | - if (camera.imageCapture.ready && main.transfer) { |
2114 | - if (main.transfer.contentType === ContentType.Videos) { |
2115 | - viewFinderView.captureMode = Camera.CaptureVideo; |
2116 | - } else { |
2117 | - viewFinderView.captureMode = Camera.CaptureStillImage; |
2118 | + if (camera.imageCapture.ready) { |
2119 | + if (camera.photoCaptureInProgress) { |
2120 | + if (photoRollHint.necessary && !main.transfer) photoRollHint.enable(); |
2121 | + camera.photoCaptureInProgress = false; |
2122 | + } |
2123 | + |
2124 | + if (main.transfer) { |
2125 | + if (main.transfer.contentType === ContentType.Videos) { |
2126 | + viewFinderView.captureMode = Camera.CaptureVideo; |
2127 | + } else { |
2128 | + viewFinderView.captureMode = Camera.CaptureStillImage; |
2129 | + } |
2130 | } |
2131 | } |
2132 | } |
2133 | + |
2134 | onCaptureFailed: { |
2135 | + console.log("Image capture failed for request " + requestId + ": " + message); |
2136 | camera.photoCaptureInProgress = false; |
2137 | - console.log("Capture failed for request " + requestId + ": " + message); |
2138 | - } |
2139 | - onImageCaptured: { |
2140 | - snapshot.source = preview; |
2141 | - if (!main.contentExportMode) { |
2142 | - viewFinderOverlay.visible = true; |
2143 | - snapshot.startOutAnimation(); |
2144 | - if (photoRollHint.necessary) { |
2145 | - photoRollHint.enable(); |
2146 | - } |
2147 | - } |
2148 | - } |
2149 | + viewFinderOverlay.visible = true; |
2150 | + PopupUtils.open(captureFailedDialogComponent); |
2151 | + } |
2152 | + |
2153 | onImageSaved: { |
2154 | - if (main.contentExportMode) { |
2155 | - viewFinderExportConfirmation.confirmExport(path); |
2156 | - } |
2157 | + if (main.contentExportMode) viewFinderExportConfirmation.mediaPath = path; |
2158 | + |
2159 | viewFinderView.photoTaken(path); |
2160 | - camera.photoCaptureInProgress = false; |
2161 | metricPhotos.increment(); |
2162 | console.log("Picture saved as " + path); |
2163 | } |
2164 | @@ -135,15 +141,19 @@ |
2165 | onRecorderStateChanged: { |
2166 | if (videoRecorder.recorderState === CameraRecorder.StoppedState) { |
2167 | metricVideos.increment() |
2168 | - viewFinderOverlay.visible = true; |
2169 | viewFinderView.videoShot(videoRecorder.actualLocation); |
2170 | if (main.contentExportMode) { |
2171 | - viewFinderExportConfirmation.confirmExport(videoRecorder.actualLocation); |
2172 | + viewFinderExportConfirmation.mediaPath = videoRecorder.actualLocation |
2173 | } else if (photoRollHint.necessary) { |
2174 | photoRollHint.enable(); |
2175 | } |
2176 | } |
2177 | } |
2178 | + onErrorCodeChanged: { |
2179 | + if (videoRecorder.errorCode !== CameraRecorder.NoError) { |
2180 | + PopupUtils.open(captureFailedDialogComponent); |
2181 | + } |
2182 | + } |
2183 | } |
2184 | } |
2185 | |
2186 | @@ -235,18 +245,21 @@ |
2187 | width: parent.width |
2188 | height: parent.height |
2189 | source: camera |
2190 | + opacity: ((main.contentExportMode && viewFinderExportConfirmation.waitingForPictureCapture) || |
2191 | + (!main.contentExportMode && camera.photoCaptureInProgress && !camera.imageCapture.ready)) |
2192 | + ? 0.1 : 1.0 |
2193 | |
2194 | /* This rotation need to be applied since the camera hardware in the |
2195 | - Galaxy Nexus phone is mounted at an angle inside the device, so the video |
2196 | - feed is rotated too. |
2197 | - FIXME: This should come from a system configuration option so that we |
2198 | - don't have to have a different codebase for each different device we want |
2199 | - to run on. Android has that information and QML has an API to reflect it: |
2200 | - the camera.orientation property. Unfortunately it is not hooked up yet. |
2201 | + Galaxy Nexus phone is mounted at an angle inside the device, so the video |
2202 | + feed is rotated too. |
2203 | + FIXME: This should come from a system configuration option so that we |
2204 | + don't have to have a different codebase for each different device we want |
2205 | + to run on. Android has that information and QML has an API to reflect it: |
2206 | + the camera.orientation property. Unfortunately it is not hooked up yet. |
2207 | |
2208 | - Ref.: http://doc.qt.io/qt-5/qml-qtmultimedia-camera.html#orientation-prop |
2209 | - http://doc.qt.io/qt-5/qcamerainfocontrol.html#cameraOrientation |
2210 | - http://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation |
2211 | + Ref.: http://doc.qt.io/qt-5/qml-qtmultimedia-camera.html#orientation-prop |
2212 | + http://doc.qt.io/qt-5/qcamerainfocontrol.html#cameraOrientation |
2213 | + http://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation |
2214 | */ |
2215 | Component.onCompleted: { |
2216 | // Set orientation only at startup because later on Screen.primaryOrientation |
2217 | @@ -254,14 +267,6 @@ |
2218 | orientation = Screen.primaryOrientation === Qt.PortraitOrientation ? -90 : 0; |
2219 | } |
2220 | |
2221 | - /* Convenience item tracking the real position and size of the real video feed. |
2222 | - Having this helps since these values depend on a lot of rules: |
2223 | - - the feed is automatically scaled to fit the viewfinder |
2224 | - - the viewfinder might apply a rotation to the feed, depending on device orientation |
2225 | - - the resolution and aspect ratio of the feed changes depending on the active camera |
2226 | - The item is also separated in a component so it can be unit tested. |
2227 | - */ |
2228 | - |
2229 | transform: Rotation { |
2230 | origin.x: viewFinder.width / 2 |
2231 | origin.y: viewFinder.height / 2 |
2232 | @@ -270,6 +275,13 @@ |
2233 | } |
2234 | } |
2235 | |
2236 | + /* Convenience item tracking the real position and size of the real video feed. |
2237 | + Having this helps since these values depend on a lot of rules: |
2238 | + - the feed is automatically scaled to fit the viewfinder |
2239 | + - the viewfinder might apply a rotation to the feed, depending on device orientation |
2240 | + - the resolution and aspect ratio of the feed changes depending on the active camera |
2241 | + The item is also separated in a component so it can be unit tested. |
2242 | + */ |
2243 | ViewFinderGeometry { |
2244 | id: viewFinderGeometry |
2245 | anchors.centerIn: parent |
2246 | @@ -330,12 +342,10 @@ |
2247 | anchors.fill: parent |
2248 | |
2249 | function start() { |
2250 | - viewFinderOverlay.visible = false; |
2251 | } |
2252 | |
2253 | function stop() { |
2254 | remainingSecsLabel.text = ""; |
2255 | - viewFinderOverlay.visible = true; |
2256 | } |
2257 | |
2258 | function showRemainingSecs(secs) { |
2259 | @@ -384,7 +394,6 @@ |
2260 | |
2261 | function start() { |
2262 | shootFeedback.opacity = 1.0; |
2263 | - viewFinderOverlay.visible = false; |
2264 | shootFeedbackAnimation.restart(); |
2265 | } |
2266 | |
2267 | @@ -393,7 +402,7 @@ |
2268 | target: shootFeedback |
2269 | from: 1.0 |
2270 | to: 0.0 |
2271 | - duration: 50 |
2272 | + duration: UbuntuAnimation.SnapDuration |
2273 | easing: UbuntuAnimation.StandardEasing |
2274 | } |
2275 | } |
2276 | @@ -410,38 +419,76 @@ |
2277 | visible: radius !== 0 |
2278 | } |
2279 | |
2280 | + PhotoRollHint { |
2281 | + id: photoRollHint |
2282 | + anchors.fill: parent |
2283 | + visible: enabled |
2284 | + |
2285 | + Connections { |
2286 | + target: viewFinderView |
2287 | + onInViewChanged: if (!viewFinderView.inView) photoRollHint.disable() |
2288 | + } |
2289 | + } |
2290 | + |
2291 | ViewFinderOverlayLoader { |
2292 | id: viewFinderOverlay |
2293 | |
2294 | anchors.fill: parent |
2295 | camera: camera |
2296 | opacity: status == Loader.Ready && overlayVisible && !photoRollHint.enabled ? 1.0 : 0.0 |
2297 | - Behavior on opacity {UbuntuNumberAnimation {duration: UbuntuAnimation.SnapDuration}} |
2298 | - } |
2299 | - |
2300 | - PhotoRollHint { |
2301 | - id: photoRollHint |
2302 | - anchors.fill: parent |
2303 | - visible: enabled && !snapshot.loading |
2304 | - |
2305 | - Connections { |
2306 | - target: viewFinderView |
2307 | - onInViewChanged: if (!viewFinderView.inView) photoRollHint.disable() |
2308 | - } |
2309 | - } |
2310 | - |
2311 | - Snapshot { |
2312 | - id: snapshot |
2313 | - anchors.fill: parent |
2314 | - orientation: viewFinder.orientation |
2315 | - geometry: viewFinderGeometry |
2316 | - deviceDefaultIsPortrait: Screen.primaryOrientation === Qt.PortraitOrientation |
2317 | + readyForCapture: main.contentExportMode && |
2318 | + viewFinderExportConfirmation.waitingForPictureCapture ? false : camera.imageCapture.ready |
2319 | + |
2320 | + Behavior on opacity { |
2321 | + enabled: !photoRollHint.enabled |
2322 | + UbuntuNumberAnimation {duration: UbuntuAnimation.SnapDuration} |
2323 | + } |
2324 | + |
2325 | + // Tapping anywhere on the screen should not trigger any camera |
2326 | + // controls while PhotoRoll hint is visible |
2327 | + MouseArea { |
2328 | + anchors.fill: parent |
2329 | + enabled: photoRollHint.visible |
2330 | + } |
2331 | } |
2332 | |
2333 | ViewFinderExportConfirmation { |
2334 | id: viewFinderExportConfirmation |
2335 | anchors.fill: parent |
2336 | - snapshot: snapshot |
2337 | + |
2338 | isVideo: main.transfer.contentType == ContentType.Videos |
2339 | + viewFinderGeometry: viewFinderGeometry |
2340 | + |
2341 | + onShowRequested: { |
2342 | + viewFinder.visible = false; |
2343 | + viewFinderOverlay.visible = false; |
2344 | + visible = true; |
2345 | + } |
2346 | + |
2347 | + onHideRequested: { |
2348 | + viewFinder.visible = true; |
2349 | + viewFinderOverlay.visible = true; |
2350 | + visible = false; |
2351 | + } |
2352 | + } |
2353 | + |
2354 | + Component { |
2355 | + id: captureFailedDialogComponent |
2356 | + Dialog { |
2357 | + id: captureFailedDialog |
2358 | + objectName: "captureFailedDialog" |
2359 | + title: i18n.tr("Capture failed") |
2360 | + |
2361 | + // If we are capturing to an SD card the problem can be a broken card, otherwise it is probably a |
2362 | + // crash in the driver and a reboot might fix things. |
2363 | + text: StorageLocations.removableStorageLocation && viewFinderOverlay.settings.preferRemovableStorage ? |
2364 | + i18n.tr("Replacing your external media, formatting it, or restarting the device might fix the problem.") : |
2365 | + i18n.tr("Restarting your device might fix the problem.") |
2366 | + |
2367 | + Button { |
2368 | + text: i18n.tr("Cancel") |
2369 | + onClicked: PopupUtils.close(captureFailedDialog) |
2370 | + } |
2371 | + } |
2372 | } |
2373 | } |
2374 | |
2375 | === modified file 'cameraapplication.cpp' |
2376 | --- cameraapplication.cpp 2015-11-25 17:47:00 +0000 |
2377 | +++ cameraapplication.cpp 2016-02-26 17:17:00 +0000 |
2378 | @@ -19,14 +19,8 @@ |
2379 | |
2380 | #include "cameraapplication.h" |
2381 | |
2382 | -#include <QtCore/QDir> |
2383 | -#include <QtCore/QUrl> |
2384 | #include <QtCore/QDebug> |
2385 | -#include <QtCore/QStringList> |
2386 | #include <QtCore/QLibrary> |
2387 | -#include <QtCore/QStandardPaths> |
2388 | -#include <QtCore/QDir> |
2389 | -#include <QDate> |
2390 | #include <QQmlContext> |
2391 | #include <QQmlEngine> |
2392 | #include <QScreen> |
2393 | @@ -95,103 +89,3 @@ |
2394 | |
2395 | return true; |
2396 | } |
2397 | - |
2398 | -QString CameraApplication::picturesLocation() const |
2399 | -{ |
2400 | - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); |
2401 | - if (locations.isEmpty()) { |
2402 | - return QString(); |
2403 | - } |
2404 | - QString location = locations.at(0) + "/" + QCoreApplication::applicationName(); |
2405 | - QDir dir; |
2406 | - // Transition from old directory 'camera' to new one; see bug #1363112 |
2407 | - // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1363112 |
2408 | - dir.rename(locations.at(0) + "/" + "camera", location); |
2409 | - dir.mkpath(location); |
2410 | - return location; |
2411 | -} |
2412 | - |
2413 | -QString CameraApplication::videosLocation() const |
2414 | -{ |
2415 | - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation); |
2416 | - if (locations.isEmpty()) { |
2417 | - return QString(); |
2418 | - } |
2419 | - QString location = locations.at(0) + "/" + QCoreApplication::applicationName(); |
2420 | - QDir dir; |
2421 | - // Transition from old directory 'camera' to new one; see bug #1363112 |
2422 | - // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1363112 |
2423 | - dir.rename(locations.at(0) + "/" + "camera", location); |
2424 | - dir.mkpath(location); |
2425 | - return location; |
2426 | -} |
2427 | - |
2428 | -QString CameraApplication::temporaryLocation() const |
2429 | -{ |
2430 | - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::TempLocation); |
2431 | - if (locations.isEmpty()) { |
2432 | - return QString(); |
2433 | - } |
2434 | - QString location = locations.at(0); |
2435 | - QDir dir; |
2436 | - dir.mkpath(location); |
2437 | - return location; |
2438 | -} |
2439 | - |
2440 | -bool CameraApplication::removableStoragePresent() const |
2441 | -{ |
2442 | - return !removableStorageLocation().isEmpty(); |
2443 | -} |
2444 | - |
2445 | -QString CameraApplication::removableStorageLocation() const |
2446 | -{ |
2447 | - /* FIXME: when Qt5.4 is available, switch to using newly introduced |
2448 | - * QStorageInfo API. |
2449 | - * Ref.: http://doc-snapshot.qt-project.org/qt5-5.4/qstorageinfo.html |
2450 | - */ |
2451 | - QString userName = qgetenv("USER"); |
2452 | - QDir media("/media/" + userName); |
2453 | - QStringList mediaDirs = media.entryList(QDir::Dirs | QDir::NoDotAndDotDot); |
2454 | - |
2455 | - if (mediaDirs.size() > 0) { |
2456 | - return QString("/media/" + userName + "/" + mediaDirs.at(0)); |
2457 | - } else { |
2458 | - return QString(); |
2459 | - } |
2460 | -} |
2461 | - |
2462 | -QString CameraApplication::removableStoragePicturesLocation() const |
2463 | -{ |
2464 | - QString storageLocation = removableStorageLocation(); |
2465 | - if (storageLocation.isEmpty()) { |
2466 | - return QString(); |
2467 | - } |
2468 | - |
2469 | - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); |
2470 | - QString pictureDir = QString(locations.at(0)).split("/").value(3); |
2471 | - if (pictureDir.isEmpty()){ |
2472 | - return QString(); |
2473 | - } |
2474 | - QString location = storageLocation + "/" + pictureDir + "/" + QCoreApplication::applicationName(); |
2475 | - QDir dir; |
2476 | - dir.mkpath(location); |
2477 | - return location; |
2478 | -} |
2479 | - |
2480 | -QString CameraApplication::removableStorageVideosLocation() const |
2481 | -{ |
2482 | - QString storageLocation = removableStorageLocation(); |
2483 | - if (storageLocation.isEmpty()) { |
2484 | - return QString(); |
2485 | - } |
2486 | - |
2487 | - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::MoviesLocation); |
2488 | - QString movieDir = QString(locations.at(0)).split("/").value(3); |
2489 | - if (movieDir.isEmpty()){ |
2490 | - return QString(); |
2491 | - } |
2492 | - QString location = storageLocation + "/" + movieDir + "/" + QCoreApplication::applicationName(); |
2493 | - QDir dir; |
2494 | - dir.mkpath(location); |
2495 | - return location; |
2496 | -} |
2497 | |
2498 | === modified file 'cameraapplication.h' |
2499 | --- cameraapplication.h 2015-11-25 17:47:00 +0000 |
2500 | +++ cameraapplication.h 2016-02-26 17:17:00 +0000 |
2501 | @@ -29,29 +29,14 @@ |
2502 | { |
2503 | Q_OBJECT |
2504 | Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT) |
2505 | - Q_PROPERTY(QString picturesLocation READ picturesLocation CONSTANT) |
2506 | - Q_PROPERTY(QString videosLocation READ videosLocation CONSTANT) |
2507 | - Q_PROPERTY(QString temporaryLocation READ temporaryLocation CONSTANT) |
2508 | - Q_PROPERTY(bool removableStoragePresent READ removableStoragePresent NOTIFY removableStoragePresentChanged) |
2509 | - Q_PROPERTY(QString removableStorageLocation READ removableStorageLocation CONSTANT) |
2510 | - Q_PROPERTY(QString removableStoragePicturesLocation READ removableStoragePicturesLocation CONSTANT) |
2511 | - Q_PROPERTY(QString removableStorageVideosLocation READ removableStorageVideosLocation CONSTANT) |
2512 | |
2513 | public: |
2514 | CameraApplication(int &argc, char **argv); |
2515 | virtual ~CameraApplication(); |
2516 | bool setup(); |
2517 | bool isDesktopMode() const; |
2518 | - QString picturesLocation() const; |
2519 | - QString videosLocation() const; |
2520 | - QString temporaryLocation() const; |
2521 | - bool removableStoragePresent() const; |
2522 | - QString removableStorageLocation() const; |
2523 | - QString removableStoragePicturesLocation() const; |
2524 | - QString removableStorageVideosLocation() const; |
2525 | |
2526 | Q_SIGNALS: |
2527 | - void removableStoragePresentChanged(); |
2528 | |
2529 | private: |
2530 | QScopedPointer<QQmlApplicationEngine> m_engine; |
2531 | |
2532 | === modified file 'debian/rules' |
2533 | --- debian/rules 2015-11-18 06:44:35 +0000 |
2534 | +++ debian/rules 2016-02-26 17:17:00 +0000 |
2535 | @@ -11,10 +11,6 @@ |
2536 | override_dh_auto_configure: |
2537 | dh_auto_configure -- -DCLICK_MODE=OFF -DINSTALL_TESTS=ON |
2538 | |
2539 | -override_dh_auto_test: |
2540 | - python3 -m flake8 . |
2541 | - dh_auto_test |
2542 | - |
2543 | override_dh_install: |
2544 | dh_install --fail-missing |
2545 | |
2546 | |
2547 | === modified file 'manifest.json.in' |
2548 | --- manifest.json.in 2015-11-25 17:56:59 +0000 |
2549 | +++ manifest.json.in 2016-02-26 17:17:00 +0000 |
2550 | @@ -1,6 +1,6 @@ |
2551 | { |
2552 | "description": "An application to take pictures and videos with the device cameras", |
2553 | - "framework": "ubuntu-sdk-15.04.3", |
2554 | + "framework": "ubuntu-sdk-15.04.4", |
2555 | "architecture": "@CLICK_ARCH@", |
2556 | "hooks": { |
2557 | "camera": { |
2558 | |
2559 | === removed file 'run_tests.sh' |
2560 | --- run_tests.sh 2012-10-24 15:18:16 +0000 |
2561 | +++ run_tests.sh 1970-01-01 00:00:00 +0000 |
2562 | @@ -1,13 +0,0 @@ |
2563 | -#!/bin/bash |
2564 | -export PATH=/opt/qt5/bin:$PATH |
2565 | -cd tests/autopilot |
2566 | - |
2567 | -echo running with arg: $1 |
2568 | - |
2569 | -if [ "$1" == "" ]; then |
2570 | - autopilot run camera_app |
2571 | -else |
2572 | - autopilot run -o ../../$1 -f xml -r -rd ../../ camera_app |
2573 | -fi |
2574 | - |
2575 | -exit 0 |
2576 | |
2577 | === modified file 'tests/autopilot/camera_app/tests/test_focus.py' |
2578 | --- tests/autopilot/camera_app/tests/test_focus.py 2015-10-05 13:14:12 +0000 |
2579 | +++ tests/autopilot/camera_app/tests/test_focus.py 2016-02-26 17:17:00 +0000 |
2580 | @@ -28,6 +28,20 @@ |
2581 | def tearDown(self): |
2582 | super(TestFocus, self).tearDown() |
2583 | |
2584 | + def verify_focus_ring_after_click_at(self, ring, x, y): |
2585 | + # The focus ring should be invisible in the beginning |
2586 | + self.assertThat(ring.opacity, Eventually(Equals(0.0))) |
2587 | + |
2588 | + # Click in the designated spot |
2589 | + self.pointing_device.move(x, y) |
2590 | + self.pointing_device.click() |
2591 | + |
2592 | + # The focus ring sould be visible now |
2593 | + self.assertThat(ring.opacity, Eventually(GreaterThan(0.5))) |
2594 | + |
2595 | + # After some seconds the focus ring should fade out |
2596 | + self.assertThat(ring.opacity, Eventually(Equals(0.0))) |
2597 | + |
2598 | """Test focusing in an area where we know the picture is""" |
2599 | @unittest.skipIf(model() == 'Galaxy Nexus', 'Unusable with Mir on maguro') |
2600 | def test_focus_valid_and_disappear(self): |
2601 | @@ -36,21 +50,16 @@ |
2602 | switch_cameras = self.main_window.get_swap_camera_button() |
2603 | exposure_button = self.main_window.get_exposure_button() |
2604 | |
2605 | - # The focus ring should be invisible in the beginning |
2606 | - self.assertThat(focus_ring.opacity, Eventually(Equals(0.0))) |
2607 | - |
2608 | - self.pointing_device.move_to_object(feed) |
2609 | - self.pointing_device.click() |
2610 | - click_coords = list(self.pointing_device.position()) |
2611 | - |
2612 | - # The focus ring sould be visible and centered to the mouse click |
2613 | - # coords now |
2614 | - # focus_ring_center = self.get_center(focus_ring) |
2615 | - self.assertThat(focus_ring.opacity, Eventually(GreaterThan(0.5))) |
2616 | -# self.assertEquals(focus_ring_center, click_coords) |
2617 | - |
2618 | - # After some seconds the focus ring should fade out |
2619 | - self.assertThat(focus_ring.opacity, Eventually(Equals(0.0))) |
2620 | + # Click in the center of the viewfinder area |
2621 | + mid_x, mid_y = self.get_center(feed) |
2622 | + self.verify_focus_ring_after_click_at(focus_ring, mid_x, mid_y) |
2623 | + |
2624 | + # Then try on the side edges and top edge to verify they |
2625 | + # are focusable too |
2626 | + self.verify_focus_ring_after_click_at(focus_ring, 1, mid_y) |
2627 | + self.verify_focus_ring_after_click_at(focus_ring, feed.width - 1, |
2628 | + mid_y) |
2629 | + self.verify_focus_ring_after_click_at(focus_ring, mid_x, 1) |
2630 | |
2631 | # Switch cameras, wait for camera to settle, and try again |
2632 | self.pointing_device.move_to_object(switch_cameras) |
2633 | @@ -58,19 +67,14 @@ |
2634 | self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
2635 | |
2636 | # Click in the center of the viewfinder area |
2637 | - click_coords = [feed.globalRect[2] // 2 + feed.globalRect[0], |
2638 | - feed.globalRect[3] // 2 + feed.globalRect[1]] |
2639 | - self.pointing_device.move(click_coords[0], click_coords[1]) |
2640 | - self.pointing_device.click() |
2641 | - |
2642 | - # The focus ring sould be visible and centered to the mouse |
2643 | - # click coords now |
2644 | - # focus_ring_center = self.get_center(focus_ring) |
2645 | - self.assertThat(focus_ring.opacity, Eventually(GreaterThan(0.5))) |
2646 | -# self.assertEquals(focus_ring_center, click_coords) |
2647 | - |
2648 | - # After some seconds the focus ring should fade out |
2649 | - self.assertThat(focus_ring.opacity, Eventually(Equals(0.0))) |
2650 | + self.verify_focus_ring_after_click_at(focus_ring, mid_x, mid_y) |
2651 | + |
2652 | + # Then try on the side edges and top edge to verify they |
2653 | + # are focusable too |
2654 | + self.verify_focus_ring_after_click_at(focus_ring, 1, mid_y) |
2655 | + self.verify_focus_ring_after_click_at(focus_ring, feed.width - 1, |
2656 | + mid_y) |
2657 | + self.verify_focus_ring_after_click_at(focus_ring, mid_x, 1) |
2658 | |
2659 | @unittest.skipIf(model() == 'Galaxy Nexus', 'Unusable with Mir on maguro') |
2660 | def test_focus_invalid(self): |
2661 | |
2662 | === modified file 'tests/autopilot/camera_app/tests/test_options.py' |
2663 | --- tests/autopilot/camera_app/tests/test_options.py 2015-11-20 15:01:02 +0000 |
2664 | +++ tests/autopilot/camera_app/tests/test_options.py 2016-02-26 17:17:00 +0000 |
2665 | @@ -42,6 +42,33 @@ |
2666 | # check overlay is closed |
2667 | self.assertThat(bottom_edge.opened, Eventually(Equals(False))) |
2668 | |
2669 | + # try opening and closing by tapping on the bottom of the viewfinder |
2670 | + bottom_edge = self.main_window.get_bottom_edge() |
2671 | + bottom_edge.open() |
2672 | + |
2673 | + # check overlay is opened |
2674 | + self.assertThat(bottom_edge.opened, Eventually(Equals(True))) |
2675 | + |
2676 | + # tap on the bottom of the viewfinder to close overlay |
2677 | + viewfinder = self.main_window.get_viewfinder() |
2678 | + x = viewfinder.globalRect.x + viewfinder.width / 2.0 |
2679 | + y = viewfinder.globalRect.y + viewfinder.height - 1.0 |
2680 | + self.pointing_device.move(x, y) |
2681 | + self.pointing_device.click() |
2682 | + |
2683 | + # check overlay is closed |
2684 | + self.assertThat(bottom_edge.opened, Eventually(Equals(False))) |
2685 | + |
2686 | + """Test that the options overlay opens properly by tapping on the hint""" |
2687 | + def test_overlay_open_tapping_hint(self): |
2688 | + options_hint = self.app.wait_select_single(objectName="indicatorsRow") |
2689 | + self.pointing_device.move_to_object(options_hint) |
2690 | + self.pointing_device.click() |
2691 | + |
2692 | + # check overlay is opened |
2693 | + bottom_edge = self.main_window.get_bottom_edge() |
2694 | + self.assertThat(bottom_edge.opened, Eventually(Equals(True))) |
2695 | + |
2696 | """Test toggling on/off grid lines option""" |
2697 | def test_toggle_grid_lines(self): |
2698 | gridlines = self.app.wait_select_single( |
2699 | |
2700 | === modified file 'tests/unittests/CMakeLists.txt' |
2701 | --- tests/unittests/CMakeLists.txt 2015-03-12 22:36:12 +0000 |
2702 | +++ tests/unittests/CMakeLists.txt 2016-02-26 17:17:00 +0000 |
2703 | @@ -33,6 +33,7 @@ |
2704 | |
2705 | qt5_use_modules(tst_storagemonitor Widgets Core Quick Qml Test) |
2706 | add_test(tst_storagemonitor tst_storagemonitor -xunitxml -o test.xml) |
2707 | +add_test(flake8 python3 -m flake8 ${CMAKE_SOURCE_DIR}/tests/autopilot) |
2708 | set_tests_properties(tst_storagemonitor PROPERTIES |
2709 | TIMEOUT ${CTEST_TESTING_TIMEOUT} |
2710 | ENVIRONMENT "QT_QPA_PLATFORM=minimal" |
2711 | |
2712 | === modified file 'tests/unittests/qstorageinfo_stub.cpp' |
2713 | --- tests/unittests/qstorageinfo_stub.cpp 2015-01-26 10:57:36 +0000 |
2714 | +++ tests/unittests/qstorageinfo_stub.cpp 2016-02-26 17:17:00 +0000 |
2715 | @@ -14,14 +14,23 @@ |
2716 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2717 | */ |
2718 | |
2719 | -#include "qstorageinfo.h" |
2720 | -#include "qstorageinfo_p.h" |
2721 | +#include <QStorageInfo> |
2722 | #include "storageinfocontrol.h" |
2723 | |
2724 | #include <QDebug> |
2725 | |
2726 | QString location; |
2727 | |
2728 | +class QStorageInfoPrivateRef { |
2729 | +public: |
2730 | + bool deref() { return false; } |
2731 | +}; |
2732 | + |
2733 | +class QStorageInfoPrivate { |
2734 | +public: |
2735 | + QStorageInfoPrivateRef ref; |
2736 | +}; |
2737 | + |
2738 | QStorageInfo::QStorageInfo() |
2739 | { |
2740 | } |
2741 | @@ -47,6 +56,11 @@ |
2742 | location = path; |
2743 | } |
2744 | |
2745 | +QString QStorageInfo::rootPath() const |
2746 | +{ |
2747 | + return location; |
2748 | +} |
2749 | + |
2750 | qint64 QStorageInfo::bytesAvailable() const |
2751 | { |
2752 | return StorageInfoControl::instance()->freeSpaceMap[location]; |
FAILED: Continuous integration, rev:642 jenkins. qa.ubuntu. com/job/ camera- app-ci/ 483/ jenkins. qa.ubuntu. com/job/ camera- app-vivid- amd64-ci/ 178 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 179 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 179/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ camera- app-vivid- i386-ci/ 178 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -vivid- touch/392 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -runner- touch/1062 jenkins. qa.ubuntu. com/job/ generic- click-builder- vivid-armhf/ 950 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 27167
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/camera- app-ci/ 483/rebuild
http://