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