• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

digikam

albumlister.cpp

Go to the documentation of this file.
00001 /* ============================================================
00002  *
00003  * This file is a part of digiKam project
00004  * http://www.digikam.org
00005  *
00006  * Date        : 2004-06-26
00007  * Description : Albums lister.
00008  *
00009  * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
00010  * Copyright (C) 2007-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
00011  * Copyright (C) 2007 by Arnd Baecker <arnd dot baecker at web dot de>
00012  *
00013  * This program is free software; you can redistribute it
00014  * and/or modify it under the terms of the GNU General
00015  * Public License as published by the Free Software Foundation;
00016  * either version 2, or (at your option)
00017  * any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * ============================================================ */
00025 
00026 #include "albumlister.moc"
00027 
00028 // C ANSI includes
00029 
00030 extern "C"
00031 {
00032 #include <sys/time.h>
00033 }
00034 
00035 // C++ includes
00036 
00037 #include <cstdio>
00038 #include <ctime>
00039 
00040 // Qt includes
00041 
00042 #include <QDataStream>
00043 #include <QFileInfo>
00044 #include <QDir>
00045 #include <QMap>
00046 #include <QPair>
00047 #include <QTimer>
00048 
00049 // KDE includes
00050 
00051 #include <kapplication.h>
00052 #include <kcursor.h>
00053 #include <kio/job.h>
00054 #include <kurl.h>
00055 #include <kdebug.h>
00056 
00057 // Local includes
00058 
00059 #include "databaseaccess.h"
00060 #include "databasewatch.h"
00061 #include "imagelister.h"
00062 #include "mimefilter.h"
00063 #include "album.h"
00064 #include "albummanager.h"
00065 #include "albumsettings.h"
00066 
00067 namespace Digikam
00068 {
00069 
00070 class AlbumListerPriv
00071 {
00072 public:
00073 
00074     AlbumListerPriv()
00075     {
00076         untaggedFilter = false;
00077         ratingFilter   = 0;
00078         filterTimer    = 0;
00079         refreshTimer   = 0;
00080         job            = 0;
00081         currAlbum      = 0;
00082         mimeTypeFilter = MimeFilter::AllFiles;
00083         ratingCond     = AlbumLister::GreaterEqualCondition;
00084         matchingCond   = AlbumLister::OrCondition;
00085         recurseAlbums  = false;
00086         recurseTags    = false;
00087     }
00088 
00089     bool                            untaggedFilter;
00090 
00091     int                             ratingFilter;
00092     int                             recurseAlbums;
00093     int                             recurseTags;
00094 
00095     QMap<qlonglong, ImageInfo>      itemMap;
00096     QMap<QDateTime, bool>           dayFilter;
00097     QSet<int>                       invalidatedItems;
00098 
00099     QList<int>                      tagFilter;
00100 
00101     QTimer                         *filterTimer;
00102     QTimer                         *refreshTimer;
00103 
00104     KIO::TransferJob               *job;
00105 
00106     SearchTextSettings              textFilterSettings;
00107 
00108     ImageInfoList                   itemList;
00109 
00110     QSet<qlonglong>                 itemListSet;
00111 
00112     Album                          *currAlbum;
00113 
00114     MimeFilter::TypeMimeFilter      mimeTypeFilter;
00115 
00116     AlbumLister::MatchingCondition  matchingCond;
00117 
00118     AlbumLister::RatingCondition    ratingCond;
00119 };
00120 
00121 AlbumLister* AlbumLister::m_instance = 0;
00122 
00123 AlbumLister* AlbumLister::instance()
00124 {
00125     if (!m_instance)
00126         new AlbumLister();
00127 
00128     return m_instance;
00129 }
00130 
00131 void AlbumLister::cleanUp()
00132 {
00133     delete m_instance;
00134 }
00135 
00136 AlbumLister::AlbumLister()
00137            : d(new AlbumListerPriv)
00138 {
00139     m_instance = this;
00140 
00141     d->filterTimer  = new QTimer(this);
00142     d->refreshTimer = new QTimer(this);
00143 
00144     d->refreshTimer->setSingleShot(true);
00145     d->filterTimer->setSingleShot(true);
00146     d->filterTimer->setInterval(100);
00147 
00148     connect(d->filterTimer, SIGNAL(timeout()),
00149             this, SLOT(slotFilterItems()));
00150 
00151     connect(d->refreshTimer, SIGNAL(timeout()),
00152             this, SLOT(slotNextRefresh()));
00153 
00154     connect(DatabaseAccess::databaseWatch(), SIGNAL(imageChange(const ImageChangeset &)),
00155             this, SLOT(slotImageChange(const ImageChangeset &)));
00156 
00157     connect(DatabaseAccess::databaseWatch(), SIGNAL(imageTagChange(const ImageTagChangeset &)),
00158             this, SLOT(slotImageTagChange(const ImageTagChangeset &)));
00159 
00160     connect(DatabaseAccess::databaseWatch(), SIGNAL(collectionImageChange(const CollectionImageChangeset &)),
00161             this, SLOT(slotCollectionImageChange(const CollectionImageChangeset &)));
00162 
00163     connect(DatabaseAccess::databaseWatch(), SIGNAL(searchChange(const SearchChangeset &)),
00164             this, SLOT(slotSearchChange(const SearchChangeset &)));
00165 }
00166 
00167 AlbumLister::~AlbumLister()
00168 {
00169     if (d->job)
00170     {
00171         d->job->kill();
00172         d->job = 0;
00173     }
00174 
00175     delete d;
00176     m_instance = 0;
00177 }
00178 
00179 void AlbumLister::openAlbum(Album *album)
00180 {
00181     d->currAlbum = album;
00182     d->filterTimer->stop();
00183     emit signalClear();
00184     d->itemList.clear();
00185     d->itemListSet.clear();
00186     d->itemMap.clear();
00187 
00188     if (d->job)
00189     {
00190         d->job->kill();
00191         d->job = 0;
00192     }
00193 
00194     if (!album)
00195         return;
00196 
00197     startListJob(album->databaseUrl());
00198 }
00199 
00200 void AlbumLister::refresh()
00201 {
00202     if (!d->currAlbum)
00203         return;
00204 
00205     d->filterTimer->stop();
00206 
00207     if (d->job)
00208     {
00209         d->job->kill();
00210         d->job = 0;
00211     }
00212 
00213     d->itemMap.clear();
00214     for (ImageInfoList::const_iterator it = d->itemList.constBegin(); it != d->itemList.constEnd(); ++it)
00215     {
00216         d->itemMap.insert(it->id(), *it);
00217     }
00218 
00219     startListJob(d->currAlbum->databaseUrl());
00220 }
00221 
00222 void AlbumLister::slotNextRefresh()
00223 {
00224     // Refresh, unless job is running, then postpone restart until job is finished
00225     // Rationale: Let the job run, don't stop it possibly several times
00226     if (d->job)
00227         d->refreshTimer->start(50);
00228     else
00229         refresh();
00230 }
00231 
00232 void AlbumLister::startListJob(const KUrl& url)
00233 {
00234     d->job = ImageLister::startListJob(url);
00235     d->job->addMetaData("listAlbumsRecursively", d->recurseAlbums ? "true" : "false");
00236     d->job->addMetaData("listTagsRecursively", d->recurseTags ? "true" : "false");
00237 
00238     connect(d->job, SIGNAL(result(KJob*)),
00239             this, SLOT(slotResult(KJob*)));
00240 
00241     connect(d->job, SIGNAL(data(KIO::Job*, const QByteArray&)),
00242             this, SLOT(slotData(KIO::Job*, const QByteArray&)));
00243 }
00244 
00245 void AlbumLister::setRecurseAlbums(bool recursive)
00246 {
00247     d->recurseAlbums = recursive;
00248     refresh();
00249 }
00250 
00251 void AlbumLister::setRecurseTags(bool recursive)
00252 {
00253     d->recurseTags = recursive;
00254     refresh();
00255 }
00256 
00257 void AlbumLister::setDayFilter(const QList<QDateTime>& days)
00258 {
00259     d->dayFilter.clear();
00260 
00261     for (QList<QDateTime>::const_iterator it = days.constBegin(); it != days.constEnd(); ++it)
00262         d->dayFilter.insert(*it, true);
00263 
00264     if (!d->filterTimer->isActive())
00265         d->filterTimer->start();
00266 }
00267 
00268 bool AlbumLister::tagFiltersIsActive()
00269 {
00270     if (!d->tagFilter.isEmpty() || d->untaggedFilter)
00271         return true;
00272 
00273     return false;
00274 }
00275 
00276 bool AlbumLister::filterIsActive()
00277 {
00278     return !d->dayFilter.isEmpty() || !d->tagFilter.isEmpty() || !d->textFilterSettings.text.isEmpty()
00279             || d->untaggedFilter || d->ratingFilter!=-1;
00280 }
00281 
00282 void AlbumLister::setTagFilter(const QList<int>& tags, const MatchingCondition& matchingCond,
00283                                bool showUnTagged)
00284 {
00285     d->tagFilter      = tags;
00286     d->matchingCond   = matchingCond;
00287     d->untaggedFilter = showUnTagged;
00288     if (!d->filterTimer->isActive())
00289         d->filterTimer->start();
00290 }
00291 
00292 void AlbumLister::setRatingFilter(int rating, const RatingCondition& ratingCond)
00293 {
00294     d->ratingFilter = rating;
00295     d->ratingCond   = ratingCond;
00296     if (!d->filterTimer->isActive())
00297         d->filterTimer->start();
00298 }
00299 
00300 void AlbumLister::setMimeTypeFilter(int mimeTypeFilter)
00301 {
00302     d->mimeTypeFilter = (MimeFilter::TypeMimeFilter)mimeTypeFilter;
00303     if (!d->filterTimer->isActive())
00304         d->filterTimer->start();
00305 }
00306 
00307 void AlbumLister::setTextFilter(const SearchTextSettings& settings)
00308 {
00309     d->textFilterSettings = settings;
00310     if (!d->filterTimer->isActive())
00311         d->filterTimer->start();
00312 }
00313 
00314 bool AlbumLister::matchesFilter(const ImageInfo& info, bool& foundText)
00315 {
00316     if (!filterIsActive())
00317         return true;
00318 
00319     bool match = false;
00320 
00321     if (!d->tagFilter.isEmpty())
00322     {
00323         QList<int> tagIds = info.tagIds();
00324         QList<int>::iterator it;
00325 
00326         if (d->matchingCond == OrCondition)
00327         {
00328             for (it = d->tagFilter.begin(); it != d->tagFilter.end(); ++it)
00329             {
00330                 if (tagIds.contains(*it))
00331                 {
00332                     match = true;
00333                     break;
00334                 }
00335             }
00336         }
00337         else
00338         {
00339             // AND matching condition...
00340 
00341             for (it = d->tagFilter.begin(); it != d->tagFilter.end(); ++it)
00342             {
00343                 if (!tagIds.contains(*it))
00344                     break;
00345             }
00346 
00347             if (it == d->tagFilter.end())
00348                 match = true;
00349         }
00350 
00351         match |= (d->untaggedFilter && tagIds.isEmpty());
00352     }
00353     else if (d->untaggedFilter)
00354     {
00355         match = info.tagIds().isEmpty();
00356     }
00357     else
00358     {
00359         match = true;
00360     }
00361 
00362     if (!d->dayFilter.isEmpty())
00363     {
00364         match &= d->dayFilter.contains(QDateTime(info.dateTime().date(), QTime()));
00365     }
00366 
00367     //-- Filter by rating ---------------------------------------------------------
00368 
00369     if (d->ratingFilter >= 0)
00370     {
00371         // for now we treat -1 (no rating) just like a rating of 0.
00372         int rating = info.rating();
00373         if (rating == -1)
00374             rating = 0;
00375 
00376         if (d->ratingCond == GreaterEqualCondition)
00377         {
00378             // If the rating is not >=, i.e it is <, then it does not match.
00379             if (rating < d->ratingFilter)
00380             {
00381                 match = false;
00382             }
00383         }
00384         else if (d->ratingCond == EqualCondition)
00385         {
00386             // If the rating is not =, i.e it is !=, then it does not match.
00387             if (rating != d->ratingFilter)
00388             {
00389                 match = false;
00390             }
00391         }
00392         else
00393         {
00394             // If the rating is not <=, i.e it is >, then it does not match.
00395             if (rating > d->ratingFilter)
00396             {
00397                 match = false;
00398             }
00399         }
00400     }
00401 
00402     // -- Filter by mime type -----------------------------------------------------
00403 
00404     switch(d->mimeTypeFilter)
00405     {
00406         // info.format is a standardized string: Only one possibility per mime type
00407         case MimeFilter::ImageFiles:
00408         {
00409             if (info.category() != DatabaseItem::Image)
00410                 match = false;
00411             break;
00412         }
00413         case MimeFilter::JPGFiles:
00414         {
00415             if (info.format() != "JPG")
00416                 match = false;
00417             break;
00418         }
00419         case MimeFilter::PNGFiles:
00420         {
00421             if (info.format() != "PNG")
00422                 match = false;
00423             break;
00424         }
00425         case MimeFilter::TIFFiles:
00426         {
00427             if (info.format() != "TIFF")
00428                 match = false;
00429             break;
00430         }
00431         case MimeFilter::DNGFiles:
00432         {
00433             if (info.format() != "RAW-DNG")
00434                 match = false;
00435             break;
00436         }
00437         case MimeFilter::NoRAWFiles:
00438         {
00439             if (info.format().startsWith(QLatin1String("RAW")))
00440                 match = false;
00441             break;
00442         }
00443         case MimeFilter::RAWFiles:
00444         {
00445             if (!info.format().startsWith(QLatin1String("RAW")))
00446                 match = false;
00447             break;
00448         }
00449         case MimeFilter::MoviesFiles:
00450         {
00451             if (info.category() != DatabaseItem::Video)
00452                 match = false;
00453             break;
00454         }
00455         case MimeFilter::AudioFiles:
00456         {
00457             if (info.category() != DatabaseItem::Audio)
00458                 match = false;
00459             break;
00460         }
00461         default:        // All Files: do nothing...
00462             break;
00463     }
00464 
00465     //-- Filter by text -----------------------------------------------------------
00466 
00467     if (!d->textFilterSettings.text.isEmpty())
00468     {
00469         foundText = false;
00470         if (info.name().contains(d->textFilterSettings.text, d->textFilterSettings.caseSensitive))
00471         {
00472             foundText = true;
00473         }
00474         if (info.comment().contains(d->textFilterSettings.text, d->textFilterSettings.caseSensitive))
00475             foundText = true;
00476         QStringList tags = AlbumManager::instance()->tagNames(info.tagIds());
00477         for (QStringList::const_iterator it = tags.constBegin() ; it != tags.constEnd() ; ++it)
00478         {
00479             if ((*it).contains(d->textFilterSettings.text, d->textFilterSettings.caseSensitive))
00480                 foundText = true;
00481         }
00482         // check for folder names
00483         PAlbum* palbum = AlbumManager::instance()->findPAlbum(info.albumId());
00484         if ((palbum && palbum->title().contains(d->textFilterSettings.text, d->textFilterSettings.caseSensitive)))
00485         {
00486             foundText = true;
00487         }
00488         match &= foundText;
00489     }
00490 
00491     return match;
00492 }
00493 
00494 void AlbumLister::stop()
00495 {
00496     d->currAlbum = 0;
00497     d->filterTimer->stop();
00498     emit signalClear();
00499 
00500     d->itemList.clear();
00501     d->itemListSet.clear();
00502     d->itemMap.clear();
00503 
00504     if (d->job)
00505     {
00506         d->job->kill();
00507         d->job = 0;
00508     }
00509 }
00510 
00511 void AlbumLister::invalidateItem(const ImageInfo& item)
00512 {
00513     d->invalidatedItems << item.id();
00514 }
00515 
00516 void AlbumLister::slotFilterItems()
00517 {
00518     if (d->job)
00519     {
00520         d->filterTimer->start();
00521         return;
00522     }
00523 
00524     ImageInfoList newFilteredItemsList;
00525     ImageInfoList deleteFilteredItemsList;
00526     bool matchForText = false;
00527     bool match        = false;
00528 
00529     for (ImageInfoListIterator it = d->itemList.begin();
00530          it != d->itemList.end(); ++it)
00531     {
00532         bool foundText = false;
00533         if (matchesFilter(*it, foundText))
00534         {
00535             match = true;
00536             newFilteredItemsList.append(*it);
00537         }
00538         else
00539         {
00540             deleteFilteredItemsList.append(*it);
00541         }
00542 
00543         if (foundText)
00544             matchForText = true;
00545     }
00546 
00547     // This takes linear time - and deleting seems to take longer. Set wait cursor for large numbers.
00548     bool setCursor = (3*deleteFilteredItemsList.count() + newFilteredItemsList.count()) > 1500;
00549     if (setCursor)
00550         kapp->setOverrideCursor(Qt::WaitCursor);
00551 
00552     emit signalItemsTextFilterMatch(matchForText);
00553     emit signalItemsFilterMatch(match);
00554 
00555     if (!deleteFilteredItemsList.isEmpty())
00556     {
00557         /*
00558         foreach(const ImageInfo& info, deleteFilteredItemsList)
00559             emit signalDeleteFilteredItem(info);
00560         */
00561         emit signalClear();
00562     }
00563     if (!newFilteredItemsList.isEmpty())
00564     {
00565         emit signalNewFilteredItems(newFilteredItemsList);
00566     }
00567 
00568     if (setCursor)
00569         kapp->restoreOverrideCursor();
00570 }
00571 
00572 void AlbumLister::slotResult(KJob* job)
00573 {
00574     d->job = 0;
00575 
00576     if (job->error())
00577     {
00578         kWarning() << "Failed to list url: " << job->errorString();
00579         d->itemMap.clear();
00580         d->invalidatedItems.clear();
00581         return;
00582     }
00583 
00584     for (QMap<qlonglong, ImageInfo>::const_iterator it = d->itemMap.constBegin();
00585          it != d->itemMap.constEnd(); ++it)
00586     {
00587         emit signalDeleteItem(it.value());
00588         emit signalDeleteFilteredItem(it.value());
00589         d->itemList.removeAll(it.value());
00590         d->itemListSet.remove(it.key());
00591     }
00592 
00593     d->itemMap.clear();
00594     d->invalidatedItems.clear();
00595 
00596     emit signalCompleted();
00597 }
00598 
00599 void AlbumLister::slotData(KIO::Job*, const QByteArray& data)
00600 {
00601     if (data.isEmpty())
00602         return;
00603 
00604     ImageInfoList newItemsList;
00605     ImageInfoList newFilteredItemsList;
00606 
00607     QByteArray tmp(data);
00608     QDataStream ds(&tmp, QIODevice::ReadOnly);
00609 
00610     while (!ds.atEnd())
00611     {
00612         bool foundText = false;
00613         ImageListerRecord record;
00614         ds >> record;
00615 
00616         if (d->itemMap.contains(record.imageID))
00617         {
00618             ImageInfo info = d->itemMap[record.imageID];
00619             d->itemMap.remove(record.imageID);
00620 
00621             if (d->invalidatedItems.contains(record.imageID))
00622             {
00623                 emit signalDeleteItem(info);
00624                 emit signalDeleteFilteredItem(info);
00625                 d->itemList.removeAll(info);
00626                 d->itemListSet.remove(info.id());
00627             }
00628             else
00629             {
00630                 if (!matchesFilter(info, foundText))
00631                 {
00632                     emit signalDeleteFilteredItem(info);
00633                 }
00634                 continue;
00635             }
00636         }
00637 
00638         ImageInfo info(record);
00639 
00640         if (matchesFilter(info, foundText))
00641             newFilteredItemsList.append(info);
00642 
00643         newItemsList.append(info);
00644         d->itemList.append(info);
00645         d->itemListSet.insert(info.id());
00646     }
00647 
00648     if (!newFilteredItemsList.isEmpty())
00649         emit signalNewFilteredItems(newFilteredItemsList);
00650 
00651     if (!newItemsList.isEmpty())
00652         emit signalNewItems(newItemsList);
00653 
00654     slotFilterItems();
00655 }
00656 
00657 void AlbumLister::slotImageChange(const ImageChangeset& changeset)
00658 {
00659     if (!d->currAlbum)
00660         return;
00661 
00662     // already scheduled to refresh?
00663     if (d->refreshTimer->isActive())
00664         return;
00665 
00666     if (d->currAlbum->type() == Album::SEARCH)
00667     {
00668         // For searches any touched field can require a refresh.
00669         // We cannot easily find out which fields are searched for, so we refresh for any change.
00670         foreach(const qlonglong& id, changeset.ids())
00671         {
00672             // if one matching image id is found, trigger a refresh
00673             if (d->itemListSet.contains(id))
00674             {
00675                 d->refreshTimer->start(100);
00676                 return;
00677             }
00678         }
00679     }
00680 
00681     // already scheduled to re-filter?
00682     if (d->filterTimer->isActive())
00683         return;
00684 
00685     // do we filter at all?
00686     if (!filterIsActive())
00687         return;
00688 
00689     // is one of the values affected that we filter by?
00690     DatabaseFields::Set set = changeset.changes();
00691     if (!(set & DatabaseFields::CreationDate) && !(set & DatabaseFields::Rating)
00692         && !(set & DatabaseFields::Category) && !(set & DatabaseFields::Format)
00693         && !(set & DatabaseFields::Name) && !(set & DatabaseFields::Comment))
00694         return;
00695 
00696     // is one of our images affected?
00697     foreach (const qlonglong& id, changeset.ids())
00698     {
00699         // if one matching image id is found, trigger a refilter
00700         if (d->itemListSet.contains(id))
00701         {
00702             d->filterTimer->start();
00703             return;
00704         }
00705     }
00706 }
00707 
00708 void AlbumLister::slotImageTagChange(const ImageTagChangeset& changeset)
00709 {
00710     if (!d->currAlbum)
00711         return;
00712 
00713     // already scheduled to refresh?
00714     if (d->refreshTimer->isActive())
00715         return;
00716 
00717     // already scheduled to re-filter?
00718     if (d->filterTimer->isActive())
00719         return;
00720 
00721     // do we filter at all?
00722     if (!tagFiltersIsActive())
00723         return;
00724 
00725     // is one of our images affected?
00726     foreach (const qlonglong& id, changeset.ids())
00727     {
00728         // if one matching image id is found, trigger a refresh
00729         if (d->itemListSet.contains(id))
00730         {
00731             d->filterTimer->start();
00732             return;
00733         }
00734     }
00735 }
00736 
00737 void AlbumLister::slotCollectionImageChange(const CollectionImageChangeset& changeset)
00738 {
00739     if (!d->currAlbum)
00740         return;
00741 
00742     // already scheduled to refresh?
00743     if (d->refreshTimer->isActive())
00744         return;
00745 
00746     bool doRefresh = false;
00747 
00748     switch (changeset.operation())
00749     {
00750         case CollectionImageChangeset::Added:
00751             switch(d->currAlbum->type())
00752             {
00753                 case Album::PHYSICAL:
00754                     // that's easy: try if our album is affected
00755                     doRefresh = changeset.containsAlbum(d->currAlbum->id());
00756                     break;
00757                 default:
00758                     // we cannot easily know if we are affected
00759                     doRefresh = true;
00760                     break;
00761             }
00762 
00763         case CollectionImageChangeset::Removed:
00764         case CollectionImageChangeset::RemovedAll:
00765             // is one of our images affected?
00766             foreach (const qlonglong& id, changeset.ids())
00767             {
00768                 // if one matching image id is found, trigger a refresh
00769                 if (d->itemListSet.contains(id))
00770                 {
00771                     doRefresh = true;
00772                     break;
00773                 }
00774             }
00775             break;
00776 
00777         default:
00778             break;
00779     }
00780 
00781     if (doRefresh)
00782     {
00783         // use timer: there may be several signals in a row
00784         if (!d->refreshTimer->isActive())
00785             d->refreshTimer->start(100);
00786     }
00787 }
00788 
00789 void AlbumLister::slotSearchChange(const SearchChangeset& changeset)
00790 {
00791     if (!d->currAlbum)
00792         return;
00793 
00794     if (changeset.operation() != SearchChangeset::Changed)
00795         return;
00796 
00797     SAlbum *album = AlbumManager::instance()->findSAlbum(changeset.searchId());
00798 
00799     if (album && d->currAlbum == album)
00800     {
00801         if (!d->refreshTimer->isActive())
00802             d->refreshTimer->start(100);
00803     }
00804 }
00805 
00806 }  // namespace Digikam

digikam

Skip menu "digikam"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • digikam
Generated for API Reference by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal