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