diff options
author | Arno Moeller <arno.moeller@bit.bremerhaven.de> | 2013-07-18 16:23:22 +0200 |
---|---|---|
committer | Arno Moeller <arno.moeller@bit.bremerhaven.de> | 2013-07-19 13:02:51 +0200 |
commit | 536643c36b61ddbce1a1b3efb70488ad83f7ae7b (patch) | |
tree | 69756bfa3cd37a5edc782db87e13829c3cf0c3ef | |
parent | 057da448ad06de20b8054ae1ba5ed7f6fb656c1b (diff) | |
download | SheMov-536643c36b61ddbce1a1b3efb70488ad83f7ae7b.tar.gz SheMov-536643c36b61ddbce1a1b3efb70488ad83f7ae7b.tar.bz2 SheMov-536643c36b61ddbce1a1b3efb70488ad83f7ae7b.zip |
Clean up the db analyzer mess
I guess I was quite drunk when I designed this overengineered,
multithreaded monstrosity. Replace it with 4 nifty dialogs.
-rw-r--r-- | archivetreeview.cpp | 13 | ||||
-rw-r--r-- | archivetreeview.h | 1 | ||||
-rw-r--r-- | dbanalyzer.cpp | 506 | ||||
-rw-r--r-- | dbanalyzer.h | 135 | ||||
-rw-r--r-- | main.cpp | 2 | ||||
-rw-r--r-- | shemov.cpp | 65 | ||||
-rw-r--r-- | shemov.h | 18 |
7 files changed, 238 insertions, 502 deletions
diff --git a/archivetreeview.cpp b/archivetreeview.cpp index 2eb0b14..d6dc7b0 100644 --- a/archivetreeview.cpp +++ b/archivetreeview.cpp @@ -156,17 +156,6 @@ void ArchiveTreeView::cleanDatabase(const QString &table){ } } -void ArchiveTreeView::selectMoviePart(int seriespartId, int seriesId){ - QModelIndex seriesIdx = mSeriesModel->findValue(seriesId, QModelIndex(), SeriesTreeModel::SeriesId); - QModelIndex partIdx = mSeriesModel->findValue(seriespartId, seriesIdx, SeriesTreeModel::SeriesPartId); - if(partIdx.isValid()){ - QModelIndex viewSelect = mSeriesWidget->seriesProxy()->mapFromSource(partIdx); - mSeriesWidget->seriesTree()->expand(viewSelect.parent()); - mSeriesWidget->seriesTree()->selectionModel()->select(viewSelect, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); - mSeriesWidget->seriesTree()->scrollTo(viewSelect.parent(), QAbstractItemView::PositionAtTop); - } -} - void ArchiveTreeView::copyPath(int type){ QModelIndexList selected = mFilesWidget->filesTree()->selectionModel()->selectedRows(); if(selected.isEmpty()){ @@ -254,7 +243,7 @@ void ArchiveTreeView::currentChanged(const QItemSelection &selected, const QItem mFilesWidget->filesTree()->header()->resizeSections(QHeaderView::ResizeToContents); setMappingItems(selectedPartIds, mActorsModel, mActorsWidget); setMappingItems(selectedPartIds, mGenresModel, mGenresWidget); - mMetaData->setSeriesPartId(selectedPartIds.at(0)); + mMetaData->setSeriesPartId(selectedPartIds.at(0)); } void ArchiveTreeView::setMappingItems(QList<int>seriesPartIds, MappingTableModel *model, MappingTableWidget *widget){ diff --git a/archivetreeview.h b/archivetreeview.h index b62d323..ad23bc1 100644 --- a/archivetreeview.h +++ b/archivetreeview.h @@ -39,7 +39,6 @@ class ArchiveTreeView : public QWidget { void showAllFiles(bool toggled); void showForBurn(bool toggled); void cleanDatabase(const QString &table); - void selectMoviePart(int seriespartId, int seriesId); void copyPath(int type); void readSettings(); diff --git a/dbanalyzer.cpp b/dbanalyzer.cpp index f9e3830..c0b47ff 100644 --- a/dbanalyzer.cpp +++ b/dbanalyzer.cpp @@ -11,441 +11,187 @@ #include <QtWidgets/QMenu> #include <QtWidgets/QStackedLayout> +#include <QStandardItemModel> +#include <QItemSelectionModel> + #include "dbanalyzer.h" #include "smtreemodel.h" #include "smtreeitem.h" #include "smglobals.h" #include "smtreeview.h" -DbAnalyzerDialog::DbAnalyzerDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f), mMarkMode(DbAnalyzer::NOMARKS), mCurrentView(0){ - //create tab widget - mTab = new QTabWidget; - - //setup analyzer - mAnalyzer = new DbAnalyzer(this); - - //no actors - QWidget *noActorsT = new QWidget; - QStringList noActorsHeaders = QStringList() << tr("Series") << tr("Part/Subtitle") << tr("Series Part") << tr("Seriespart Id") << tr("Series Id") << tr("Seriespart"); - mNoActorsV = new SmTreeView; - mNoActorsM = new SmTreeModel(noActorsHeaders, this); - mNoActorsV->setModel(mNoActorsM); - QVBoxLayout *noActorsL = new QVBoxLayout; - noActorsL->addWidget(mNoActorsV); - mNoActorsV->setColumnHidden(2, true); - mNoActorsV->setColumnHidden(3, true); - mNoActorsV->setColumnHidden(4, true); - mNoActorsV->setColumnHidden(5, true); - mNoActorsV->setEditTriggers(QTreeView::NoEditTriggers); - mNoActorsV->setSelectionBehavior(QAbstractItemView::SelectRows); - mNoActorsV->setSelectionMode(QAbstractItemView::ExtendedSelection); - mNoActorsV->setAlternatingRowColors(true); - connect(mNoActorsV, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(noDataDoubleClicked(QModelIndex))); - noActorsT->setLayout(noActorsL); - mCurrentView = mNoActorsV; - mMarkMode = DbAnalyzer::MARKS_ACTORS; - - //no covers - QWidget *noCoversT = new QWidget; - QStringList noCoversHeaders = QStringList() << tr("Series") << tr("Part/Subtitle") << tr("Series Part") << tr("Seriespart Id") << tr("Series Id") << tr("Seriespart"); - mNoCoversV = new SmTreeView; - mNoCoversM = new SmTreeModel(noCoversHeaders, this); - mNoCoversV->setModel(mNoCoversM); - QVBoxLayout *noCoversL = new QVBoxLayout; - noCoversL->addWidget(mNoCoversV); - mNoCoversV->setColumnHidden(2, true); - mNoCoversV->setColumnHidden(3, true); - mNoCoversV->setColumnHidden(4, true); - mNoCoversV->setColumnHidden(5, true); - mNoCoversV->setEditTriggers(QTreeView::NoEditTriggers); - mNoCoversV->setSelectionBehavior(QAbstractItemView::SelectRows); - mNoCoversV->setSelectionMode(QAbstractItemView::ExtendedSelection); - mNoCoversV->setAlternatingRowColors(true); - connect(mNoCoversV, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(noDataDoubleClicked(QModelIndex))); - noCoversT->setLayout(noCoversL); - - //stray actors - QWidget *strayActorsT = new QWidget; - QStringList strayActorsHeaders = QStringList() << tr("Actor") << tr("Actor Id") << tr("Count"); - mStrayActorsV = new SmTreeView; - mStrayActorsM = new SmTreeModel(strayActorsHeaders, this); - mStrayActorsV->setModel(mStrayActorsM); - QVBoxLayout *strayActorsL = new QVBoxLayout; - strayActorsL->addWidget(mStrayActorsV); - mStrayActorsV->setColumnHidden(1, true); - mStrayActorsV->setEditTriggers(QTreeView::NoEditTriggers); - mStrayActorsV->setSelectionBehavior(QAbstractItemView::SelectRows); - mStrayActorsV->setSelectionMode(QAbstractItemView::ExtendedSelection); - mStrayActorsV->setAlternatingRowColors(true); - strayActorsT->setLayout(strayActorsL); - - //stray genres - QWidget *strayGenresT = new QWidget; - QStringList strayGenresHeaders = QStringList() << tr("Genre") << tr("Genre Id") << tr("Count"); - mStrayGenresV = new SmTreeView; - mStrayGenresM = new SmTreeModel(strayGenresHeaders, this); - mStrayGenresV->setModel(mStrayGenresM); - QVBoxLayout *strayGenresL = new QVBoxLayout; - strayGenresL->addWidget(mStrayGenresV); - mStrayGenresV->setColumnHidden(1, true); - mStrayGenresV->setEditTriggers(QTreeView::NoEditTriggers); - mStrayGenresV->setSelectionBehavior(QAbstractItemView::SelectRows); - mStrayGenresV->setSelectionMode(QAbstractItemView::ExtendedSelection); - mStrayGenresV->setAlternatingRowColors(true); - strayGenresT->setLayout(strayGenresL); - - //buttons - mCancel = new QPushButton(tr("Cancel")); - connect(mCancel, SIGNAL(clicked()), this, SLOT(cancelAnalyzer())); - mRefresh = new QPushButton(tr("Refresh")); - connect(mRefresh, SIGNAL(clicked()), this, SLOT(refresh())); +DbEmptyDialog::DbEmptyDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){ + mDb = QSqlDatabase::database("treedb"); + mDb.open(); + QString c = QString(tr("<b>Unused %1</b>")).arg(caption); + QLabel *l = new QLabel(c); + mView = new SmTreeView(this); + mModel = new QStandardItemModel; + mView->setModel(mModel); + + mDelete = new QPushButton(tr("Delete")); + connect(mDelete, SIGNAL(clicked()), this, SLOT(deleteItem())); mClose = new QPushButton(tr("Close")); connect(mClose, SIGNAL(clicked()), this, SLOT(accept())); - mMark = new QPushButton(tr("Mark")); - - //button menu - QMenu *markMenu = new QMenu(mMark); - QAction *markOkA = new QAction(tr("Set OK"), this); - QAction *deleteMarkA = new QAction(tr("Delete mark"), this); - markMenu->addAction(markOkA); - markMenu->addAction(deleteMarkA); - mMark->setMenu(markMenu); - connect(markOkA, SIGNAL(triggered()), this, SLOT(setMarks())); - connect(deleteMarkA, SIGNAL(triggered()), this, SLOT(deleteMarks())); - mDelete = new QPushButton(tr("Delete...")); - connect(mDelete, SIGNAL(clicked()), this, SLOT(deleteItems())); - mButtonStack = new QStackedLayout; - mButtonStack->addWidget(mMark); - mButtonStack->addWidget(mDelete); - - //setup dialog - mTab->addTab(noActorsT, tr("No Actors")); - mTab->addTab(noCoversT, tr("No Covers")); - mTab->addTab(strayActorsT, tr("Stray actors")); - mTab->addTab(strayGenresT, tr("Stray genres")); - //buttons QHBoxLayout *buttonLayout = new QHBoxLayout; - buttonLayout->addWidget(mCancel); - buttonLayout->addWidget(mRefresh); + buttonLayout->addWidget(mDelete); buttonLayout->addStretch(); - buttonLayout->addLayout(mButtonStack); buttonLayout->addWidget(mClose); - //totals - mTotal = new QLabel(tr("<b>Total items: 0</b>")); - mTotal->setAlignment(Qt::AlignCenter); - QHBoxLayout *totalLayout = new QHBoxLayout; - totalLayout->addWidget(mTotal); - - //setup dialog QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(mTab); - mainLayout->addLayout(totalLayout); + mainLayout->addWidget(l); + mainLayout->addWidget(mView); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); - setMinimumWidth(500); - - //get things going - connect(mTab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); - connect(mAnalyzer, SIGNAL(started()), this, SLOT(analyzerStarted())); - connect(mAnalyzer, SIGNAL(finished()), this, SLOT(analyzerFinished())); - for(int i = 0; i < mTab->count(); ++i){ - mTotals << QString(); - } - mAnalyzer->start(); } -void DbAnalyzerDialog::refresh(){ - if(!mAnalyzer->isRunning()){ - mAnalyzer->start(); - } +QItemSelectionModel *DbEmptyDialog::selectionModel(){ + return mView->selectionModel(); } -void DbAnalyzerDialog::cancelAnalyzer(){ - mAnalyzer->setCancel(true); +void DbEmptyDialog::populate(){ + return; } -void DbAnalyzerDialog::analyzerStarted(){ - mCancel->setEnabled(true); - mRefresh->setEnabled(false); - mClose->setEnabled(false); +void DbEmptyDialog::deleteItem(){ + return; } -void DbAnalyzerDialog::analyzerFinished(){ - mCancel->setEnabled(false); - mRefresh->setEnabled(true); - mClose->setEnabled(true); - populate(mNoActorsV, mNoActorsM, mAnalyzer->noActors(), mAnalyzer->actorMarks()); - populate(mNoCoversV, mNoCoversM, mAnalyzer->noCovers(), mAnalyzer->coverMarks()); - populate(mStrayActorsV, mStrayActorsM, mAnalyzer->strayActors()); - populate(mStrayGenresV, mStrayGenresM, mAnalyzer->strayGenres()); - QString totalString = QString(tr("<b>Total items: %1</b>")); - mTotals[0] = totalString.arg(QString::number(mAnalyzer->noActors().count())); - mTotals[1] = totalString.arg(QString::number(mAnalyzer->noCovers().count())); - mTotals[2] = totalString.arg(QString::number(mAnalyzer->strayActors().count())); - mTotals[3] = totalString.arg(QString::number(mAnalyzer->strayGenres().count())); - mTotal->setText(mTotals.at(mTab->currentIndex())); -} +EmptyActorsDialog::EmptyActorsDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f) : DbEmptyDialog(caption, parent, f){} -void DbAnalyzerDialog::noDataDoubleClicked(const QModelIndex &idx){ - if(mTab->currentIndex() > 1){ - return; - } - if(!idx.isValid()){ - return; +void EmptyActorsDialog::populate(){ + model()->clear(); + model()->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Count") << tr("Id")); + QSqlQuery q("SELECT actors.tactorname, actors.iactors_id, COUNT(seriesparts_actormap.iactors_id) FROM actors LEFT JOIN seriesparts_actormap ON actors.iactors_id = seriesparts_actormap.iactors_id WHERE seriesparts_actormap.iactors_id IS NULL GROUP BY actors.iactors_id, actors.tactorname ORDER BY actors.tactorname", db()); + while(q.next()){ + QStandardItem *nameItem = new QStandardItem(q.value(0).toString()); + nameItem->setIcon(QIcon(":/chastity_belt.png")); + QStandardItem *idItem = new QStandardItem(QString::number(q.value(1).toInt())); + idItem->setData(q.value(1)); + QStandardItem *countItem = new QStandardItem(QString::number(q.value(2).toInt())); + countItem->setData(q.value(2)); + + model()->appendRow(QList<QStandardItem*>() << nameItem << countItem << idItem); } - const QAbstractItemModel *model = idx.model(); - QModelIndex seriesPartIdx = model->index(idx.row(), 5, idx.parent()); - QModelIndex seriesIdx = model->index(idx.row(), 4, idx.parent()); - emit partClicked(seriesPartIdx.data().toInt(), seriesIdx.data().toInt()); } -void DbAnalyzerDialog::deleteItems(){ - SmTreeView *view = 0; - int deleteMode; - switch(mTab->currentIndex()){ - case 0: - case 1: - return; - break; - case 2: - view = mStrayActorsV; - deleteMode = Actors; - break; - case 3: - view = mStrayGenresV; - deleteMode = Genres; - break; - default: - view = 0; - break; +void EmptyActorsDialog::deleteItem(){ + QModelIndexList sel = selectionModel()->selectedRows(2); + if(sel.isEmpty()){ + return; } - Q_ASSERT(view); - QModelIndexList selected = view->selectionModel()->selectedRows(1); - QList<int> ids; - foreach(QModelIndex i, selected){ - ids << i.data().toInt(); + QSqlQuery deleteQ(db()); + deleteQ.prepare("DELETE FROM actors WHERE iactors_id = :id"); + foreach(QModelIndex i, sel){ + QStandardItem *item = model()->itemFromIndex(i); + deleteQ.bindValue(":id", item->data()); + deleteQ.exec(); } - emit delItems(deleteMode, ids); + populate(); } -void DbAnalyzerDialog::tabChanged(int index){ - switch(index){ - case 0: - mMarkMode = DbAnalyzer::MARKS_ACTORS; - mCurrentView = mNoActorsV; - mButtonStack->setCurrentWidget(mMark); - break; - case 1: - mMarkMode = DbAnalyzer::MARKS_COVERS; - mCurrentView = mNoCoversV; - mButtonStack->setCurrentWidget(mMark); - break; - case 2: - mMarkMode = DbAnalyzer::NOMARKS; - mCurrentView = mStrayActorsV; - mButtonStack->setCurrentWidget(mDelete); - break; - case 3: - mMarkMode = DbAnalyzer::NOMARKS; - mCurrentView = mStrayGenresV; - mButtonStack->setCurrentWidget(mDelete); - break; - default: - mMarkMode = DbAnalyzer::NOMARKS; - mCurrentView = 0; - break; - } - mTotal->setText(mTotals.at(index)); -} +EmptyGenresDialog::EmptyGenresDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f) : DbEmptyDialog(caption, parent, f){} -void DbAnalyzerDialog::setMarks(){ - if(mMarkMode != DbAnalyzer::NOMARKS){ - const QList<int> curIds = currentIds(); - mAnalyzer->setMarks(curIds, mMarkMode, 1); - refresh(); - } -} +void EmptyGenresDialog::populate(){ + model()->clear(); + model()->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Count") << tr("Id")); + QSqlQuery q("SELECT genres.tgenrename, genres.igenres_id, COUNT(seriesparts_genremap.igenres_id) FROM genres LEFT JOIN seriesparts_genremap ON genres.igenres_id = seriesparts_genremap.igenres_id WHERE seriesparts_genremap.igenres_id IS NULL GROUP BY genres.igenres_id, genres.tgenrename ORDER BY genres.tgenrename", db()); + while(q.next()){ + QStandardItem *nameItem = new QStandardItem(q.value(0).toString()); + nameItem->setIcon(QIcon(":/chastity_belt.png")); + QStandardItem *idItem = new QStandardItem(QString::number(q.value(1).toInt())); + idItem->setData(q.value(1)); + QStandardItem *countItem = new QStandardItem(QString::number(q.value(2).toInt())); + countItem->setData(q.value(2)); -void DbAnalyzerDialog::deleteMarks(){ - if(mMarkMode != DbAnalyzer::NOMARKS){ - const QList<int> curIds = currentIds(); - mAnalyzer->deleteMarks(curIds, mMarkMode); - refresh(); + model()->appendRow(QList<QStandardItem*>() << nameItem << countItem << idItem); } } -void DbAnalyzerDialog::populate(SmTreeView *view, SmTreeModel *model, const QList<QList<QVariant> > &data, const QHash<int, QVariant> &marks){ - if(data.isEmpty()){ - return; - } - const int columns = data.first().count(); - if(columns == 0){ +void EmptyGenresDialog::deleteItem(){ + QModelIndexList sel = selectionModel()->selectedRows(2); + if(sel.isEmpty()){ return; } - SmTreeItem *root = new SmTreeItem(columns); - foreach(QList<QVariant> l, data){ - SmTreeItem *child = new SmTreeItem(l, root); - if(!marks.isEmpty()){ - int seriesId = l.at(4).toInt(); - QColor fgColor = Qt::red; - if(marks.contains(seriesId) && marks.value(seriesId).toInt() > 0){ - fgColor = Qt::green; - } - child->setForegroundColor(fgColor); - } - root->appendChild(child); + QSqlQuery deleteQ(db()); + deleteQ.prepare("DELETE FROM genres WHERE igenres_id = :id"); + foreach(QModelIndex i, sel){ + QStandardItem *item = model()->itemFromIndex(i); + deleteQ.bindValue(":id", item->data()); + deleteQ.exec(); } - model->setRoot(root); - view->resizeColumnToContents(0); + populate(); } -const QList<int> DbAnalyzerDialog::currentIds() const { - SmTreeView *curView = qobject_cast<SmTreeView*>(mCurrentView); - Q_ASSERT(curView); - QModelIndexList curIdxs = curView->selectionModel()->selectedRows(4); - QList<int> retval; - foreach(QModelIndex i, curIdxs){ - retval << i.data().toInt(); - } - return retval; -} +EmptySeriesDialog::EmptySeriesDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f) : DbEmptyDialog(caption, parent, f){} -DbAnalyzer::DbAnalyzer(QObject *parent) : QThread(parent), mCanceled(false), mStatus(Fail) { - mDb = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), "analyzerDb"); - mDb.open(); - mStatus = mDb.isOpen() ? Ok : Fail; - mNoActorQuery = new QSqlQuery(mDb); - mNoActorQuery->prepare("SELECT series.tseries_name, seriesparts.iseriespart, seriesparts.tsubtitle, series.iseries_id, seriesparts.iseriesparts_id FROM series, seriesparts LEFT JOIN seriesparts_actormap ON seriesparts.iseriesparts_id = seriesparts_actormap.iseriesparts_id WHERE iactors_id IS NULL AND seriesparts.iseries_id = series.iseries_id ORDER BY tseries_name"); - mStrayActorsQuery = new QSqlQuery(mDb); - mStrayActorsQuery->prepare("SELECT actors.tactorname, actors.iactors_id, COUNT(seriesparts_actormap.iactors_id) FROM actors LEFT JOIN seriesparts_actormap ON actors.iactors_id = seriesparts_actormap.iactors_id WHERE seriesparts_actormap.iactors_id IS NULL GROUP BY actors.iactors_id, actors.tactorname ORDER BY actors.tactorname"); - mStrayGenresQuery = new QSqlQuery(mDb); - mStrayGenresQuery->prepare("SELECT genres.tgenrename, genres.igenres_id, COUNT(seriesparts_genremap.igenres_id) FROM genres LEFT JOIN seriesparts_genremap ON genres.igenres_id = seriesparts_genremap.igenres_id WHERE seriesparts_genremap.igenres_id IS NULL GROUP BY genres.igenres_id, genres.tgenrename ORDER BY genres.tgenrename"); - mNoCoverQuery = new QSqlQuery(mDb); - mNoCoverQuery->prepare("SELECT series.tseries_name, seriesparts.iseriespart, seriesparts.tsubtitle, series.iseries_id, seriesparts.iseriesparts_id FROM files, series, seriesparts WHERE files.iseriespart_id = seriesparts.iseriesparts_id AND seriesparts.iseries_id = series.iseries_id GROUP BY files.iseriespart_id, series.tseries_name,seriesparts.iseriespart, seriesparts.tsubtitle, seriesparts.iseriesparts_id, series.iseries_id HAVING COUNT(iseriespart_id) = 1 ORDER BY series.tseries_name"); - mMarksQuery = new QSqlQuery(mDb); - mMarksQuery->prepare("SELECT id, mark_id FROM marks where mark_reason = :reason"); - mSetMarksQuery = new QSqlQuery(mDb); - mSetMarksQuery->prepare("INSERT INTO marks (id, mark_reason, mark_id) VALUES(:seriesid, :reason, :mark_id)"); - mDeleteMarksQuery = new QSqlQuery(mDb); - mDeleteMarksQuery->prepare("DELETE FROM marks WHERE id = :id AND mark_reason = :reason"); -} - -DbAnalyzer::~DbAnalyzer(){ - delete mNoActorQuery; - delete mNoCoverQuery; - delete mStrayActorsQuery; - delete mStrayGenresQuery; - delete mMarksQuery; - delete mSetMarksQuery; - delete mDeleteMarksQuery; - mDb.close(); - mDb = QSqlDatabase(); - QSqlDatabase::removeDatabase("analyzerDb"); -} - -void DbAnalyzer::setCancel(bool canceled){ - QMutexLocker m(&mCancelMutex); - mCanceled = canceled; -} - -void DbAnalyzer::setMarks(const QList<int> &ids, int reason, int mark_id){ - mDb.transaction(); - mSetMarksQuery->bindValue(":reason", reason); - mSetMarksQuery->bindValue(":mark_id", mark_id); - foreach(int id, ids){ - mSetMarksQuery->bindValue(":seriesid", id); - if(!mSetMarksQuery->exec()){ - mDb.rollback(); - return; - } +void EmptySeriesDialog::populate(){ + model()->clear(); + model()->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Count") << tr("Id")); + QSqlQuery q("SELECT series.tseries_name, COUNT(seriesparts.iseries_id), series.iseries_id FROM series LEFT JOIN seriesparts ON series.iseries_id = seriesparts.iseries_id GROUP BY 1,3 HAVING COUNT(seriesparts.iseries_id) = 0 ORDER BY series.tseries_name ASC", db()); + while(q.next()){ + QStandardItem *nameItem = new QStandardItem(q.value(0).toString()); + nameItem->setIcon(QIcon(":/chastity_belt.png")); + QStandardItem *countItem = new QStandardItem(QString::number(q.value(1).toInt())); + countItem->setData(q.value(1)); + QStandardItem *idItem = new QStandardItem(QString::number(q.value(2).toInt())); + idItem->setData(q.value(2)); + model()->appendRow(QList<QStandardItem*>() << nameItem << countItem << idItem); } - mDb.commit(); } -void DbAnalyzer::deleteMarks(const QList<int> &ids, int reason){ - mDb.transaction(); - mDeleteMarksQuery->bindValue(":reason", reason); - foreach(int id, ids){ - mDeleteMarksQuery->bindValue(":id", id); - if(!mDeleteMarksQuery->exec()){ - mDb.rollback(); - return; - } +void EmptySeriesDialog::deleteItem(){ + QModelIndexList sel = selectionModel()->selectedRows(2); + if(sel.isEmpty()){ + return; } - mDb.commit(); -} - -void DbAnalyzer::run(){ - mNoActorR = noDataCheck(mNoActorQuery); - mActorMarks = marks(MARKS_ACTORS); - mNoCoverR = noDataCheck(mNoCoverQuery); - mCoverMarks = marks(MARKS_COVERS); - mStrayActorR = strayCheck(mStrayActorsQuery); - mStrayGenresR = strayCheck(mStrayGenresQuery); + QSqlQuery deleteQ(db()); + deleteQ.prepare("DELETE FROM series WHERE iseries_id = :id"); + foreach(QModelIndex i, sel){ + QStandardItem *item = model()->itemFromIndex(i); + deleteQ.bindValue(":id", item->data()); + deleteQ.exec(); + } + populate(); } -const QList<QList<QVariant> > DbAnalyzer::noDataCheck(QSqlQuery *query){ - if(!query->exec()){ - setStatus(Fail); - return QList<QList<QVariant> >(); - } +EmptyPartsDialog::EmptyPartsDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f) : DbEmptyDialog(caption, parent, f){} - //read data - QList<QList<QVariant> > retval; - while(query->next()){ - if(mCanceled){ - break; +void EmptyPartsDialog::populate(){ + model()->clear(); + model()->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Count") << tr("Id")); + QSqlQuery q("SELECT seriesparts.iseriesparts_id, series.tseries_name, seriesparts.iseriespart, seriesparts.tsubtitle, COUNT(files.ifiles_id) FROM seriesparts LEFT JOIN files ON files.iseriespart_id = seriesparts.iseriesparts_id INNER JOIN series ON series.iseries_id = seriesparts.iseries_id GROUP BY 1,2,3,4 HAVING COUNT(files.ifiles_id) = 0 ORDER BY series.tseries_name ASC", db()); + while(q.next()){ + QString sName = q.value(1).toString(); + int part = q.value(2).toInt(); + if(part > 0){ + sName.append(QString(" %1").arg(QString::number(part))); } - QList<QVariant> res; - res << query->value(0); - if(!query->value(2).isNull()){ - res << query->value(2); - }else{ - res << query->value(1); + if(!q.value(3).toString().isEmpty()){ + sName.append(QString(" - %1").arg(q.value(3).toString())); } - res << query->value(1) << query->value(2) << query->value(3) << query->value(4); - retval << res; + QStandardItem *nameItem = new QStandardItem(sName); + nameItem->setIcon(QIcon(":/chastity_belt.png")); + QStandardItem *countItem = new QStandardItem(QString::number(q.value(4).toInt())); + countItem->setData(q.value(4)); + QStandardItem *idItem = new QStandardItem(QString::number(q.value(0).toInt())); + idItem->setData(q.value(0)); + model()->appendRow(QList<QStandardItem*>() << nameItem << countItem << idItem); } - return retval; } -const QList<QList<QVariant> > DbAnalyzer::strayCheck(QSqlQuery *query){ - if(!query->exec()){ - QMutexLocker m(&mStatusMutex); - mStatus = Fail; - return QList<QList<QVariant> >(); - } - QList<QList<QVariant> > retval; - while(query->next()){ - if(mCanceled){ - break; - } - QList<QVariant> res; - res << query->value(0) << query->value(1) << query->value(2); - retval << res; - } - return retval; -} - -QHash<int, QVariant> DbAnalyzer::marks(int markType){ - QHash<int, QVariant> retval; - if(markType == NOMARKS){ - return retval; - } - mMarksQuery->bindValue(":reason", markType); - if(!mMarksQuery->exec()){ - setStatus(Fail); - return retval; +void EmptyPartsDialog::deleteItem(){ + QModelIndexList sel = selectionModel()->selectedRows(2); + if(sel.isEmpty()){ + return; } - while(mMarksQuery->next()){ - retval.insert(mMarksQuery->value(0).toInt(), mMarksQuery->value(1)); + QSqlQuery deleteQ(db()); + deleteQ.prepare("DELETE FROM seriesparts WHERE iseriesparts_id = :id"); + foreach(QModelIndex i, sel){ + QStandardItem *item = model()->itemFromIndex(i); + deleteQ.bindValue(":id", item->data()); + deleteQ.exec(); } - return retval; -} - -void DbAnalyzer::setStatus(int status){ - QMutexLocker m(&mStatusMutex); - mStatus = status; + populate(); } diff --git a/dbanalyzer.h b/dbanalyzer.h index cc88bbc..9fc2ef2 100644 --- a/dbanalyzer.h +++ b/dbanalyzer.h @@ -8,116 +8,75 @@ #ifndef DBANALYZER_H #define DBANALYZER_H -#include <QThread> -#include <QtWidgets/QDialog> +#include <QDialog> #include <QSqlDatabase> -#include <QMutex> #include <QModelIndex> -class QTabWidget; class SmTreeView; -class SmTreeModel; -class DbAnalyzer; class QLabel; class QStackedLayout; -class DbAnalyzerDialog : public QDialog { +class QStandardItemModel; +class QItemSelectionModel; + +class DbEmptyDialog : public QDialog { Q_OBJECT public: - enum Mode { Actors, Genres }; - explicit DbAnalyzerDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); - - public slots: - void refresh(); - - signals: - void partClicked(int seriesPartId, int seriesId); - void delItems(int mode, QList<int> &ids); - - private slots: - void cancelAnalyzer(); - void analyzerStarted(); - void analyzerFinished(); - void noDataDoubleClicked(const QModelIndex &); - void deleteItems(); - void tabChanged(int index); - void setMarks(); - void deleteMarks(); + DbEmptyDialog(const QString &caption, QWidget *parent = 0, Qt::WindowFlags f = 0); + QStandardItemModel *model() { return mModel; } + QSqlDatabase db() { return mDb; } + QItemSelectionModel *selectionModel(); + + public slots: + virtual void populate(); + virtual void deleteItem(); private: - void populate(SmTreeView *view ,SmTreeModel *model, const QList<QList<QVariant> > &data, const QHash<int, QVariant> &marks = QHash<int, QVariant>()); - const QList<int> currentIds() const; - QTabWidget *mTab; - SmTreeView *mNoActorsV; - SmTreeView *mNoCoversV; - SmTreeView *mStrayActorsV; - SmTreeView *mStrayGenresV; - SmTreeModel *mNoActorsM; - SmTreeModel *mNoCoversM; - SmTreeModel *mStrayActorsM; - SmTreeModel *mStrayGenresM; + SmTreeView *mView; QPushButton *mClose; - QPushButton *mCancel; - QPushButton *mMark; - QPushButton *mRefresh; QPushButton *mDelete; - QLabel *mTotal; - QList<QString> mTotals; - DbAnalyzer *mAnalyzer; - int mMarkMode; - SmTreeView *mCurrentView; - QStackedLayout *mButtonStack; + QStandardItemModel *mModel; + QSqlDatabase mDb; }; -class DbAnalyzer : public QThread { +class EmptyActorsDialog : public DbEmptyDialog { Q_OBJECT public: - enum Status { Ok, Fail }; - enum Marks { NOMARKS = 0, MARKS_ACTORS = 1, MARKS_COVERS = 2 }; - explicit DbAnalyzer(QObject *parent = 0); - ~DbAnalyzer(); - int status() { return mStatus; } - const QList<QList<QVariant> > noActors() const { return mNoActorR; } - const QHash<int, QVariant> actorMarks() const { return mActorMarks; } - const QList<QList<QVariant> > noCovers() const { return mNoCoverR; } - const QHash<int, QVariant> coverMarks() const { return mCoverMarks; } - const QList<QList<QVariant> > strayActors() { return mStrayActorR; } - const QList<QList<QVariant> > strayGenres() { return mStrayGenresR; } + explicit EmptyActorsDialog(const QString &caption, QWidget *parent = 0, Qt::WindowFlags f = 0); public slots: - void setCancel(bool canceled); - void setMarks(const QList<int> &ids, int reason, int mark_id); - void deleteMarks(const QList<int> &ids, int reason); + virtual void populate(); + virtual void deleteItem(); +}; - signals: - void message(const QString &); +class EmptyGenresDialog : public DbEmptyDialog{ + Q_OBJECT + public: + explicit EmptyGenresDialog(const QString &caption, QWidget *parent = 0, Qt::WindowFlags f = 0); - protected: - void run(); + public slots: + virtual void populate(); + virtual void deleteItem(); +}; - private: - const QList<QList<QVariant> > noDataCheck(QSqlQuery *query); - const QList<QList<QVariant> > strayCheck(QSqlQuery *query); - QHash<int, QVariant> marks(int markType); - void setStatus(int status); - QSqlDatabase mDb; - QSqlQuery *mNoActorQuery; - QSqlQuery *mNoCoverQuery; - QSqlQuery *mStrayActorsQuery; - QSqlQuery *mStrayGenresQuery; - QSqlQuery *mMarksQuery; - QSqlQuery *mSetMarksQuery; - QSqlQuery *mDeleteMarksQuery; - QList<QList<QVariant> > mNoActorR; - QList<QList<QVariant> > mNoCoverR; - QList<QList<QVariant> > mStrayActorR; - QList<QList<QVariant> > mStrayGenresR; - QHash<int, QVariant> mActorMarks; - QHash<int, QVariant> mCoverMarks; - QMutex mCancelMutex; - QMutex mStatusMutex; - bool mCanceled; - int mStatus; +class EmptySeriesDialog : public DbEmptyDialog{ + Q_OBJECT + public: + explicit EmptySeriesDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f = 0); + + public slots: + virtual void populate(); + virtual void deleteItem(); +}; + +class EmptyPartsDialog : public DbEmptyDialog{ + Q_OBJECT + public: + explicit EmptyPartsDialog(const QString &caption, QWidget *parent, Qt::WindowFlags f = 0); + + public slots: + virtual void populate(); + virtual void deleteItem(); }; #endif // DBANALYZER_H @@ -5,7 +5,7 @@ 2 of the License, or (at your option) any later version. */ -#include <QtWidgets/QApplication> +#include <QApplication> #include "shemov.h" @@ -100,9 +100,6 @@ SheMov::SheMov(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, fla mNewMovieWizard->setMinimumWidth(1024); ArchiveController *c = SmGlobals::instance()->archiveController(); connect(mNewMovieWizard, SIGNAL(accepted()), c->archiveTreeModel(), SLOT(refresh())); - mDbAnalyzerDialog = new DbAnalyzerDialog(this); - connect(mDbAnalyzerDialog, SIGNAL(partClicked(int, int)), mATree, SLOT(selectMoviePart(int, int))); - connect(mDbAnalyzerDialog, SIGNAL(delItems(int,QList<int>&)), this, SLOT(analyzeDelete(int,QList<int>&))); mNewPicsDialog = new NewPicsDialog(this); QVBoxLayout *mainLayout = new QVBoxLayout; @@ -392,8 +389,6 @@ void SheMov::createActions(){ connect(mArchiveSelectedPicsA, SIGNAL(triggered()), this, SLOT(newPicsDialogWithFiles())); mConsistencyA = new QAction(tr("Check consisteny..."), this); connect(mConsistencyA, SIGNAL(triggered()), this, SLOT(checkConsistency())); - mAnalyzerA = new QAction(QIcon(":/higheels.png"), tr("Analyze Db..."), this); - connect(mAnalyzerA, SIGNAL(triggered()), this, SLOT(analyzeDb())); mNewPicsA = new QAction(tr("Archive pics...."), this); connect(mNewPicsA, SIGNAL(triggered()), this, SLOT(newPicsDialog())); @@ -768,18 +763,36 @@ void SheMov::createActions(){ mArchiveViewMetadataA->setData(ArchiveModel::SeriesPartNode); connect(mArchiveViewMetadataA, SIGNAL(triggered()), c->archiveTree(), SLOT(editMetadata())); - // ArchiveFiles actions + // ArchiveFiles actions <- ArchiveView! + // play selected mArchiveFilesPlayA = new QAction(tr("Play selected..."), this); connect(mArchiveFilesPlayA, SIGNAL(triggered()), c, SLOT(playSelectedFiles())); + // set quality mArchiveFilesQualityA = new QAction(tr("Set Quality..."), this); connect(mArchiveFilesQualityA, SIGNAL(triggered()), c, SLOT(editQuality())); + // set dvd mArchiveFilesDvdNoA = new QAction(tr("Set Dvd No. ..."), this); connect(mArchiveFilesDvdNoA, SIGNAL(triggered()), c, SLOT(editDvdNo())); + // set file type mArchiveFilesTypeA = new QAction(tr("Set file type..."), this); connect(mArchiveFilesTypeA, SIGNAL(triggered()), c, SLOT(editFileType())); + // set file no mArchiveFilesFileNoA = new QAction(tr("Set File No. ..."), this); connect(mArchiveFilesFileNoA, SIGNAL(triggered()), c, SLOT(editFileNo())); + // db analyzer dialogs + // analyze actors + mAnalyzeActorsA = new QAction(tr("Actors..."), this); + connect(mAnalyzeActorsA, SIGNAL(triggered()), this, SLOT(analyzeActors())); + // analyze genres + mAnalyzeGenresA = new QAction(tr("Genres..."), this); + connect(mAnalyzeGenresA, SIGNAL(triggered()), this, SLOT(analyzeGenres())); + // analyze series + mAnalyzeSeriesA = new QAction(tr("Series..."), this); + connect(mAnalyzeSeriesA, SIGNAL(triggered()), this, SLOT(analyzeSeries())); + // anaylze series parts + mAnalyzePartsA = new QAction(tr("Series Parts..."), this); + connect(mAnalyzePartsA, SIGNAL(triggered()), this, SLOT(analyzeParts())); //don't add actions with checkable(true) unless you know what you're doing! mPicActionGroup = new QActionGroup(this); @@ -804,7 +817,12 @@ void SheMov::createMenus(){ fileMenu->addAction(mNewPicsA); fileMenu->addSeparator(); fileMenu->addAction(mConsistencyA); - fileMenu->addAction(mAnalyzerA); + QMenu *analyzeMenu = new QMenu(tr("Analyze"), this); + analyzeMenu->addAction(mAnalyzeActorsA); + analyzeMenu->addAction(mAnalyzeGenresA); + analyzeMenu->addAction(mAnalyzeSeriesA); + analyzeMenu->addAction(mAnalyzePartsA); + fileMenu->addMenu(analyzeMenu); fileMenu->addAction(mRebuildFrameCacheA); fileMenu->addSeparator(); fileMenu->addAction(mQuitA); @@ -1095,7 +1113,6 @@ void SheMov::createToolBar(){ toolBar->addAction(mCdupA); toolBar->addSeparator(); toolBar->addAction(mConfigA); - toolBar->addAction(mAnalyzerA); toolBar->addSeparator(); toolBar->addAction(mShowNormalA); toolBar->addAction(mShowArchivedA); @@ -1197,16 +1214,36 @@ void SheMov::rebuildFrameCache(){ } } +void SheMov::analyzeActors(){ + EmptyActorsDialog d(tr("Actors"), this); + d.populate(); + d.exec(); +} + +void SheMov::analyzeGenres(){ + EmptyGenresDialog d(tr("Genres"), this); + d.populate(); + d.exec(); +} + +void SheMov::analyzeSeries(){ + EmptySeriesDialog d(tr("Series"), this); + d.populate(); + d.exec(); +} + +void SheMov::analyzeParts(){ + EmptyPartsDialog d(tr("Series Parts"), this); + d.populate(); + d.exec(); +} + void SheMov::checkConsistency(){ ConsistencyCheck c; c.exec(); } -void SheMov::analyzeDb(){ - mDbAnalyzerDialog->show(); -} - -void SheMov::analyzeDelete(int mode, QList<int> &ids){ +/*void SheMov::analyzeDelete(int mode, QList<int> &ids){ QString message = QString(tr("Really delete %1 items?")).arg(QString::number(ids.count())); int res = QMessageBox::question(this, tr("Delete items"), message, QMessageBox::Yes | QMessageBox::No); if(res != QMessageBox::Yes){ @@ -1226,7 +1263,7 @@ void SheMov::analyzeDelete(int mode, QList<int> &ids){ Q_ASSERT(model); model->deleteItems(ids); mDbAnalyzerDialog->refresh(); -} +}*/ void SheMov::toggleHover(QObject *object){ QAction *action = qobject_cast<QAction*>(object); @@ -8,7 +8,7 @@ #ifndef SHEMOV_H #define SHEMOV_H -#include <QtWidgets/QMainWindow> +#include <QMainWindow> #include <QVariant> class QTabWidget; @@ -18,7 +18,6 @@ class QSignalMapper; class QActionGroup; class ArchiveTreeView; class NewMovieWizard; -class DbAnalyzerDialog; class PicturesWidget; class SmTreeModel; class NewPicsDialog; @@ -48,8 +47,6 @@ class SheMov : public QMainWindow { void setSize(qint64 size); void setDuration(const QVariant dur); void checkConsistency(); - void analyzeDb(); - void analyzeDelete(int mode, QList<int> &ids); void toggleHover(QObject *object); void checkMount(bool mounted); void toggleFilterGroup(bool checked); @@ -58,6 +55,11 @@ class SheMov : public QMainWindow { void newPicsDialogWithFiles(); void rebuildFrameCache(); + void analyzeActors(); + void analyzeGenres(); + void analyzeSeries(); + void analyzeParts(); + signals: void configChanged(); @@ -107,7 +109,6 @@ class SheMov : public QMainWindow { QAction *mArchiveSelectedMovsA; QAction *mArchiveSelectedPicsA; QAction *mConsistencyA; - QAction *mAnalyzerA; QAction *mNewPicsA; QAction *mHoverDirectoriesA; QAction *mRebuildFrameCacheA; @@ -202,6 +203,12 @@ class SheMov : public QMainWindow { QAction *mArchiveFilesTypeA; QAction *mArchiveFilesFileNoA; + //DB analyze actions + QAction *mAnalyzeActorsA; + QAction *mAnalyzeGenresA; + QAction *mAnalyzeSeriesA; + QAction *mAnalyzePartsA; + QSignalMapper *mOpenWithMapperFS; QSignalMapper *mOpenWithMapperAV; QSignalMapper *mFilterMapper; @@ -234,7 +241,6 @@ class SheMov : public QMainWindow { ArchiveTreeView *mATree; NewMovieWizard *mNewMovieWizard; NewPicsDialog *mNewPicsDialog; - DbAnalyzerDialog *mDbAnalyzerDialog; PicturesWidget *mPicWidget; ArchiveView *mArchive; }; |