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

« back to all changes in this revision

Viewing changes to libs/database/collectionscanner.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:
69
69
public:
70
70
 
71
71
    NewlyAppearedFile() : albumId(0) {}
72
 
    NewlyAppearedFile(int albumId, const QString &fileName)
 
72
    NewlyAppearedFile(int albumId, const QString& fileName)
73
73
        : albumId(albumId), fileName(fileName) {}
74
74
 
75
 
    bool operator==(const NewlyAppearedFile &other) const
 
75
    bool operator==(const NewlyAppearedFile& other) const
76
76
    {
77
77
        return albumId == other.albumId && fileName == other.fileName;
78
78
    }
81
81
    QString fileName;
82
82
};
83
83
 
84
 
inline uint qHash(const NewlyAppearedFile &file)
 
84
inline uint qHash(const NewlyAppearedFile& file)
85
85
{
86
86
    return ::qHash(file.albumId) ^ ::qHash(file.fileName);
87
87
}
109
109
    QDateTime         removedItemsTime;
110
110
 
111
111
    QHash<CollectionScannerHints::DstPath, CollectionScannerHints::Album>
112
 
                      albumHints;
 
112
    albumHints;
113
113
    QHash<NewlyAppearedFile, qlonglong>
114
 
                      itemHints;
 
114
    itemHints;
115
115
    QHash<int,int>    establishedSourceAlbums;
116
116
    QSet<int>         modifiedItemHints;
117
117
    QSet<int>         rescanItemHints;
118
118
 
119
119
    CollectionScannerObserver* observer;
120
120
 
121
 
    void resetRemovedItemsTime() { removedItemsTime = QDateTime(); }
122
 
    void removedItems() { removedItemsTime = QDateTime::currentDateTime(); }
 
121
    void resetRemovedItemsTime()
 
122
    {
 
123
        removedItemsTime = QDateTime();
 
124
    }
 
125
    void removedItems()
 
126
    {
 
127
        removedItemsTime = QDateTime::currentDateTime();
 
128
    }
123
129
 
124
130
    inline bool checkObserver()
125
131
    {
127
133
        {
128
134
            return observer->continueQuery();
129
135
        }
 
136
 
130
137
        return true;
131
138
    }
132
139
};
133
140
 
134
141
CollectionScanner::CollectionScanner()
135
 
                 : d(new CollectionScannerPriv)
 
142
    : d(new CollectionScannerPriv)
136
143
{
137
144
}
138
145
 
166
173
    {
167
174
        QList<qlonglong> ids = hint.srcIds();
168
175
        QStringList dstNames = hint.dstNames();
169
 
        for(int i=0;i<ids.size();++i)
 
176
 
 
177
        for (int i=0; i<ids.size(); ++i)
170
178
        {
171
179
            d->itemHints[NewlyAppearedFile(hint.albumIdDst(), dstNames[i])] = ids[i];
172
180
        }
178
186
    foreach(const ItemChangeHint& hint, hints)
179
187
    {
180
188
        QList<qlonglong> ids = hint.ids();
181
 
        for(int i=0;i<ids.size();++i)
 
189
 
 
190
        for (int i=0; i<ids.size(); ++i)
182
191
        {
183
192
            if (hint.isModified())
184
193
            {
210
219
    d->nameFilters = d->imageFilterSet + d->audioFilterSet + d->videoFilterSet;
211
220
}
212
221
 
213
 
void CollectionScanner::setObserver(CollectionScannerObserver *observer)
 
222
void CollectionScanner::setObserver(CollectionScannerObserver* observer)
214
223
{
215
224
    d->observer = observer;
216
225
}
281
290
    }
282
291
 
283
292
    updateRemovedItemsTime();
 
293
 
284
294
    // Items may be set to status removed, without being definitely deleted.
285
295
    // This deletion shall be done after a certain time, as checked by checkedDeleteRemoved
286
296
    if (checkDeleteRemoved())
329
339
    {
330
340
        // Install ScanController::instance()->suspendCollectionScan around your DatabaseTransaction
331
341
        kError() << "Detected an active database transaction when starting a collection scan. "
332
 
                         "Please report this error.";
 
342
                 "Please report this error.";
333
343
        return;
334
344
    }
335
345
 
405
415
    {
406
416
        // Install ScanController::instance()->suspendCollectionScan around your DatabaseTransaction
407
417
        kError() << "Detected an active database transaction when starting a collection file scan. "
408
 
                         "Please report this error.";
 
418
                 "Please report this error.";
409
419
        return -1;
410
420
    }
411
421
 
447
457
    else
448
458
    {
449
459
        ItemScanInfo scanInfo = DatabaseAccess().db()->getItemScanInfo(imageId);
 
460
 
450
461
        switch (mode)
451
462
        {
452
463
            case NormalScan:
475
486
    {
476
487
        // Install ScanController::instance()->suspendCollectionScan around your DatabaseTransaction
477
488
        kError() << "Detected an active database transaction when starting a collection file scan. "
478
 
                         "Please report this error.";
 
489
                 "Please report this error.";
479
490
        return;
480
491
    }
481
492
 
527
538
void CollectionScanner::scanForStaleAlbums(QList<CollectionLocation> locations)
528
539
{
529
540
    Q_UNUSED(locations);
 
541
 
530
542
    if (d->wantSignals)
531
543
    {
532
544
        emit startScanningForStaleAlbums();
544
556
    */
545
557
 
546
558
    QList<AlbumShortInfo>::const_iterator it;
 
559
 
547
560
    for (it = albumList.constBegin(); it != albumList.constEnd(); ++it)
548
561
    {
549
562
        CollectionLocation location = CollectionManager::instance()->locationForAlbumRootId((*it).albumRootId);
 
563
 
550
564
        // Only handle albums on available locations
551
565
        if (location.isAvailable())
552
566
        {
553
567
            QFileInfo fileInfo(location.albumRootPath() + (*it).relativePath);
 
568
 
554
569
            if (!fileInfo.exists() || !fileInfo.isDir())
555
570
            {
556
571
                toBeDeleted << (*it).id;
568
583
        // go through all album copy/move hints
569
584
        QHash<CollectionScannerHints::DstPath, CollectionScannerHints::Album>::const_iterator it;
570
585
        int toBeDeletedIndex;
 
586
 
571
587
        for (it = d->albumHints.constBegin(); it != d->albumHints.constEnd(); ++it)
572
588
        {
573
589
            // if the src entry of a hint is found in toBeDeleted, we have a move/rename, no copy. Handle these here.
574
590
            toBeDeletedIndex = toBeDeleted.indexOf(it.value().albumId);
 
591
 
575
592
            if (toBeDeletedIndex != -1)
576
593
            {
577
594
                // check for existence of target
578
595
                CollectionLocation location = CollectionManager::instance()->locationForAlbumRootId(it.key().albumRootId);
 
596
 
579
597
                if (location.isAvailable())
580
598
                {
581
599
                    QFileInfo fileInfo(location.albumRootPath() + it.key().relativePath);
 
600
 
582
601
                    if (fileInfo.exists() && fileInfo.isDir())
583
602
                    {
584
603
                        // Just set a new root/relativePath to the album. Further scanning will care for all cases or error.
628
647
 
629
648
        // have album this one was copied from?
630
649
        CollectionScannerHints::Album src = d->albumHints.value(CollectionScannerHints::DstPath(location.id(), album));
 
650
 
631
651
        if (!src.isNull())
632
652
        {
633
653
            //kDebug() << "Identified album" << src.albumId << "as source of new album" << fi.filePath();
651
671
    if ( !dir.exists() || !dir.isReadable() )
652
672
    {
653
673
        kWarning() << "Folder does not exist or is not readable: "
654
 
                        << dir.path();
 
674
                   << dir.path();
655
675
        return;
656
676
    }
657
677
 
667
687
    // create a hash filename -> index in list
668
688
    QHash<QString, int> fileNameIndexHash;
669
689
    QSet<qlonglong> itemIdSet;
 
690
 
670
691
    for (int i = 0; i < scanInfos.size(); ++i)
671
692
    {
672
693
        fileNameIndexHash[scanInfos[i].itemName] = i;
674
695
    }
675
696
 
676
697
    const QFileInfoList list = dir.entryInfoList(QDir::AllDirs | QDir::Files  | QDir::NoDotAndDotDot);
 
698
 
677
699
    QFileInfoList::const_iterator fi;
678
700
 
679
701
    int counter = -1;
 
702
 
680
703
    for (fi = list.constBegin(); fi != list.constEnd(); ++fi)
681
704
    {
682
705
        if (!d->checkObserver())
685
708
        }
686
709
 
687
710
        counter++;
 
711
 
688
712
        if (d->wantSignals && counter && (counter % 100 == 0))
689
713
        {
690
714
            emit scannedFiles(counter);
695
719
        {
696
720
            // filter with name filter
697
721
            QString suffix = fi->suffix().toLower();
 
722
 
698
723
            if (!d->nameFilters.contains(suffix))
699
724
            {
700
725
                continue;
701
726
            }
702
727
 
703
728
            int index = fileNameIndexHash.value(fi->fileName(), -1);
 
729
 
704
730
            if (index != -1)
705
731
            {
706
732
                // mark item as "seen"
730
756
        else if ( fi->isDir() )
731
757
        {
732
758
            QString subalbum;
 
759
 
733
760
            if (album == "/")
734
761
            {
735
762
                subalbum = '/' + fi->fileName();
781
808
    {
782
809
        // compare modification date
783
810
        QDateTime fiModifyDate = fi.lastModified();
 
811
 
784
812
        if (fiModifyDate != scanInfo.modificationDate)
785
813
        {
786
814
            // allow a "modify window" of one second.
787
815
            // FAT filesystems store the modify date in 2-second resolution.
788
816
            int diff = fiModifyDate.secsTo(scanInfo.modificationDate);
 
817
 
789
818
            if (abs(diff) > 1)
790
819
            {
791
820
                // file has been modified
806
835
 
807
836
    // Check copy/move hints for single items
808
837
    qlonglong srcId = d->itemHints.value(NewlyAppearedFile(albumId, info.fileName()));
 
838
 
809
839
    if (srcId != 0)
810
840
    {
811
841
        scanner.copiedFrom(albumId, srcId);
814
844
    {
815
845
        // Check copy/move hints for whole albums
816
846
        int srcAlbum = d->establishedSourceAlbums.value(albumId);
 
847
 
817
848
        if (srcAlbum)
818
849
        {
819
850
            // if we have one source album, find out if there is a file with the same name
862
893
    {
863
894
        return;
864
895
    }
 
896
 
865
897
    ImageScanner::copyProperties(source.id(), dest.id());
866
898
}
867
899
 
870
902
    int items = 0;
871
903
 
872
904
    QDir dir( directory );
 
905
 
873
906
    if ( !dir.exists() || !dir.isReadable() )
874
907
    {
875
908
        return 0;
880
913
    items += list.count();
881
914
 
882
915
    QFileInfoList::const_iterator fi;
 
916
 
883
917
    for (fi = list.constBegin(); fi != list.constEnd(); ++fi)
884
918
    {
885
919
        if ( fi->isDir() &&
968
1002
    // retrieve last time removed items were (definitely) deleted from db
969
1003
    QString deleteRemovedTimeString = access.db()->getSetting("DeleteRemovedTime");
970
1004
    QDateTime removedItemsTime, deleteRemovedTime;
 
1005
 
971
1006
    if (!removedItemsTimeString.isNull())
972
1007
    {
973
1008
        removedItemsTime = QDateTime::fromString(removedItemsTimeString, Qt::ISODate);
974
1009
    }
 
1010
 
975
1011
    if (!deleteRemovedTimeString.isNull())
976
1012
    {
977
1013
        deleteRemovedTime = QDateTime::fromString(deleteRemovedTimeString, Qt::ISODate);
978
1014
    }
 
1015
 
979
1016
    QDateTime now = QDateTime::currentDateTime();
980
1017
 
981
1018
    // retrieve number of complete collection scans since the last time that removed items were deleted
1012
1049
void CollectionScanner::scanForStaleAlbums()
1013
1050
{
1014
1051
    QStringList albumRootPaths = CollectionManager::instance()->allAvailableAlbumRootPaths();
 
1052
 
1015
1053
    for (QStringList::const_iterator it = albumRootPaths.constBegin(); it != albumRootPaths.constEnd(); ++it)
1016
1054
    {
1017
1055
        scanForStaleAlbums(*it);
1025
1063
    QList<AlbumShortInfo> toBeDeleted;
1026
1064
 
1027
1065
    QList<AlbumShortInfo>::const_iterator it;
 
1066
 
1028
1067
    for (it = albumList.constBegin(); it != albumList.constEnd(); ++it)
1029
1068
    {
1030
1069
        QFileInfo fileInfo((*it).albumRoot + (*it).url);
 
1070
 
1031
1071
        if (!fileInfo.exists() || !fileInfo.isDir())
1032
1072
        {
1033
1073
            m_foldersToBeDeleted << (*it);
1039
1079
{
1040
1080
    QStringList list;
1041
1081
    QList<AlbumShortInfo>::const_iterator it;
 
1082
 
1042
1083
    for (it = m_foldersToBeDeleted.constBegin(); it != m_foldersToBeDeleted.constEnd(); ++it)
1043
1084
    {
1044
1085
        list << (*it).url;
1045
1086
    }
 
1087
 
1046
1088
    return list;
1047
1089
}
1048
1090
 
1051
1093
    DatabaseAccess access;
1052
1094
    DatabaseTransaction transaction(&access);
1053
1095
    QList<AlbumShortInfo>::const_iterator it;
 
1096
 
1054
1097
    for (it = m_foldersToBeDeleted.constBegin(); it != m_foldersToBeDeleted.constEnd(); ++it)
1055
1098
    {
1056
1099
        kDebug() << "Removing album " << (*it).albumRoot + '/' + (*it).url;
1064
1107
 
1065
1108
    DatabaseAccess access;
1066
1109
    QList< QPair<QString,int> >::const_iterator it;
 
1110
 
1067
1111
    for (it = m_filesToBeDeleted.constBegin(); it != m_filesToBeDeleted.constEnd(); ++it)
1068
1112
    {
1069
1113
        QString location = " (" + access.db()->getAlbumPath((*it).second) + ')';
1079
1123
    DatabaseAccess access;
1080
1124
    DatabaseTransaction transaction(&access);
1081
1125
    QList< QPair<QString,int> >::const_iterator it;
 
1126
 
1082
1127
    for (it = m_filesToBeDeleted.constBegin(); it != m_filesToBeDeleted.constEnd(); ++it)
1083
1128
    {
1084
1129
        kDebug() << "Removing: " << (*it).first << " in "
1091
1136
{
1092
1137
    QStringList albumRootPaths = CollectionManager::instance()->allAvailableAlbumRootPaths();
1093
1138
    int count = 0;
 
1139
 
1094
1140
    for (QStringList::const_iterator it = albumRootPaths.constBegin(); it != albumRootPaths.constEnd(); ++it)
1095
1141
    {
1096
1142
        count += countItemsInFolder(*it);
1113
1159
 
1114
1160
void CollectionScanner::scan(const QString& folderPath)
1115
1161
{
1116
 
    CollectionManager *manager = CollectionManager::instance();
 
1162
    CollectionManager* manager = CollectionManager::instance();
1117
1163
    KUrl url;
1118
1164
    url.setPath(folderPath);
1119
1165
    QString albumRoot = manager->albumRootPath(url);
1144
1190
        QStringList fileList(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot));
1145
1191
 
1146
1192
        DatabaseTransaction transaction;
 
1193
 
1147
1194
        for (QStringList::const_iterator fileIt = fileList.constBegin(); fileIt != fileList.constEnd(); ++fileIt)
1148
1195
        {
1149
1196
            scanAlbum(albumRoot, '/' + (*fileIt));
1175
1222
    // - Does not add stale albums to m_foldersToBeDeleted.
1176
1223
 
1177
1224
    QDir dir( albumRoot + album );
 
1225
 
1178
1226
    if ( !dir.exists() || !dir.isReadable() )
1179
1227
    {
1180
1228
        kWarning() << "Folder does not exist or is not readable: " << dir.path();
1203
1251
    }
1204
1252
 
1205
1253
    const QFileInfoList list = dir.entryInfoList(m_nameFilters, QDir::AllDirs | QDir::Files  | QDir::NoDotAndDotDot /*not CaseSensitive*/);
 
1254
 
1206
1255
    QFileInfoList::const_iterator fi;
1207
1256
 
1208
1257
    for (fi = list.constBegin(); fi != list.constEnd(); ++fi)
1234
1283
    if (!filesFoundInDB.isEmpty())
1235
1284
    {
1236
1285
        QSetIterator<QString> it(filesFoundInDB);
 
1286
 
1237
1287
        while (it.hasNext())
1238
1288
        {
1239
1289
            QPair<QString,int> pair(it.next(),albumID);
 
1290
 
1240
1291
            if (m_filesToBeDeleted.indexOf(pair) == -1)
1241
1292
            {
1242
1293
                m_filesToBeDeleted << pair;
1257
1308
 
1258
1309
    {
1259
1310
        DatabaseTransaction transaction;
 
1311
 
1260
1312
        for (QStringList::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it)
1261
1313
        {
1262
1314
            emit scanningFile(*it);
1294
1346
    int items = 0;
1295
1347
 
1296
1348
    QDir dir( directory );
 
1349
 
1297
1350
    if ( !dir.exists() || !dir.isReadable() )
1298
1351
    {
1299
1352
        return 0;
1304
1357
    items += list.count();
1305
1358
 
1306
1359
    QFileInfoList::const_iterator fi;
 
1360
 
1307
1361
    for (fi = list.constBegin(); fi != list.constEnd(); ++fi)
1308
1362
    {
1309
1363
        if ( fi->isDir()           &&
1380
1434
}
1381
1435
 
1382
1436
void CollectionScanner::updateItemDate(Digikam::DatabaseAccess& access, int albumID,
1383
 
                                 const QString& albumRoot, const QString& album, const QString& fileName)
 
1437
                                       const QString& albumRoot, const QString& album, const QString& fileName)
1384
1438
{
1385
1439
    QString filePath = albumRoot + album + '/' + fileName;
1386
1440