diff options
-rw-r--r-- | consistencycheck.cpp | 215 | ||||
-rw-r--r-- | consistencycheck.h | 29 |
2 files changed, 193 insertions, 51 deletions
diff --git a/consistencycheck.cpp b/consistencycheck.cpp index 43e06d2..7330cd2 100644 --- a/consistencycheck.cpp +++ b/consistencycheck.cpp @@ -24,20 +24,42 @@ #include <QDir> #include <QFileDialog> #include <QMessageBox> +#include <QProgressBar> +#include <QGroupBox> #include "consistencycheck.h" #include "helper.h" ConsistencyCheck::ConsistencyCheck(QWidget *parent, Qt::WindowFlags f) : SmDialog(parent, f), mChecker(0){ // setup widget - QLabel *okLabel = new QLabel(tr("Ok")); + // OK + QGroupBox *okBox = new QGroupBox(tr("Ok")); + QHBoxLayout *okLayout = new QHBoxLayout; mOkDisplay = new QPlainTextEdit; mOkDisplay->setReadOnly(true); mOkDisplay->setLineWrapMode(QPlainTextEdit::NoWrap); - QLabel *errorLabel = new QLabel(tr("Errors")); + okLayout->addWidget(mOkDisplay); + okBox->setLayout(okLayout); + + // Errors + QGroupBox *errorBox = new QGroupBox(tr("Errors")); + QHBoxLayout *errorLayout = new QHBoxLayout; mErrorDisplay = new QPlainTextEdit; mErrorDisplay->setReadOnly(true); mErrorDisplay->setLineWrapMode(QPlainTextEdit::NoWrap); + errorLayout->addWidget(mErrorDisplay); + errorBox->setLayout(errorLayout); + + // Progress + QGroupBox *progressBox = new QGroupBox(tr("Progress")); + QVBoxLayout *progressLayout = new QVBoxLayout; + mProgress = new QProgressBar(); + progressLayout->addWidget(mProgress); + mActivity = new QLabel(tr("Idle...")); + progressLayout->addWidget(mActivity); + progressBox->setLayout(progressLayout); + + // Buttons mCancelExit = new QPushButton(tr("Close")); mCheckDb = new QPushButton(tr("Check database")); mCheckFs = new QPushButton(tr("Check Filesystem")); @@ -65,19 +87,36 @@ ConsistencyCheck::ConsistencyCheck(QWidget *parent, Qt::WindowFlags f) : SmDialo connect(mChecker, SIGNAL(started()), this, SLOT(checkerStarted())); connect(mChecker, SIGNAL(finished()), this, SLOT(checkerFinished())); connect(mChecker, SIGNAL(consistencyMsg(QString)), this, SLOT(addMessage(QString))); + connect(mChecker, SIGNAL(approxTotal(int)), this, SLOT(setProgressBarMax(int))); + connect(mChecker, SIGNAL(progress(int)), this, SLOT(setProgress(int))); // main layout QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(okLabel); - mainLayout->addWidget(mOkDisplay); - mainLayout->addWidget(errorLabel); - mainLayout->addWidget(mErrorDisplay); + mainLayout->addWidget(okBox); + mainLayout->addWidget(errorBox); + mainLayout->addWidget(progressBox); mainLayout->addLayout(buttonLayout); setWindowTitle(tr("Checking consistency")); setLayout(mainLayout); setMinimumWidth(600); } +void ConsistencyCheck::setProgressBarMax(int max){ + mProgress->reset(); + mProgress->setMaximum(max); + QString activity = QString(tr("Expecting %1 files")).arg(QString::number(max)); + mActivity->setText(activity); +} + +void ConsistencyCheck::setProgress(int value){ + if(value >= mProgress->maximum()){ + mProgress->setMaximum(value + 100); + QString activity = QString(tr("Just got pregnant. Expecting %1 now.")).arg(QString::number(value + 100)); + mActivity->setText(activity); + } + mProgress->setValue(value); +} + void ConsistencyCheck::startChecker(int checkerType){ if(mChecker->status() == ConsistencyChecker::Fail){ return; @@ -125,13 +164,15 @@ void ConsistencyCheck::checkerStarted(){ } void ConsistencyCheck::checkerFinished(){ + mProgress->setValue(mProgress->maximum()); + mActivity->setText(tr("Idle...")); mCheckDb->setEnabled(true); mCheckFs->setEnabled(true); mCancelExit->setText(tr("Close")); mCancelExit->disconnect(); connect(mCancelExit, SIGNAL(clicked()), this, SLOT(accept())); mChecker->setCancel(false); - if(!mChecker->strayFiles().isEmpty() || !mChecker->strayIds().isEmpty()){ + if(!mChecker->strayFiles().isEmpty() || !mChecker->strayFileIds().isEmpty()){ mCleanup->setEnabled(true); } } @@ -144,14 +185,22 @@ void ConsistencyCheck::cleanup(){ QStringList strayFiles = mChecker->strayFiles(); moveFiles(strayFiles); if(mChecker->mode() == DbCheck){ - QList<int> fileIds = mChecker->strayIds(); + QList<int> fileIds = mChecker->strayFileIds(); if(!fileIds.isEmpty()){ - QString msg = QString(tr("Really delete %1 entries from database?")).arg(QString::number(fileIds.count())); + QString msg = QString(tr("Really delete %1 files from database?")).arg(QString::number(fileIds.count())); int retval = QMessageBox::critical(this, tr("Delete from database"), msg, QMessageBox::Yes | QMessageBox::No); if(retval == QMessageBox::Yes){ - mChecker->deleteIds(fileIds); + mChecker->deleteFileIds(fileIds); } } + QList<int> picIds = mChecker->strayPicIds(); + if(!picIds.isEmpty()){ + QString msg = QString(tr("Really delete %1 pictures from database?")).arg(QString::number(picIds.count())); + int retval = QMessageBox::critical(this, tr("Delete from database"), msg, QMessageBox::Yes | QMessageBox::No); + if(retval == QMessageBox::Yes){ + //mChecker->deleteIds(fileIds); + } + } } mCleanup->setEnabled(false); } @@ -210,14 +259,19 @@ void ConsistencyChecker::clearStrayFiles(){ mStrayFiles.clear(); } -const QList<int> ConsistencyChecker::strayIds(){ - QMutexLocker locker(&mStrayIdsMutex); - return mStrayIds; +const QList<int> ConsistencyChecker::strayFileIds(){ + QMutexLocker locker(&mStrayFileIdMutex); + return mStrayFileIds; +} + +const QList<int> ConsistencyChecker::strayPicIds(){ + QMutexLocker locker(&mStrayPicsIdMutex); + return mStrayPicIds; } void ConsistencyChecker::clearStrayIds(){ - QMutexLocker locker(&mStrayIdsMutex); - mStrayIds.clear(); + QMutexLocker locker(&mStrayFileIdMutex); + mStrayFileIds.clear(); } void ConsistencyChecker::setCancel(bool cancel){ @@ -225,7 +279,7 @@ void ConsistencyChecker::setCancel(bool cancel){ mCanceled = cancel; } -void ConsistencyChecker::deleteIds(const QList<int> &ids){ +void ConsistencyChecker::deleteFileIds(const QList<int> &ids){ QSqlQuery idQuery(mDb); idQuery.prepare("DELETE FROM files WHERE ifiles_id = :id"); foreach(int id, ids){ @@ -234,6 +288,15 @@ void ConsistencyChecker::deleteIds(const QList<int> &ids){ } } +void ConsistencyChecker::deletePicIds(const QList<int> &ids){ + QSqlQuery idQuery(mDb); + idQuery.prepare("DELETE FROM pics WHERE ipicsid = :id"); + foreach(int id, ids){ + idQuery.bindValue(":id", id); + idQuery.exec(); + } +} + void ConsistencyChecker::run(){ clearStrayFiles(); clearStrayIds(); @@ -241,14 +304,18 @@ void ConsistencyChecker::run(){ fsCheck(); } if(mMode == ConsistencyCheck::DbCheck){ - dbCheck(); + dbCheck(); } } -void ConsistencyChecker::dbCheck(){ +void ConsistencyChecker::doDbCheckFiles(){ QSqlQuery fileDbQuery = QSqlQuery("SELECT tfilename, cmd5sum, idvd, ifiles_id FROM files ORDER BY tfilename", mDb); while(fileDbQuery.next()){ - QMutexLocker locker(&mCancelMutex); + ++mCurCount; + if(mCurCount % 50 == 0){ + emit progress(mCurCount); + } + QMutexLocker locker(&mCancelMutex); if(mCanceled){ quit(); }else{ @@ -263,9 +330,9 @@ void ConsistencyChecker::dbCheck(){ if(dvdNo != -1){ emit consistencyMsg(QString(tr("OK: %1")).arg(fileName)); }else{ - mStrayIdsMutex.lock(); - mStrayIds << fileId; - mStrayIdsMutex.unlock(); + mStrayFileIdMutex.lock(); + mStrayFileIds << fileId; + mStrayFileIdMutex.unlock(); emit consistencyMsg(QString(tr("NOT FOUND: %1")).arg(fileName)); } }else{ @@ -288,44 +355,102 @@ void ConsistencyChecker::dbCheck(){ quit(); } +void ConsistencyChecker::doDbCheckPics(){ + QSqlQuery picsQuery = QSqlQuery("SELECT tfilename, cmd5sum, ipicsid FROM pics ORDER BY tfilename", mDb); + while(picsQuery.next()){ + ++mCurCount; + if(mCurCount % 50 == 0){ + emit progress(mCurCount); + } + QMutexLocker locker(&mCancelMutex); + if(mCanceled){ + quit(); + }else{ + locker.unlock(); + } + QString fileName = picsQuery.value(0).toString(); + QString md5sum = picsQuery.value(1).toString(); + QString fullPath = archivePath(fileName, md5sum); + if(fullPath.isEmpty()){ + mStrayPicsIdMutex.lock(); + mStrayPicIds << picsQuery.value(2).toInt(); + mStrayPicsIdMutex.unlock(); + emit consistencyMsg(QString(tr("NOT FOUND: %1")).arg(fileName)); + }else{ + emit consistencyMsg(QString(tr("OK: %1")).arg(fileName)); + } + } +} + +void ConsistencyChecker::dbCheck(){ + QSqlQuery numFilesQ("SELECT COUNT(*) FROM files", mDb); + int numFiles; + while(numFilesQ.next()){ + numFiles = numFilesQ.value(0).toInt(); + } + QSqlQuery numPicsQ("SELECT COUNT(*) FROM pics", mDb); + int numPics; + while(numPicsQ.next()){ + numPics = numPicsQ.value(0).toInt(); + } + emit approxTotal(numFiles + numPics); + mCurCount = 0; + doDbCheckFiles(); + doDbCheckPics(); + quit(); +} + void ConsistencyChecker::fsCheck(){ mStrayFilesMutex.lock(); mStrayFiles.clear(); mStrayFilesMutex.unlock(); + QVector<QString> md5sums; + QSqlQuery picsmd5("SELECT cmd5sum FROM pics", mDb); + while(picsmd5.next()){ + md5sums << picsmd5.value(0).toString(); + } + QSqlQuery filesmd5("SELECT cmd5sum FROM files", mDb); + while(filesmd5.next()){ + md5sums << filesmd5.value(0).toString(); + } + emit approxTotal(md5sums.size()); + mCurCount = 0; QSettings s; QString startDir = s.value("paths/archivedir").toString(); QFileInfo startFi(startDir); - doFsCheck(startFi); + doFsCheck(startFi, md5sums); quit(); } -void ConsistencyChecker::doFsCheck(const QFileInfo &start){ +void ConsistencyChecker::doFsCheck(const QFileInfo &start, const QVector<QString> &md5sums){ if(start.isDir()){ - QMutexLocker locker(&mCancelMutex); - if(mCanceled){ - quit(); - }else{ - locker.unlock(); - } QDir curDir(start.absoluteFilePath()); foreach(QFileInfo fi, curDir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)){ + mCancelMutex.lock(); + if(mCanceled){ + mCancelMutex.unlock(); + return; + } + mCancelMutex.unlock(); if(fi.isDir()){ - doFsCheck(fi); - }else{ + if(fi.fileName() == ".frameCache"){ + continue; + } + doFsCheck(fi, md5sums); + }else{ QString md5sum = Helper::md5Sum(fi.absoluteFilePath()); - mFileQuery->bindValue(":md5sum", md5sum); - mFileQuery->exec(); - while(mFileQuery->next()){ - int count = mFileQuery->value(0).toInt(); - if(count > 0){ - emit consistencyMsg(QString(tr("OK: %1 -> %2")).arg(fi.fileName()).arg(md5sum)); - }else{ - mStrayFilesMutex.lock(); - mStrayFiles << fi.absoluteFilePath(); - mStrayFilesMutex.unlock(); - emit consistencyMsg(QString(tr("NOT FOUND: %1 -> %2")).arg(fi.fileName()).arg(md5sum)); - } - } + if(md5sums.contains(md5sum)){ + emit consistencyMsg(QString(tr("OK: %1 -> %2")).arg(fi.fileName()).arg(md5sum)); + }else{ + mStrayFilesMutex.lock(); + mStrayFiles << fi.absoluteFilePath(); + mStrayFilesMutex.unlock(); + emit consistencyMsg(QString(tr("NOT FOUND: %1 -> %2")).arg(fi.fileName()).arg(md5sum)); + } + ++mCurCount; + if(mCurCount % 50 == 0){ + emit progress(mCurCount); + } } } } diff --git a/consistencycheck.h b/consistencycheck.h index b62dfbc..ca078f1 100644 --- a/consistencycheck.h +++ b/consistencycheck.h @@ -23,6 +23,7 @@ class QString; class QSqlQuery; class QFileInfo; class ConsistencyChecker; +class QProgressBar; class ConsistencyCheck : public SmDialog { Q_OBJECT @@ -30,6 +31,10 @@ class ConsistencyCheck : public SmDialog { enum Mode { DbCheck, FsCheck }; explicit ConsistencyCheck(QWidget *parent = 0, Qt::WindowFlags f = 0); + public slots: + void setProgressBarMax(int max); + void setProgress(int value); + private slots: void startChecker(int checkerType); void addMessage(const QString &message); @@ -46,6 +51,8 @@ class ConsistencyCheck : public SmDialog { QPushButton *mCleanup; QPlainTextEdit *mOkDisplay; QPlainTextEdit *mErrorDisplay; + QLabel *mActivity; + QProgressBar *mProgress; ConsistencyChecker *mChecker; }; @@ -56,32 +63,39 @@ class ConsistencyChecker : public QThread { explicit ConsistencyChecker(QObject *parent = 0); ~ConsistencyChecker(); int mode() const { return mMode; } + int count() const { return mCurCount; } void setMode(int mode) { mMode = mode; } int status() const { return mStatus; } void setStatus(int status) { mStatus = status; } void check(); const QStringList strayFiles(); void clearStrayFiles(); - const QList<int> strayIds(); + const QList<int> strayFileIds(); + const QList<int> strayPicIds(); void clearStrayIds(); public slots: void setCancel(bool cancel); - void deleteIds(const QList<int> &ids); + void deleteFileIds(const QList<int> &ids); + void deletePicIds(const QList<int> &ids); private slots: - void dbCheck(); + void dbCheck(); void fsCheck(); signals: void consistencyMsg(const QString &msg); + void approxTotal(int); + void progress(int); protected: void run(); private: QString archivePath(const QString &fileName, const QString &md5sum) const; - void doFsCheck(const QFileInfo &start); + void doFsCheck(const QFileInfo &start, const QVector<QString> &md5sums); + void doDbCheckFiles(); + void doDbCheckPics(); bool mCanceled; int mMode; int mStatus; @@ -89,9 +103,12 @@ class ConsistencyChecker : public QThread { QSqlQuery *mFileQuery; QMutex mCancelMutex; QMutex mStrayFilesMutex; - QMutex mStrayIdsMutex; + QMutex mStrayFileIdMutex; + QMutex mStrayPicsIdMutex; QStringList mStrayFiles; - QList<int> mStrayIds; + QList<int> mStrayFileIds; + QList<int> mStrayPicIds; + int mCurCount; }; #endif // CONSISTENCYCHECK_H |