/* 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 "newpicsdialog.h" #include "smtreeitem.h" #include "helper.h" #include "mappingtreewidget.h" #include "mappingtreemodel.h" #include "mappingtreeresultmodel.h" #include "mappingtreeview.h" #include "mappingeditwidget.h" #include "delegates.h" #include "smglobals.h" NewPicsDialog::NewPicsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f), mFilesCtr(0) { qRegisterMetaType("MappingData"); setupDlg(); } void NewPicsDialog::setupDlg(){ mDb = QSqlDatabase::database("treedb"); mFilesWidget = new QWidget; mFilesV = new SmTreeView; mFilesProxy = new QSortFilterProxyModel(this); mFilesModel = new NewPicFilesModel(QStringList() << tr("Filename") << tr("Size") << tr("Val.") << tr("Md5") << tr("Mime type") << tr("Full path") << tr("Pic. Size"), this); mFilesProxy->setSourceModel(mFilesModel); mFilesV->setModel(mFilesProxy); mFilesV->setSortingEnabled(true); mFilesV->setColumnHidden(NewPicFilesModel::Valid, true); mFilesV->setItemDelegateForColumn(NewPicFilesModel::Size, new SizeDelegate(this)); mFilesV->header()->moveSection(6, 2); //move picsize to front mFilesV->header()->moveSection(5, 3); //move mime type to front mFilesV->setAlternatingRowColors(true); QHBoxLayout *fileButtonLayout = new QHBoxLayout; fileButtonLayout->addStretch(); QVBoxLayout *filesLayout = new QVBoxLayout; filesLayout->addWidget(mFilesV); filesLayout->addLayout(fileButtonLayout); mFilesWidget->setLayout(filesLayout); setWindowTitle(tr("SheMov - Archive pictures")); //mapping widget mMappingEditWidget = new MappingEditWidget; //dialog buttons mOk = new QPushButton(tr("Ok")); mOk->setFocusPolicy(Qt::ClickFocus); connect(mOk, &QPushButton::clicked, this, &NewPicsDialog::accept); mCancel = new QPushButton(tr("Cancel")); mCancel->setFocusPolicy(Qt::ClickFocus); connect(mCancel, &QPushButton::clicked, this, &NewPicsDialog::reject); QHBoxLayout *dlgButtonLayout = new QHBoxLayout; dlgButtonLayout->addStretch(); dlgButtonLayout->addWidget(mCancel); dlgButtonLayout->addWidget(mOk); //put it together setMinimumWidth(600); setMinimumHeight(400); mTab = new QTabWidget; mTab->addTab(mFilesWidget, tr("Files")); mTab->addTab(mMappingEditWidget, tr("Mappings")); mTab->setFocusPolicy(Qt::ClickFocus); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mTab); mainLayout->addLayout(dlgButtonLayout); setLayout(mainLayout); mMappingEditWidget->treeWidget()->mappingTreeView()->setFocus(); connect(mMappingEditWidget->treeWidget()->mappingTreeView(), &MappingTreeView::acceptPics, this, &NewPicsDialog::accept); readSettings(); } void NewPicsDialog::selectFiles(){ QSettings s; QString startDir = s.value("paths/lastpicopendir", QDir::homePath()).toString(); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select pictures"), startDir); if(!files.isEmpty()){ addFiles(files); QFileInfo fi(files.first()); s.setValue("paths/lastpicopendir", fi.absolutePath()); } } void NewPicsDialog::addFiles(const QStringList &files){ if(files.isEmpty()){ return; } mFilesV->setSortingEnabled(false); for(const auto &f : files){ mFilesModel->addFile(f); } mFilesV->setSortingEnabled(true); for(int i = 0; i < NewPicFilesModel::NumFields; ++i){ mFilesV->resizeColumnToContents(i); } } void NewPicsDialog::setFile(const QString &file){ clearFiles(); mFilesModel->addFile(file); for(int i = 0; i < NewPicFilesModel::NumFields; ++i){ mFilesV->resizeColumnToContents(i); } } void NewPicsDialog::setDir(const QString &dir){ mFiles.clear(); QDir d(dir); for(const auto &fi : d.entryInfoList(QDir::Files, QDir::Name)){ mFiles << fi.absoluteFilePath(); } mFilesCtr = 0; setNextPic(); } void NewPicsDialog::clearFiles(){ mFilesV->setSortingEnabled(false); SmTreeItem *rootItem = new SmTreeItem(NewPicFilesModel::NumFields); mFilesModel->setRoot(rootItem); mFilesV->setSortingEnabled(true); } void NewPicsDialog::setFocusToMappings(){ mTab->setCurrentIndex(1); mMappingEditWidget->treeWidget()->mappingTreeView()->setFocus(); } void NewPicsDialog::setNextPic(){ if(mFilesCtr < mFiles.count()){ QString fp = mFiles.at(mFilesCtr); setFile(fp); SmGlobals::instance()->pictureViewer()->setFile(fp); } } void NewPicsDialog::removeFiles(){ QModelIndexList selected = mFilesV->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } QModelIndexList real; for(QModelIndex i : selected){ real << mFilesProxy->mapToSource(i); } QList perm; for(QModelIndex i : real){ perm << i; } for(const auto &pi : perm){ mFilesModel->removeRows(pi.row(), 1, pi.parent()); } } void NewPicsDialog::accept(){ archive(); return QDialog::accept(); } void NewPicsDialog::archive(){ writeSettings(); QList files = mFilesModel->validFiles(); if(files.isEmpty()){ return QDialog::accept(); } QList mappingParentsIds = mMappingEditWidget->model()->getMappings(mMappingEditWidget->model()->root()); if(mappingParentsIds.isEmpty()){ QMessageBox::critical(this, tr("No mappings"), tr("Cannot continue without mappings!")); return; } QSqlQuery addFileQ(mDb); addFileQ.prepare("INSERT INTO pics (tfilename, cmd5sum, isize, tformat, cpicsize) VALUES(:fn, :md5, :size, :format, :picsize)"); QSqlQuery addMappingQ(mDb); addMappingQ.prepare("INSERT INTO pics_mappings(ipics_id, imappings_parents_id) VALUES((SELECT ipicsid FROM pics where cmd5sum = :md5), :mapid)"); QProgressDialog progress(tr("Processing..."), QString(), 0, files.size(), this); progress.setMinimumWidth(400); progress.show(); int pgctr = 0; for(const auto &d : files){ ++pgctr; progress.setValue(pgctr); qApp->processEvents(); QString archivefn = Helper::moveToArchive(d.fullPath, d.md5sum); if(archivefn.isEmpty()){ continue; } QFileInfo fi(archivefn); QString fn = fi.fileName(); addFileQ.bindValue(":fn", fn); addFileQ.bindValue(":md5", d.md5sum); addFileQ.bindValue(":size", d.size); addFileQ.bindValue(":format", d.mimeType); addFileQ.bindValue(":picsize", d.picSize); if(addFileQ.exec()){ for(const auto &mpid : mappingParentsIds){ addMappingQ.bindValue(":mapid", mpid); addMappingQ.bindValue(":md5", d.md5sum); addMappingQ.exec(); } mFilesModel->clear(); } } } void NewPicsDialog::writeSettings(){ mMappingEditWidget->saveMappings("ui/newpicmappings"); QSettings s; QPoint curPos = pos(); s.setValue("ui/newpicsdialogpos", curPos); } void NewPicsDialog::readSettings(){ mMappingEditWidget->loadMappings("ui/newpicmappings"); QSettings s; QPoint p = s.value("ui/newpicsdialogpos", QPoint(0,0)).toPoint(); move(p); } NewPicFilesModel::NewPicFilesModel(const QStringList &header, QObject *parent) : SmTreeModel(header, parent){ mDb = QSqlDatabase::database("treedb"); } Qt::ItemFlags NewPicFilesModel::flags(const QModelIndex &index) const{ Q_UNUSED(index); return (Qt::ItemIsSelectable | Qt::ItemIsEnabled); } QVariant NewPicFilesModel::data(const QModelIndex &index, int role) const{ if(!index.isValid()){ return QVariant(); } SmTreeItem *item = itemAt(index); if(role == FileNameRole){ return item->data(FileName); } if(role == ValidRole){ return item->data(Valid); } if(role == Md5SumRole){ return item->data(Md5Sum); } if(role == MimeTypeRole){ return item->data(MimeType); } if(role == FullPathRole){ return item->data(FullPath); } if(role == PicSizeRole){ return item->data(PicSize); } if(role == Qt::DecorationRole && index.column() == 0){ bool valid = item->data(Valid).toBool(); if(valid){ return QIcon(":/gaping_ass.png"); }else{ return QIcon(":/chastity_belt.png"); } } if(role == Qt::FontRole && index.column() == Md5Sum){ return QFont("Monospace"); } return SmTreeModel::data(index, role); } bool NewPicFilesModel::setData(const QModelIndex &index, const QVariant &value, int role){ if(role == Qt::EditRole || !index.isValid()){ return false; } SmTreeItem *item = itemAt(index); if(role == FileNameRole){ item->setData(FileName, value); } if(role == SizeRole){ item->setData(Size, value); } if(role == ValidRole){ item->setData(Valid, value); } if(role == Md5SumRole){ item->setData(Md5Sum, value); } if(role == MimeTypeRole){ item->setData(MimeType, value); } if(role == FullPathRole){ item->setData(FullPath, value); } if(role == PicSizeRole){ item->setData(PicSize, value); } return true; } void NewPicFilesModel::setFiles(const QStringList &paths) { SmTreeItem *rootItem = new SmTreeItem(NumFields); for(const auto &file : paths){ QFileInfo fi(file); QList fileData; if(!fi.exists()){ continue; } QString md5 = Helper::md5Sum(fi.absoluteFilePath()); QString mt = Helper::mimeType(fi.absoluteFilePath()).toLower(); bool valid = true; if(!mt.startsWith("image")){ valid = false; } if(haveMd5(md5)){ valid = false; } fileData << fi.fileName() << valid << md5 << mt << fi.absoluteFilePath(); QVariant picSize = Helper::picSize(fi.absoluteFilePath()); fileData << picSize; SmTreeItem *newFile = new SmTreeItem(fileData, rootItem); rootItem->appendChild(newFile); } setRoot(rootItem); } void NewPicFilesModel::addFile(const QString &path){ QFileInfo fi(path); if(!fi.exists() || !fi.isFile()){ return; } QString md5 = Helper::md5Sum(fi.absoluteFilePath()); QString mt = Helper::mimeType(fi.absoluteFilePath()); bool valid = true; if(!mt.startsWith("image")){ valid = false; } if(haveMd5(md5)){ valid = false; } if(!valid){ return; } QVariant picSize = Helper::picSize(fi.absoluteFilePath()); if(picSize == QVariant()){ return; } insertRows(0, 1, QModelIndex()); QModelIndex inserted = index(0, 1, QModelIndex()); setData(inserted, fi.fileName(), FileNameRole); setData(inserted, fi.size(), SizeRole); setData(inserted, valid, ValidRole); setData(inserted, md5, Md5SumRole); setData(inserted, mt, MimeTypeRole); setData(inserted, fi.absoluteFilePath(), FullPathRole); setData(inserted, picSize, PicSizeRole); } void NewPicFilesModel::removeFile(const QModelIndex &idx){ if(!idx.isValid()){ return; } removeRows(idx.row(), 1, idx.parent()); } QList NewPicFilesModel::validFiles() const { SmTreeItem *rootItem = root(); QList retval; for(int i = 0; i < rootItem->childCount(); ++i){ SmTreeItem *child = rootItem->child(i); if(!child->data(Valid).toBool()){ continue; } FileData data; data.fileName = child->data(FileName).toString(); data.size = child->data(Size).toInt(); data.valid = child->data(Valid).toBool(); data.md5sum = child->data(Md5Sum).toString(); data.mimeType = child->data(MimeType).toString(); data.fullPath = child->data(FullPath).toString(); data.picSize = child->data(PicSize).toString(); retval << data; } return retval; } void NewPicFilesModel::clear(){ SmTreeItem *newRoot = new SmTreeItem(NumFields); setRoot(newRoot); } bool NewPicFilesModel::haveMd5(const QString &md5) const { QSqlQuery md5Query(mDb); md5Query.prepare("SELECT COUNT(*) FROM pics WHERE cmd5sum = :md5"); md5Query.bindValue(":md5", md5); md5Query.exec(); int count = 0; while(md5Query.next()){ count = md5Query.value(0).toInt(); } return ((count > 0) ? true : false); }