filehandle.cpp 6.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/**
 * Copyright (C) 2004 Scott Wheeler <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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
16

17
#include "filehandle.h"
18

19 20 21 22
#include <QFileInfo>

#include <limits.h>
#include <stdlib.h>
23

24
#include "filehandleproperties.h"
25
#include "tag.h"
26
#include "cache.h"
27
#include "coverinfo.h"
Michael Pyne's avatar
Michael Pyne committed
28
#include "juk_debug.h"
29

Dirk Mueller's avatar
Dirk Mueller committed
30 31 32 33 34 35 36 37 38 39 40
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())
41
AddProperty(Extension, fileInfo().suffix())
42

43 44 45 46
static QString resolveSymLinks(const QFileInfo &file) // static
{
    char real[PATH_MAX];

47
    if(file.exists() && realpath(QFile::encodeName(file.absoluteFilePath()).data(), real))
48
        return QFile::decodeName(real);
49
    else
50
        return file.filePath();
51 52
}

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/**
 * 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() :
72
        tag(0),
73
        coverInfo(0) {}
74

Scott Wheeler's avatar
Scott Wheeler committed
75 76 77
    ~FileHandlePrivate()
    {
        delete tag;
78
        delete coverInfo;
Scott Wheeler's avatar
Scott Wheeler committed
79 80
    }

81
    mutable Tag *tag;
82
    mutable CoverInfo *coverInfo;
83
    mutable QString absFilePath;
84 85 86
    QFileInfo fileInfo;
    QDateTime modificationTime;
    QDateTime lastModified;
87 88 89 90 91 92 93 94
};

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

FileHandle::FileHandle()
{
95 96
    static FileHandlePrivate nullPrivate;
    d = &nullPrivate;
97
    d->ref();
98 99
}

100 101
FileHandle::FileHandle(const FileHandle &f) :
    d(f.d)
102
{
103
    if(!d) {
Michael Pyne's avatar
Michael Pyne committed
104
        qCDebug(JUK_LOG) << "The source FileHandle was not initialized.";
105
        d = null().d;
106
    }
107 108 109
    d->ref();
}

110 111
FileHandle::FileHandle(const QFileInfo &info, const QString &path) :
    d(0)
112
{
113
    setup(info, path);
114 115
}

116 117
FileHandle::FileHandle(const QString &path) :
    d(0)
118
{
119
    setup(QFileInfo(path), path);
120 121
}

122 123 124
FileHandle::FileHandle(const QString &path, CacheDataStream &s)
{
    d = new FileHandlePrivate;
125
    if(!QFile::exists(path)) {
Michael Pyne's avatar
Michael Pyne committed
126
        qCWarning(JUK_LOG) << "File" << path << "no longer exists!";
127 128
        return;
    }
129
    d->fileInfo = QFileInfo(path);
130
    d->absFilePath = path;
131 132 133
    read(s);
}

134 135 136 137 138 139
FileHandle::~FileHandle()
{
    if(d->deref())
        delete d;
}

140 141 142 143
void FileHandle::refresh()
{
    d->fileInfo.refresh();
    delete d->tag;
144
    d->tag = new Tag(d->absFilePath);
145 146
}

147 148
void FileHandle::setFile(const QString &path)
{
Michael Pyne's avatar
Michael Pyne committed
149
    if(path.isEmpty()) {
150
        qCCritical(JUK_LOG) << "trying to set an empty path";
Michael Pyne's avatar
Michael Pyne committed
151 152 153 154
        return;
    }

    if(!QFile::exists(path)) {
155
        qCCritical(JUK_LOG) << "trying to set non-existent file: " << path;
Michael Pyne's avatar
Michael Pyne committed
156 157 158
        return;
    }

159 160 161
    if(!d || isNull())
        setup(QFileInfo(path), path);
    else {
162
        d->absFilePath = resolveSymLinks(path);
163
        d->fileInfo.setFile(path);
164
        d->tag->setFileName(d->absFilePath);
165
    }
166 167
}

168 169
Tag *FileHandle::tag() const
{
170
    if(!d->tag)
171
        d->tag = new Tag(d->absFilePath);
172

173 174 175
    return d->tag;
}

176 177 178
CoverInfo *FileHandle::coverInfo() const
{
    if(!d->coverInfo)
179
        d->coverInfo = new CoverInfo(*this);
180 181 182 183

    return d->coverInfo;
}

184 185
QString FileHandle::absFilePath() const
{
186
    if(d->absFilePath.isEmpty())
187
        d->absFilePath = resolveSymLinks(d->fileInfo.absoluteFilePath());
188 189 190 191 192 193 194 195
    return d->absFilePath;
}

const QFileInfo &FileHandle::fileInfo() const
{
    return d->fileInfo;
}

196 197 198 199 200
bool FileHandle::isNull() const
{
    return *this == null();
}

201 202
bool FileHandle::current() const
{
203 204 205
    return (d->modificationTime.isValid() &&
            lastModified().isValid() &&
            d->modificationTime >= lastModified());
206 207 208 209
}

const QDateTime &FileHandle::lastModified() const
{
210 211 212 213 214 215 216 217 218 219 220 221
    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)
222
            d->tag = new Tag(d->absFilePath, true);
223

224 225 226 227
        s >> *(d->tag);
        s >> d->modificationTime;
        break;
    }
228 229
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
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;
}
248 249 250 251 252 253

bool FileHandle::operator!=(const FileHandle &f) const
{
    return d != f.d;
}

254 255 256 257 258 259 260
QStringList FileHandle::properties() // static
{
    return FileHandleProperties::properties();
}

QString FileHandle::property(const QString &name) const
{
Michael Pyne's avatar
Michael Pyne committed
261
    return FileHandleProperties::property(*this, name.toUtf8());
262 263
}

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
const FileHandle &FileHandle::null() // static
{
    static FileHandle f;
    return f;
}

////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////

void FileHandle::setup(const QFileInfo &info, const QString &path)
{
    if(d && !isNull())
        return;

279
    QString fileName = path.isEmpty() ? info.absoluteFilePath() : path;
280

281 282 283 284 285
    d = new FileHandlePrivate;
    d->fileInfo = info;
    d->absFilePath = resolveSymLinks(fileName);
    d->modificationTime = info.lastModified();
    if(!info.exists())
Michael Pyne's avatar
Michael Pyne committed
286
        qCWarning(JUK_LOG) << "File" << path << "no longer exists!";
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
}

////////////////////////////////////////////////////////////////////////////////
// related functions
////////////////////////////////////////////////////////////////////////////////

QDataStream &operator<<(QDataStream &s, const FileHandle &f)
{
    s << *(f.tag())
      << f.lastModified();

    return s;
}

CacheDataStream &operator>>(CacheDataStream &s, FileHandle &f)
{
    f.read(s);
    return s;
}
306 307

// vim: set et sw=4 tw=0 sta: