1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2007-11-01
7  * Description : Access item position stored in database.
8  *
9  * Copyright (C) 2007-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "itemposition.h"
25 
26 // Local includes
27 
28 #include "coredbaccess.h"
29 #include "coredb.h"
30 #include "coredbfields.h"
31 #include "dmetadata.h"
32 #include "metadatainfo.h"
33 
34 namespace Digikam
35 {
36 
37 class Q_DECL_HIDDEN ItemPositionPriv : public QSharedData
38 {
39 
40 public:
41 
ItemPositionPriv()42     ItemPositionPriv()
43       : empty       (true),
44         // NOTE: Do not initialize the QVariants here, they are expected to be null
45         imageId     (-1),
46         dirtyFields (DatabaseFields::ItemPositionsNone)
47     {
48     }
49 
resetData()50     void resetData()
51     {
52         description.clear();
53         latitude.clear();
54         longitude.clear();
55         latitudeNumber  = QVariant();
56         longitudeNumber = QVariant();
57         altitude        = QVariant();
58         orientation     = QVariant();
59         tilt            = QVariant();
60         roll            = QVariant();
61         empty           = true;
62         dirtyFields     = DatabaseFields::ItemPositionsNone;
63     }
64 
65     void init(const CoreDbAccess& access, qlonglong imageId);
66 
67 public:
68 
69     bool                           empty;
70 
71     QVariant                       latitudeNumber;
72     QVariant                       longitudeNumber;
73     QVariant                       altitude;
74     QVariant                       orientation;
75     QVariant                       tilt;
76     QVariant                       roll;
77     QVariant                       accuracy;
78 
79     qlonglong                      imageId;
80 
81     QString                        description;
82     QString                        latitude;
83     QString                        longitude;
84 
85     DatabaseFields::ItemPositions  dirtyFields;
86 };
87 
init(const CoreDbAccess & access,qlonglong id)88 void ItemPositionPriv::init(const CoreDbAccess& access, qlonglong id)
89 {
90     imageId             = id;
91     QVariantList values = access.db()->getItemPosition(imageId);
92 
93     if (values.size() == 10)
94     {
95         empty           = false;
96         latitude        = values.at(0).toString();
97         latitudeNumber  = values.at(1);
98         longitude       = values.at(2).toString();
99         longitudeNumber = values.at(3);
100         altitude        = values.at(4);
101         orientation     = values.at(5);
102         tilt            = values.at(6);
103         roll            = values.at(7);
104         accuracy        = values.at(8);
105         description     = values.at(9).toString();
106     }
107 }
108 
109 // ------------------------------------------------------
110 
ItemPosition()111 ItemPosition::ItemPosition()
112 {
113 }
114 
ItemPosition(qlonglong imageId)115 ItemPosition::ItemPosition(qlonglong imageId)
116     : d(new ItemPositionPriv)
117 {
118     CoreDbAccess access;
119     d->init(access, imageId);
120 }
121 
ItemPosition(const CoreDbAccess & access,qlonglong imageId)122 ItemPosition::ItemPosition(const CoreDbAccess& access, qlonglong imageId)
123     : d(new ItemPositionPriv)
124 {
125     d->init(access, imageId);
126 }
127 
ItemPosition(const ItemPosition & other)128 ItemPosition::ItemPosition(const ItemPosition& other)
129     : d(other.d)
130 {
131 }
132 
~ItemPosition()133 ItemPosition::~ItemPosition()
134 {
135     apply();
136 }
137 
operator =(const ItemPosition & other)138 ItemPosition& ItemPosition::operator=(const ItemPosition& other)
139 {
140     d = other.d;
141 
142     return *this;
143 }
144 
isNull() const145 bool ItemPosition::isNull() const
146 {
147     return !d;
148 }
149 
isEmpty() const150 bool ItemPosition::isEmpty() const
151 {
152     return (!d || d->empty);
153 }
154 
latitude() const155 QString ItemPosition::latitude() const
156 {
157     if (!d)
158     {
159         return QString();
160     }
161 
162     return d->latitude;
163 }
164 
longitude() const165 QString ItemPosition::longitude() const
166 {
167     if (!d)
168     {
169         return QString();
170     }
171 
172     return d->longitude;
173 }
174 
latitudeNumber() const175 double ItemPosition::latitudeNumber() const
176 {
177     if (!d)
178     {
179         return 0;
180     }
181 
182     return d->latitudeNumber.toDouble();
183 }
184 
longitudeNumber() const185 double ItemPosition::longitudeNumber() const
186 {
187     if (!d)
188     {
189         return 0;
190     }
191 
192     return d->longitudeNumber.toDouble();
193 }
194 
latitudeFormatted() const195 QString ItemPosition::latitudeFormatted() const
196 {
197     if (!d)
198     {
199         return QString();
200     }
201 
202     return DMetadata::valueToString(d->latitude, MetadataInfo::Latitude);
203 }
204 
longitudeFormatted() const205 QString ItemPosition::longitudeFormatted() const
206 {
207     if (!d)
208     {
209         return QString();
210     }
211 
212     return DMetadata::valueToString(d->longitude, MetadataInfo::Longitude);
213 }
214 
latitudeUserPresentableNumbers(int * degrees,int * minutes,double * seconds,char * directionReference)215 bool ItemPosition::latitudeUserPresentableNumbers(int* degrees, int* minutes, double* seconds, char* directionReference)
216 {
217     if (!d)
218     {
219         return false;
220     }
221 
222     return DMetadata::convertToUserPresentableNumbers(d->latitude, degrees, minutes, seconds, directionReference);
223 }
224 
longitudeUserPresentableNumbers(int * degrees,int * minutes,double * seconds,char * directionReference)225 bool ItemPosition::longitudeUserPresentableNumbers(int* degrees, int* minutes, double* seconds, char* directionReference)
226 {
227     if (!d)
228     {
229         return false;
230     }
231 
232     return DMetadata::convertToUserPresentableNumbers(d->longitude, degrees, minutes, seconds, directionReference);
233 }
234 
altitude() const235 double ItemPosition::altitude() const
236 {
237     if (!d)
238     {
239         return 0;
240     }
241 
242     return d->altitude.toDouble();
243 }
244 
altitudeFormatted() const245 QString ItemPosition::altitudeFormatted() const
246 {
247     if (!d)
248     {
249         return QString();
250     }
251 
252     return DMetadata::valueToString(d->altitude, MetadataInfo::Altitude);
253 }
254 
orientation() const255 double ItemPosition::orientation() const
256 {
257     if (!d)
258     {
259         return 0;
260     }
261 
262     return d->orientation.toDouble();
263 }
264 
tilt() const265 double ItemPosition::tilt() const
266 {
267     if (!d)
268     {
269         return 0;
270     }
271 
272     return d->tilt.toDouble();
273 }
274 
roll() const275 double ItemPosition::roll() const
276 {
277     if (!d)
278     {
279         return 0;
280     }
281 
282     return d->roll.toDouble();
283 }
284 
accuracy() const285 double ItemPosition::accuracy() const
286 {
287     if (!d)
288     {
289         return 0;
290     }
291 
292     return d->accuracy.toDouble();
293 }
294 
description() const295 QString ItemPosition::description() const
296 {
297     if (!d)
298     {
299         return QString();
300     }
301 
302     return d->description;
303 }
304 
hasCoordinates() const305 bool ItemPosition::hasCoordinates() const
306 {
307     return (d && !d->latitudeNumber.isNull() && !d->longitudeNumber.isNull());
308 }
309 
hasAltitude() const310 bool ItemPosition::hasAltitude() const
311 {
312     return (d && !d->altitude.isNull());
313 }
314 
hasOrientation() const315 bool ItemPosition::hasOrientation() const
316 {
317     return (d && !d->orientation.isNull());
318 }
319 
hasTilt() const320 bool ItemPosition::hasTilt() const
321 {
322     return (d && !d->tilt.isNull());
323 }
324 
hasRoll() const325 bool ItemPosition::hasRoll() const
326 {
327     return (d && !d->roll.isNull());
328 }
329 
hasAccuracy() const330 bool ItemPosition::hasAccuracy() const
331 {
332     return (d && !d->accuracy.isNull());
333 }
334 
setLatitude(const QString & latitude)335 bool ItemPosition::setLatitude(const QString& latitude)
336 {
337     if (!d)
338     {
339         return false;
340     }
341 
342     double number;
343 
344     if (!DMetadata::convertFromGPSCoordinateString(latitude, &number))
345     {
346         return false;
347     }
348 
349     d->latitude       = latitude;
350     d->latitudeNumber = number;
351     d->dirtyFields   |= DatabaseFields::Latitude | DatabaseFields::LatitudeNumber;
352 
353     return true;
354 }
355 
setLongitude(const QString & longitude)356 bool ItemPosition::setLongitude(const QString& longitude)
357 {
358     if (!d)
359     {
360         return false;
361     }
362 
363     double number;
364 
365     if (!DMetadata::convertFromGPSCoordinateString(longitude, &number))
366     {
367         return false;
368     }
369 
370     d->longitude       = longitude;
371     d->longitudeNumber = number;
372     d->dirtyFields    |= DatabaseFields::Longitude | DatabaseFields::LongitudeNumber;
373 
374     return true;
375 }
376 
setLatitude(double latitudeNumber)377 bool ItemPosition::setLatitude(double latitudeNumber)
378 {
379     if (!d)
380     {
381         return false;
382     }
383 
384     QString string = DMetadata::convertToGPSCoordinateString(true, latitudeNumber);
385 
386     if (string.isNull())
387     {
388         return false;
389     }
390 
391     d->latitude       = string;
392     d->latitudeNumber = latitudeNumber;
393     d->dirtyFields   |= DatabaseFields::Latitude | DatabaseFields::LatitudeNumber;
394 
395     return true;
396 }
397 
setLongitude(double longitudeNumber)398 bool ItemPosition::setLongitude(double longitudeNumber)
399 {
400     if (!d)
401     {
402         return false;
403     }
404 
405     QString string = DMetadata::convertToGPSCoordinateString(false, longitudeNumber);
406 
407     if (string.isNull())
408     {
409         return false;
410     }
411 
412     d->longitude       = string;
413     d->longitudeNumber = longitudeNumber;
414     d->dirtyFields    |= DatabaseFields::Longitude | DatabaseFields::LongitudeNumber;
415 
416     return true;
417 }
418 
setAltitude(double altitude)419 void ItemPosition::setAltitude(double altitude)
420 {
421     if (!d)
422     {
423         return;
424     }
425 
426     d->altitude     = altitude;
427     d->dirtyFields |= DatabaseFields::Altitude;
428 }
429 
setOrientation(double orientation)430 void ItemPosition::setOrientation(double orientation)
431 {
432     if (!d)
433     {
434         return;
435     }
436 
437     d->orientation  = orientation;
438     d->dirtyFields |= DatabaseFields::PositionOrientation;
439 }
440 
setTilt(double tilt)441 void ItemPosition::setTilt(double tilt)
442 {
443     if (!d)
444     {
445         return;
446     }
447 
448     d->tilt         = tilt;
449     d->dirtyFields |= DatabaseFields::PositionTilt;
450 }
451 
setRoll(double roll)452 void ItemPosition::setRoll(double roll)
453 {
454     if (!d)
455     {
456         return;
457     }
458 
459     d->roll         = roll;
460     d->dirtyFields |= DatabaseFields::PositionRoll;
461 }
462 
setAccuracy(double accuracy)463 void ItemPosition::setAccuracy(double accuracy)
464 {
465     if (!d)
466     {
467         return;
468     }
469 
470     d->accuracy     = accuracy;
471     d->dirtyFields |= DatabaseFields::PositionAccuracy;
472 }
473 
setDescription(const QString & description)474 void ItemPosition::setDescription(const QString& description)
475 {
476     if (!d)
477     {
478         return;
479     }
480 
481     d->description  = description;
482     d->dirtyFields |= DatabaseFields::PositionDescription;
483 }
484 
apply()485 void ItemPosition::apply()
486 {
487     if (!d)
488     {
489         return;
490     }
491 
492     if (d->dirtyFields == DatabaseFields::ItemPositionsNone)
493     {
494         return;
495     }
496 
497     QVariantList values;
498 
499     if (d->dirtyFields & DatabaseFields::Latitude)
500     {
501         values << d->latitude;
502     }
503 
504     if (d->dirtyFields & DatabaseFields::LatitudeNumber)
505     {
506         values << d->latitudeNumber;
507     }
508 
509     if (d->dirtyFields & DatabaseFields::Longitude)
510     {
511         values << d->longitude;
512     }
513 
514     if (d->dirtyFields & DatabaseFields::LongitudeNumber)
515     {
516         values << d->longitudeNumber;
517     }
518 
519     if (d->dirtyFields & DatabaseFields::Altitude)
520     {
521         values << d->altitude;
522     }
523 
524     if (d->dirtyFields & DatabaseFields::PositionOrientation)
525     {
526         values << d->orientation;
527     }
528 
529     if (d->dirtyFields & DatabaseFields::PositionTilt)
530     {
531         values << d->tilt;
532     }
533 
534     if (d->dirtyFields & DatabaseFields::PositionRoll)
535     {
536         values << d->roll;
537     }
538 
539     if (d->dirtyFields & DatabaseFields::PositionAccuracy)
540     {
541         values << d->accuracy;
542     }
543 
544     if (d->dirtyFields & DatabaseFields::PositionDescription)
545     {
546         values << d->description;
547     }
548 
549     if (d->empty)
550     {
551         CoreDbAccess().db()->addItemPosition(d->imageId, values, d->dirtyFields);
552         d->empty = false;
553     }
554     else
555     {
556         CoreDbAccess().db()->changeItemPosition(d->imageId, values, d->dirtyFields);
557     }
558 
559     d->dirtyFields = DatabaseFields::ItemPositionsNone;
560 }
561 
remove()562 void ItemPosition::remove()
563 {
564     CoreDbAccess().db()->removeItemPosition(d->imageId);
565     d->resetData();
566 }
567 
removeAltitude()568 void ItemPosition::removeAltitude()
569 {
570     CoreDbAccess().db()->removeItemPositionAltitude(d->imageId);
571     d->dirtyFields &= ~DatabaseFields::Altitude;
572     d->altitude     = QVariant();
573 }
574 
575 } // namespace Digikam
576