/* 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 "randomtab.h" #include "helper.h" RandomTab::RandomTab(QWidget *parent) : QWidget(parent) { mDb = QSqlDatabase::database("treedb"); mLog = new QTextEdit; mLog->setFont(QFont("courier new", -1 , QFont::Bold)); mGenreModel = new QStandardItemModel(this); mActorModel = new QStandardItemModel(this); setupModels(); setupGui(); setupActions(); mFileView->setContextMenu(mContextMenu); clearAll(); readSettings(); mValidDvds = validDvdNos(); select(); } RandomTab::~RandomTab(){ writeSettings(); } void RandomTab::setupGui(){ QGroupBox *numBox = new QGroupBox(tr("Select no.")); mNumber = new QLineEdit; QIntValidator *numValidator = new QIntValidator(1, 100, this); mNumber->setValidator(numValidator); mNumber->setText("10"); QHBoxLayout *numL = new QHBoxLayout; numL->addWidget(mNumber); numBox->setLayout(numL); QGroupBox *genreBox = new QGroupBox(tr("Genres")); mGenre1 = new QComboBox; mGenre1->setModel(mGenreModel); mGenre2 = new QComboBox; mGenre2->setModel(mGenreModel); mGenre3 = new QComboBox; mGenre3->setModel(mGenreModel); mGenreBoxes << mGenre1 << mGenre2 << mGenre3; QVBoxLayout *genreL = new QVBoxLayout; genreL->addWidget(mGenre1); genreL->addWidget(mGenre2); genreL->addWidget(mGenre3); genreBox->setLayout(genreL); QGroupBox *actorBox = new QGroupBox(tr("Actors")); mActor1 = new QComboBox; mActor1->setModel(mActorModel); mActor2 = new QComboBox; mActor2->setModel(mActorModel); mActor3 = new QComboBox; mActor3->setModel(mActorModel); mActorBoxes << mActor1 << mActor2 << mActor3; QVBoxLayout *actorL = new QVBoxLayout; actorL->addWidget(mActor1); actorL->addWidget(mActor2); actorL->addWidget(mActor3); actorBox->setLayout(actorL); QGroupBox *actionBox = new QGroupBox(tr("Energize!")); mRefresh = new QPushButton(QIcon(":/refresh.png"), tr("Refresh")); connect(mRefresh, SIGNAL(clicked()), this, SLOT(refreshComboboxes())); mClear = new QPushButton(QIcon(":/delete.png"), tr("Clear")); connect(mClear, SIGNAL(clicked()), this, SLOT(clearAll())); mSelect = new QPushButton(QIcon(":/huge_bra.png"), tr("Go!")); connect(mSelect, SIGNAL(clicked()), this, SLOT(select())); QGridLayout *actionL = new QGridLayout; actionL->addWidget(mClear, 0, 0); actionL->addWidget(mRefresh, 0, 1); actionL->addWidget(mSelect, 1, 0, 2, 0); actionBox->setLayout(actionL); QGroupBox *playBox = new QGroupBox(tr("Play")); mPlayAll = new QPushButton(QIcon(":/gaping_ass.png"), tr("Play All")); connect(mPlayAll, SIGNAL(clicked()), this, SLOT(playAll())); mPlaySelected = new QPushButton(QIcon(":/big_ass.png"), tr("Play Selected")); connect(mPlaySelected, SIGNAL(clicked()), this, SLOT(playSelected())); QVBoxLayout *playL = new QVBoxLayout; playL->addWidget(mPlaySelected); playL->addWidget(mPlayAll); playBox->setLayout(playL); QWidget *leftWidget = new QWidget; QVBoxLayout *lwL = new QVBoxLayout; lwL->addWidget(numBox); lwL->addWidget(genreBox); lwL->addWidget(actorBox); lwL->addWidget(actionBox); lwL->addWidget(playBox); lwL->addStretch(); leftWidget->setLayout(lwL); mFileView = new RandomFileView; mFileView->setAlternatingRowColors(true); mFileView->setRootIsDecorated(false); mFileView->setSelectionMode(QAbstractItemView::ExtendedSelection); mFileView->setSelectionBehavior(QAbstractItemView::SelectRows); connect(mFileView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(playDoubleclicked(QModelIndex))); mFileModel = new QStandardItemModel; mFileProxy = new QSortFilterProxyModel; mFileProxy->setSourceModel(mFileModel); mFileView->setModel(mFileProxy); QGroupBox *logBox = new QGroupBox(tr("Log")); QHBoxLayout *logL = new QHBoxLayout; logL->addWidget(mLog); logBox->setLayout(logL); QSplitter *topBottmSplitter = new QSplitter(Qt::Vertical); topBottmSplitter->addWidget(mFileView); topBottmSplitter->addWidget(logBox); topBottmSplitter->setStretchFactor(0, 4); QSplitter *leftRightSplitter = new QSplitter(Qt::Horizontal); leftRightSplitter->addWidget(leftWidget); leftRightSplitter->addWidget(topBottmSplitter); leftRightSplitter->setStretchFactor(1, 4); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(leftRightSplitter); setLayout(mainLayout); } void RandomTab::setupActions(){ mPlayAllA = new QAction(QIcon(":/gaping_ass.png"), tr("Play All"), this); connect(mPlayAllA, SIGNAL(triggered()), this, SLOT(playAll())); mPlaySelectedA = new QAction(QIcon(":/big_ass.png"), tr("Play Selected"), this); connect(mPlaySelectedA, SIGNAL(triggered()), this, SLOT(playSelected())); mRefreshA = new QAction(QIcon(":/refresh.png"), tr("Refresh")); connect(mRefreshA, SIGNAL(triggered()), this, SLOT(refreshComboboxes())); mClearA = new QAction(QIcon(":/delete.png"), tr("Clear"), this); connect(mClearA, SIGNAL(triggered()), this, SLOT(clearAll())); mGoA = new QAction(QIcon(":/huge_bra.png"), tr("Select"), this); connect(mGoA, SIGNAL(triggered()), this, SLOT(select())); mConfigureA = new QAction(QIcon(":/chastity_belt.png"), tr("Configure..."), this); connect(mConfigureA, SIGNAL(triggered()), this, SIGNAL(configure())); mFileView->actions() << mPlayAllA << mPlaySelectedA << mRefreshA << mClearA << mGoA << mConfigureA; mContextMenu = new QMenu(this); mContextMenu->addAction(mPlaySelectedA); mContextMenu->addAction(mPlayAllA); mContextMenu->addSeparator(); mContextMenu->addAction(mGoA); mEditMenu = new QMenu(tr("&Edit"), this); mEditMenu->addAction(mPlaySelectedA); mEditMenu->addAction(mPlayAllA); mEditMenu->addSeparator(); mEditMenu->addAction(mRefreshA); mEditMenu->addAction(mClearA); mEditMenu->addAction(mGoA); mEditMenu->addSeparator(); mEditMenu->addAction(mConfigureA); } void RandomTab::writeSettings(){ QSettings s; QStringList selGenres; foreach(QComboBox *c, mGenreBoxes){ selGenres << c->currentText(); } s.setValue("random/genres", selGenres); QStringList selActors; foreach(QComboBox *c,mActorBoxes){ selActors << c->currentText(); } s.setValue("random/actors", selActors); s.setValue("random/filecount", mNumber->text()); } void RandomTab::readSettings(){ QSettings s; mNumber->setText(s.value("random/filecount", "10").toString()); QStringList genres = s.value("random/genres").toStringList(); for(int i = 0; i < genres.count(); ++i){ mGenreBoxes.at(i)->setCurrentText(genres.at(i)); } QStringList actors = s.value("random/actors").toStringList(); for(int i = 0; i < actors.count(); ++i){ mActorBoxes.at(i)->setCurrentText(actors.at(i)); } } QStringList RandomTab::validDvdNos(){ QStringList retval; QSettings s; QString usbDir = s.value("paths/usb").toString(); logMessage(QString(tr("Traversing %1")).arg(usbDir)); QDirIterator it(usbDir); while(it.hasNext()){ it.next(); QString next = it.fileName(); if(next.startsWith("DVD_")){ QString no = QString(next.right(3)); retval << no; } } logMessage(QString(tr("Found %1 valid Dirs: (%2)")).arg(QString::number(retval.count())).arg(retval.join(','))); return retval; } void RandomTab::setupModels(){ // Genres mGenreModel->clear(); QStandardItem *genreRoot = mGenreModel->invisibleRootItem(); QStandardItem *noneG = new QStandardItem; noneG->setText(tr("")); noneG->setData(-1, IdRole); genreRoot->appendRow(noneG); logMessage(tr("Collecting Genres")); QSqlQuery genQ("SELECT tgenrename, igenres_id FROM genres ORDER BY tgenrename ASC", mDb); while(genQ.next()){ QStandardItem *i = new QStandardItem; i->setText(genQ.value(0).toString()); i->setData(genQ.value(1), IdRole); genreRoot->appendRow(i); } logMessage(tr("Collecting Genres -> Done!")); logMessage(QString(tr("Have %1 Genres")).arg(QString::number(genreRoot->rowCount()))); // Actors mActorModel->clear(); QStandardItem *actorRoot = mActorModel->invisibleRootItem(); QStandardItem *noneA = new QStandardItem; noneA->setText(tr("")); noneA->setData(-1, IdRole); actorRoot->appendRow(noneA); logMessage(tr("Collecting Actors")); QSqlQuery actQ("SELECT tactorname, iactors_id FROM actors ORDER BY tactorname ASC", mDb); while(actQ.next()){ QStandardItem *i = new QStandardItem; i->setText(actQ.value(0).toString()); i->setData(actQ.value(1), IdRole); actorRoot->appendRow(i); } logMessage(tr("Collecting Actors -> Done!")); logMessage(QString(tr("Have %1 Actors")).arg(QString::number(actorRoot->rowCount()))); } void RandomTab::clearAll(){ logMessage(tr("Clearing Selection!")); mGenre1->setCurrentIndex(0); mGenre2->setCurrentIndex(0); mGenre3->setCurrentIndex(0); mActor1->setCurrentIndex(0); mActor2->setCurrentIndex(0); mActor3->setCurrentIndex(0); } void RandomTab::refreshComboboxes(){ logMessage(tr("Refreshing genres and actors...")); writeSettings(); setupModels(); clearAll(); readSettings(); logMessage(tr("Refreshing genres and actors -> Done!")); } void RandomTab::select(){ logMessage(tr("Selecting...")); // Genres QStringList genreIds; foreach(QComboBox *c, mGenreBoxes){ int curId = c->currentData(IdRole).toInt(); if(curId != -1){ genreIds << QString::number(curId); } } QVector gIds; QString gids = genreIds.join(','); logMessage(QString(tr("Genres: (%1)")).arg(gids)); QString genreQString = QString("SELECT ifiles_id FROM files WHERE iseriespart_id IN (SELECT distinct(iseriesparts_id) FROM seriesparts_genremap WHERE igenres_id IN (%1)) AND sifiletype = 1 AND (idvd = -1 OR idvd IN (%2))").arg(gids).arg(mValidDvds.join(',')); logMessage(genreQString); QSqlQuery gQ(genreQString, mDb); while(gQ.next()){ gIds << gQ.value(0).toInt(); } logMessage(QString(tr("Selected %1 Genre files")).arg(QString::number(gIds.count()))); // Actors QStringList actorIds; foreach(QComboBox *c, mActorBoxes){ int curId = c->currentData(IdRole).toInt(); if(curId != -1){ actorIds << QString::number(curId); } } QVector aIds; QString aids = actorIds.join(','); logMessage(QString(tr("Actors: (%1)")).arg(aids)); QString actorQString = QString("SELECT ifiles_id FROM files WHERE iseriespart_id IN (SELECT distinct(iseriesparts_id) FROM seriesparts_actormap WHERE iactors_id IN (%1)) AND sifiletype = 1 AND (idvd = -1 OR idvd IN (%2))").arg(aids).arg(mValidDvds.join(',')); logMessage(actorQString); QSqlQuery aQ(actorQString, mDb); while(aQ.next()){ aIds << aQ.value(0).toInt(); } logMessage(QString(tr("Selected %1 Actor files")).arg(QString::number(aIds.count()))); // Join! QVector finalIds; if(!aIds.isEmpty() && !gIds.isEmpty()){ logMessage(tr("Intersecting...")); std::sort(aIds.begin(), aIds.end()); std::sort(gIds.begin(), gIds.end()); QVector intersection; std::set_intersection(aIds.begin(), aIds.end(), gIds.begin(), gIds.end(), std::back_inserter(intersection)); logMessage(QString(tr("Joined to %1 ids")).arg(QString::number(intersection.count()))); finalIds = intersection; }else if(aIds.count() > 0){ logMessage(tr("Using Actors")); finalIds = aIds; }else if(gIds.count() > 0){ logMessage(tr("Using Genres")); finalIds = gIds; } std::random_device rd; std::mt19937 g(rd()); std::shuffle(finalIds.begin(), finalIds.end(), g); QSqlQuery randomFilesQ(mDb); randomFilesQ.prepare("SELECT tfilename, bisize, iduration, cmd5sum, idvd FROM files WHERE ifiles_id = :id"); QSqlQuery otherQ(mDb); otherQ.prepare("SELECT iseriespart, tsubtitle, tseries_name FROM seriesparts, series, files WHERE files.ifiles_id = :fid AND files.iseriespart_id = seriesparts.iseriesparts_id AND seriesparts.iseries_id = series.iseries_id"); int selCount = mNumber->text().toInt(); int count = selCount; if(finalIds.count() < selCount){ count = finalIds.count();; } logMessage(QString(tr("Count is %1 out of %2")).arg(QString::number(count)).arg(QString::number(finalIds.count()))); mFileModel->clear(); mFileModel->setHorizontalHeaderLabels(QStringList() << tr("Filename") << tr("Size (MB)") << tr("Dur.") << tr("MD5") << tr("LOC") << tr("Full Path")); QLocale l; QStandardItem *fRootItem = mFileModel->invisibleRootItem(); logMessage(tr("Filling View...")); for(int i = 0; i < count; ++i){ QList fData; randomFilesQ.bindValue(":id", finalIds.at(i)); randomFilesQ.exec(); while(randomFilesQ.next()){ for(int i = 0; i < ColumnCount; ++i){ QStandardItem *item = new QStandardItem; item->setFont(QFont("courier new", -1, QFont::Bold)); item->setEditable(false); fData << item; } fData[0]->setText(randomFilesQ.value(0).toString()); fData[0]->setIcon(QIcon(":/huge_bra.png")); fData[1]->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); qint64 dbSize = randomFilesQ.value(1).toLongLong(); float mbSize = dbSize / 1024.0 / 1024.0; QString sizeStr = QString("%1").arg(mbSize, 0, 'f', 2); fData[1]->setText(sizeStr); fData[1]->setData(dbSize, SizeRole); qint64 durSecs = randomFilesQ.value(2).toLongLong(); Helper::Duration dur(durSecs); fData[2]->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); fData[2]->setText(dur.toString()); fData[2]->setData(durSecs, DurationRole); fData[3]->setText(randomFilesQ.value(3).toString()); fData[4]->setText(l.toString(randomFilesQ.value(4).toInt())); int dvdno = randomFilesQ.value(4).toInt(); if(dvdno == -1){ fData[4]->setText(tr("ARC")); }else{ fData[4]->setText(tr("USB")); } QString fullPath; if(randomFilesQ.value(4).toInt() < 0){ fullPath = Helper::createArchivePath(randomFilesQ.value(0).toString(), randomFilesQ.value(3).toString()); }else{ otherQ.bindValue(":fid", finalIds.at(i)); otherQ.exec(); while(otherQ.next()){ int seriesPart = otherQ.value(0).toInt(); QString subTitle = otherQ.value(1).toString(); QString seriesName = otherQ.value(2).toString(); fullPath = Helper::createUSBPath(randomFilesQ.value(0).toString(), seriesName, subTitle, randomFilesQ.value(4).toInt(), seriesPart); } } fData[5]->setText(fullPath); } fRootItem->appendRow(fData); } logMessage(tr("Filling View -> Done!")); for(int i = ColumnCount - 1; i >= 0; --i){ mFileView->resizeColumnToContents(i); } } void RandomTab::playAll(){ logMessage(tr("Playing All")); QStringList files; QStandardItem *root = mFileModel->invisibleRootItem(); for(int i = 0; i < root->rowCount(); ++i){ QStandardItem *c = root->child(i, FullPath); logMessage(QString(tr("Adding %1")).arg(c->text())); files << c->text(); } play(files); } void RandomTab::playSelected(){ logMessage(tr("Playing Selected")); QStringList files; QModelIndexList idxs = mFileView->selectionModel()->selectedRows(FullPath); foreach(QModelIndex i, idxs){ QString fp = i.data().toString(); logMessage(QString(tr("Adding %1")).arg(fp)); files << fp; } play(files); } void RandomTab::playDoubleclicked(QModelIndex idx){ QString fp = idx.sibling(0, FullPath).data().toString(); logMessage(QString(tr("Doubleclick on %1")).arg(fp)); QStringList f = QStringList() << fp; play(f); } void RandomTab::play(const QStringList &files){ QPair pgdata = Helper::programData("movieviewer"); QString program = pgdata.first; QStringList args = pgdata.second; args.append(files); logMessage(QString(tr("Cmd: %1 %2")).arg(program).arg(args.join(" "))); QProcess::startDetached(program, args); } void RandomTab::logMessage(const QString &msg){ QDateTime now = QDateTime::currentDateTime(); QString msg1 = QString("[%1] %2").arg(now.toString()).arg(msg); mLog->append(msg1); } RandomFileView::RandomFileView(QWidget *parent) : QTreeView(parent) {} void RandomFileView::contextMenuEvent(QContextMenuEvent *e){ mCtxMenu->exec(e->globalPos()); }