~ubuntu-branches/ubuntu/saucy/digikam/saucy

« back to all changes in this revision

Viewing changes to libs/models/imagemodel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2010-12-21 23:19:11 UTC
  • mfrom: (1.2.33 upstream) (3.1.7 experimental)
  • Revision ID: james.westby@ubuntu.com-20101221231911-z9jip7s5aht1jqn9
Tags: 2:1.7.0-1ubuntu1
* Merge from Debian Experimental. Remaining Ubuntu changes:
  - Export .pot name and copy to plugins in debian/rules
  - Version build-depends on kipi-plugins-dev to ensure build is against the
    same version on all archs
* Drop debian/patches/kubuntu_01_linker.diff, incoporated upstream
* Remove patches directory and unused patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
    bool                  itemDrag;
64
64
    bool                  itemDrop;
65
65
    ImageModelDragDropHandler
66
 
                         *dragDropHandler;
 
66
    *dragDropHandler;
67
67
 
68
68
    bool                  keepFilePathCache;
69
69
    QHash<QString, qlonglong>
70
 
                          filePathHash;
 
70
    filePathHash;
71
71
 
72
 
    QObject              *preprocessor;
 
72
    QObject*              preprocessor;
73
73
    bool                  refreshing;
74
74
    bool                  reAdding;
75
75
    bool                  incrementalRefreshRequested;
77
77
    DatabaseFields::Set   watchFlags;
78
78
 
79
79
    class ImageModelIncrementalUpdater
80
 
                         *incrementalUpdater;
 
80
            *incrementalUpdater;
81
81
};
82
82
 
83
83
class ImageModelIncrementalUpdater
84
84
{
85
85
public:
86
 
    ImageModelIncrementalUpdater(ImageModelPriv *d);
 
86
    ImageModelIncrementalUpdater(ImageModelPriv* d);
87
87
    void appendInfos(const QList<ImageInfo>& infos);
88
88
    QList<QPair<int,int> > oldIndexes() const;
89
89
 
91
91
    QList<ImageInfo>         newInfos;
92
92
};
93
93
 
94
 
ImageModel::ImageModel(QObject *parent)
95
 
          : QAbstractListModel(parent),
96
 
            d(new ImageModelPriv)
 
94
ImageModel::ImageModel(QObject* parent)
 
95
    : QAbstractListModel(parent),
 
96
      d(new ImageModelPriv)
97
97
{
98
 
    connect(DatabaseAccess::databaseWatch(), SIGNAL(imageChange(const ImageChangeset &)),
99
 
            this, SLOT(slotImageChange(const ImageChangeset &)));
 
98
    connect(DatabaseAccess::databaseWatch(), SIGNAL(imageChange(const ImageChangeset&)),
 
99
            this, SLOT(slotImageChange(const ImageChangeset&)));
100
100
 
101
 
    connect(DatabaseAccess::databaseWatch(), SIGNAL(imageTagChange(const ImageTagChangeset &)),
102
 
            this, SLOT(slotImageTagChange(const ImageTagChangeset &)));
 
101
    connect(DatabaseAccess::databaseWatch(), SIGNAL(imageTagChange(const ImageTagChangeset&)),
 
102
            this, SLOT(slotImageTagChange(const ImageTagChangeset&)));
103
103
}
104
104
 
105
105
ImageModel::~ImageModel()
133
133
ImageInfo ImageModel::imageInfo(const QModelIndex& index) const
134
134
{
135
135
    if (!index.isValid())
 
136
    {
136
137
        return ImageInfo();
 
138
    }
 
139
 
137
140
    return d->infos[index.row()];
138
141
}
139
142
 
145
148
qlonglong ImageModel::imageId(const QModelIndex& index) const
146
149
{
147
150
    if (!index.isValid())
 
151
    {
148
152
        return 0;
 
153
    }
 
154
 
149
155
    return d->infos[index.row()].id();
150
156
}
151
157
 
172
178
ImageInfo ImageModel::imageInfo(int row) const
173
179
{
174
180
    if (row >= d->infos.size())
 
181
    {
175
182
        return ImageInfo();
 
183
    }
 
184
 
176
185
    return d->infos[row];
177
186
}
178
187
 
184
193
qlonglong ImageModel::imageId(int row) const
185
194
{
186
195
    if (row >= d->infos.size())
 
196
    {
187
197
        return -1;
 
198
    }
 
199
 
188
200
    return d->infos[row].id();
189
201
}
190
202
 
196
208
QModelIndex ImageModel::indexForImageId(qlonglong id) const
197
209
{
198
210
    int index = d->idHash.value(id, -1);
 
211
 
199
212
    if (index != -1)
 
213
    {
200
214
        return createIndex(index, 0);
 
215
    }
 
216
 
201
217
    return QModelIndex();
202
218
}
203
219
 
205
221
ImageInfo ImageModel::retrieveImageInfo(const QModelIndex& index)
206
222
{
207
223
    if (!index.isValid())
 
224
    {
208
225
        return ImageInfo();
 
226
    }
209
227
 
210
 
    ImageModel *model = index.data(ImageModelPointerRole).value<ImageModel*>();
 
228
    ImageModel* model = index.data(ImageModelPointerRole).value<ImageModel*>();
211
229
    int row = index.data(ImageModelInternalId).toInt();
212
230
    return model->imageInfo(row);
213
231
}
216
234
qlonglong ImageModel::retrieveImageId(const QModelIndex& index)
217
235
{
218
236
    if (!index.isValid())
 
237
    {
219
238
        return 0;
 
239
    }
220
240
 
221
 
    ImageModel *model = index.data(ImageModelPointerRole).value<ImageModel*>();
 
241
    ImageModel* model = index.data(ImageModelPointerRole).value<ImageModel*>();
222
242
    int row = index.data(ImageModelInternalId).toInt();
223
243
    return model->imageId(row);
224
244
}
232
252
    else
233
253
    {
234
254
        const int size = d->infos.size();
 
255
 
235
256
        for (int i=0; i<size; ++i)
236
257
            if (d->infos[i].filePath() == filePath)
 
258
            {
237
259
                return createIndex(i, 0);
 
260
            }
238
261
    }
 
262
 
239
263
    return QModelIndex();
240
264
}
241
265
 
244
268
    if (d->keepFilePathCache)
245
269
    {
246
270
        qlonglong id = d->filePathHash.value(filePath);
 
271
 
247
272
        if (id)
248
273
        {
249
274
            int index = d->idHash.value(id, -1);
 
275
 
250
276
            if (index != -1)
 
277
            {
251
278
                return d->infos[index];
 
279
            }
252
280
        }
253
281
    }
254
282
    else
261
289
            }
262
290
        }
263
291
    }
 
292
 
264
293
    return ImageInfo();
265
294
}
266
295
 
267
296
void ImageModel::addImageInfos(const QList<ImageInfo>& infos)
268
297
{
269
298
    if (infos.isEmpty())
 
299
    {
270
300
        return;
 
301
    }
271
302
 
272
303
    if (d->incrementalUpdater)
 
304
    {
273
305
        d->incrementalUpdater->appendInfos(infos);
 
306
    }
274
307
    else
 
308
    {
275
309
        appendInfos(infos);
 
310
    }
276
311
}
277
312
 
278
313
void ImageModel::clearImageInfos()
312
347
void ImageModel::emitDataChangedForAll()
313
348
{
314
349
    if (d->infos.isEmpty())
 
350
    {
315
351
        return;
 
352
    }
 
353
 
316
354
    QModelIndex first = createIndex(0, 0);
317
355
    QModelIndex last = createIndex(d->infos.size() - 1, 0);
318
356
    emit dataChanged(first, last);
331
369
 
332
370
// ------------ Preprocessing -------------
333
371
 
334
 
void ImageModel::setPreprocessor(QObject *preprocessor)
 
372
void ImageModel::setPreprocessor(QObject* preprocessor)
335
373
{
336
374
    unsetPreprocessor(d->preprocessor);
337
375
    d->preprocessor = preprocessor;
338
376
}
339
377
 
340
 
void ImageModel::unsetPreprocessor(QObject *preprocessor)
 
378
void ImageModel::unsetPreprocessor(QObject* preprocessor)
341
379
{
342
380
    if (preprocessor && d->preprocessor == preprocessor)
343
381
    {
350
388
void ImageModel::appendInfos(const QList<ImageInfo>& infos)
351
389
{
352
390
    if (infos.isEmpty())
 
391
    {
353
392
        return;
 
393
    }
354
394
 
355
395
    if (d->preprocessor)
356
396
    {
358
398
        emit preprocess(infos);
359
399
    }
360
400
    else
 
401
    {
361
402
        publiciseInfos(infos);
 
403
    }
362
404
}
363
405
 
364
406
void ImageModel::reAddImageInfos(const QList<ImageInfo>& infos)
395
437
    // Any remaining batches from non-incremental refreshing subclasses have been received in appendInfos(),
396
438
    // any batches sent to preprocessor for re-adding have been re-added.
397
439
    if (d->refreshing || d->reAdding)
 
440
    {
398
441
        return;
 
442
    }
399
443
 
400
444
    if (d->incrementalRefreshRequested)
401
445
    {
411
455
void ImageModel::publiciseInfos(const QList<ImageInfo>& infos)
412
456
{
413
457
    if (infos.isEmpty())
 
458
    {
414
459
        return;
 
460
    }
415
461
 
416
462
    emit imageInfosAboutToBeAdded(infos);
417
463
    int firstNewIndex = d->infos.size();
418
464
    int lastNewIndex = d->infos.size() + infos.size() - 1;
419
465
    beginInsertRows(QModelIndex(), firstNewIndex, lastNewIndex);
420
466
    d->infos << infos;
 
467
 
421
468
    for (int i=firstNewIndex; i<=lastNewIndex; ++i)
422
469
    {
423
 
        ImageInfo &info = d->infos[i];
 
470
        ImageInfo& info = d->infos[i];
424
471
        qlonglong id = info.id();
425
472
        d->idHash[id] = i;
 
473
 
426
474
        if (d->keepFilePathCache)
 
475
        {
427
476
            d->filePathHash[info.filePath()] = id;
 
477
        }
428
478
    }
 
479
 
429
480
    endInsertRows();
430
481
    emit imageInfosAdded(infos);
431
482
}
450
501
void ImageModel::startIncrementalRefresh()
451
502
{
452
503
    if (d->incrementalUpdater)
 
504
    {
453
505
        delete d->incrementalUpdater;
 
506
    }
 
507
 
454
508
    d->incrementalUpdater = new ImageModelIncrementalUpdater(d);
455
509
}
456
510
 
457
511
void ImageModel::finishIncrementalRefresh()
458
512
{
459
513
    if (!d->incrementalUpdater)
 
514
    {
460
515
        return;
 
516
    }
461
517
 
462
518
    // Remove old indexes
463
519
    // Keep in mind that when calling beginRemoveRows all structures announced to be removed
466
522
    QList<QPair<int,int> > pairs = d->incrementalUpdater->oldIndexes();
467
523
    int begin, end, removedRows, offset = 0;
468
524
    typedef QPair<int,int> IntPair; // to make foreach macro happy
469
 
    foreach (const IntPair &pair, pairs)
 
525
    foreach (const IntPair& pair, pairs)
470
526
    {
471
527
        begin = pair.first - offset;
472
528
        end = pair.second - offset; // inclusive
481
537
 
482
538
        // update idHash - which points to indexes of d->infos, and these change now!
483
539
        QHash<qlonglong, int>::iterator it;
 
540
 
484
541
        for (it = d->idHash.begin(); it != d->idHash.end(); )
485
542
        {
486
543
            if (it.value() >= begin)
497
554
                    continue;
498
555
                }
499
556
            }
 
557
 
500
558
            ++it;
501
559
        }
502
560
 
510
568
    if (d->keepFilePathCache)
511
569
    {
512
570
        QHash<QString, qlonglong>::iterator it;
 
571
 
513
572
        for (it = d->filePathHash.begin(); it != d->filePathHash.end(); )
514
573
        {
515
574
            if (d->incrementalUpdater->oldIds.contains(it.value()))
 
575
            {
516
576
                it = d->filePathHash.erase(it);
 
577
            }
517
578
            else
 
579
            {
518
580
                ++it;
 
581
            }
519
582
        }
520
583
    }
521
584
 
526
589
    d->incrementalUpdater = 0;
527
590
}
528
591
 
529
 
ImageModelIncrementalUpdater::ImageModelIncrementalUpdater(ImageModelPriv *d)
 
592
ImageModelIncrementalUpdater::ImageModelIncrementalUpdater(ImageModelPriv* d)
530
593
{
531
594
    oldIds = d->idHash;
532
595
}
533
596
 
534
597
void ImageModelIncrementalUpdater::appendInfos(const QList<ImageInfo>& infos)
535
598
{
536
 
    foreach (const ImageInfo &info, infos)
 
599
    foreach (const ImageInfo& info, infos)
537
600
    {
538
601
        QHash<qlonglong,int>::iterator it = oldIds.find(info.id());
 
602
 
539
603
        if (it != oldIds.end())
 
604
        {
540
605
            oldIds.erase(it);
 
606
        }
541
607
        else
 
608
        {
542
609
            newInfos << info;
 
610
        }
543
611
    }
544
612
}
545
613
 
547
615
{
548
616
    // Take the removed indexes and return them as contiguous pairs [begin, end]
549
617
    QList<QPair<int,int> > pairs;
 
618
 
550
619
    if (oldIds.isEmpty())
 
620
    {
551
621
        return pairs;
 
622
    }
552
623
 
553
624
    QList<int> ids = oldIds.values();
554
625
    qSort(ids);
555
626
 
556
627
    QPair<int,int> pair(ids.first(), ids.first());
 
628
 
557
629
    for (int i=1; i<ids.size(); ++i)
558
630
    {
559
631
        int index = ids[i];
 
632
 
560
633
        if (index == pair.second + 1)
561
634
        {
562
635
            pair.second = index;
563
636
            continue;
564
637
        }
 
638
 
565
639
        pairs << pair; // insert last pair
566
640
        pair.first = index;
567
641
        pair.second  = index;
568
642
    }
 
643
 
569
644
    pairs << pair;
570
645
 
571
646
    return pairs;
576
651
QVariant ImageModel::data(const QModelIndex& index, int role) const
577
652
{
578
653
    if (!index.isValid())
 
654
    {
579
655
        return QVariant();
 
656
    }
580
657
 
581
658
    switch (role)
582
659
    {
590
667
        case CreationDateRole:
591
668
            return d->infos[index.row()].dateTime();
592
669
    }
 
670
 
593
671
    return QVariant();
594
672
}
595
673
 
604
682
int ImageModel::rowCount(const QModelIndex& parent) const
605
683
{
606
684
    if (parent.isValid())
 
685
    {
607
686
        return 0;
 
687
    }
608
688
 
609
689
    return d->infos.size();
610
690
}
612
692
Qt::ItemFlags ImageModel::flags(const QModelIndex& index) const
613
693
{
614
694
    if (!index.isValid())
 
695
    {
615
696
        return 0;
 
697
    }
616
698
 
617
699
    Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
 
700
 
618
701
    if (d->itemDrag)
 
702
    {
619
703
        f |= Qt::ItemIsDragEnabled;
 
704
    }
 
705
 
620
706
    if (d->itemDrop)
 
707
    {
621
708
        f |= Qt::ItemIsDropEnabled;
 
709
    }
 
710
 
622
711
    return f;
623
712
}
624
713
 
625
714
QModelIndex ImageModel::index(int row, int column, const QModelIndex& parent) const
626
715
{
627
716
    if (column != 0 || row < 0 || parent.isValid() || row >= d->infos.size())
 
717
    {
628
718
        return QModelIndex();
 
719
    }
629
720
 
630
721
    return createIndex(row, 0);
631
722
}
640
731
QStringList ImageModel::mimeTypes() const
641
732
{
642
733
    if (d->dragDropHandler)
 
734
    {
643
735
        return d->dragDropHandler->mimeTypes();
 
736
    }
 
737
 
644
738
    return QStringList();
645
739
}
646
740
 
647
 
bool ImageModel::dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &)
 
741
bool ImageModel::dropMimeData(const QMimeData*, Qt::DropAction, int, int, const QModelIndex&)
648
742
{
649
743
    // we require custom solutions
650
744
    return false;
651
745
}
652
746
 
653
 
QMimeData *ImageModel::mimeData(const QModelIndexList& indexes) const
 
747
QMimeData* ImageModel::mimeData(const QModelIndexList& indexes) const
654
748
{
655
749
    if (!d->dragDropHandler)
 
750
    {
656
751
        return 0;
 
752
    }
657
753
 
658
754
    return d->dragDropHandler->createMimeData(indexes);
659
755
}
668
764
    d->itemDrop = enable;
669
765
}
670
766
 
671
 
void ImageModel::setDragDropHandler(ImageModelDragDropHandler *handler)
 
767
void ImageModel::setDragDropHandler(ImageModelDragDropHandler* handler)
672
768
{
673
769
    d->dragDropHandler = handler;
674
770
}
675
771
 
676
 
ImageModelDragDropHandler *ImageModel::dragDropHandler() const
 
772
ImageModelDragDropHandler* ImageModel::dragDropHandler() const
677
773
{
678
774
    return d->dragDropHandler;
679
775
}
683
779
void ImageModel::slotImageChange(const ImageChangeset& changeset)
684
780
{
685
781
    if (d->infos.isEmpty())
 
782
    {
686
783
        return;
 
784
    }
687
785
 
688
786
    if (d->watchFlags & changeset.changes())
689
787
    {
691
789
        foreach (const qlonglong& id, changeset.ids())
692
790
        {
693
791
            QModelIndex index = indexForImageId(id);
 
792
 
694
793
            if (index.isValid())
 
794
            {
695
795
                items.select(index, index);
 
796
            }
696
797
        }
 
798
 
697
799
        if (!items.isEmpty())
698
800
        {
699
801
            emitDataChangedForSelection(items);
705
807
void ImageModel::slotImageTagChange(const ImageTagChangeset& changeset)
706
808
{
707
809
    if (d->infos.isEmpty())
 
810
    {
708
811
        return;
 
812
    }
709
813
 
710
814
    QItemSelection items;
711
815
    foreach (const qlonglong& id, changeset.ids())
712
816
    {
713
817
        QModelIndex index = indexForImageId(id);
 
818
 
714
819
        if (index.isValid())
 
820
        {
715
821
            items.select(index, index);
 
822
        }
716
823
    }
 
824
 
717
825
    if (!items.isEmpty())
718
826
    {
719
827
        emitDataChangedForSelection(items);