You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/digikam/kipiinterface.cpp

725 lines
18 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2004-08-02
* Description : digiKam kipi library interface.
*
* Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
* Copyright (C) 2004-2005 by Ralf Holzer <ralf at well.com>
* Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// C Ansi includes
extern "C"
{
#include <sys/types.h>
#include <utime.h>
}
// TQt includes.
#include <tqdir.h>
#include <tqdatetime.h>
#include <tqfileinfo.h>
#include <tqfile.h>
#include <tqregexp.h>
// KDE includes.
#include <tdelocale.h>
#include <tdeconfig.h>
#include <tdefilemetainfo.h>
#include <tdeio/netaccess.h>
// libKipi includes.
#include <libkipi/version.h>
// Local includes.
#include "constants.h"
#include "ddebug.h"
#include "albummanager.h"
#include "albumitemhandler.h"
#include "album.h"
#include "albumdb.h"
#include "albumsettings.h"
#include "dmetadata.h"
#include "imageattributeswatch.h"
#include "kipiinterface.h"
#include "kipiinterface.moc"
namespace Digikam
{
//-- Image Info ------------------------------------------------------------------
DigikamImageInfo::DigikamImageInfo( KIPI::Interface* interface, const KURL& url )
: KIPI::ImageInfoShared( interface, url ), palbum_(0)
{
}
DigikamImageInfo::~DigikamImageInfo()
{
}
PAlbum* DigikamImageInfo::parentAlbum()
{
if (!palbum_)
{
KURL u(_url.directory());
palbum_ = AlbumManager::instance()->findPAlbum(u);
}
return palbum_;
}
TQString DigikamImageInfo::title()
{
return _url.fileName();
}
TQString DigikamImageInfo::description()
{
PAlbum* p = parentAlbum();
if (p)
{
AlbumDB* db = AlbumManager::instance()->albumDB();
return db->getItemCaption(p->id(), _url.fileName());
}
return TQString();
}
void DigikamImageInfo::setTitle( const TQString& newName )
{
// Here we get informed that a plugin has renamed the file
PAlbum* p = parentAlbum();
if ( p && !newName.isEmpty() )
{
AlbumDB* db = AlbumManager::instance()->albumDB();
db->moveItem(p->id(), _url.fileName(), p->id(), newName);
_url = _url.upURL();
_url.addPath(newName);
}
}
void DigikamImageInfo::setDescription( const TQString& description )
{
PAlbum* p = parentAlbum();
if ( p )
{
AlbumDB* db = AlbumManager::instance()->albumDB();
TQ_LLONG imageId = db->getImageId(p->id(), _url.filename());
db->setItemCaption(imageId, description);
ImageAttributesWatch::instance()->imageCaptionChanged(imageId);
// See B.K.O #140133. Do not set here metadata comments of picture.
// Only the database comments must be set.
}
}
TQDateTime DigikamImageInfo::time( KIPI::TimeSpec /*spec*/ )
{
PAlbum* p = parentAlbum();
if (p)
{
AlbumDB* db = AlbumManager::instance()->albumDB();
return db->getItemDate(p->id(), _url.fileName());
}
return TQDateTime();
}
void DigikamImageInfo::setTime(const TQDateTime& time, KIPI::TimeSpec)
{
if ( !time.isValid() )
{
DWarning() << k_funcinfo << "Invalid datetime specified" << endl;
return;
}
PAlbum* p = parentAlbum();
if ( p )
{
AlbumDB* db = AlbumManager::instance()->albumDB();
TQ_LLONG imageId = db->getImageId(p->id(), _url.filename());
db->setItemDate(imageId, time);
ImageAttributesWatch::instance()->imageDateChanged(imageId);
AlbumManager::instance()->refreshItemHandler( _url );
}
}
void DigikamImageInfo::cloneData( ImageInfoShared* other )
{
setDescription( other->description() );
setTime( other->time(KIPI::FromInfo), KIPI::FromInfo );
addAttributes( other->attributes() );
}
TQStringVariantMap DigikamImageInfo::attributes()
{
TQStringVariantMap res;
PAlbum* p = parentAlbum();
if (p)
{
AlbumDB* db = AlbumManager::instance()->albumDB();
TQ_LLONG imageId = db->getImageId(p->id(), _url.filename());
// Get digiKam Tags list of picture.
TQStringList tags = db->getItemTagNames(imageId);
res["tags"] = tags;
// Get digiKam Rating of picture.
int rating = db->getItemRating(imageId);
res["rating"] = rating;
// TODO: add here future picture attributes stored by digiKam database
}
return res;
}
void DigikamImageInfo::addAttributes(const TQStringVariantMap& res)
{
PAlbum* p = parentAlbum();
if (p)
{
AlbumDB* db = AlbumManager::instance()->albumDB();
TQ_LLONG imageId = db->getImageId(p->id(), _url.filename());
TQStringVariantMap attributes = res;
// Set digiKam Tags list of picture.
if (attributes.find("tags") != attributes.end())
{
TQStringList tags = attributes["tags"].asStringList();
//TODO
}
// Set digiKam Rating of picture.
if (attributes.find("rating") != attributes.end())
{
int rating = attributes["rating"].asInt();
if (rating >= RatingMin && rating <= RatingMax)
db->setItemRating(imageId, rating);
}
// TODO: add here future picture attributes stored by digiKam database
}
// To update sidebar content. Some kipi-plugins use this way to refresh sidebar
// using an empty TQMap().
ImageAttributesWatch::instance()->fileMetadataChanged(_url);
}
void DigikamImageInfo::clearAttributes()
{
// TODO ! This will used for the futures tags digiKam features.
}
int DigikamImageInfo::angle()
{
AlbumSettings *settings = AlbumSettings::instance();
if (settings->getExifRotate())
{
DMetadata metadata(_url.path());
DMetadata::ImageOrientation orientation = metadata.getImageOrientation();
switch (orientation)
{
case DMetadata::ORIENTATION_ROT_180:
return 180;
case DMetadata::ORIENTATION_ROT_90:
case DMetadata::ORIENTATION_ROT_90_HFLIP:
case DMetadata::ORIENTATION_ROT_90_VFLIP:
return 90;
case DMetadata::ORIENTATION_ROT_270:
return 270;
default:
return 0;
}
}
return 0;
}
void DigikamImageInfo::setAngle( int )
{
// TODO : add here a DMetadata call (thru Exiv2) to set Exif orientation tag.
}
//-- Image Collection ------------------------------------------------------------
DigikamImageCollection::DigikamImageCollection( Type tp, Album* album, const TQString& filter )
: tp_( tp ), album_(album), imgFilter_(filter)
{
if (!album)
{
DWarning() << k_funcinfo << "This should not happen. No album specified" << endl;
}
}
DigikamImageCollection::~DigikamImageCollection()
{
}
TQString DigikamImageCollection::name()
{
if ( album_->type() == Album::TAG )
{
return i18n("Tag: %1").arg(album_->title());
}
else
return album_->title();
}
TQString DigikamImageCollection::category()
{
if ( album_->type() == Album::PHYSICAL )
{
PAlbum *p = dynamic_cast<PAlbum*>(album_);
return p->collection();
}
else if ( album_->type() == Album::TAG )
{
TAlbum *p = dynamic_cast<TAlbum*>(album_);
return i18n("Tag: %1").arg(p->tagPath());
}
else
return TQString();
}
TQDate DigikamImageCollection::date()
{
if ( album_->type() == Album::PHYSICAL )
{
PAlbum *p = dynamic_cast<PAlbum*>(album_);
return p->date();
}
else
return TQDate();
}
TQString DigikamImageCollection::comment()
{
if ( album_->type() == Album::PHYSICAL )
{
PAlbum *p = dynamic_cast<PAlbum*>(album_);
return p->caption();
}
else
return TQString();
}
static TQValueList<TQRegExp> makeFilterList( const TQString &filter )
{
TQValueList<TQRegExp> regExps;
if ( filter.isEmpty() )
return regExps;
TQChar sep( ';' );
int i = filter.find( sep, 0 );
if ( i == -1 && filter.find( ' ', 0 ) != -1 )
sep = TQChar( ' ' );
TQStringList list = TQStringList::split( sep, filter );
TQStringList::Iterator it = list.begin();
while ( it != list.end() )
{
regExps << TQRegExp( (*it).stripWhiteSpace(), false, true );
++it;
}
return regExps;
}
static bool matchFilterList( const TQValueList<TQRegExp>& filters, const TQString &fileName )
{
TQValueList<TQRegExp>::ConstIterator rit = filters.begin();
while ( rit != filters.end() )
{
if ( (*rit).exactMatch(fileName) )
return true;
++rit;
}
return false;
}
KURL::List DigikamImageCollection::images()
{
switch ( tp_ )
{
case AllItems:
{
if (album_->type() == Album::PHYSICAL)
{
return imagesFromPAlbum(dynamic_cast<PAlbum*>(album_));
}
else if (album_->type() == Album::TAG)
{
return imagesFromTAlbum(dynamic_cast<TAlbum*>(album_));
}
else if (album_->type() == Album::DATE ||
album_->type() == Album::SEARCH)
{
AlbumItemHandler* handler = AlbumManager::instance()->getItemHandler();
if (handler)
{
return handler->allItems();
}
return KURL::List();
}
else
{
DWarning() << k_funcinfo << "Unknown album type" << endl;
return KURL::List();
}
break;
}
case SelectedItems:
{
AlbumItemHandler* handler = AlbumManager::instance()->getItemHandler();
if (handler)
{
return handler->selectedItems();
}
return KURL::List();
break;
}
default:
break;
}
// We should never reach here
return KURL::List();
}
/** get the images from the Physical album in database and return the items found */
KURL::List DigikamImageCollection::imagesFromPAlbum(PAlbum* album) const
{
// get the images from the database and return the items found
AlbumDB* db = AlbumManager::instance()->albumDB();
db->beginTransaction();
TQStringList urls = db->getItemURLsInAlbum(album->id());
db->commitTransaction();
KURL::List urlList;
TQValueList<TQRegExp> regex = makeFilterList(imgFilter_);
for (TQStringList::iterator it = urls.begin(); it != urls.end(); ++it)
{
if (matchFilterList(regex, *it))
urlList.append(*it);
}
return urlList;
}
/** get the images from the Tags album in database and return the items found */
KURL::List DigikamImageCollection::imagesFromTAlbum(TAlbum* album) const
{
AlbumDB* db = AlbumManager::instance()->albumDB();
db->beginTransaction();
TQStringList urls = db->getItemURLsInTag(album->id());
db->commitTransaction();
KURL::List urlList;
TQValueList<TQRegExp> regex = makeFilterList(imgFilter_);
for (TQStringList::iterator it = urls.begin(); it != urls.end(); ++it)
{
if (matchFilterList(regex, *it))
urlList.append(*it);
}
return urlList;
}
KURL DigikamImageCollection::path()
{
if (album_->type() == Album::PHYSICAL)
{
PAlbum *p = dynamic_cast<PAlbum*>(album_);
KURL url;
url.setPath(p->folderPath());
return url;
}
else
{
DWarning() << k_funcinfo << "Requesting kurl from a virtual album" << endl;
return TQString();
}
}
KURL DigikamImageCollection::uploadPath()
{
if (album_->type() == Album::PHYSICAL)
{
PAlbum *p = dynamic_cast<PAlbum*>(album_);
KURL url;
url.setPath(p->folderPath());
return url;
}
else
{
DWarning() << k_funcinfo << "Requesting kurl from a virtual album" << endl;
return KURL();
}
}
KURL DigikamImageCollection::uploadRoot()
{
return KURL(AlbumManager::instance()->getLibraryPath() + '/');
}
TQString DigikamImageCollection::uploadRootName()
{
return i18n("My Albums");
}
bool DigikamImageCollection::isDirectory()
{
if (album_->type() == Album::PHYSICAL)
return true;
else
return false;
}
bool DigikamImageCollection::operator==(ImageCollectionShared& imgCollection)
{
DigikamImageCollection* thatCollection = static_cast<DigikamImageCollection*>(&imgCollection);
return (album_ == thatCollection->album_);
}
//-- LibKipi interface -----------------------------------------------------------
DigikamKipiInterface::DigikamKipiInterface( TQObject *parent, const char *name)
: KIPI::Interface( parent, name )
{
albumManager_ = AlbumManager::instance();
albumDB_ = albumManager_->albumDB();
connect( albumManager_, TQ_SIGNAL( signalAlbumItemsSelected( bool ) ),
this, TQ_SLOT( slotSelectionChanged( bool ) ) );
connect( albumManager_, TQ_SIGNAL( signalAlbumCurrentChanged(Album*) ),
this, TQ_SLOT( slotCurrentAlbumChanged(Album*) ) );
}
DigikamKipiInterface::~DigikamKipiInterface()
{
}
KIPI::ImageCollection DigikamKipiInterface::currentAlbum()
{
Album* currAlbum = albumManager_->currentAlbum();
if ( currAlbum )
{
return KIPI::ImageCollection(
new DigikamImageCollection( DigikamImageCollection::AllItems,
currAlbum, fileExtensions() ) );
}
else
{
return KIPI::ImageCollection(0);
}
}
KIPI::ImageCollection DigikamKipiInterface::currentSelection()
{
Album* currAlbum = albumManager_->currentAlbum();
if ( currAlbum )
{
return KIPI::ImageCollection(
new DigikamImageCollection( DigikamImageCollection::SelectedItems,
currAlbum, fileExtensions() ) );
}
else
{
return KIPI::ImageCollection(0);
}
}
TQValueList<KIPI::ImageCollection> DigikamKipiInterface::allAlbums()
{
TQValueList<KIPI::ImageCollection> result;
TQString fileFilter(fileExtensions());
AlbumList palbumList = albumManager_->allPAlbums();
for ( AlbumList::Iterator it = palbumList.begin();
it != palbumList.end(); ++it )
{
// don't add the root album
if ((*it)->isRoot())
continue;
DigikamImageCollection* col = new DigikamImageCollection( DigikamImageCollection::AllItems,
*it, fileFilter );
result.append( KIPI::ImageCollection( col ) );
}
AlbumList talbumList = albumManager_->allTAlbums();
for ( AlbumList::Iterator it = talbumList.begin();
it != talbumList.end(); ++it )
{
// don't add the root album
if ((*it)->isRoot())
continue;
DigikamImageCollection* col = new DigikamImageCollection( DigikamImageCollection::AllItems,
*it, fileFilter );
result.append( KIPI::ImageCollection( col ) );
}
return result;
}
KIPI::ImageInfo DigikamKipiInterface::info( const KURL& url )
{
return KIPI::ImageInfo( new DigikamImageInfo( this, url ) );
}
void DigikamKipiInterface::refreshImages( const KURL::List& urls )
{
KURL::List ulist = urls;
// Re-scan metadata from pictures. This way will update Metadata sidebar and database.
for ( KURL::List::Iterator it = ulist.begin() ; it != ulist.end() ; ++it )
ImageAttributesWatch::instance()->fileMetadataChanged(*it);
// Refresh preview.
albumManager_->refreshItemHandler(urls);
}
int DigikamKipiInterface::features() const
{
return (
// HostSupportsTags feature require libkipi version > 1.4.0
#if KIPI_VERSION>0x000104
KIPI::HostSupportsTags |
#endif
KIPI::ImagesHasComments | KIPI::AcceptNewImages |
KIPI::AlbumsHaveComments | KIPI::ImageTitlesWritable |
KIPI::ImagesHasTime | KIPI::AlbumsHaveCategory |
KIPI::AlbumsHaveCreationDate | KIPI::AlbumsUseFirstImagePreview
);
}
bool DigikamKipiInterface::addImage( const KURL& url, TQString& errmsg )
{
// Nota : All copy/move operations are processed by the plugins.
if ( url.isValid() == false )
{
errmsg = i18n("Target URL %1 is not valid.").arg(url.path());
return false;
}
PAlbum *targetAlbum = albumManager_->findPAlbum(url.directory());
if ( !targetAlbum )
{
errmsg = i18n("Target album is not in the album library.");
return false;
}
albumManager_->refreshItemHandler( url );
return true;
}
void DigikamKipiInterface::delImage( const KURL& url )
{
KURL rootURL(albumManager_->getLibraryPath());
if ( !rootURL.isParentOf(url) )
{
DWarning() << k_funcinfo << "URL not in the album library" << endl;
}
// Is there a PAlbum for this url
PAlbum *palbum = albumManager_->findPAlbum( KURL(url.directory()) );
if ( palbum )
{
// delete the item from the database
albumDB_->deleteItem( palbum->id(), url.fileName() );
}
else
{
DWarning() << k_funcinfo << "Cannot find Parent album in album library" << endl;
}
}
void DigikamKipiInterface::slotSelectionChanged( bool b )
{
emit selectionChanged( b );
}
void DigikamKipiInterface::slotCurrentAlbumChanged( Album *album )
{
emit currentAlbumChanged( album != 0 );
}
TQString DigikamKipiInterface::fileExtensions()
{
// do not save this into a local variable, as this
// might change in the main app
AlbumSettings* s = AlbumSettings::instance();
return (s->getImageFileFilter() + ' ' +
s->getMovieFileFilter() + ' ' +
s->getAudioFileFilter() + ' ' +
s->getRawFileFilter());
}
} // namespace Digikam