/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "seriestreewidget.h" #include "smtreemodel.h" #include "smglobals.h" #include "seriestreemodel.h" #include "filestreemodel.h" #include "helper.h" #include "hoverwindow.h" #include "propertiesdialog.h" SeriesTreeWidget::SeriesTreeWidget(QWidget *parent) : QWidget(parent){ //filter bar QLabel *l1 = new QLabel(tr("&Filter:")); mFilterEdit = new QLineEdit; l1->setBuddy(mFilterEdit); mFilter = new QPushButton(tr("Filter")); mClear = new QPushButton(tr("Clear")); QHBoxLayout *filterLayout = new QHBoxLayout; connect(mFilter, SIGNAL(clicked()), this, SLOT(filter())); connect(mFilterEdit, SIGNAL(returnPressed()), this, SLOT(filter())); connect(mClear, SIGNAL(clicked()), this, SLOT(clearFilter())); filterLayout->addWidget(l1); filterLayout->addWidget(mFilterEdit); filterLayout->addWidget(mFilter); filterLayout->addWidget(mClear); mFilterCompleter = new QCompleter(this); mFilterEdit->setCompleter(mFilterCompleter); //the view mView = new SeriesTreeView; mProxy = new SeriesTreeSortModel(this); mModel = static_cast(SmGlobals::instance()->model("SeriesModel")); mProxy->setSourceModel(mModel); mView->setModel(mProxy); mView->setSortingEnabled(true); for(int i = 1; i < SeriesTreeModel::NumFields; ++i){ mView->setColumnHidden(i, true); } mView->resizeColumnToContents(0); mView->setSelectionMode(QAbstractItemView::ExtendedSelection); mView->setEditTriggers(QAbstractItemView::NoEditTriggers); mView->setExpandsOnDoubleClick(false); connect(mModel, SIGNAL(needResort()), this, SLOT(resort())); connect(mView, SIGNAL(expanded(QModelIndex)), this, SLOT(itemExpanded(QModelIndex))); connect(mView, SIGNAL(collapsed(QModelIndex)), this, SLOT(itemCollaped(QModelIndex))); //cover dialog mCoverDialog = new AddCoverDialog(this); //layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(filterLayout); mainLayout->addWidget(mView); setLayout(mainLayout); //misc mCompleterProducerThread = new QThread(this); mCompleterProducer = new CompleterProducer; mCompleterProducer->moveToThread(mCompleterProducerThread); connect(mCompleterProducerThread, SIGNAL(started()), mCompleterProducer, SLOT(produce())); connect(mCompleterProducer, SIGNAL(done(QStringListModel*)), this, SLOT(producerFinished(QStringListModel*))); } SeriesTreeWidget::~SeriesTreeWidget(){ if(mCompleterProducerThread->isRunning()){ mCompleterProducerThread->terminate(); } delete mCompleterProducerThread; delete mCompleterProducer; } void SeriesTreeWidget::newSeries(){ QList data; data << tr("") << QVariant() << QVariant() << QVariant() << SeriesTreeModel::NewSeries; if(mModel->addRow(data, QModelIndex())){ QModelIndex newRow = mModel->index(mModel->rowCount(QModelIndex()) - 1, 0, QModelIndex()); if(newRow.isValid()){ QModelIndex proxyIndex = mProxy->mapFromSource(newRow); mView->selectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect); mView->edit(proxyIndex); } } } void SeriesTreeWidget::seriesAdded(QString seriesName, int seriesPart, bool resort){ if(resort){ mProxy->invalidate(); foreach(QString e, mExpandedItems){ QModelIndex idx = mProxy->mapFromSource(mModel->findValue(e)); mView->expand(idx); } } QModelIndex destIdx = mModel->findValue(seriesName); if(destIdx.isValid()){ QModelIndex proxySeries = mProxy->mapFromSource(destIdx); mView->expand(proxySeries); mView->scrollTo(proxySeries, QAbstractItemView::PositionAtCenter); QModelIndex seriesPartIdx = mModel->findValue(seriesPart, destIdx, SeriesTreeModel::SeriesPart); if(seriesPartIdx.isValid()){ destIdx = seriesPartIdx; } } if(destIdx.isValid()){ QModelIndex proxyIndex = mProxy->mapFromSource(destIdx); mView->selectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current | QItemSelectionModel::Rows); } } void SeriesTreeWidget::toggleFavorite(){ QModelIndexList selected = mView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } foreach(QModelIndex idx, selected){ if(idx.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Part){ bool curFav = idx.data(SeriesTreeModel::FavoriteRole).toBool(); QModelIndex source = mProxy->mapToSource(idx); if(source.isValid()){ source = mModel->index(source.row(), SeriesTreeModel::Favorite, source.parent()); } mModel->setData(source, !curFav, Qt::EditRole); } } } void SeriesTreeWidget::deleteFromSeries(){ QModelIndexList selected = mView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } QList series; QList parts; foreach(QModelIndex s, selected){ QModelIndex real = mProxy->mapToSource(s); if(real.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Series || real.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::NewSeries){ series << QPersistentModelIndex(real); } if(real.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Part){ parts << QPersistentModelIndex(real); } } QList removeParts; foreach(QPersistentModelIndex s, parts){ if(series.contains(s.parent())){ removeParts << s; } } foreach(QPersistentModelIndex s, removeParts){ parts.removeAll(s); } QFileInfoList files; foreach(QPersistentModelIndex s, series){ files.append(mModel->findFiles(s)); } foreach(QPersistentModelIndex p, parts){ files.append(mModel->findFiles(p)); } QString message; if(!files.isEmpty()){ message = QString(tr("

This operation will delete %1 file(s) permanently:

")).arg(files.count()); message.append(tr("
    ")); int ctr = 0; foreach(QFileInfo f, files){ ++ctr; QString li = QString(tr("
  • %1
  • ")).arg(f.absoluteFilePath()); message.append(li); if(ctr == 20){ QString elide = QString(tr("
  • (%1 more files)
  • ")).arg(files.count() - ctr); message.append(elide); break; } } message.append(tr("
")); message.append(tr("

Continue?

")); }else{ message = QString(tr("

This operation will delete no files. Continue?

")); } int retval = QMessageBox::critical(this, tr("Delete Series"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if(retval == QMessageBox::Yes){ foreach(QPersistentModelIndex s, series){ mModel->deleteFromSeries(s); } foreach(QPersistentModelIndex s, parts){ mModel->deleteFromSeries(s); } } } void SeriesTreeWidget::readSettings(){ QSettings s; QStringList expanded = s.value("archive/expanded").toStringList(); expanded.removeDuplicates(); expandItems(expanded); int sortOrder = s.value("archive/sortorder", Qt::DescendingOrder).toInt(); mView->sortByColumn(0, static_cast(sortOrder)); QString selectedSeries = s.value("archive/selectedseries").toString(); QModelIndex seriesIdx = mModel->findValue(selectedSeries); if(seriesIdx.isValid()){ QModelIndex real = mProxy->mapFromSource(seriesIdx); mView->scrollTo(real, QAbstractItemView::PositionAtCenter); mView->selectionModel()->select(real, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current | QItemSelectionModel::Rows); mView->setCurrentIndex(real); } mFilterEdit->setText(s.value("archive/filtertext").toString()); mModel->readSettings(); } void SeriesTreeWidget::writeSettings(){ QSettings s; s.setValue("archive/expanded", mExpandedItems); s.setValue("archive/sortorder", mProxy->sortOrder()); QModelIndexList selected = mView->selectionModel()->selectedRows(); if(!selected.isEmpty()){ s.setValue("archive/selectedseries", selected.at(0).data(SeriesTreeModel::NameRole).toString()); } s.setValue("archive/filtermode", mFilterMode); s.setValue("archive/filtertext", mFilterEdit->text()); } void SeriesTreeWidget::expandCurrent(){ QModelIndexList selected = mView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } QModelIndex idx = selected.at(0); mView->expand(idx); } void SeriesTreeWidget::filter(){ QString filterText = mFilterEdit->text(); if(filterText.isEmpty()){ clearFilter(); return; } switch(mFilterMode){ case FilterActor: mModel->setMappingFilter(filterText, "actor"); break; case FilterGenre: mModel->setMappingFilter(filterText, "genre"); break; case FilterQuality: mModel->setFileFilter(filterText, "siquality", SeriesTreeModel::NumericQuery); break; case FilterFileName: mModel->setFileFilter(filterText, "tfilename", SeriesTreeModel::TextQuery); break; case FilterDvdNo: mModel->setFileFilter(filterText, "idvd", SeriesTreeModel::NumericQuery); break; case FilterSize: mModel->setFileFilter(filterText, "bisize", SeriesTreeModel::NumericQuery); break; default: mProxy->setFilterRegExp(mFilterEdit->text()); } seriesTree()->expand(QModelIndex()); expandItems(mExpandedItems); } void SeriesTreeWidget::filterFavorites(bool checked){ if(checked){ mOldFilterText = mFilterEdit->text(); clearFilter(); mModel->setFavoriteFilter(); expandItems(mExpandedItems); }else{ mFilterEdit->setText(mOldFilterText); filter(); } mFilterEdit->setEnabled(!checked); mFilter->setEnabled(!checked); mClear->setEnabled(!checked); } void SeriesTreeWidget::clearFilter(){ mModel->clearFilter(); mProxy->setFilterRegExp(QString()); mFilterEdit->clear(); expandItems(mExpandedItems); } void SeriesTreeWidget::resort(){ mView->sortByColumn(0, mProxy->sortOrder()); mView->scrollTo(mView->selectionModel()->currentIndex(), QAbstractItemView::PositionAtCenter); } void SeriesTreeWidget::itemExpanded(const QModelIndex &what){ if(!mExpandedItems.contains(what.data(SeriesTreeModel::NameRole).toString())){ mExpandedItems << what.data(SeriesTreeModel::NameRole).toString(); } } void SeriesTreeWidget::itemCollaped(const QModelIndex &what){ QString itemName = what.data(SeriesTreeModel::NameRole).toString(); if(mExpandedItems.contains(itemName)){ mExpandedItems.removeAll(itemName); } } void SeriesTreeWidget::expandItems(const QStringList &items){ QStringList expand = items; if(items.isEmpty()){ expand = mExpandedItems; } foreach(QString s, expand){ QModelIndex idx = mProxy->mapFromSource(mModel->findValue(s)); mView->expand(idx); } } void SeriesTreeWidget::editItem(){ QModelIndex current = mView->selectionModel()->currentIndex(); QModelIndex real = mProxy->mapToSource(current); if(real.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Part){ PropertiesDialog dlg(this); dlg.populate(real.data(SeriesTreeModel::SeriesPartIdRole).toInt()); dlg.exec(); } /*QModelIndex real = mProxy->mapToSource(current); EditSeriesDialog dlg(real, this); dlg.exec();*/ } void SeriesTreeWidget::producerFinished(QStringListModel *model){ mFilterCompleter->setModel(model); mCompleterProducerThread->quit(); } void SeriesTreeWidget::addCover(){ QModelIndexList selected = mView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } if(selected.count() > 1){ QMessageBox::critical(this, tr("Error"), tr("Please don't select more than one item when adding covers.")); return; } QModelIndex real = mProxy->mapToSource(selected.at(0)); if(real.data(SeriesTreeModel::TypeRole).toInt() != SeriesTreeModel::Part){ QMessageBox::critical(this, tr("Error"), tr("Please select a series part when adding covers.")); return; } int retval = mCoverDialog->exec(); if(retval == QDialog::Accepted){ QString fileName = mCoverDialog->file(); QFileInfo fi(fileName); if(fi.exists()){ FilesTreeModel *filesModel = static_cast(SmGlobals::instance()->model("FilesModel")); int seriesPartId = real.data(SeriesTreeModel::SeriesPartIdRole).toInt(); int type = mCoverDialog->fileType(); if(filesModel->addFile(fileName, type, 0, -1, seriesPartId, -1)){ QString md5sum = Helper::md5Sum(fileName); Helper::moveToArchive(fileName, md5sum); filesModel->setIds(QList() << seriesPartId); emit filesReload(); } } } } void SeriesTreeWidget::setFilterMode(int mode){ mFilterMode = mode; mCompleterProducer->setMode(mode); mCompleterProducerThread->start(); } SeriesTreeView::SeriesTreeView(QWidget *parent) : QTreeView(parent), mHover(false) { setAttribute(Qt::WA_Hover); mHoverWin = new HoverWindow(this); readSettings(); } void SeriesTreeView::readSettings(){ QSettings s; mHover = s.value("ui/hoverarchive", true).toBool(); mHoverWin->setWindowOpacity(s.value("ui/hoveropacity", 10).toFloat() / 10.0); mCursorOffset = s.value("ui/cursoroffset").toInt(); } void SeriesTreeView::contextMenuEvent(QContextMenuEvent *e){ QMenu contextMenu(this); foreach(QAction *a, actions()){ contextMenu.addAction(a); } contextMenu.exec(e->globalPos()); } bool SeriesTreeView::event(QEvent *e){ QHoverEvent *hEvent = dynamic_cast(e); if(!hEvent){ return QTreeView::event(e); } if(!mHover){ return true; } QPoint hotSpot(hEvent->pos().x(), hEvent->pos().y() + mCursorOffset); QModelIndex curIdx = indexAt(hotSpot); if((e->type() == QEvent::HoverEnter) || (e->type() == QEvent::HoverMove)){ if(!curIdx.isValid() || (curIdx.parent() != QModelIndex())){ return exitHover(); } } if(e->type() == QEvent::HoverEnter){ mCurHover = curIdx; mHoverWin->setContent(curIdx.data(Qt::DisplayRole).toString(), children(curIdx)); mHoverWin->setPos(); mHoverWin->setVisible(true); return true; } if(e->type() == QEvent::HoverMove){ if(curIdx != mCurHover){ mCurHover = curIdx; mHoverWin->setContent(curIdx.data(Qt::DisplayRole).toString(), children(curIdx)); //mHoverWin->setVisible(false); mHoverWin->setPos(); mHoverWin->setVisible(true); return true; }else{ mHoverWin->setPos(); return true; } } if(e->type() == QEvent::HoverLeave){ return exitHover(); } return QTreeView::event(e); } bool SeriesTreeView::exitHover(bool exitVal){ mHoverWin->setVisible(false); mCurHover = QModelIndex(); return exitVal; } QStringList SeriesTreeView::children(const QModelIndex &idx) const{ if(!idx.isValid()){ return QStringList(); } QStringList retval; QModelIndex curIdx = idx.child(0,0); while(curIdx.isValid()){ retval << curIdx.data(Qt::DisplayRole).toString(); curIdx = idx.model()->index(curIdx.row() + 1, curIdx.column(), curIdx.parent()); } return retval; } SeriesTreeSortModel::SeriesTreeSortModel(QObject *parent) : QSortFilterProxyModel(parent) {} bool SeriesTreeSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const{ if(left.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Part && right.data(SeriesTreeModel::TypeRole).toInt() == SeriesTreeModel::Part){ return left.data(SeriesTreeModel::SeriesPartRole).toInt() < right.data(SeriesTreeModel::SeriesPartRole).toInt(); } return QSortFilterProxyModel::lessThan(left, right); } bool SeriesTreeSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { SeriesTreeModel *seriesModel = static_cast(sourceModel()); int rowFilter = seriesModel->rowFilter(); QModelIndex curIdx = sourceModel()->index(source_row, 0, source_parent); QString name = curIdx.data(SeriesTreeModel::NameRole).toString(); QRegExp filterRe = filterRegExp(); if(rowFilter == SeriesTreeModel::All){ if(filterRe.isEmpty()){ return true; }else{ return (filterRe.indexIn(name) != -1); } } if(!curIdx.isValid()){ return true; } int type = curIdx.data(SeriesTreeModel::TypeRole).toInt(); bool filterLocal = (rowFilter == SeriesTreeModel::Local); if(type == SeriesTreeModel::Series){ int row = 0; QModelIndex child = curIdx.child(row, 0); while(child.isValid()){ bool hasLocals = child.data(SeriesTreeModel::IsLocalRole).toBool(); if(hasLocals == filterLocal){ return (filterRe.indexIn(name) != -1); } child = curIdx.child(++row, 0); } }else if(type == SeriesTreeModel::Part){ bool accept = (curIdx.data(SeriesTreeModel::IsLocalRole).toBool() == filterLocal); if(accept){ return (filterRe.indexIn(name) != -1); } } return false; } AddCoverDialog::AddCoverDialog(QWidget *parent, Qt::WindowFlags f) : SmDialog(parent, f){ //File selection QLabel *l1 = new QLabel(tr("Select file")); mFile = new QLineEdit; QPushButton *mSelectFile = new QPushButton(tr("Browse...")); connect(mSelectFile, SIGNAL(clicked()), this, SLOT(selectFile())); QHBoxLayout *fileLayout = new QHBoxLayout; fileLayout->addWidget(l1); fileLayout->addWidget(mFile); fileLayout->addWidget(mSelectFile); //file type mFilesModel = static_cast(SmGlobals::instance()->model("FilesModel")); QHash coverTypes = mFilesModel->coverTypes(); mFileType = new QComboBox; QStringList types; foreach(QString t, coverTypes.values()){ types << t; } connect(mFileType, SIGNAL(currentIndexChanged(QString)), this, SLOT(typeChanged(QString))); mFileType->addItems(types); QHBoxLayout *typesLayout = new QHBoxLayout; typesLayout->setAlignment(Qt::AlignCenter); typesLayout->addWidget(mFileType); //buttons mOk = new QPushButton(tr("Ok")); connect(mOk, SIGNAL(clicked()), this, SLOT(accept())); mCancel = new QPushButton(tr("Cancel")); connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); buttonLayout->addWidget(mOk); buttonLayout->addWidget(mCancel); //main layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(fileLayout); mainLayout->addLayout(typesLayout); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); } const QString AddCoverDialog::file() const { return mFile->text(); } void AddCoverDialog::selectFile(){ QString startDir = mLastOpenedDir; if(startDir.isEmpty()){ QSettings s; startDir = s.value("paths/selecteddir").toString(); } QString file = QFileDialog::getOpenFileName(this, tr("Select cover"), startDir); mFile->setText(file); QFileInfo fi(file); mLastOpenedDir = fi.absolutePath(); } void AddCoverDialog::typeChanged(const QString &type){ QHash::const_iterator it = mFilesModel->coverTypes().constBegin(); while(it != mFilesModel->coverTypes().constEnd()){ if(it.value() == type){ mCurrentType = it.key(); return; } ++it; } } EditSeriesDialog::EditSeriesDialog(const QModelIndex &idx, QWidget *parent) : QDialog(parent), mIdx(idx) { //title + subtitle QGroupBox *seriesTitleBox = new QGroupBox(tr("Title")); mTitle = new QLineEdit; QString title = mIdx.data(SeriesTreeModel::NameRole).toString(); QFontMetrics fm(qApp->font()); int titleWidth = fm.width(title); mTitle->setMinimumWidth(titleWidth + fm.maxWidth()); mTitle->setText(title); QFormLayout *titleLayout = new QFormLayout; titleLayout->addRow(tr("&Title"), mTitle); mSubtitle = new QLineEdit; mSubtitle->setEnabled(false); int type = mIdx.data(SeriesTreeModel::TypeRole).toInt(); if(type == SeriesTreeModel::Part){ titleLayout->addRow(tr("&Subtitle"), mSubtitle); mSubtitle->setEnabled(true); mSubtitle->setText(mIdx.data(SeriesTreeModel::SubtitleRole).toString()); mTitle->setEnabled(false); } seriesTitleBox->setLayout(titleLayout); //seriespart + favorite QGroupBox *partDataBox = new QGroupBox(tr("Other data")); QHBoxLayout *partNoLayout = new QHBoxLayout; mPartNo = new QSpinBox; mPartNo->setMinimum(1); mPartNo->setValue(mIdx.data(SeriesTreeModel::SeriesPartRole).toInt()); mHasPartNo = new QCheckBox(tr("Element has Part no.")); connect(mHasPartNo, SIGNAL(stateChanged(int)), this, SLOT(hasPartNoStateChanged(int))); mHasPartNo->setChecked(mIdx.data(SeriesTreeModel::SeriesPartRole).toInt()); partNoLayout->addWidget(mHasPartNo); partNoLayout->addStretch(); partNoLayout->addWidget(mPartNo); mFavorite = new QCheckBox(tr("Favorite")); mFavorite->setChecked(mIdx.data(SeriesTreeModel::FavoriteRole).toBool()); QVBoxLayout *partDataLayout = new QVBoxLayout; partDataLayout->addLayout(partNoLayout); partDataLayout->addWidget(mFavorite); partDataBox->setLayout(partDataLayout); //buttons QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); mOk = new QPushButton(tr("Ok")); connect(mOk, SIGNAL(clicked()), this, SLOT(accept())); buttonLayout->addWidget(mOk); mCancel = new QPushButton(tr("Cancel")); connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); buttonLayout->addWidget(mCancel); //main layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(seriesTitleBox); mainLayout->addWidget(partDataBox); partDataBox->setVisible(type == SeriesTreeModel::Part); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); } void EditSeriesDialog::accept(){ SeriesTreeModel *model = static_cast(SmGlobals::instance()->model("SeriesModel")); QModelIndex favoriteIdx = model->index(mIdx.row(), SeriesTreeModel::Favorite, mIdx.parent()); model->setData(favoriteIdx, (mFavorite->checkState() == Qt::Checked), Qt::EditRole); QModelIndex titleIdx = model->index(mIdx.row(), SeriesTreeModel::Name, mIdx.parent()); model->setData(titleIdx, mTitle->text().toLower().trimmed(), Qt::EditRole); QModelIndex subtitleIdx = model->index(mIdx.row(), SeriesTreeModel::Subtitle, mIdx.parent()); model->setData(subtitleIdx, mSubtitle->text().toLower().trimmed(), Qt::EditRole); bool hasPartNo = mHasPartNo->isChecked(); int partNo = hasPartNo ? mPartNo->value() : 0; QModelIndex partNoIdx = model->index(mIdx.row(), SeriesTreeModel::SeriesPart, mIdx.parent()); model->setData(partNoIdx, partNo, Qt::EditRole); QDialog::accept(); } void EditSeriesDialog::hasPartNoStateChanged(int state){ mPartNo->setEnabled(state == Qt::Checked); } CompleterProducer::CompleterProducer(int Mode, QObject *parent) : QObject(parent), mMode(Mode){ mDb = QSqlDatabase::cloneDatabase(QSqlDatabase::database("treedb"), "complprod"); mDb.open(); mSeriesQuery = new QSqlQuery(mDb); mSeriesQuery->prepare("SELECT DISTINCT(tseries_name) FROM series"); mQueryHash.insert(SeriesTreeWidget::FilterSeries, mSeriesQuery); mActorsQuery = new QSqlQuery(mDb); mActorsQuery->prepare("SELECT DISTINCT(tactorname) FROM actors"); mQueryHash.insert(SeriesTreeWidget::FilterActor, mActorsQuery); mGenresQuery = new QSqlQuery(mDb); mGenresQuery->prepare("SELECT DISTINCT(tgenrename) FROM genres"); mQueryHash.insert(SeriesTreeWidget::FilterGenre, mGenresQuery); mFileNameQuery = new QSqlQuery(mDb); mFileNameQuery->prepare("SELECT DISTINCT(tfilename) FROM files"); mQueryHash.insert(SeriesTreeWidget::FilterFileName, mFileNameQuery); mSizeQuery = new QSqlQuery(mDb); mSizeQuery->prepare("SELECT DISTINCT(bisize) FROM files"); mQueryHash.insert(SeriesTreeWidget::FilterSize, mSizeQuery); mQualityQuery = new QSqlQuery(mDb); mQualityQuery->prepare("SELECT DISTINCT(siquality) FROM files"); mQueryHash.insert(SeriesTreeWidget::FilterQuality, mQualityQuery); mDvdNoQuery = new QSqlQuery(mDb); mDvdNoQuery->prepare("SELECT DISTINCT(siquality) FROM files"); mQueryHash.insert(SeriesTreeWidget::FilterDvdNo, mDvdNoQuery); mModel = new QStringListModel; } CompleterProducer::~CompleterProducer(){ delete mSeriesQuery; delete mActorsQuery; delete mGenresQuery; delete mFileNameQuery; delete mSizeQuery; delete mQualityQuery; delete mDvdNoQuery; mDb.close(); mDb = QSqlDatabase(); } void CompleterProducer::produce(){ QSqlQuery *query = mQueryHash.value(mMode); QStringList values; query->exec(); while(query->next()){ values << query->value(0).toString(); } mModel->setStringList(values); emit done(mModel); }