Fix possible memory leak after switching from Q3PtrList to QList
[kphotoalbum.git] / DB / ImageDB.cpp
blobfa1ae943d4a3d84c1f5846e2c7cadc55be66b0d0
1 /* Copyright (C) 2003-2006 Jesper K. Pedersen <blackie@kde.org>
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
18 #include "ImageDB.h"
19 #include "XMLDB/Database.h"
20 #include <klocale.h>
21 #include <qfileinfo.h>
22 #include <QList>
23 #include "Browser/BrowserWidget.h"
24 #include "DB/CategoryCollection.h"
25 #include "DB/ResultId.h"
26 #include <QProgressBar>
27 #include <qapplication.h>
28 #include "NewImageFinder.h"
29 #include <DB/MediaCount.h>
30 #include <config-kpa-sqldb.h>
31 #ifdef SQLDB_SUPPORT
32 #include "SQLDB/Database.h"
33 #include "SQLDB/DatabaseAddress.h"
34 #endif
35 #include <QProgressDialog>
37 using namespace DB;
39 ImageDB* ImageDB::_instance = 0;
41 ImageDB* DB::ImageDB::instance()
43 if ( _instance == 0 )
44 qFatal("ImageDB::instance must not be called before ImageDB::setup");
45 return _instance;
48 void ImageDB::setupXMLDB( const QString& configFile )
50 if (_instance)
51 qFatal("ImageDB::setupXMLDB: Setup must be called only once.");
52 _instance = new XMLDB::Database( configFile );
53 connectSlots();
56 #ifdef SQLDB_SUPPORT
57 void ImageDB::setupSQLDB( const SQLDB::DatabaseAddress& address )
59 if (_instance)
60 qFatal("ImageDB::setupSQLDB: Setup must be called only once.");
61 _instance = new SQLDB::Database(address);
63 connectSlots();
65 #endif /* SQLDB_SUPPORT */
67 void ImageDB::deleteInstance()
69 delete _instance;
70 _instance = 0;
73 void ImageDB::connectSlots()
75 connect( Settings::SettingsData::instance(), SIGNAL( locked( bool, bool ) ), _instance, SLOT( lockDB( bool, bool ) ) );
76 connect( &_instance->memberMap(), SIGNAL( dirty() ), _instance, SLOT( markDirty() ));
79 QString ImageDB::NONE()
81 return QString::fromLatin1("**NONE**");
84 DB::Result ImageDB::currentScope(bool requireOnDisk) const
86 // TODO: DEPENDENCY: DB:: should not depend on other directories.
87 return search( Browser::BrowserWidget::instance()->currentContext(), requireOnDisk );
90 void ImageDB::markDirty()
92 emit dirty();
95 void ImageDB::setDateRange( const ImageDate& range, bool includeFuzzyCounts )
97 _selectionRange = range;
98 _includeFuzzyCounts = includeFuzzyCounts;
101 void ImageDB::clearDateRange()
103 _selectionRange = ImageDate();
106 void ImageDB::slotRescan()
108 bool newImages = NewImageFinder().findImages();
109 if ( newImages )
110 markDirty();
112 emit totalChanged( totalCount() );
115 void ImageDB::slotRecalcCheckSums(const DB::Result& inputList)
117 DB::Result list = inputList;
118 if (list.isEmpty()) {
119 list = images();
120 md5Map()->clear();
123 bool d = NewImageFinder().calculateMD5sums( list, md5Map() );
124 if ( d )
125 markDirty();
127 emit totalChanged( totalCount() );
130 StringSet DB::ImageDB::imagesWithMD5Changed()
132 MD5Map map;
133 bool wasCanceled;
134 NewImageFinder().calculateMD5sums(images(), &map, &wasCanceled);
135 if ( wasCanceled )
136 return StringSet();
138 StringSet changes = md5Map()->diff( map );
139 StringSet res;
140 for ( StringSet::const_iterator it = changes.begin(); it != changes.end(); ++it )
141 res.insert( Settings::SettingsData::instance()->imageDirectory() + *it );
142 return res;
147 ImageDB::ImageDB()
151 DB::MediaCount ImageDB::count( const ImageSearchInfo& searchInfo )
153 uint images = 0;
154 uint videos = 0;
155 Q_FOREACH(const DB::ImageInfoPtr inf, search(searchInfo).fetchInfos()) {
156 if ( inf->mediaType() == Image )
157 ++images;
158 else
159 ++videos;
161 return MediaCount( images, videos );
164 void ImageDB::convertBackend(ImageDB* newBackend, QProgressBar* progressBar)
166 const DB::Result allImages = images();
168 CategoryCollection* origCategories = categoryCollection();
169 CategoryCollection* newCategories = newBackend->categoryCollection();
171 QList<CategoryPtr> categories = origCategories->categories();
173 if (progressBar) {
174 progressBar->setMaximum(categories.count() + allImages.size());
175 progressBar->setValue(0);
178 uint n = 0;
180 // Convert the Category info
181 for( QList<CategoryPtr>::ConstIterator it = categories.constBegin(); it != categories.constEnd(); ++it ) {
182 newCategories->addCategory( (*it)->name(), (*it)->iconName(), (*it)->viewType(),
183 (*it)->thumbnailSize(), (*it)->doShow() );
184 newCategories->categoryForName( (*it)->name() )->addOrReorderItems( (*it)->items() );
186 if (progressBar) {
187 progressBar->setValue(n++);
188 qApp->processEvents();
192 // Convert member map
193 newBackend->memberMap() = memberMap();
195 // Convert all images to the new back end
196 uint count = 0;
197 ImageInfoList list;
198 Q_FOREACH(const DB::ImageInfoPtr info, allImages.fetchInfos()) {
199 list.append(info);
200 if (++count % 100 == 0) {
201 newBackend->addImages( list );
202 list.clear();
204 if (progressBar) {
205 progressBar->setValue(n++);
206 qApp->processEvents();
209 newBackend->addImages(list);
210 if (progressBar)
211 progressBar->setValue(n);
214 void ImageDB::slotReread( const QStringList& list, DB::ExifMode mode)
216 // Do here a reread of the exif info and change the info correctly in the database without loss of previous added data
217 QProgressDialog dialog( i18n("Loading information from images"),
218 i18n("Cancel"), 0, list.count() );
220 uint count=0;
221 for( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it, ++count ) {
222 if ( count % 10 == 0 ) {
223 dialog.setValue( count ); // ensure to call setProgress(0)
224 qApp->processEvents( QEventLoop::AllEvents );
226 if ( dialog.wasCanceled() )
227 return;
230 QFileInfo fi( *it );
232 if (fi.exists())
233 info(*it, DB::AbsolutePath)->readExif(*it, mode);
234 markDirty();
238 DB::ResultId ImageDB::findFirstItemInRange(const DB::Result& images,
239 const ImageDate& range,
240 bool includeRanges) const
242 DB::ResultId candidate;
243 QDateTime candidateDateStart;
244 Q_FOREACH(DB::ResultId id, images) {
245 ImageInfoPtr iInfo = id.fetchInfo();
247 ImageDate::MatchType match = iInfo->date().isIncludedIn(range);
248 if (match == DB::ImageDate::ExactMatch ||
249 (includeRanges && match == DB::ImageDate::RangeMatch)) {
250 if (candidate.isNull() ||
251 iInfo->date().start() < candidateDateStart) {
252 candidate = id;
253 // Looking at this, can't this just be iInfo->date().start()?
254 // Just in the middle of refactoring other stuff, so leaving
255 // this alone now. TODO(hzeller): revisit.
256 candidateDateStart = info(candidate)->date().start();
260 return candidate;
263 /** \fn void ImageDB::renameCategory( const QString& oldName, const QString newName )
264 * \brief Rename category in media items stored in database.
267 #include "ImageDB.moc"