/*************************************************************************** begin : Sun Feb 29 2004 copyright : (C) 2004 by Scott Wheeler email : wheeler@kde.org ***************************************************************************/ /*************************************************************************** * * * 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 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "filehandle.h" #include "filehandleproperties.h" #include "tag.h" #include "cache.h" #include "coverinfo.h" AddProperty(Title, tag()->title()) AddProperty(Artist, tag()->artist()) AddProperty(Album, tag()->album()) AddProperty(Genre, tag()->genre()) AddNumberProperty(Track, tag()->track()) AddNumberProperty(Year, tag()->year()) AddProperty(Comment, tag()->comment()) AddNumberProperty(Seconds, tag()->seconds()) AddNumberProperty(Bitrate, tag()->bitrate()) AddProperty(Path, absFilePath()) AddNumberProperty(Size, fileInfo().size()) AddProperty(Extension, fileInfo().extension(false)) static TQString resolveSymLinks(const TQFileInfo &file) // static { char real[PATH_MAX]; if(file.exists() && realpath(TQFile::encodeName(file.absFilePath()).data(), real)) return TQFile::decodeName(real); else return file.filePath(); } /** * A simple reference counter -- pasted from TagLib. */ class RefCounter { public: RefCounter() : refCount(1) {} void ref() { refCount++; } bool deref() { return ! --refCount ; } int count() const { return refCount; } private: uint refCount; }; class FileHandle::FileHandlePrivate : public RefCounter { public: FileHandlePrivate() : tag(0), coverInfo(0) {} ~FileHandlePrivate() { delete tag; delete coverInfo; } mutable Tag *tag; mutable CoverInfo *coverInfo; mutable TQString absFilePath; TQFileInfo fileInfo; TQDateTime modificationTime; TQDateTime lastModified; }; //////////////////////////////////////////////////////////////////////////////// // public methods //////////////////////////////////////////////////////////////////////////////// FileHandle::FileHandle() { static FileHandlePrivate nullPrivate; d = &nullPrivate; d->ref(); } FileHandle::FileHandle(const FileHandle &f) : d(f.d) { if(!d) { kdDebug(65432) << "The source FileHandle was not initialized." << endl; d = null().d; } d->ref(); } FileHandle::FileHandle(const TQFileInfo &info, const TQString &path) : d(0) { setup(info, path); } FileHandle::FileHandle(const TQString &path) : d(0) { setup(TQFileInfo(path), path); } FileHandle::FileHandle(const TQString &path, CacheDataStream &s) { d = new FileHandlePrivate; d->fileInfo = TQFileInfo(path); d->absFilePath = path; read(s); Cache::instance()->insert(*this); } FileHandle::~FileHandle() { if(d->deref()) delete d; } void FileHandle::refresh() { d->fileInfo.refresh(); delete d->tag; d->tag = new Tag(d->absFilePath); } void FileHandle::setFile(const TQString &path) { if(!d || isNull()) setup(TQFileInfo(path), path); else { d->absFilePath = resolveSymLinks(path); d->fileInfo.setFile(path); d->tag->setFileName(d->absFilePath); } } Tag *FileHandle::tag() const { if(!d->tag) d->tag = new Tag(d->absFilePath); return d->tag; } CoverInfo *FileHandle::coverInfo() const { if(!d->coverInfo) d->coverInfo = new CoverInfo(*this); return d->coverInfo; } TQString FileHandle::absFilePath() const { if(d->absFilePath.isNull()) d->absFilePath = resolveSymLinks(d->fileInfo.absFilePath()); return d->absFilePath; } const TQFileInfo &FileHandle::fileInfo() const { return d->fileInfo; } bool FileHandle::isNull() const { return *this == null(); } bool FileHandle::current() const { return (d->modificationTime.isValid() && lastModified().isValid() && d->modificationTime >= lastModified()); } const TQDateTime &FileHandle::lastModified() const { if(d->lastModified.isNull()) d->lastModified = d->fileInfo.lastModified(); return d->lastModified; } void FileHandle::read(CacheDataStream &s) { switch(s.cacheVersion()) { case 1: default: if(!d->tag) d->tag = new Tag(d->absFilePath, true); s >> *(d->tag); s >> d->modificationTime; break; } } FileHandle &FileHandle::operator=(const FileHandle &f) { if(&f == this) return *this; if(d->deref()) delete d; d = f.d; d->ref(); return *this; } bool FileHandle::operator==(const FileHandle &f) const { return d == f.d; } bool FileHandle::operator!=(const FileHandle &f) const { return d != f.d; } TQStringList FileHandle::properties() // static { return FileHandleProperties::properties(); } TQString FileHandle::property(const TQString &name) const { return FileHandleProperties::property(*this, name.latin1()); } const FileHandle &FileHandle::null() // static { static FileHandle f; return f; } //////////////////////////////////////////////////////////////////////////////// // private methods //////////////////////////////////////////////////////////////////////////////// void FileHandle::setup(const TQFileInfo &info, const TQString &path) { if(d && !isNull()) return; TQString fileName = path.isNull() ? info.absFilePath() : path; FileHandle cached = Cache::instance()->value(resolveSymLinks(fileName)); if(cached != null()) { d = cached.d; d->ref(); } else { d = new FileHandlePrivate; d->fileInfo = info; d->absFilePath = resolveSymLinks(fileName); d->modificationTime = info.lastModified(); Cache::instance()->insert(*this); } } //////////////////////////////////////////////////////////////////////////////// // related functions //////////////////////////////////////////////////////////////////////////////// TQDataStream &operator<<(TQDataStream &s, const FileHandle &f) { s << *(f.tag()) << f.lastModified(); return s; } CacheDataStream &operator>>(CacheDataStream &s, FileHandle &f) { f.read(s); return s; }