~ubuntu-branches/ubuntu/trusty/gwenview/trusty

« back to all changes in this revision

Viewing changes to lib/imagemetainfomodel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Rohan Garg
  • Date: 2011-07-20 13:46:34 UTC
  • Revision ID: james.westby@ubuntu.com-20110720134634-92930fdjeed4gdc9
Tags: upstream-4.6.90+repack
ImportĀ upstreamĀ versionĀ 4.6.90+repack

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
2
/*
 
3
Gwenview: an image viewer
 
4
Copyright 2007 AurĆ©lien GĆ¢teau <agateau@kde.org>
 
5
 
 
6
This program is free software; you can redistribute it and/or
 
7
modify it under the terms of the GNU General Public License
 
8
as published by the Free Software Foundation; either version 2
 
9
of the License, or (at your option) any later version.
 
10
 
 
11
This program is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program; if not, write to the Free Software
 
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
19
 
 
20
*/
 
21
// Self
 
22
#include "imagemetainfomodel.h"
 
23
 
 
24
// Qt
 
25
 
 
26
// KDE
 
27
#include <kdebug.h>
 
28
#include <kfileitem.h>
 
29
#include <kglobal.h>
 
30
#include <klocale.h>
 
31
 
 
32
// Exiv2
 
33
#include <exiv2/exif.hpp>
 
34
#include <exiv2/image.hpp>
 
35
#include <exiv2/iptc.hpp>
 
36
 
 
37
// Local
 
38
 
 
39
 
 
40
namespace Gwenview {
 
41
 
 
42
 
 
43
enum GroupRow {
 
44
        NoGroupSpace= -2,
 
45
        NoGroup = -1,
 
46
        GeneralGroup,
 
47
        ExifGroup,
 
48
        IptcGroup,
 
49
        XmpGroup
 
50
};
 
51
 
 
52
 
 
53
class MetaInfoGroup {
 
54
public:
 
55
        enum {
 
56
                InvalidRow = -1
 
57
        };
 
58
 
 
59
        class Entry {
 
60
        public:
 
61
                Entry(const QString& key, const QString& label, const QString& value)
 
62
                : mKey(key), mLabel(label.trimmed()), mValue(value.trimmed())
 
63
                {}
 
64
 
 
65
                QString key() const { return mKey; }
 
66
                QString label() const { return mLabel; }
 
67
 
 
68
                QString value() const { return mValue; }
 
69
                void setValue(const QString& value) { mValue = value.trimmed(); }
 
70
 
 
71
                void appendValue(const QString& value) {
 
72
                        if (mValue.length() > 0) {
 
73
                                mValue += '\n';
 
74
                        }
 
75
                        mValue += value.trimmed();
 
76
                }
 
77
 
 
78
        private:
 
79
                QString mKey;
 
80
                QString mLabel;
 
81
                QString mValue;
 
82
        };
 
83
 
 
84
        MetaInfoGroup(const QString& label)
 
85
        : mLabel(label) {}
 
86
 
 
87
 
 
88
        ~MetaInfoGroup() {
 
89
                qDeleteAll(mList);
 
90
        }
 
91
 
 
92
 
 
93
        void clear() {
 
94
                qDeleteAll(mList);
 
95
                mList.clear();
 
96
                mRowForKey.clear();
 
97
        }
 
98
 
 
99
 
 
100
        void addEntry(const QString& key, const QString& label, const QString& value) {
 
101
                addEntry(new Entry(key, label, value));
 
102
        }
 
103
 
 
104
 
 
105
        void addEntry(Entry* entry) {
 
106
                mList << entry;
 
107
                mRowForKey[entry->key()] = mList.size() - 1;
 
108
        }
 
109
 
 
110
 
 
111
        void getInfoForKey(const QString& key, QString* label, QString* value) const {
 
112
                Entry* entry = getEntryForKey(key);
 
113
                if (entry) {
 
114
                        *label = entry->label();
 
115
                        *value = entry->value();
 
116
                }
 
117
        }
 
118
 
 
119
 
 
120
        QString getKeyAt(int row) const {
 
121
                Q_ASSERT(row < mList.size());
 
122
                return mList[row]->key();
 
123
        }
 
124
 
 
125
 
 
126
        QString getLabelForKeyAt(int row) const {
 
127
                Q_ASSERT(row < mList.size());
 
128
                return mList[row]->label();
 
129
        }
 
130
 
 
131
 
 
132
        QString getValueForKeyAt(int row) const {
 
133
                Q_ASSERT(row < mList.size());
 
134
                return mList[row]->value();
 
135
        }
 
136
 
 
137
 
 
138
        void setValueForKeyAt(int row, const QString& value) {
 
139
                Q_ASSERT(row < mList.size());
 
140
                mList[row]->setValue(value);
 
141
        }
 
142
 
 
143
 
 
144
        int getRowForKey(const QString& key) const {
 
145
                return mRowForKey.value(key, InvalidRow);
 
146
        }
 
147
 
 
148
 
 
149
        int size() const {
 
150
                return mList.size();
 
151
        }
 
152
 
 
153
 
 
154
        QString label() const {
 
155
                return mLabel;
 
156
        }
 
157
 
 
158
        const QList<Entry*>& entryList() const {
 
159
                return mList;
 
160
        }
 
161
 
 
162
private:
 
163
        Entry* getEntryForKey(const QString& key) const {
 
164
                int row = getRowForKey(key);
 
165
                if (row == InvalidRow) {
 
166
                        return 0;
 
167
                }
 
168
                return mList[row];
 
169
        }
 
170
 
 
171
        QList<Entry*> mList;
 
172
        QHash<QString, int> mRowForKey;
 
173
        QString mLabel;
 
174
};
 
175
 
 
176
 
 
177
struct ImageMetaInfoModelPrivate {
 
178
        QVector<MetaInfoGroup*> mMetaInfoGroupVector;
 
179
        ImageMetaInfoModel* mModel;
 
180
 
 
181
 
 
182
        void clearGroup(MetaInfoGroup* group, const QModelIndex& parent) {
 
183
                if (group->size() > 0) {
 
184
                        mModel->beginRemoveRows(parent, 0, group->size() - 1);
 
185
                        group->clear();
 
186
                        mModel->endRemoveRows();
 
187
                }
 
188
        }
 
189
 
 
190
 
 
191
        void setGroupEntryValue(GroupRow groupRow, const QString& key, const QString& value) {
 
192
                MetaInfoGroup* group = mMetaInfoGroupVector[groupRow];
 
193
                int entryRow = group->getRowForKey(key);
 
194
                if (entryRow == MetaInfoGroup::InvalidRow) {
 
195
                        kWarning() << "No row for key" << key;
 
196
                        return;
 
197
                }
 
198
                group->setValueForKeyAt(entryRow, value);
 
199
                QModelIndex groupIndex = mModel->index(groupRow, 0);
 
200
                QModelIndex entryIndex = mModel->index(entryRow, 1, groupIndex);
 
201
                emit mModel->dataChanged(entryIndex, entryIndex);
 
202
        }
 
203
 
 
204
 
 
205
        QVariant displayData(const QModelIndex& index) const {
 
206
                if (index.internalId() == NoGroup) {
 
207
                        if (index.column() != 0) {
 
208
                                return QVariant();
 
209
                        }
 
210
                        QString label = mMetaInfoGroupVector[index.row()]->label();
 
211
                        return QVariant(label);
 
212
                }
 
213
 
 
214
                if (index.internalId() == NoGroupSpace) {
 
215
                        return QVariant(QString());
 
216
                }
 
217
 
 
218
                MetaInfoGroup* group = mMetaInfoGroupVector[index.internalId()];
 
219
                if (index.column() == 0) {
 
220
                        return group->getLabelForKeyAt(index.row());
 
221
                } else {
 
222
                        return group->getValueForKeyAt(index.row());
 
223
                }
 
224
        }
 
225
 
 
226
 
 
227
        void initGeneralGroup() {
 
228
                MetaInfoGroup* group = mMetaInfoGroupVector[GeneralGroup];
 
229
                group->addEntry("General.Name", i18nc("@item:intable Image file name", "Name"), QString());
 
230
                group->addEntry("General.Size", i18nc("@item:intable", "File Size"), QString());
 
231
                group->addEntry("General.Time", i18nc("@item:intable", "File Time"), QString());
 
232
                group->addEntry("General.ImageSize", i18nc("@item:intable", "Image Size"), QString());
 
233
        }
 
234
 
 
235
 
 
236
        template <class Container, class Iterator>
 
237
        void fillExivGroup(const QModelIndex& parent, MetaInfoGroup* group, const Container& container) {
 
238
                // key aren't always unique (for example, "Iptc.Application2.Keywords"
 
239
                // may appear multiple times) so we can't know how many rows we will
 
240
                // insert before going through them. That's why we create a hash
 
241
                // before.
 
242
                typedef QHash<QString, MetaInfoGroup::Entry*> EntryHash;
 
243
                EntryHash hash;
 
244
 
 
245
                Iterator
 
246
                        it = container.begin(),
 
247
                        end = container.end();
 
248
 
 
249
                if (it == end) {
 
250
                        return;
 
251
                }
 
252
 
 
253
                for (;it != end; ++it) {
 
254
                        QString key = QString::fromUtf8(it->key().c_str());
 
255
                        QString label = QString::fromLocal8Bit(it->tagLabel().c_str());
 
256
                        std::ostringstream stream;
 
257
                        stream << *it;
 
258
                        QString value = QString::fromLocal8Bit(stream.str().c_str());
 
259
 
 
260
                        EntryHash::iterator hashIt = hash.find(key);
 
261
                        if (hashIt != hash.end()) {
 
262
                                hashIt.value()->appendValue(value);
 
263
                        } else {
 
264
                                hash.insert(key, new MetaInfoGroup::Entry(key, label, value));
 
265
                        }
 
266
                }
 
267
 
 
268
                mModel->beginInsertRows(parent, 0, hash.size() - 1);
 
269
                Q_FOREACH(MetaInfoGroup::Entry* entry, hash) {
 
270
                        group->addEntry(entry);
 
271
                }
 
272
                mModel->endInsertRows();
 
273
        }
 
274
};
 
275
 
 
276
 
 
277
ImageMetaInfoModel::ImageMetaInfoModel()
 
278
: d(new ImageMetaInfoModelPrivate) {
 
279
        d->mModel = this;
 
280
        d->mMetaInfoGroupVector.resize(4);
 
281
        d->mMetaInfoGroupVector[GeneralGroup] = new MetaInfoGroup(i18nc("@title:group General info about the image", "General"));
 
282
        d->mMetaInfoGroupVector[ExifGroup] = new MetaInfoGroup("EXIF");
 
283
        d->mMetaInfoGroupVector[IptcGroup] = new MetaInfoGroup("IPTC");
 
284
        d->mMetaInfoGroupVector[XmpGroup]  = new MetaInfoGroup("XMP");
 
285
        d->initGeneralGroup();
 
286
}
 
287
 
 
288
 
 
289
ImageMetaInfoModel::~ImageMetaInfoModel() {
 
290
        qDeleteAll(d->mMetaInfoGroupVector);
 
291
        delete d;
 
292
}
 
293
 
 
294
 
 
295
void ImageMetaInfoModel::setUrl(const KUrl& url) {
 
296
        KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
 
297
        QString sizeString = KGlobal::locale()->formatByteSize(item.size());
 
298
 
 
299
        d->setGroupEntryValue(GeneralGroup, "General.Name", item.name());
 
300
        d->setGroupEntryValue(GeneralGroup, "General.Size", sizeString);
 
301
        d->setGroupEntryValue(GeneralGroup, "General.Time", item.timeString());
 
302
}
 
303
 
 
304
 
 
305
void ImageMetaInfoModel::setImageSize(const QSize& size) {
 
306
        QString imageSize;
 
307
        if (size.isValid()) {
 
308
                imageSize = i18nc(
 
309
                        "@item:intable %1 is image width, %2 is image height",
 
310
                        "%1x%2", size.width(), size.height());
 
311
 
 
312
                double megaPixels = size.width() * size.height() / 1000000.;
 
313
                if (megaPixels > 0.1) {
 
314
                        QString megaPixelsString = QString::number(megaPixels, 'f', 1);
 
315
                        imageSize += ' ';
 
316
                        imageSize += i18nc(
 
317
                                "@item:intable %1 is number of millions of pixels in image",
 
318
                                "(%1MP)", megaPixelsString);
 
319
                }
 
320
        } else {
 
321
                imageSize = "-";
 
322
        }
 
323
        d->setGroupEntryValue(GeneralGroup, "General.ImageSize", imageSize);
 
324
}
 
325
 
 
326
 
 
327
void ImageMetaInfoModel::setExiv2Image(const Exiv2::Image* image) {
 
328
        MetaInfoGroup* exifGroup = d->mMetaInfoGroupVector[ExifGroup];
 
329
        MetaInfoGroup* iptcGroup = d->mMetaInfoGroupVector[IptcGroup];
 
330
        MetaInfoGroup* xmpGroup  = d->mMetaInfoGroupVector[XmpGroup];
 
331
        QModelIndex exifIndex = index(ExifGroup, 0);
 
332
        QModelIndex iptcIndex = index(IptcGroup, 0);
 
333
        QModelIndex xmpIndex  = index(XmpGroup, 0);
 
334
        d->clearGroup(exifGroup, exifIndex);
 
335
        d->clearGroup(iptcGroup, iptcIndex);
 
336
        d->clearGroup(xmpGroup,  xmpIndex);
 
337
 
 
338
        if (!image) {
 
339
                return;
 
340
        }
 
341
 
 
342
        if (image->checkMode(Exiv2::mdExif) & Exiv2::amRead) {
 
343
                const Exiv2::ExifData& exifData = image->exifData();
 
344
                d->fillExivGroup<Exiv2::ExifData, Exiv2::ExifData::const_iterator>(exifIndex, exifGroup, exifData);
 
345
        }
 
346
 
 
347
        if (image->checkMode(Exiv2::mdIptc) & Exiv2::amRead) {
 
348
                const Exiv2::IptcData& iptcData = image->iptcData();
 
349
                d->fillExivGroup<Exiv2::IptcData, Exiv2::IptcData::const_iterator>(iptcIndex, iptcGroup, iptcData);
 
350
        }
 
351
 
 
352
        if (image->checkMode(Exiv2::mdXmp) & Exiv2::amRead) {
 
353
                const Exiv2::XmpData& xmpData = image->xmpData();
 
354
                d->fillExivGroup<Exiv2::XmpData, Exiv2::XmpData::const_iterator>(xmpIndex, xmpGroup, xmpData);
 
355
        }
 
356
}
 
357
 
 
358
 
 
359
void ImageMetaInfoModel::getInfoForKey(const QString& key, QString* label, QString* value) const {
 
360
        MetaInfoGroup* group;
 
361
        if (key.startsWith(QLatin1String("General"))) {
 
362
                group = d->mMetaInfoGroupVector[GeneralGroup];
 
363
        } else if (key.startsWith(QLatin1String("Exif"))) {
 
364
                group = d->mMetaInfoGroupVector[ExifGroup];
 
365
        } else if (key.startsWith(QLatin1String("Iptc"))) {
 
366
                group = d->mMetaInfoGroupVector[IptcGroup];
 
367
        } else if (key.startsWith(QLatin1String("Xmp"))) {
 
368
                group = d->mMetaInfoGroupVector[XmpGroup];
 
369
        } else {
 
370
                kWarning() << "Unknown metainfo key" << key;
 
371
                return;
 
372
        }
 
373
        group->getInfoForKey(key, label, value);
 
374
}
 
375
 
 
376
 
 
377
QString ImageMetaInfoModel::getValueForKey(const QString& key) const {
 
378
        QString label, value;
 
379
        getInfoForKey(key, &label, &value);
 
380
        return value;
 
381
}
 
382
 
 
383
 
 
384
QString ImageMetaInfoModel::keyForIndex(const QModelIndex& index) const {
 
385
        if (index.internalId() == NoGroup) {
 
386
                return QString();
 
387
        }
 
388
        MetaInfoGroup* group = d->mMetaInfoGroupVector[index.internalId()];
 
389
        return group->getKeyAt(index.row());
 
390
}
 
391
 
 
392
 
 
393
QModelIndex ImageMetaInfoModel::index(int row, int col, const QModelIndex& parent) const {
 
394
        if (col < 0 || col > 1) {
 
395
                return QModelIndex();
 
396
        }
 
397
        if (!parent.isValid()) {
 
398
                // This is a group
 
399
                if (row < 0 || row >= d->mMetaInfoGroupVector.size()) {
 
400
                        return QModelIndex();
 
401
                }
 
402
                return createIndex(row, col, col == 0 ? NoGroup : NoGroupSpace);
 
403
        } else {
 
404
                // This is an entry
 
405
                int group = parent.row();
 
406
                if (row < 0 || row >= d->mMetaInfoGroupVector[group]->size()) {
 
407
                        return QModelIndex();
 
408
                }
 
409
                return createIndex(row, col, group);
 
410
        }
 
411
}
 
412
 
 
413
 
 
414
QModelIndex ImageMetaInfoModel::parent(const QModelIndex& index) const {
 
415
        if (!index.isValid()) {
 
416
                return QModelIndex();
 
417
        }
 
418
        if (index.internalId() == NoGroup || index.internalId() == NoGroupSpace) {
 
419
                return QModelIndex();
 
420
        } else {
 
421
                return createIndex(index.internalId(), 0, NoGroup);
 
422
        }
 
423
}
 
424
 
 
425
 
 
426
int ImageMetaInfoModel::rowCount(const QModelIndex& parent) const {
 
427
        if (!parent.isValid()) {
 
428
                return d->mMetaInfoGroupVector.size();
 
429
        } else if (parent.internalId() == NoGroup) {
 
430
                return d->mMetaInfoGroupVector[parent.row()]->size();
 
431
        } else {
 
432
                return 0;
 
433
        }
 
434
}
 
435
 
 
436
 
 
437
int ImageMetaInfoModel::columnCount(const QModelIndex& /*parent*/) const {
 
438
        return 2;
 
439
}
 
440
 
 
441
 
 
442
QVariant ImageMetaInfoModel::data(const QModelIndex& index, int role) const {
 
443
        if (!index.isValid()) {
 
444
                return QVariant();
 
445
        }
 
446
 
 
447
        switch (role) {
 
448
        case Qt::DisplayRole:
 
449
                return d->displayData(index);
 
450
        default:
 
451
                return QVariant();
 
452
        }
 
453
}
 
454
 
 
455
 
 
456
QVariant ImageMetaInfoModel::headerData(int section, Qt::Orientation orientation, int role) const {
 
457
        if (orientation == Qt::Vertical || role != Qt::DisplayRole) {
 
458
                return QVariant();
 
459
        }
 
460
 
 
461
        QString caption;
 
462
        if (section == 0) {
 
463
                caption = i18nc("@title:column", "Property");
 
464
        } else if (section == 1) {
 
465
                caption = i18nc("@title:column", "Value");
 
466
        } else {
 
467
                kWarning() << "Unknown section" << section;
 
468
        }
 
469
 
 
470
        return QVariant(caption);
 
471
}
 
472
 
 
473
 
 
474
} // namespace