/* 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 #include "smdirmodel.h" #include "smdirwatcher.h" #include "smtreeitem.h" #include "helper.h" SmDirWatcher::SmDirWatcher(int numFields, QObject *parent) : QThread(parent), mFd(0), mDescr(0), mNumFields(numFields) { mBufLen = 1024 * (sizeof(struct inotify_event) + 16); mINdata = new char[mBufLen]; mFd = inotify_init(); mAsyncPool = new QThreadPool(this); } void SmDirWatcher::setDir(const QString &dir){ if(mDescr){ inotify_rm_watch(mFd, mDescr); //generates IN_IGNORE ??? } foreach(AsyncTask *s, mAsyncTasks){ s->skipMe(); } mAsyncPool->waitForDone(); foreach(AsyncTask *s, mAsyncTasks){ s->deleteLater(); } mAsyncTasks.clear(); mCurrent = dir; QDir d(mCurrent); SmTreeItem *rootItem = new SmTreeItem(mNumFields); foreach(QFileInfo fi, d.entryInfoList()){ if(fi.fileName() == "." || fi.fileName() == ".."){ continue; } QList data = generalData(fi.absoluteFilePath()); QString mime = data.at(SmDirModel::Type).toString(); SmTreeItem *newItem = new SmTreeItem(data, rootItem); rootItem->appendChild(newItem); Md5Summer *s = new Md5Summer(fi.absoluteFilePath()); s->setAutoDelete(false); connect(s, SIGNAL(md5sumDone(QString,QString)), this, SIGNAL(setMd5Sum(QString,QString))); mAsyncTasks.append(s); if(mime.startsWith("video")){ FfmpegGatherer *g = new FfmpegGatherer(fi.absoluteFilePath()); g->setAutoDelete(false); connect(g, SIGNAL(ffmpegDone(QString,QVariantMap)), this, SIGNAL(setFfmpeg(QString,QVariantMap))); mAsyncTasks.append(g); }else if(mime.startsWith("image")){ PicSizeGatherer *pg = new PicSizeGatherer(fi.absoluteFilePath()); pg->setAutoDelete(false); connect(pg, SIGNAL(picSizeDone(QString,QVariant)), this, SIGNAL(setPicSize(QString,QVariant))); mAsyncTasks.append(pg); } } emit population(rootItem); /* mask rationale: * IN_DELETE_SELF cannot happen since we're only * watching one directory at all time. * We don't care about the other events */ mDescr = inotify_add_watch(mFd, qPrintable(dir), IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO); } void SmDirWatcher::startAsyncJobs(){ foreach(AsyncTask *s, mAsyncTasks){ mAsyncPool->start(s); } } void SmDirWatcher::gatherAsync(const QString &path){ QString mimeType = Helper::mimeType(path); Md5Summer *s = new Md5Summer(path); connect(s, SIGNAL(md5sumDone(QString,QString)), this, SIGNAL(setMd5Sum(QString,QString))); mAsyncPool->start(s); if(mimeType.startsWith("video")){ FfmpegGatherer *g = new FfmpegGatherer(path); connect(g, SIGNAL(ffmpegDone(QString,QVariantMap)), this, SIGNAL(setFfmpeg(QString,QVariantMap))); mAsyncPool->start(g); }else if(mimeType.startsWith("image")){ PicSizeGatherer *ps = new PicSizeGatherer(path); connect(ps, SIGNAL(picSizeDone(QString,QVariant)), this, SIGNAL(setPicSize(QString,QVariant))); mAsyncPool->start(ps); } } QList SmDirWatcher::generalData(const QString &path){ QFileInfo fi(path); QList data; data << fi.fileName() << fi.size(); QString mime = Helper::mimeType(fi.absoluteFilePath()); data << mime; data << fi.lastModified(); data << QVariant() << QVariant() << QVariant(); data << fi.absoluteFilePath() << 0; return data; } void SmDirWatcher::run(){ int r = read(mFd, mINdata, mBufLen); if(r <= 0){ return; } int i = 0; while(i < r){ inotify_event *e = reinterpret_cast(&mINdata[i]); if((!e->len) || (e->mask & IN_IGNORED)){ i += sizeof(inotify_event) + e->len; continue; } quint32 mask = e->mask; QString name = QString("%1/%2").arg(mCurrent).arg(e->name); QList d = generalData(name); if(mask & IN_CREATE || mask & IN_MOVED_TO){ emit newData(d, Added); }else if(mask & IN_DELETE || mask & IN_MOVED_FROM){ emit newData(d, Deleted); }else if(mask & IN_MODIFY){ emit newData(d, Modified); }else if(mask & IN_CLOSE_WRITE){ emit newData(d, CloseWrite); } i += sizeof(inotify_event) + e->len; } } void SmDirWatcher::stop(){ quit(); } AsyncTask::AsyncTask(const QString &path) : mSkip(false), mPath(path) {} bool AsyncTask::skipMe(){ if(mStatusMx.tryLock()){ mSkip = true; mStatusMx.unlock(); return true; } return false; } #include Md5Summer::Md5Summer(const QString &path) : AsyncTask(path) {} void Md5Summer::run(){ mStatusMx.lock(); bool skip = mSkip; mStatusMx.unlock(); if(skip){ return; } QString md5 = Helper::md5Sum(mPath); emit md5sumDone(mPath, md5); } FfmpegGatherer::FfmpegGatherer(const QString &path) : AsyncTask(path) {} void FfmpegGatherer::run(){ mStatusMx.lock(); bool skip = mSkip; mStatusMx.unlock(); if(skip){ return; } QVariantMap retval = Helper::ffmpegData(mPath); emit ffmpegDone(mPath, retval); } PicSizeGatherer::PicSizeGatherer(const QString &path) : AsyncTask(path) {} void PicSizeGatherer::run(){ mStatusMx.lock(); bool skip = mSkip; mStatusMx.unlock(); if(skip){ return; } QVariant retval = Helper::picSize(mPath); emit picSizeDone(mPath, retval); }