#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 "filewidget.h" #include "filesorter.h" #include "filedisplay.h" #include "helper.h" FileWidget::FileWidget(QWidget *parent) : QWidget(parent) { setupGui(); gatherData(); } FileWidget::~FileWidget(){ writeHeaderData(); writeSettings(); } void FileWidget::setupGui(){ mDir = new QLineEdit; QCompleter *fsCompleter = new QCompleter(this); QDirModel *dirModel = new QDirModel(this); fsCompleter->setModel(dirModel); fsCompleter->setCompletionMode(QCompleter::PopupCompletion); mDir->setCompleter(fsCompleter); connect(mDir, SIGNAL(returnPressed()), this, SLOT(gatherData())); mSelDir = new QPushButton(tr("Browse...")); connect(mSelDir, SIGNAL(clicked()), this, SLOT(selectDir())); QLabel *dirL = new QLabel(tr("&Directory")); dirL->setBuddy(mDir); mSearchFile = new QLineEdit; connect(mSearchFile, SIGNAL(returnPressed()), this, SLOT(searchFile())); mSearch = new QPushButton(tr("Search")); connect(mSearch, SIGNAL(clicked()), this, SLOT(searchFile())); QLabel *searchL = new QLabel(tr("&Search")); searchL->setBuddy(mSearchFile); QGridLayout *topL = new QGridLayout; topL->addWidget(dirL, 0, 0); topL->addWidget(mDir, 0, 1); topL->addWidget(mSelDir, 0, 2); topL->addWidget(searchL, 1, 0); topL->addWidget(mSearchFile, 1, 1); topL->addWidget(mSearch, 1, 2); mFileView = new QTreeView; mFileView->setSortingEnabled(true); mFileView->setSelectionBehavior(QAbstractItemView::SelectRows); mFileView->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(mFileView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); mModel = new QStandardItemModel; mProxy = new VideoSorter; mProxy->setSourceModel(mModel); mFileView->setModel(mProxy); readSettings(); QSqlDatabase mDb = QSqlDatabase::database("shemovdb"); if(!mDb.isOpen()){ mDb.open(); } mQOrigin = QSqlQuery(mDb); mQOrigin.prepare("SELECT COUNT(*) FROM files_origin WHERE cmd5sum = :md5"); mQFiles = QSqlQuery(mDb); mQFiles.prepare("SELECT COUNT(*) FROM files WHERE cmd5sum = :md5"); mFileDisplay = new FileDisplay(this); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(topL); mainLayout->addWidget(mFileView); setLayout(mainLayout); connect(mFileView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(fileSelectionChanged(QItemSelection,QItemSelection))); } void FileWidget::selectDir(){ QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), QDir::homePath()); mDir->setText(QDir::toNativeSeparators(dir)); gatherData(); } void FileWidget::gatherData(){ QDir d(mDir->text()); QFileInfoList fl = d.entryInfoList(QStringList() << "*", QDir::Files | QDir::Dirs | QDir::NoDot, QDir::Name | QDir::DirsFirst); mModel->clear(); QStandardItem *root = mModel->invisibleRootItem(); mModel->setHorizontalHeaderLabels(QStringList() << QChar(0x26A7) << tr("Name") << tr("MIME") << tr("Duration") << tr("MD5")); QBrush redBrush(Qt::red); QBrush greenBrush(Qt::darkGreen); QMimeDatabase db; qApp->setOverrideCursor(Qt::BusyCursor); foreach(QFileInfo fi, fl){ QMimeType mime = db.mimeTypeForFile(fi); QList fData; FileAttrs attr = NotPresent; Helper::Duration dur; for(int i = 0; i < ColumnCount; ++i){ QStandardItem *item = new QStandardItem; item->setEditable(false); if(i == Md5Column){ item->setFont(QFont("courier new")); } fData << item; } fData[NameColumn]->setText(fi.fileName()); QString md5(tr("n/a")); QString duration(tr("n/a")); qint64 seconds = 0; if(mime.name().startsWith("video")){ md5 = Helper::md5Sum(fi.absoluteFilePath()); fData[Md5Column]->setText(md5); int haveFile = md5Count(md5); if(haveFile){ fData[IconColumn]->setIcon(QIcon(":/huge_bra.png")); fData[NameColumn]->setForeground(greenBrush); attr = Present; }else{ fData[IconColumn]->setIcon(QIcon(":/chastity_belt.png")); fData[NameColumn]->setForeground(redBrush); attr = NotPresent; } QJsonDocument jDoc = Helper::ffpmegData(fi.absoluteFilePath()); QJsonObject jObj = jDoc.object(); QJsonValue durationV = jObj["format"].toObject()["duration"]; seconds = durationV.toVariant().toDouble(); dur = Helper::Duration(seconds); duration = dur.toString(); }else if(fi.isDir()){ if(fi.fileName() == ".."){ fData[IconColumn]->setIcon(QIcon(":/up_dick.png")); attr = ParentDir; }else{ fData[IconColumn]->setIcon(QIcon(":/folder.png")); attr = Directory; } }else{ fData[IconColumn]->setIcon(QIcon(":/gaping_ass.png")); attr = NoVideo; } fData[DurationColumn]->setText(duration); fData[DurationColumn]->setData(seconds, SecondsRole); fData[Md5Column]->setText(md5); fData[MimeColumn]->setText(mime.name()); if(mime.name() == "inode/directory"){ fData[MimeColumn]->setText("directory"); } for(int i = 0; i < ColumnCount; ++i){ fData[i]->setData(attr, AttrsRole); fData[i]->setData(fi.absoluteFilePath(), FullPathRole); fData[i]->setData(md5, MD5SumRole); } root->appendRow(fData); } readHeaderData(); qApp->restoreOverrideCursor(); } int FileWidget::md5Count(const QString &md5) { mQOrigin.bindValue(":md5", md5); mQOrigin.exec(); int retval = 0; while(mQOrigin.next()){ retval = mQOrigin.value(0).toInt(); } if(!retval){ mQFiles.bindValue(":md5", md5); while(mQFiles.next()){ retval = mQFiles.value(0).toInt(); } } return retval; } void FileWidget::readHeaderData(){ QSettings s; QByteArray headers = s.value("video/fileheaders").toByteArray(); if(!headers.isEmpty()){ mFileView->header()->restoreState(headers); } } void FileWidget::writeHeaderData(){ QSettings s; s.setValue("video/fileheaders", mFileView->header()->saveState()); } void FileWidget::readSettings(){ QSettings s; QString dir = s.value("video/searchdir", QDir::toNativeSeparators(QDir::homePath())).toString(); mDir->setText(dir); } void FileWidget::writeSettings(){ QSettings s; s.setValue("video/searchdir", mDir->text()); } void FileWidget::searchFile(){ mFileView->selectionModel()->clear(); int count = mProxy->rowCount(); if(mSearchFile->text().isEmpty()){ return; } QRegularExpression regex(mSearchFile->text(), QRegularExpression::CaseInsensitiveOption); int success = 0; for(int i = 0; i < count; ++i){ QModelIndex cur = mProxy->index(i, 1); QString fn = cur.data().toString(); QRegularExpressionMatch m = regex.match(fn); if(m.hasMatch()){ ++success; mFileView->selectionModel()->select(cur, QItemSelectionModel::Select | QItemSelectionModel::Rows); if(success == 1){ mFileView->scrollTo(cur); } } } } void FileWidget::fileSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected){ Q_UNUSED(selected); Q_UNUSED(deselected); int count = mFileView->selectionModel()->selectedRows().count(); int total = mModel->rowCount(); QString msg = QString("%1/%2").arg(QString::number(count)).arg(QString::number(total)); emit selectionCountChanged(msg); QModelIndexList idxl = mFileView->selectionModel()->selectedRows(DurationColumn); qint64 seconds = 0; foreach(QModelIndex idx, idxl){ seconds += idx.data(SecondsRole).toLongLong(); } Helper::Duration dur(seconds); emit durationChanged(dur.toString()); } void FileWidget::itemDoubleClicked(const QModelIndex &idx){ if(idx.column() == NameColumn){ int attr = idx.data(AttrsRole).toInt(); if(attr == ParentDir || attr == Directory){ QDir d(mDir->text()); d.cd(idx.data().toString()); QString newDir = d.absolutePath(); mDir->setText(QDir::toNativeSeparators(newDir)); gatherData(); return; } if(attr == Present){ QString fp = idx.data(FullPathRole).toString(); QString md5 = idx.data(MD5SumRole).toString(); mFileDisplay->setFileData(fp, md5); mFileDisplay->show(); } } }