Replaced QtMobility BatteryInfo
[harmattan/cameraplus] / qml / main.qml
1 // -*- qml -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 import QtQuick 1.1
24 import com.nokia.meego 1.1
25 import com.nokia.extras 1.1
26 import QtCamera 1.0
27 import QtMobility.systeminfo 1.2
28 import QtMobility.location 1.2
29
30 // TODO: this has to be below QtMobility.systeminfo
31 // We define an element called BatteryInfo which conflicts with the one defined by QtMobility
32 // Thus we have to be the last so our element can be used instead of the one from QtMobility
33 import CameraPlus 1.0
34
35 // TODO: flash not ready (battery low or flash not ready message)
36 // TODO: portrait/landscape
37 // TODO: grid lines, face tracking
38 // TODO: select primary/secondary camera.
39 // TODO: disable debug builds.
40 // TODO: a way to get buffers to the application
41 // TODO: fcam like functionality (precise control over capture parameters).
42
43 PageStackWindow {
44         id: root
45
46         property alias dimmer: camDimmer
47
48         showStatusBar: false
49
50         Component.onCompleted: {
51                 theme.inverted = true;
52                 // TODO: hardcoding device id
53                 root.resetCamera(0, settings.mode);
54         }
55
56         function showError(msg) {
57                 error.text = msg;
58                 error.show();
59         }
60
61         function resetCamera(deviceId, mode) {
62                 if (!cam.reset(deviceId, mode)) {
63                         showError(qsTr("Failed to set camera device and mode. Please restart the application."));
64                 }
65         }
66
67         PositionSource {
68                 // NOTE: The source will not reset the position when we lose the signal.
69                 // This shouldn't be a big problem as we are course enough.
70                 // If we ever need street level updates then this will be an issue.
71                 id: positionSource
72                 active: settings.useGps
73                 // TODO: we cannot bind to cam.running because camera will stop
74                 // when the connection dialog pops up and we end up with an infinite loop
75                 // active: cam.running && settings.useGps
76                 onPositionChanged: geocode.search(position.coordinate.longitude, position.coordinate.latitude);
77         }
78
79         MetaData {
80                 id: metaData
81                 camera: cam
82                 manufacturer: deviceInfo.manufacturer
83                 model: deviceInfo.model
84                 country: geocode.country
85                 city: geocode.city
86                 suburb: geocode.suburb
87                 longitude: positionSource.position.coordinate.longitude
88                 longitudeValid: positionSource.position.longitudeValid && settings.useGps
89                 latitude: positionSource.position.coordinate.latitude
90                 latitudeValid: positionSource.position.latitudeValid && settings.useGps
91                 elevation: positionSource.position.coordinate.altitude
92                 elevationValid: positionSource.position.altitudeValid && settings.useGps
93                 orientation: orientation.orientation
94                 artist: settings.creatorName
95                 captureDirection: compass.direction
96                 captureDirectionValid: compass.directionValid
97                 horizontalError: positionSource.position.horizontalAccuracy
98                 horizontalErrorValid: positionSource.position.horizontalAccuracyValid && settings.useGps
99                 dateTimeEnabled: true
100         }
101
102         Orientation {
103                 id: orientation
104                 active: cam.running
105         }
106
107         Compass {
108                 id: compass
109                 active: cam.running
110         }
111
112         ReverseGeocode {
113                 id: geocode
114                 active: cam.running && settings.useGps && settings.useGeotags
115         }
116
117         PipelineManager {
118                 id: pipelineManager
119                 camera: cam
120         }
121
122         DeviceInfo {
123                 id: deviceInfo
124         }
125
126         FSMonitor {
127                 id: fileSystem
128         }
129
130         InfoBanner {
131                 id: error
132         }
133
134         Settings {
135                 id: settings
136         }
137
138         FileNaming {
139                 id: fileNaming
140                 imageSuffix: cam.imageSuffix
141                 videoSuffix: cam.videoSuffix
142         }
143
144         MountProtector {
145                 id: mountProtector
146                 path: fileNaming.path
147         }
148
149         BatteryInfo {
150                 id: batteryMonitor
151                 active: cam.running
152
153                 function check() {
154                         if (!checkBattery()) {
155                                 pageStack.currentPage.batteryLow();
156                         }
157                 }
158
159                 onChargingChanged: {
160                         batteryMonitor.check();
161                 }
162
163                 onCriticalChanged: {
164                         batteryMonitor.check();
165                 }
166         }
167
168         function replacePage(file) {
169                 pageStack.replace(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true);
170         }
171
172         function openFile(file) {
173                 pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer});
174         }
175
176         function openFileNow(file) {
177                 pageStack.push(Qt.resolvedUrl(file), {cam: cam, dimmer: root.dimmer}, true);
178         }
179
180         function checkBattery() {
181                 // We are fine if we are connected to the charger:
182                 if (batteryMonitor.charging) {
183                         return true;
184                 }
185
186                 // If we have enough battery then we are fine:
187                 if (!batteryMonitor.critical) {
188                         return true;
189                 }
190
191                 return false;
192         }
193
194         platformStyle: PageStackWindowStyle {
195                 cornersVisible: false
196                 background: ""
197                 backgroundColor: "transparent"
198         }
199
200         ImageSettings {
201                 id: imageSettings
202                 camera: cam
203                 function setImageResolution() {
204                         if (!imageSettings.setResolution(settings.imageAspectRatio, settings.imageResolution)) {
205                                 showError(qsTr("Failed to set required resolution"));
206                         }
207                 }
208
209                 onReadyChanged: {
210                         if (ready) {
211                                 imageSettings.setImageResolution();
212                         }
213                 }
214         }
215
216         VideoSettings {
217                 id: videoSettings
218                 camera: cam
219
220                 function setVideoResolution() {
221                         if (!videoSettings.setResolution(settings.videoAspectRatio, settings.videoResolution)) {
222                                 showError(qsTr("Failed to set required resolution"));
223                         }
224                 }
225
226                 onReadyChanged: {
227                         if (ready) {
228                                 videoSettings.setVideoResolution();
229                         }
230                 }
231         }
232
233         Connections {
234                 target: settings
235
236                 onImageAspectRatioChanged: {
237                         imageSettings.setImageResolution();
238                 }
239
240                 onImageResolutionChanged: {
241                         imageSettings.setImageResolution();
242                 }
243
244                 onVideoResolutionChanged: {
245                         videoSettings.setVideoResolution();
246                 }
247         }
248
249         Camera {
250                 id: cam
251                 anchors.fill: parent
252
253                 FocusReticle {
254                         id: focusReticle
255                         cam: cam
256                         visible: pageStack.currentPage && pageStack.currentPage.controlsVisible && pageStack.currentPage.focusReticleVisible && cam && cam.autoFocus.canFocus(cam.scene.value);
257                         cafStatus: cam ? cam.autoFocus.cafStatus : -1
258                         status: cam ? cam.autoFocus.status : -1
259                 }
260
261 /*
262                 onDeviceIdChanged: {
263                         // TODO: is this needed ?
264                         if (platformWindow.active) {
265                                 cam.start();
266                         }
267                 }
268 */
269                 onError: {
270                         if (pipelineManager.error) {
271                                 // Ignore any subsequent errors.
272                                 // Killing pulseaudio while recording will lead to an
273                                 // infinite supply of errors which will break the UI
274                                 // if we show a banner for each.
275                                 return;
276                         }
277
278                         pipelineManager.error = true;
279                         pageStack.currentPage.cameraError();
280                         console.log("Camera error (" + code + "): " + message + " " + debug);
281                         showError(qsTr("Camera error. Please restart the application."));
282
283                         // We cannot stop camera here. Seems there is a race condition somewhere
284                         // which leads to a freeze if we do so.
285                 }
286
287                 onRunningChanged: {
288                         if (!cam.running) {
289                                 mountProtector.unlock();
290                         }
291                 }
292
293                 Component.onDestruction: cam.stop();
294
295                 // We need to show viewfinder below pages.
296                 z: -1
297
298                 Rectangle {
299                         property bool dimmed: false
300                         id: camDimmer
301                         z: 1
302                         anchors.fill: parent
303                         opacity: dimmed ? 1.0 : 0.0
304                         color: "black"
305                         Behavior on opacity {
306                                 PropertyAnimation { duration: 150 }
307                         }
308                 }
309
310                 notifications: Sounds {
311                         id: sounds
312                         mute: !settings.soundEnabled
313                 }
314
315         }
316
317         Binding {
318                 target: cam.flash
319                 property: "value"
320                 when: cam.mode == Camera.ImageMode
321                 value: settings.imageFlashMode
322         }
323
324         Binding {
325                 target: settings
326                 property: "imageFlashMode"
327                 when: cam.mode == Camera.ImageMode
328                 value: cam.flash.value
329         }
330
331         Binding {
332                 target: cam.scene
333                 property: "value"
334                 when: cam.mode == Camera.VideoMode
335                 value: settings.videoSceneMode
336         }
337
338         Binding {
339                 target: cam.scene
340                 property: "value"
341                 when: cam.mode == Camera.ImageMode
342                 value: settings.imageSceneMode
343         }
344
345         Binding {
346                 target: cam.evComp
347                 property: "value"
348                 when: cam.mode == Camera.ImageMode
349                 value: settings.imageEvComp
350         }
351
352         Binding {
353                 target: cam.evComp
354                 property: "value"
355                 when: cam.mode == Camera.VideoMode
356                 value: settings.videoEvComp
357         }
358
359         Binding {
360                 target: settings
361                 property: "imageEvComp"
362                 when: cam.mode == Camera.ImageMode
363                 value: cam.evComp.value
364         }
365
366         Binding {
367                 target: settings
368                 property: "videoEvComp"
369                 when: cam.mode == Camera.VideoMode
370                 value: cam.evComp.value
371         }
372
373         Binding {
374                 target: cam.whiteBalance
375                 property: "value"
376                 when: cam.mode == Camera.ImageMode
377                 value: settings.imageWhiteBalance
378         }
379
380         Binding {
381                 target: cam.whiteBalance
382                 property: "value"
383                 when: cam.mode == Camera.VideoMode
384                 value: settings.videoWhiteBalance
385         }
386
387         Binding {
388                 target: cam.colorTone
389                 property: "value"
390                 when: cam.mode == Camera.ImageMode
391                 value: settings.imageColorFilter
392         }
393
394         Binding {
395                 target: cam.colorTone
396                 property: "value"
397                 when: cam.mode == Camera.VideoMode
398                 value: settings.videoColorFilter
399         }
400
401         Binding {
402                 target: cam.iso
403                 property: "value"
404                 when: cam.mode == Camera.ImageMode
405                 value: settings.imageIso
406         }
407
408         Binding {
409                 target: settings
410                 property: "imageIso"
411                 when: cam.mode == Camera.ImageMode
412                 value: cam.iso.value
413         }
414
415         Binding {
416                 target: cam.videoMute
417                 property: "enabled"
418                 value: settings.videoMuted
419         }
420
421         TrackerStore {
422                 id: trackerStore
423                 active: cam.running
424                 manufacturer: deviceInfo.manufacturer
425                 model: deviceInfo.model
426         }
427
428         ModeController {
429                 id: cameraMode
430                 cam: cam
431                 dimmer: root.dimmer
432         }
433
434         Connections {
435                 target: cam
436                 onModeChanged: {
437                         if (cam.mode == Camera.VideoMode) {
438                                 replacePage("VideoPage.qml");
439                         }
440                         else {
441                                 replacePage("ImagePage.qml");
442                         }
443                 }
444         }
445
446         Standby {
447                 policyLost: pipelineManager.state == "policyLost"
448                 show: !pageStack.currentPage || (pageStack.currentPage.standbyVisible && pageStack.currentPage.status == PageStatus.Active && pipelineManager.showStandBy)
449         }
450 }