From 6fec376f7f44145efa509668927a0179c8ffa65e Mon Sep 17 00:00:00 2001 From: Arno Date: Sat, 1 Jun 2013 22:52:19 +0200 Subject: Gather archive data in a thread Fetching data sometimes takes a long time, so do it in a QThread and show a progress dialog. Some kludges included :) --- archivemodel.cpp | 125 ++++++++++++++++++++++++++++++++----------------------- archivemodel.h | 38 ++++++++++++++--- archiveview.cpp | 44 ++++++++++++++++++-- archiveview.h | 29 +++++++++++-- shemov.cpp | 3 ++ smdirwatcher.h | 2 +- 6 files changed, 177 insertions(+), 64 deletions(-) diff --git a/archivemodel.cpp b/archivemodel.cpp index 90c6cd9..c317c32 100644 --- a/archivemodel.cpp +++ b/archivemodel.cpp @@ -15,7 +15,8 @@ ArchiveModel::ArchiveModel(const QStringList &headers, QObject *parent) : SmTree mAvailableOrders.insert("Series Name", SeriesName); mAvailableOrders.insert("Actor", Actor); mAvailableOrders.insert("Genre", Genre); - setOrder(mOrder); + mCollector = new ArchiveCollector(NumFields, this); + connect(mCollector, SIGNAL(finished()), this, SLOT(collectorFinished())); } const QStringList ArchiveModel::availableOrders() const { @@ -58,83 +59,103 @@ QVariant ArchiveModel::data(const QModelIndex &index, int role) const{ void ArchiveModel::setOrder(int order) { mOrder = order; - switch (order) { - case SeriesName: + SmTreeItem *rootItem = new SmTreeItem(NumFields); + mCollector->populate(mOrder, rootItem); + if(!mCollector->isRunning()){ + mCollector->start(); + } +} + +void ArchiveModel::setOrder(const QString &order){ + int orderNum = mAvailableOrders.value(order); + setOrder(orderNum); +} + +void ArchiveModel::collectorFinished(){ + SmTreeItem *item = mCollector->rootItem(); + setRoot(item); +} + +ArchiveCollector::ArchiveCollector(int numFields, QObject *parent) : QThread(parent), mNumFields(numFields) { + mDb = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), "archivedb"); + mDb.open(); +} + +void ArchiveCollector::populate(int order, SmTreeItem *rootItem){ + mRootItem = rootItem; + mSortOrder = order; +} + +void ArchiveCollector::run(){ + switch (mSortOrder){ + case ArchiveModel::SeriesName: populateBySeriesName(); break; - case Actor: - populateByActor(); - break; - case Genre: + case ArchiveModel::Genre: populateByGenre(); break; + case ArchiveModel::Actor: + populateByActor(); + break; default: return; } } -void ArchiveModel::setOrder(const QString &order){ - int orderNum = mAvailableOrders.value(order); - setOrder(orderNum); -} - -void ArchiveModel::populateBySeriesName() { - SmTreeItem *rootItem = new SmTreeItem(NumFields); - fetchChildren(rootItem); - fetchSeries(QVariant(), rootItem); - for(int i = 0; i < rootItem->childCount(); ++i){ - fetchParts(QVariant(), rootItem->child(i)); +void ArchiveCollector::populateBySeriesName() { + fetchSeries(QVariant(), mRootItem); + for(int i = 0; i < mRootItem->childCount(); ++i){ + QString msg = QString("Processing %1").arg(mRootItem->child(i)->data(ArchiveModel::Name).toString()); + emit message(msg); + fetchParts(QVariant(), mRootItem->child(i)); } - setRoot(rootItem); } -void ArchiveModel::populateByGenre(){ +void ArchiveCollector::populateByGenre(){ QSqlQuery genreIdQuery = QSqlQuery("SELECT igenres_id, tgenrename FROM genres ORDER BY tgenrename", mDb); - SmTreeItem *rootItem = new SmTreeItem(NumFields); while(genreIdQuery.next()){ QList genreIdData; - genreIdData << genreIdQuery.value(1) << genreIdQuery.value(0) << QVariant() << QVariant() << GenreNode << false << QVariant() << QVariant() << QVariant(); - SmTreeItem *genreIdItem = new SmTreeItem(genreIdData, rootItem); - rootItem->appendChild(genreIdItem); + genreIdData << genreIdQuery.value(1) << genreIdQuery.value(0) << QVariant() << QVariant() << ArchiveModel::GenreNode << false << QVariant() << QVariant() << QVariant(); + SmTreeItem *genreIdItem = new SmTreeItem(genreIdData, mRootItem); + mRootItem->appendChild(genreIdItem); } - fetchChildren(rootItem); - setRoot(rootItem); + fetchChildren(mRootItem); } -void ArchiveModel::populateByActor(){ +void ArchiveCollector::populateByActor(){ QSqlQuery actorIdQuery = QSqlQuery("SELECT iactors_id, tactorname FROM actors ORDER BY tactorname", mDb); - SmTreeItem *rootItem = new SmTreeItem(NumFields); while(actorIdQuery.next()){ QList actorIdData; - actorIdData << actorIdQuery.value(1) << actorIdQuery.value(0) << QVariant() << QVariant() << GenreNode << false << QVariant() << QVariant() << QVariant(); - SmTreeItem *actorIdItem = new SmTreeItem(actorIdData, rootItem); - rootItem->appendChild(actorIdItem); + actorIdData << actorIdQuery.value(1) << actorIdQuery.value(0) << QVariant() << QVariant() << ArchiveModel::GenreNode << false << QVariant() << QVariant() << QVariant(); + SmTreeItem *actorIdItem = new SmTreeItem(actorIdData, mRootItem); + mRootItem->appendChild(actorIdItem); } - fetchChildren(rootItem); - setRoot(rootItem); + fetchChildren(mRootItem); } -void ArchiveModel::fetchChildren(SmTreeItem *parent){ +void ArchiveCollector::fetchChildren(SmTreeItem *parent){ for(int i = 0; i < parent->childCount(); ++i){ - fetchSeries(parent->child(i)->data(GenericId), parent->child(i)); + QString msg = QString("Processing %1").arg(parent->child(i)->data(ArchiveModel::Name).toString()); + emit message(msg); + fetchSeries(parent->child(i)->data(ArchiveModel::GenericId), parent->child(i)); for(int j = 0; j < parent->child(i)->childCount(); ++j){ SmTreeItem *seriesItem = parent->child(i)->child(j); - fetchParts(parent->child(i)->data(GenericId), seriesItem); + fetchParts(parent->child(i)->data(ArchiveModel::GenericId), seriesItem); } } } -void ArchiveModel::fetchSeries(const QVariant &id, SmTreeItem *parent){ +void ArchiveCollector::fetchSeries(const QVariant &id, SmTreeItem *parent){ QSqlQuery seriesIdQuery(mDb); - switch (mOrder) { - case SeriesName: + switch (mSortOrder) { + case ArchiveModel::SeriesName: seriesIdQuery.prepare("SELECT iseries_id, tseries_name FROM series ORDER BY tseries_name"); break; - case Genre: + case ArchiveModel::Genre: seriesIdQuery.prepare("SELECT distinct(series.iseries_id), tseries_name FROM series, seriesparts, seriesparts_genremap WHERE seriesparts_genremap.igenres_id = :genreid AND seriesparts_genremap.iseriesparts_id = seriesparts.iseriesparts_id AND seriesparts.iseries_id = series.iseries_id ORDER BY tseries_name"); seriesIdQuery.bindValue(":genreid", id); break; - case Actor: + case ArchiveModel::Actor: seriesIdQuery.prepare("SELECT distinct(series.iseries_id), tseries_name FROM series, seriesparts, seriesparts_actormap WHERE seriesparts_actormap.iactors_id = :actorid AND seriesparts_actormap.iseriesparts_id = seriesparts.iseriesparts_id AND seriesparts.iseries_id = series.iseries_id ORDER BY tseries_name"); seriesIdQuery.bindValue(":actorid", id); break; @@ -148,34 +169,34 @@ void ArchiveModel::fetchSeries(const QVariant &id, SmTreeItem *parent){ } while(seriesIdQuery.next()){ QList seriesData; - seriesData << seriesIdQuery.value(1) << seriesIdQuery.value(0) << QVariant() << QVariant() << SeriesNode << false << QVariant() << QVariant() << QVariant(); + seriesData << seriesIdQuery.value(1) << seriesIdQuery.value(0) << QVariant() << QVariant() << ArchiveModel::SeriesNode << false << QVariant() << QVariant() << QVariant(); SmTreeItem *seriesItem = new SmTreeItem(seriesData, parent); parent->appendChild(seriesItem); } - parent->setData(Count, parent->childCount()); + parent->setData(ArchiveModel::Count, parent->childCount()); } -void ArchiveModel::fetchParts(const QVariant &id, SmTreeItem *parent){ +void ArchiveCollector::fetchParts(const QVariant &id, SmTreeItem *parent){ QSqlQuery partsQuery(mDb); - if(mOrder == SeriesName){ + if(mSortOrder == ArchiveModel::SeriesName){ partsQuery.prepare("SELECT iseriesparts_id, iseriespart, bfavorite, tsubtitle FROM seriesparts WHERE iseries_id = :id ORDER BY iseriespart"); - partsQuery.bindValue(":id", parent->data(GenericId)); - }else if(mOrder == Genre){ + partsQuery.bindValue(":id", parent->data(ArchiveModel::GenericId)); + }else if(mSortOrder == ArchiveModel::Genre){ partsQuery.prepare("SELECT seriesparts.iseriesparts_id, iseriespart, bfavorite, tsubtitle FROM seriesparts, seriesparts_genremap WHERE iseries_id = :id AND seriesparts.iseriesparts_id = seriesparts_genremap.iseriesparts_id AND seriesparts_genremap.igenres_id = :genreid ORDER BY iseriespart"); - partsQuery.bindValue(":id", parent->data(GenericId)); + partsQuery.bindValue(":id", parent->data(ArchiveModel::GenericId)); partsQuery.bindValue(":genreid", id); - }else if(mOrder == Actor){ + }else if(mSortOrder == ArchiveModel::Actor){ partsQuery.prepare("SELECT seriesparts.iseriesparts_id, iseriespart, bfavorite, tsubtitle FROM seriesparts, seriesparts_actormap WHERE iseries_id = :id AND seriesparts.iseriesparts_id = seriesparts_actormap.iseriesparts_id AND seriesparts_actormap.iactors_id = :actorid ORDER BY iseriespart"); - partsQuery.bindValue(":id", parent->data(GenericId)); + partsQuery.bindValue(":id", parent->data(ArchiveModel::GenericId)); partsQuery.bindValue(":actorid", id); } partsQuery.exec(); while(partsQuery.next()){ QList partData; - partData << parent->data(Name) << parent->data(GenericId) << partsQuery.value(0) << partsQuery.value(1) << SeriesPartNode << partsQuery.value(2) << partsQuery.value(3) << QVariant(); + partData << parent->data(ArchiveModel::Name) << parent->data(ArchiveModel::GenericId) << partsQuery.value(0) << partsQuery.value(1) << ArchiveModel::SeriesPartNode << partsQuery.value(2) << partsQuery.value(3) << QVariant(); SmTreeItem *partItem = new SmTreeItem(partData, parent); parent->appendChild(partItem); } - parent->setData(Count, parent->childCount()); + parent->setData(ArchiveModel::Count, parent->childCount()); } diff --git a/archivemodel.h b/archivemodel.h index 1f39717..c07fc7b 100644 --- a/archivemodel.h +++ b/archivemodel.h @@ -8,11 +8,14 @@ #ifndef ARCHIVEMODEL_H #define ARCHIVEMODEL_H -#include #include +#include +#include #include "smtreemodel.h" +class ArchiveCollector; + class ArchiveModel : public SmTreeModel { Q_OBJECT public: @@ -24,14 +27,38 @@ class ArchiveModel : public SmTreeModel { explicit ArchiveModel(const QStringList &headers, QObject *parent = 0); const QStringList availableOrders() const; const QHash availableOrdersHash() const { return mAvailableOrders; } + ArchiveCollector *collector() { return mCollector; } virtual QVariant data(const QModelIndex &index, int role) const; - signals: - public slots: void setOrder(int order); void setOrder(const QString &order); + private slots: + void collectorFinished(); + + private: + QSqlDatabase mDb; + QHash mAvailableOrders; + ArchiveCollector *mCollector; + int mOrder; +}; + +class ArchiveCollector : public QThread { + Q_OBJECT + public: + explicit ArchiveCollector(int numFields, QObject *parent = 0); + SmTreeItem *rootItem() { return mRootItem; } + + public slots: + void populate(int order, SmTreeItem *rootItem); + + signals: + void message(const QString message); + + protected: + virtual void run(); + private: void populateBySeriesName(); void populateByGenre(); @@ -40,8 +67,9 @@ class ArchiveModel : public SmTreeModel { void fetchSeries(const QVariant &id, SmTreeItem *parent); void fetchParts(const QVariant &id, SmTreeItem *parent); QSqlDatabase mDb; - QHash mAvailableOrders; - int mOrder; + SmTreeItem *mRootItem; + int mNumFields; + int mSortOrder; }; #endif // ARCHIVEMODEL_H diff --git a/archiveview.cpp b/archiveview.cpp index def3609..dbc3c39 100644 --- a/archiveview.cpp +++ b/archiveview.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -17,9 +18,15 @@ #include "archiveview.h" #include "smglobals.h" -ArchiveView::ArchiveView(QWidget *parent) : QWidget(parent) { +ArchiveView::ArchiveView(QWidget *parent) : QWidget(parent), mConstructing(true) { QSettings s; mArchiveModel = static_cast(SmGlobals::instance()->model("ArchiveModel")); + connect(mArchiveModel->collector(), SIGNAL(started()), this, SLOT(collectorStarted())); + connect(mArchiveModel->collector(), SIGNAL(finished()), this, SLOT(collectorFinished())); + mProgress = new ArchiveProgressDialog(this); + mProgress->setHidden(true); + connect(mArchiveModel->collector(), SIGNAL(message(QString)), mProgress, SLOT(setMessage(QString))); + mProxy = new ArchiveProxy; mProxy->setSourceModel(mArchiveModel); mTree = new ArchiveTree; @@ -32,12 +39,16 @@ ArchiveView::ArchiveView(QWidget *parent) : QWidget(parent) { mTree->setColumnHidden(ArchiveModel::Subtitle, true); mTree->setColumnHidden(ArchiveModel::Count, true); mTree->resizeColumnToContents(ArchiveModel::Name); + QString sortOrderName = s.value("archivemodel/sortorder", "Series Name").toString(); mSortOrder = new QComboBox; mSortOrder->addItems(mArchiveModel->availableOrders()); - connect(mSortOrder, SIGNAL(currentIndexChanged(QString)), mArchiveModel, SLOT(setOrder(QString))); - connect(mSortOrder, SIGNAL(currentTextChanged(QString)), mArchiveModel, SLOT(setOrder(QString))); mSortOrder->setCurrentText(sortOrderName); + // this is _not_ redundant! when sortOrderName is the first + // item in the list, nothing will happen otherwise! + mArchiveModel->setOrder(sortOrderName); + connect(mSortOrder, SIGNAL(currentIndexChanged(QString)), mArchiveModel, SLOT(setOrder(QString))); + QLabel *l1 = new QLabel(tr("Filter")); mFilter = new QLineEdit; QString savedFilter = s.value("archivemodel/filter", QString()).toString(); @@ -80,6 +91,10 @@ void ArchiveView::writeSettings() { s.setValue("archivemodel/filter", mFilter->text()); } +QWidget *ArchiveView::progressDialog(){ + return qobject_cast(mProgress); +} + void ArchiveView::setFilter(){ QString filter = mFilter->text(); mProxy->setFilter(filter, currentSortOrder()); @@ -92,9 +107,32 @@ void ArchiveView::clearFilter(){ mTree->collapseAll(); } +void ArchiveView::collectorStarted(){ + if(mConstructing){ + return; + } + mProgress->show(); +} + +void ArchiveView::collectorFinished(){ + mProgress->hide(); +} + ArchiveTree::ArchiveTree(QWidget *parent) : SmTreeView(parent) { } +ArchiveProgressDialog::ArchiveProgressDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){ + QHBoxLayout *mainLayout = new QHBoxLayout; + mMessage = new QLabel; + mainLayout->addWidget(mMessage); + setLayout(mainLayout); +} + +void ArchiveProgressDialog::setMessage(const QString &msg){ + QString message = QString(tr("Gathering data... please wait!
  • %1
")).arg(msg); + mMessage->setText(message); +} + ArchiveFiles::ArchiveFiles(QWidget *parent) : SmTreeView(parent){ } diff --git a/archiveview.h b/archiveview.h index b76e487..a62fd66 100644 --- a/archiveview.h +++ b/archiveview.h @@ -8,20 +8,23 @@ #ifndef ARCHIVEVIEW_H #define ARCHIVEVIEW_H -#include -#include +#include #include +#include +#include #include "archivemodel.h" #include "smtreeview.h" -class QSortFilterProxyModel; class QComboBox; +class QLabel; class QLineEdit; +class QSortFilterProxyModel; class ArchiveTree; class ArchiveFiles; class ArchiveProxy; +class ArchiveProgressDialog; class ArchiveView : public QWidget { Q_OBJECT @@ -29,10 +32,16 @@ class ArchiveView : public QWidget { explicit ArchiveView(QWidget *parent = 0); int currentSortOrder() const; void writeSettings(); + // this is needed for displaying the progress dialog in the + // center of the main window... + void setConstructingDone() { mConstructing = false; } + QWidget *progressDialog(); private slots: void setFilter(); void clearFilter(); + void collectorStarted(); + void collectorFinished(); private: QComboBox *mSortOrder; @@ -41,6 +50,8 @@ class ArchiveView : public QWidget { ArchiveFiles *mFiles; ArchiveModel *mArchiveModel; ArchiveProxy *mProxy; + ArchiveProgressDialog *mProgress; + bool mConstructing; }; class ArchiveTree : public SmTreeView { @@ -52,6 +63,18 @@ class ArchiveTree : public SmTreeView { ArchiveModel *mModel; }; +class ArchiveProgressDialog : public QDialog { + Q_OBJECT + public: + explicit ArchiveProgressDialog(QWidget *parent = 0, Qt::WindowFlags f = Qt::WindowStaysOnTopHint); + + public slots: + void setMessage(const QString &msg); + + private: + QLabel *mMessage; +}; + class ArchiveFiles : public SmTreeView { public: explicit ArchiveFiles(QWidget *parent = 0); diff --git a/shemov.cpp b/shemov.cpp index 6c53879..1baa7d5 100644 --- a/shemov.cpp +++ b/shemov.cpp @@ -140,6 +140,9 @@ SheMov::SheMov(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, fla readSettings(); mFSWidget->fileView()->setFocus(Qt::ActiveWindowFocusReason); mPicWidget->readSettings(); + mArchive->setConstructingDone(); + Helper::centerWidget(mArchive->progressDialog()); + mArchive->progressDialog()->show(); Helper::centerWidget(picViewer); } diff --git a/smdirwatcher.h b/smdirwatcher.h index 5f3ef55..b0edd2f 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 -- cgit v1.2.3-70-g09d2