diff options
author | Arno <am@disconnect.de> | 2013-09-03 06:12:33 +0200 |
---|---|---|
committer | Arno <am@disconnect.de> | 2013-09-03 06:12:33 +0200 |
commit | 130e0a3115cd66e38ec57846e06f69e7fd284400 (patch) | |
tree | dd2a1cd7eaa32d1f515ec45bdc009e7cbbb354aa | |
parent | 3f0a819948d36d06f1ddf07e5a51ff771ddda4da (diff) | |
download | SheMov-130e0a3115cd66e38ec57846e06f69e7fd284400.tar.gz SheMov-130e0a3115cd66e38ec57846e06f69e7fd284400.tar.bz2 SheMov-130e0a3115cd66e38ec57846e06f69e7fd284400.zip |
Switch to QRunnable + QThreadPool
Get rid of SmDataCollector and do its job in small, QRunnable tasks and
let QThreadPool manage the treads.
Works well with a local Filesystem. Yet to see how it works over
networked Filesystems.
Ah, before I forget: NEVER, EVER USE QPixmap in THREADS -> Random
crashes! (Yes, I know, it's documented...)
-rw-r--r-- | filesystemwidget.cpp | 35 | ||||
-rw-r--r-- | filesystemwidget.h | 9 | ||||
-rw-r--r-- | fileview.cpp | 4 | ||||
-rw-r--r-- | helper.cpp | 6 | ||||
-rw-r--r-- | shemov.pro | 2 | ||||
-rw-r--r-- | smdirmodel.cpp | 71 | ||||
-rw-r--r-- | smdirmodel.h | 12 | ||||
-rw-r--r-- | smdirwatcher.cpp | 255 | ||||
-rw-r--r-- | smdirwatcher.h | 93 |
9 files changed, 256 insertions, 231 deletions
diff --git a/filesystemwidget.cpp b/filesystemwidget.cpp index 24d9ec3..64f5ee8 100644 --- a/filesystemwidget.cpp +++ b/filesystemwidget.cpp @@ -43,10 +43,6 @@ FilesystemWidget::FilesystemWidget(QWidget *parent) : QWidget(parent), mClipboar mFileModel = new SmDirModel(fHeaders, this); connect(mFileModel, SIGNAL(needResize()), this, SLOT(resizeFileView())); - mProgressDlg = 0; - connect(mFileModel->collector(), SIGNAL(totalFiles(int)), this, SLOT(setupProgressDlg(int))); - connect(mFileModel->collector(), SIGNAL(progress()), this, SLOT(progress())); - mDirProxy = new FilesystemDirProxy; mDirProxy->setSourceModel(mModel); mDirView = new SmTreeView; @@ -171,7 +167,7 @@ void FilesystemWidget::fileViewActivated(const QModelIndex &idx){ /* we cannot use idx from the SIGNAL here, since the model * may already have changed */ Q_UNUSED(idx); - TimerHandler h(mFileModel->refresTimer()); + TimerHandler h(mFileModel->refreshTimer()); QModelIndexList selected = mFileView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; @@ -229,7 +225,7 @@ void FilesystemWidget::goBack(){ } void FilesystemWidget::deleteFiles(){ - TimerHandler h(mFileModel->refresTimer()); + TimerHandler h(mFileModel->refreshTimer()); QSortFilterProxyModel *proxy = qobject_cast<QSortFilterProxyModel*>(mFileView->model()); QModelIndexList selected = mFileView->selectionModel()->selectedRows(); if(selected.isEmpty()){ @@ -247,7 +243,7 @@ void FilesystemWidget::deleteFiles(){ } void FilesystemWidget::toClipboard(int clipmode){ - TimerHandler h(mFileModel->refresTimer()); + TimerHandler h(mFileModel->refreshTimer()); mClipboardMode = clipmode; QClipboard *clip = qApp->clipboard(); QModelIndexList selected = mFileView->selectionModel()->selectedRows(); @@ -294,7 +290,7 @@ void FilesystemWidget::fromClipboard(){ } void FilesystemWidget::renameFile(){ - TimerHandler h(mFileModel->refresTimer()); + TimerHandler h(mFileModel->refreshTimer()); QModelIndex curIdx = mFileView->currentIndex(); if(curIdx.data().toString() == ".."){ return; @@ -303,7 +299,7 @@ void FilesystemWidget::renameFile(){ } void FilesystemWidget::playSelected(const QString &player){ - TimerHandler h(mFileModel->refresTimer()); + TimerHandler h(mFileModel->refreshTimer()); QStringList files = selectedFiles(); if(files.isEmpty()){ statusbarMessage(tr("Nothing selected.")); @@ -436,27 +432,6 @@ void FilesystemWidget::setWindowTitle(){ emit windowTitle(mWindowTitle); } -void FilesystemWidget::setupProgressDlg(int max){ - if(max <= 0){ - return; - } - if(!mProgressDlg){ - mProgressDlg = new QProgressDialog(this); - mProgressDlg->setLabel(new QLabel(tr("Gathering data... please wait!"))); - } - mProgressDlg->setMinimum(1); - mProgressDlg->setMaximum(max); - Helper::centerWidget(mProgressDlg); - mProgressDlg->show(); -} - -void FilesystemWidget::progress(){ - mProgressDlg->setValue(mProgressDlg->value() + 1); - if(mProgressDlg->value() >= mProgressDlg->maximum()){ - mProgressDlg->hide(); - } -} - void FilesystemWidget::deleteRecursive(const QFileInfo &start){ if(start.isDir()){ QDir curDir = QDir(start.absoluteFilePath());; diff --git a/filesystemwidget.h b/filesystemwidget.h index b9f082d..e3a2597 100644 --- a/filesystemwidget.h +++ b/filesystemwidget.h @@ -8,8 +8,8 @@ #ifndef FILESYSTEMWIDGET_H #define FILESYSTEMWIDGET_H -#include <QtWidgets/QWidget> -#include <QtWidgets/QFileSystemModel> +#include <QWidget> +#include <QFileSystemModel> #include <QSqlDatabase> #include <QDateTime> @@ -18,7 +18,6 @@ class FilesystemDirProxy; class FileView; class FilesystemFileProxy; class QLineEdit; -class QProgressDialog; class PictureViewer2; class FileSystemModel; class SheMovIconProvider; @@ -60,8 +59,6 @@ class FilesystemWidget : public QWidget { void moveToArchive(); void selectAllPV(); void setWindowTitle(); - void setupProgressDlg(int max); - void progress(); private slots: void dirExpanded(const QModelIndex &idx); @@ -70,7 +67,6 @@ class FilesystemWidget : public QWidget { void resizeFileView(); private: - void deleteRecursive(const QFileInfo &start); void copyFiles(const QStringList &files, const QString &dest); void moveFiles(const QStringList &files, const QString &dest); @@ -86,7 +82,6 @@ class FilesystemWidget : public QWidget { FilesystemDirProxy *mDirProxy; FilesystemFileProxy *mFileProxy; QLineEdit *mDirEdit; - QProgressDialog *mProgressDlg; QString mWindowTitle; QString mTemplate; qint64 mSize; diff --git a/fileview.cpp b/fileview.cpp index 80a81bd..cc636ad 100644 --- a/fileview.cpp +++ b/fileview.cpp @@ -103,8 +103,6 @@ void FileView::readConfig(){ mWhen = s.value("ui/grabframe", "00:00:00").toString(); mHoverWin->setWindowOpacity(s.value("ui/hoveropacity", 10).toFloat() / 10.0); mCursorOffset = s.value("ui/cursoroffset").toInt(); - bool checkPresent = s.value("database/checkpresent").toBool(); - mModel->setCheckForPresent(checkPresent); readHeaderConfig(); } @@ -117,7 +115,7 @@ void FileView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint h QSortFilterProxyModel *proxy = qobject_cast<QSortFilterProxyModel*>(model()); QModelIndex sourceIdx = proxy->mapToSource(currentIndex()); emit editorClosed(sourceIdx); - mModel->refresTimer()->start(); + mModel->refreshTimer()->start(); } void FileView::contextMenuEvent(QContextMenuEvent *e){ @@ -305,9 +305,9 @@ namespace Helper { } QVariant picSize(const QString &path){ - QPixmap pm(path); - if(!pm.isNull()){ - QString retval = QString("%1x%2").arg(QString::number(pm.width())).arg(QString::number(pm.height())); + QImage img(path); + if(!img.isNull()){ + QString retval = QString("%1x%2").arg(QString::number(img.width())).arg(QString::number(img.height())); return retval; } return QVariant(); @@ -4,7 +4,7 @@ CONFIG += warn_on \ qt \ debug CONFIG -= release -QT += core gui widgets sql +QT += core gui widgets sql concurrent SOURCES = main.cpp \ filesystemdirproxy.cpp \ filesystemwidget.cpp \ diff --git a/smdirmodel.cpp b/smdirmodel.cpp index 6a7ac39..6c84784 100644 --- a/smdirmodel.cpp +++ b/smdirmodel.cpp @@ -16,6 +16,7 @@ #include "helper.h" SmDirModel::SmDirModel(const QStringList &headers, QObject *parent) : SmTreeModel(headers, parent), mHeaders(headers){ + mDb = QSqlDatabase::database("treedb"); mWatch = new SmDirWatcher(NumFields, this); connect(mWatch, SIGNAL(needRefresh()), this, SLOT(refresh())); mRunTimer = new QTimer(this); @@ -25,9 +26,12 @@ SmDirModel::SmDirModel(const QStringList &headers, QObject *parent) : SmTreeMode mRefreshTimer = new QTimer(this); readSettings(); - mCollector = mWatch->collector(); - connect(mCollector, SIGNAL(population(SmTreeItem*)), this, SLOT(populate(SmTreeItem*))); - connect(mCollector, SIGNAL(newData(QList<QVariant>,int)), this, SLOT(dirEvent(QList<QVariant>,int)), Qt::BlockingQueuedConnection); + connect(this, SIGNAL(modelReset()), mWatch, SLOT(startAsyncJobs())); + connect(mWatch, SIGNAL(population(SmTreeItem*)), this, SLOT(populate(SmTreeItem*))); + connect(mWatch, SIGNAL(setMd5Sum(QString,QString)), this, SLOT(setMd5Sum(QString,QString))); + connect(mWatch, SIGNAL(setFfmpeg(QString,QVariantMap)), this, SLOT(setFfmpeg(QString,QVariantMap))); + connect(mWatch, SIGNAL(setPicSize(QString,QVariant)), this, SLOT(setPicSize(QString,QVariant))); + connect(mWatch, SIGNAL(newData(QList<QVariant>,int)), this, SLOT(dirEvent(QList<QVariant>,int))); } SmDirModel::~SmDirModel(){ @@ -127,7 +131,6 @@ QFileInfo SmDirModel::fileInfo(const QModelIndex &idx) const { void SmDirModel::setDir(const QString &dir){ mCurrentDir = dir; - mCollector->start(); mWatch->setDir(mCurrentDir); } @@ -135,9 +138,11 @@ void SmDirModel::dirEvent(const QList<QVariant> &data, int e){ if(e == SmDirWatcher::Added){ /* for some reason SmTreeModel::addRow() doesn't work, * couldn't figure it out in 5 hours, so customize it - * and reset the model - */ + * and reset the model... gatherAsync is done by + * modelReset(); + */ addFile(data); + return; } QModelIndex idx = find(data.at(Name), Name, rootIndex()); if(!idx.isValid()){ @@ -146,10 +151,13 @@ void SmDirModel::dirEvent(const QList<QVariant> &data, int e){ if(e == SmDirWatcher::Deleted){ removeRow(idx.row()); } - if(e == SmDirWatcher::Modified){ + if(e == SmDirWatcher::Modified || e == SmDirWatcher::CloseWrite){ for(int i = 0; i < mHeaders.count(); ++i){ QModelIndex c = index(idx.row(), i, QModelIndex()); setData(c, data.at(i), Qt::EditRole); + if(e == SmDirWatcher::CloseWrite){ + mWatch->gatherAsync(data.at(FullPath).toString()); + } } } emit needResize(); @@ -175,8 +183,53 @@ void SmDirModel::refresh(){ setDir(mCurrentDir); } -void SmDirModel::setCheckForPresent(bool check){ - mCollector->setCheckForPresent(check); +void SmDirModel::setMd5Sum(QString path, QString md5){ + QModelIndex idx = find(path, FullPath); + if(idx.isValid()){ + QModelIndex md5Idx = createIndex(idx.column(), Md5sum, idx.internalPointer()); + setData(md5Idx, md5, Qt::EditRole); + QString mimeType = idx.data(TypeRole).toString(); + int present = 0; + QSqlQuery presentQ(mDb); + if(mimeType.startsWith("video")){ + presentQ.prepare("SELECT COUNT(*) FROM files WHERE cmd5sum = :md5"); + }else if(mimeType.startsWith("image")){ + presentQ.prepare("SELECT COUNT(*) FROM pics WHERE cmd5sum = :md5"); + }else{ + goto out; + } + presentQ.bindValue(":md5", md5); + presentQ.exec(); + while(presentQ.next()){ + present = presentQ.value(0).toInt(); + } + if(present){ + QModelIndex presentIdx = createIndex(idx.column(), Present, idx.internalPointer()); + setData(presentIdx, present, Qt::EditRole); + } + } + out: + emit needResize(); +} + +void SmDirModel::setFfmpeg(QString path, QVariantMap data){ + QModelIndex idx = find(path, FullPath); + if(idx.isValid()){ + QModelIndex durIdx = createIndex(idx.column(), DurSize, idx.internalPointer()); + setData(durIdx, data["duration"].toDouble(), Qt::EditRole); + QModelIndex bitrateIdx = createIndex(idx.column(), Bitrate, idx.internalPointer()); + setData(bitrateIdx, data["bit_rate"], Qt::EditRole); + } + emit needResize(); +} + +void SmDirModel::setPicSize(QString path, QVariant data){ + QModelIndex idx = find(path, FullPath); + if(idx.isValid()){ + QModelIndex psIdx = createIndex(idx.column(), DurSize, idx.internalPointer()); + setData(psIdx, data, Qt::EditRole); + } + emit needResize(); } void SmDirModel::populate(SmTreeItem *root){ diff --git a/smdirmodel.h b/smdirmodel.h index 02ad608..26f34cf 100644 --- a/smdirmodel.h +++ b/smdirmodel.h @@ -9,6 +9,7 @@ #define SMDIRMODEL_H #include <QDir> +#include <QSqlDatabase> #include <smtreemodel.h> #include <smdirwatcher.h> @@ -31,17 +32,18 @@ class SmDirModel : public SmTreeModel { virtual QVariant data(const QModelIndex &index, int role) const; virtual bool setData(const QModelIndex &index, const QVariant &value, int role); bool isDir(const QModelIndex &idx) const; - SmDataColletor *collector() const { return mCollector; } QDir dir() const; QFileInfo fileInfo(const QModelIndex &idx) const; - QTimer *refresTimer() { return mRefreshTimer; } + QTimer *refreshTimer() { return mRefreshTimer; } public slots: void setDir(const QString &dir); void dirEvent(const QList<QVariant> &data, int e); void readSettings(); void refresh(); - void setCheckForPresent(bool check); + void setMd5Sum(QString path, QString md5); + void setFfmpeg(QString path, QVariantMap data); + void setPicSize(QString path, QVariant data); private slots: void populate(SmTreeItem *root); @@ -56,12 +58,10 @@ class SmDirModel : public SmTreeModel { SmDirWatcher *mWatch; QStringList mHeaders; QString mCurrentDir; - QString mCur; QTimer *mRunTimer; QTimer *mRefreshTimer; QMap<QString, QIcon> mIcons; - QMutex *mCollectorMx; - SmDataColletor *mCollector; + QSqlDatabase mDb; }; class TimerHandler { diff --git a/smdirwatcher.cpp b/smdirwatcher.cpp index 2b03179..d825c2c 100644 --- a/smdirwatcher.cpp +++ b/smdirwatcher.cpp @@ -5,56 +5,105 @@ 2 of the License, or (at your option) any later version. */ -#include <QVarLengthArray> -#include <QMutexLocker> #include <QDateTime> #include <QDir> -#include <QSemaphore> #include <QImage> #include <sys/inotify.h> -#include <stropts.h> -#include <sys/ioctl.h> #include <unistd.h> -#include <errno.h> +#include "smdirmodel.h" #include "smdirwatcher.h" #include "smtreeitem.h" #include "helper.h" -extern int errno; - -SmDirWatcher::SmDirWatcher(int numFields, QObject *parent) : QThread(parent), mFd(0), mDescr(0) { +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(); - - mCollector = new SmDataColletor(numFields, this); - mSemFree = new QSemaphore(1024); - mSemUsed = new QSemaphore; - mQueueMx = new QMutex; - mDataQueue = new QQueue<QPair<QString, DWEvent> >(); - mCollector->init(mSemFree, mSemUsed, mDataQueue, mQueueMx); - mCollector->start(); + 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<QVariant> 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); - mCurrent = dir; - mSemFree->acquire(); - QPair<QString, DWEvent> c = qMakePair(dir, Populate); - mQueueMx->lock(); - mDataQueue->enqueue(c); - mQueueMx->unlock(); - mSemUsed->release(); +} + +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<QVariant> SmDirWatcher::generalData(const QString &path){ + QFileInfo fi(path); + QList<QVariant> 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(){ @@ -69,142 +118,74 @@ void SmDirWatcher::run(){ i += sizeof(inotify_event) + e->len; continue; } - mSemFree->acquire(); quint32 mask = e->mask; QString name = QString("%1/%2").arg(mCurrent).arg(e->name); - DWEvent curEvent = None; - QPair<QString, DWEvent> c; + QList<QVariant> d = generalData(name); if(mask & IN_CREATE || mask & IN_MOVED_TO){ - curEvent = Added; + emit newData(d, Added); }else if(mask & IN_DELETE || mask & IN_MOVED_FROM){ - curEvent = Deleted; - }else if(mask & IN_CLOSE_WRITE || e->mask & IN_MODIFY){ - curEvent = Modified; - }else{ - goto out; + emit newData(d, Deleted); + }else if(mask & IN_MODIFY){ + emit newData(d, Modified); + }else if(mask & IN_CLOSE_WRITE){ + emit newData(d, CloseWrite); } - c = qMakePair(name, curEvent); - mQueueMx->lock(); - mDataQueue->enqueue(c); - mQueueMx->unlock(); - out: - mSemUsed->release(); i += sizeof(inotify_event) + e->len; } } void SmDirWatcher::stop(){ - mSemFree->acquire(); - mCollector->stop(); - mSemUsed->release(); - if(mCollector->isRunning()){ - mCollector->wait(); - } quit(); } -SmDataColletor::SmDataColletor(const int numFields, QObject *parent) : QThread(parent), mSemFree(0), mSemUsed(0), mDataQueue(0), mNumFields(numFields), mCheckForPresent(true), mCancel(false) { - QSqlDatabase db = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), "collectordb"); - db.open(); - mPicPresentQ = new QSqlQuery(db); - mPicPresentQ->prepare("SELECT COUNT(cmd5sum) FROM pics WHERE cmd5sum = :md5"); - mMovPresentQ = new QSqlQuery(db); - mMovPresentQ->prepare("SELECT COUNT(cmd5sum) FROM files WHERE cmd5sum = :md5"); -} +AsyncTask::AsyncTask(const QString &path) : mSkip(false), mPath(path) {} -void SmDataColletor::init(QSemaphore *set, QSemaphore *get, QQueue<QPair<QString, SmDirWatcher::DWEvent> > *data, QMutex *queueMx){ - mSemFree = set; - mSemUsed = get; - mDataQueue = data; - mQueueMx = queueMx; +bool AsyncTask::skipMe(){ + if(mStatusMx.tryLock()){ + mSkip = true; + mStatusMx.unlock(); + return true; + } + return false; } -void SmDataColletor::setCheckForPresent(bool present){ - QMutexLocker l(&mCheckForPresentMx); - mCheckForPresent = present; -} +#include <QDebug> -void SmDataColletor::run(){ - forever { - mSemUsed->acquire(); - if(mCancel){ - QSqlDatabase::database("collectordb").close(); - mSemFree->release(); - break; - } - mQueueMx->lock(); - QPair<QString, SmDirWatcher::DWEvent> cur = mDataQueue->dequeue(); - mQueueMx->unlock(); - if(cur.second == SmDirWatcher::Populate){ - SmTreeItem *i = populate(cur.first); - SmTreeItem *copy = new SmTreeItem(*i); - emit population(copy); - mSemFree->release(); - continue; +Md5Summer::Md5Summer(const QString &path) : AsyncTask(path) {} - } - QFileInfo fi(cur.first); - QList<QVariant> fd = fileData(fi); - emit newData(fd, cur.second); - mSemFree->release(); +void Md5Summer::run(){ + mStatusMx.lock(); + bool skip = mSkip; + mStatusMx.unlock(); + if(skip){ + return; } - quit(); + QString md5 = Helper::md5Sum(mPath); + emit md5sumDone(mPath, md5); } -SmTreeItem * SmDataColletor::populate(const QString &dir){ - SmTreeItem *retval = new SmTreeItem(mNumFields); - QDir d = QDir(dir); - emit totalFiles(d.entryInfoList().size()); - foreach(QFileInfo fi, d.entryInfoList()){ - emit progress(); - if(fi.fileName() == "."){ - continue; - } - QList<QVariant> data = fileData(fi); - SmTreeItem *newItem = new SmTreeItem(data, retval); - retval->appendChild(newItem); +FfmpegGatherer::FfmpegGatherer(const QString &path) : AsyncTask(path) {} + +void FfmpegGatherer::run(){ + mStatusMx.lock(); + bool skip = mSkip; + mStatusMx.unlock(); + if(skip){ + return; } - return retval; + QVariantMap retval = Helper::ffmpegData(mPath); + emit ffmpegDone(mPath, retval); } -const QList<QVariant> SmDataColletor::fileData(const QFileInfo &fi){ - QList<QVariant> data; - data << fi.fileName() << fi.size(); - QString mime = Helper::mimeType(fi.absoluteFilePath()); - data << mime; - data << fi.lastModified(); - QList<QVariant> si = QList<QVariant>() << QVariant() << QVariant(); - if(mime.startsWith("video")){ - QVariantMap ffData = Helper::ffmpegData(fi.absoluteFilePath()); - si[0] = ffData.value("duration").toDouble(); - si[1] = ffData.value("bit_rate").toInt(); - }else if(mime.startsWith("image")){ - si[0] = Helper::picSize(fi.absoluteFilePath()); - } - data << Helper::md5Sum(fi.absoluteFilePath()); - data << si << fi.absoluteFilePath(); - data << 0; - mCheckForPresentMx.lock(); - bool p = mCheckForPresent; - mCheckForPresentMx.unlock(); - if(p){ - QSqlQuery *curQuery = 0; - if(mime.startsWith("video")){ - curQuery = mMovPresentQ; - } - if(mime.startsWith("image")){ - curQuery = mPicPresentQ; - } - if(curQuery){ - curQuery->bindValue(":md5", data.at(4)); - if(curQuery->exec()){ - QVariant res; - while(curQuery->next()){ - res = curQuery->value(0); - } - data[8] = res; - } - } +PicSizeGatherer::PicSizeGatherer(const QString &path) : AsyncTask(path) {} + +void PicSizeGatherer::run(){ + mStatusMx.lock(); + bool skip = mSkip; + mStatusMx.unlock(); + if(skip){ + return; } - return data; + QVariant retval = Helper::picSize(mPath); + emit picSizeDone(mPath, retval); } diff --git a/smdirwatcher.h b/smdirwatcher.h index fccc1ed..9ec9181 100644 --- a/smdirwatcher.h +++ b/smdirwatcher.h @@ -1,4 +1,4 @@ - /* +/* 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 @@ -16,73 +16,96 @@ #include <QMutex> #include <QSqlDatabase> #include <QSqlQuery> +#include <QThreadPool> +#include <QRunnable> class SmTreeItem; class QSemaphore; class SmDataColletor; +class AsyncTask; +class Md5Summer; class SmDirWatcher : public QThread { Q_OBJECT public: - enum DWEvent { None, Added, Deleted, Modified, Populate }; + enum DWEvent { None, Added, Deleted, Modified, Populate, CloseWrite }; explicit SmDirWatcher(int numFields, QObject *parent = 0); - SmDataColletor *collector() { return mCollector; } signals: void dwEvent(const QString& file, int event); + void setMd5Sum(QString path, QString md5); + void setFfmpeg(QString path, QVariantMap data); + void setPicSize(QString path, QVariant size); void needRefresh(); + void population(SmTreeItem*); + void newData(const QList<QVariant>,int); public slots: void run(); void stop(); void setDir(const QString &dir); + void startAsyncJobs(); + void gatherAsync(const QString &path); private: + QList<QVariant> generalData(const QString &path); int mFd; int mDescr; QString mCurrent; - SmDataColletor *mCollector; - QSemaphore *mSemFree; - QSemaphore *mSemUsed; - QQueue<QPair<QString, DWEvent> > *mDataQueue; - QMutex *mQueueMx; char *mINdata; int mBufLen; + QThreadPool *mAsyncPool; + int mNumFields; + QList<AsyncTask*> mAsyncTasks; }; -class SmDataColletor : public QThread { +class AsyncTask : public QObject, public QRunnable { Q_OBJECT public: - explicit SmDataColletor(const int numFields, QObject *parent = 0); - void init(QSemaphore *set, QSemaphore *get, QQueue<QPair<QString, SmDirWatcher::DWEvent> > *data, QMutex *queueMx); + explicit AsyncTask(const QString &path = QString()); + bool skipMe(); - public slots: - void setCheckForPresent(bool present); - void run(); - void stop() { mCancel = true; } + protected: + virtual void run() = 0; + bool mSkip; + QMutex mStatusMx; + const QString mPath; +}; + +class Md5Summer : public AsyncTask { + Q_OBJECT + public: + explicit Md5Summer(const QString &path); signals: - void newData(const QList<QVariant>,int); - void population(SmTreeItem*); - void needRefresh(); - void totalFiles(int numFiles); - void progress(); + void md5sumDone(QString, QString); - private: - SmTreeItem *populate(const QString &dir); - const QList<QVariant> fileData(const QFileInfo &fi); - QString mCurrent; - QSemaphore *mSemFree; - QSemaphore *mSemUsed; - QMutex *mQueueMx; - QQueue<QPair<QString, SmDirWatcher::DWEvent> > *mDataQueue; - int mMode; - const int mNumFields; - bool mCheckForPresent; - bool mCancel; - QMutex mCheckForPresentMx; - QSqlQuery *mPicPresentQ; - QSqlQuery *mMovPresentQ; + protected: + virtual void run(); +}; + +class FfmpegGatherer : public AsyncTask { + Q_OBJECT + public: + explicit FfmpegGatherer(const QString &path); + + signals: + void ffmpegDone(QString, QVariantMap); + + protected: + virtual void run(); +}; + +class PicSizeGatherer : public AsyncTask { + Q_OBJECT + public: + explicit PicSizeGatherer(const QString &path); + + signals: + void picSizeDone(QString, QVariant); + + protected: + virtual void run(); }; #endif // SMDIRWATCHER_H |