/* 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 "newmoviewizard.h" #include "smtreeitem.h" #include "seriestreemodel.h" #include "filestreemodel.h" #include "smglobals.h" #include "mappingtablewidget.h" #include "mappingtablemodel.h" #include "filestreemodel.h" #include "helper.h" #include "pictureviewer.h" NewMovieWizard::NewMovieWizard(QWidget *parent) : QWizard(parent){ mInfoPage = new MovieInfoPage; mActorPage = new MovieMappingPage("actors"); mGenrePage = new MovieMappingPage("genres"); addPage(mInfoPage); addPage(mActorPage); addPage(mGenrePage); setOption(QWizard::IndependentPages, true); } void NewMovieWizard::accept(){ //conjure up models SeriesTreeModel *seriesModel = static_cast(SmGlobals::instance()->model("SeriesModel")); FilesTreeModel *filesModel = static_cast(SmGlobals::instance()->model("FilesModel")); //handle series QString series = field("title").toString(); series = series.toLower().trimmed(); QModelIndex seriesIdx = seriesModel->find(series); if(!seriesIdx.isValid()){ if(seriesModel->addSeries(series, QModelIndex())){ seriesIdx = seriesModel->find(series); }else{ QMessageBox::critical(this, tr("Error"), tr("Failed to create new series!")); return; } } //handle seriespart int seriesno = field("seriesNo").toInt(); QModelIndex seriesPartIdx = seriesModel->find(seriesno, SeriesTreeModel::SeriesPart, seriesIdx); if(seriesPartIdx.isValid()){ QString error = QString(tr("Already have part %1 of %2")).arg(seriesno).arg(series); QMessageBox::critical(this, tr("Error"), error); return; } if(!seriesModel->addSeriesPart(seriesno, seriesIdx)){ QMessageBox::critical(this, tr("Error"), tr("Failed to create series part!")); return; } seriesPartIdx = seriesModel->find(seriesno, SeriesTreeModel::SeriesPart, seriesIdx); int seriesPartId = seriesPartIdx.data(SeriesTreeModel::SeriesPartIdRole).toInt(); //handle files MovieInfoPage *movieInfoPage = static_cast(page(0)); WizardTreeModel *wizardModel = movieInfoPage->model(); int quality = field("quality").toInt(); int dvdNo = -1; bool onDvd = field("onDvd").toBool(); if(onDvd){ dvdNo = field("dvdNo").toInt(); } //int partNo = field("partNo").toInt(); QHash fileData = wizardModel->files(); QHash::const_iterator it = fileData.constBegin(); while(it != fileData.constEnd()){ QString path = it.key(); int type = it.value(); int partNo = wizardModel->filesPart(path); if(filesModel->addFile(path, type, quality, partNo, seriesPartId, dvdNo)){ QString md5sum = Helper::md5Sum(path); Helper::moveToArchive(path, md5sum); } ++it; } if(onDvd){ filesModel->addFile(tr("DVD"), FilesTreeModel::Movie, quality, -1, seriesPartId, dvdNo); } //handle actors MovieMappingPage *actorPage = static_cast(page(1)); MappingTableItemModel *actorItemModel = actorPage->model(); QStringList actors = actorItemModel->stringList(); MappingTableModel *actorModel = static_cast(SmGlobals::instance()->model("actors")); actorModel->setMappings(actors, seriesPartId); //handle genres MovieMappingPage *genrePage = static_cast(page(2)); MappingTableItemModel *genreItemModel = genrePage->model(); QStringList genres = genreItemModel->stringList(); MappingTableModel *genreModel = static_cast(SmGlobals::instance()->model("genres")); genreModel->setMappings(genres, seriesPartId); //make picviewer setting persistent QSettings s; s.setValue("ui/archiveusepicviewer", field("usePicViewer")); //done emit seriesAdded(series, seriesno); QDialog::accept(); } MovieInfoPage::MovieInfoPage(QWidget *parent) : QWizardPage(parent){ setupGui(); mPicViewer = SmGlobals::instance()->pictureViewer(); connect(mFileView, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); } void MovieInfoPage::setupGui(){ setTitle(tr("Collect files for movie")); setSubTitle(tr("Select files by clicking the \"Add files...\" button. After adding files select one by one and set the appropriate file type. The series no is the number the movie has in the series: 14 in case of e.g. rogue adventures 14. The part number only has to be set if the movie is split in several parts.")); setPixmap(QWizard::LogoPixmap, QPixmap(":/shemov.png")); //files model setup QStringList modelHeaders = QStringList() << tr("File name") << tr("Size") << tr("File Type") << tr("Part") << tr("Full path"); mFileModel = new WizardTreeModel(modelHeaders, this); initModel(); //files view mFileView = new QTreeView; mFileView->setModel(mFileModel); connect(mFileView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(fileSelectionChanged(QModelIndex,QModelIndex))); mFileView->setAlternatingRowColors(true); //add + remove files QHBoxLayout *fileButtonLayout = new QHBoxLayout; fileButtonLayout->addStretch(); mAddFile = new QPushButton(tr("Add files...")); fileButtonLayout->addWidget(mAddFile); connect(mAddFile, SIGNAL(clicked()), this, SLOT(addFiles())); mRemoveFile = new QPushButton(tr("Remove file")); fileButtonLayout->addWidget(mRemoveFile); connect(mRemoveFile, SIGNAL(clicked()), this, SLOT(removeFile())); //movie name QHBoxLayout *movieTitleLayout = new QHBoxLayout; QLabel *l1 = new QLabel(tr("Movie &title")); mTitle = new QLineEdit; l1->setBuddy(mTitle); movieTitleLayout->addWidget(l1); movieTitleLayout->addWidget(mTitle); SeriesTreeModel *seriesModel = static_cast(SmGlobals::instance()->model("SeriesModel")); QCompleter *completer = new QCompleter(this); completer->setModel(seriesModel); mTitle->setCompleter(completer); //file type QHBoxLayout *numberLayout = new QHBoxLayout; QLabel *l2 = new QLabel(tr("File &type")); mFileType = new QComboBox; l2->setBuddy(mFileType); mFileType->addItems(mFileModel->types()); numberLayout->addWidget(l2); numberLayout->addWidget(mFileType); numberLayout->addStretch(); connect(mFileType, SIGNAL(currentIndexChanged(QString)), this, SLOT(typeChanged(QString))); //series, part + quality QLabel *l3 = new QLabel(tr("&Series no.")); mSeriesNo = new QSpinBox; l3->setBuddy(mSeriesNo); mSeriesNo->setMinimum(1); numberLayout->addWidget(l3); numberLayout->addWidget(mSeriesNo); QLabel *l4 = new QLabel(tr("&Part no.")); mPartno = new QSpinBox; l4->setBuddy(mPartno); mPartno->setMinimum(-1); connect(mPartno, SIGNAL(valueChanged(int)), this, SLOT(seriesPartChanged(int))); numberLayout->addWidget(l4); numberLayout->addWidget(mPartno); QLabel *l5 = new QLabel(tr("&Quality")); mQuality = new QSpinBox; l5->setBuddy(mQuality); mQuality->setMinimum(1); mQuality->setMaximum(10); numberLayout->addWidget(l5); numberLayout->addWidget(mQuality); //dvd QHBoxLayout *dvdLayout = new QHBoxLayout; mOnDvd = new QCheckBox(tr("Movie is on DVD")); dvdLayout->addWidget(mOnDvd); dvdLayout->addStretch(); QLabel *l6 = new QLabel(tr("Dvd no.")); dvdLayout->addWidget(l6); mDvdNo = new QSpinBox; mDvdNo->setMinimum(1); dvdLayout->addWidget(mDvdNo); connect(mOnDvd, SIGNAL(stateChanged(int)), this, SLOT(onDvd(int))); mNextDvdNo = new QPushButton(tr("Get next")); dvdLayout->addWidget(mNextDvdNo); connect(mNextDvdNo, SIGNAL(clicked()), this, SLOT(setNextDvdNo())); setNextDvdNo(); mNextDvdNo->setChecked(false); mDvdNo->setEnabled(false); mNextDvdNo->setEnabled(false); //picviewer QHBoxLayout *picViewerLayout = new QHBoxLayout; picViewerLayout->setAlignment(Qt::AlignRight | Qt::AlignHCenter); mUsePicViewer = new QCheckBox(tr("Use picture viewer when selecting item")); picViewerLayout->addWidget(mUsePicViewer); QSettings s; bool usePicViewer = s.value("ui/archiveusepicviewer", false).toBool(); mUsePicViewer->setChecked(usePicViewer); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mFileView); mainLayout->addLayout(fileButtonLayout); mainLayout->addLayout(movieTitleLayout); mainLayout->addLayout(numberLayout); mainLayout->addLayout(dvdLayout); mainLayout->addLayout(picViewerLayout); setLayout(mainLayout); //expose data registerField("title*", mTitle); registerField("seriesNo", mSeriesNo); registerField("partNo", mPartno); registerField("quality", mQuality); registerField("dvdNo", mDvdNo); registerField("onDvd", mOnDvd); registerField("usePicViewer", mUsePicViewer); } void MovieInfoPage::initializePage(){ initModel(); mTitle->clear(); mSeriesNo->setValue(1); mPartno->setValue(1); mQuality->setValue(8); mOnDvd->setChecked(false); } void MovieInfoPage::addFile(const QString &file){ QFileInfo fi(file); if(fi.exists()){ QList itemData; QModelIndex parent = QModelIndex(); itemData << fi.fileName() << fi.size() << QVariant() << QVariant() << fi.absoluteFilePath(); QString mimeType = Helper::mimeType(fi.absoluteFilePath()); if(mimeType.startsWith("video")){ itemData[WizardTreeModel::FileType] = WizardTreeModel::Movie; parent = mFileModel->find("Movie files"); }else{ QString baseName = fi.completeBaseName(); QRegExp reFront = QRegExp("front"); reFront.setCaseSensitivity(Qt::CaseInsensitive); QRegExp reBack = QRegExp("back"); reBack.setCaseSensitivity(Qt::CaseInsensitive); if(baseName.endsWith('f') || (reFront.indexIn(baseName) != -1)){ itemData[WizardTreeModel::FileType] = WizardTreeModel::FrontCover; }else if(baseName.endsWith('b') || (reBack.indexIn(baseName) != -1)){ itemData[WizardTreeModel::FileType] = WizardTreeModel::BackCover; }else{ itemData[WizardTreeModel::FileType] = WizardTreeModel::GeneralCover; } parent = mFileModel->find("Cover files"); } if(parent.isValid()){ mFileModel->addRow(itemData, parent); } } mFileView->expandAll(); mFileView->resizeColumnToContents(0); mFileView->resizeColumnToContents(1); mFileView->resizeColumnToContents(2); } void MovieInfoPage::addFiles(){ QSettings s; QString startDir = s.value("paths/addfilespath", QDir::homePath()).toString(); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files"), startDir); if(files.isEmpty()){ return; } foreach(QString f, files){ addFile(f); } QFileInfo fi(files.at(0)); s.setValue("paths/addfilespath", fi.absolutePath()); } void MovieInfoPage::removeFile(){ QModelIndexList selected = mFileView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } mFileModel->removeRows(selected.at(0).row(), 1, selected.at(0).parent()); } void MovieInfoPage::onDvd(int state){ mDvdNo->setEnabled(state == Qt::Checked); mNextDvdNo->setEnabled(state == Qt::Checked); } void MovieInfoPage::typeChanged(QString type){ QModelIndexList selected = mFileView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } int newTypeId = mFileModel->typeId(type); if(newTypeId == -1){ return; } QModelIndex item = selected.at(0); QModelIndex typeIndex = mFileModel->index(item.row(), WizardTreeModel::FileType, item.parent()); QModelIndex oldParent = typeIndex.parent(); mFileModel->setData(typeIndex, newTypeId, Qt::EditRole); QModelIndex newParent; if(newTypeId == WizardTreeModel::Movie){ newParent = mFileModel->find("Movie files"); }else{ newParent = mFileModel->find("Cover files"); } if(oldParent != newParent){ mFileModel->reparent(item, newParent); } } void MovieInfoPage::seriesPartChanged(int partNo){ QModelIndexList selected = mFileView->selectionModel()->selectedRows(); if(selected.isEmpty()){ return; } QModelIndex item = selected.at(0); if(item.data(WizardTreeModel::FileTypeRole).toInt() == WizardTreeModel::Movie){ QModelIndex seriesPartIdx = mFileModel->index(item.row(), WizardTreeModel::FilePart, item.parent()); QVariant data = (partNo == 0) ? QVariant() : QVariant(partNo); mFileModel->setData(seriesPartIdx, data, Qt::EditRole); } } void MovieInfoPage::setNextDvdNo(){ SeriesTreeModel *seriesTreeModel = static_cast(SmGlobals::instance()->model("SeriesModel")); int nextdvd = seriesTreeModel->findNextDvdNo(); mDvdNo->setValue(nextdvd + 1); } void MovieInfoPage::initModel(){ SmTreeItem *root = new SmTreeItem(5); mMoviesItem= new SmTreeItem(QList() << tr("Movie files") << QVariant() << QVariant() << QVariant() << QVariant(), root); root->appendChild(mMoviesItem); mCoversItem = new SmTreeItem(QList() << tr("Cover files") << QVariant() << QVariant() << QVariant() << QVariant(), root); root->appendChild(mCoversItem); mFileModel->setRoot(root); } void MovieInfoPage::fileSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous){ Q_UNUSED(previous); int type = current.data(WizardTreeModel::FileTypeRole).toInt(); if(type == WizardTreeModel::Movie){ int part = 1; QVariant filePart= current.data(WizardTreeModel::FilePartRole); if(filePart.isValid()){ part = filePart.toInt(); } mPartno->blockSignals(true); mPartno->setValue(part); mPartno->blockSignals(false); } QString typeString = mFileModel->typeName(type); int comboIdx = mFileType->findText(typeString); if(comboIdx != -1){ mFileType->blockSignals(true); mFileType->setCurrentIndex(comboIdx); mFileType->blockSignals(false); } } void MovieInfoPage::itemClicked(const QModelIndex &index){ if(!field("usePicViewer").toBool()){ return; } int type = index.data(WizardTreeModel::FileTypeRole).toInt(); switch(type){ case WizardTreeModel::Movie:{ QString framePath = SmGlobals::instance()->frameCache()->entryPath(index.data(WizardTreeModel::FullPathRole).toString(), QString()); mPicViewer->showPic(framePath, false); break; } case WizardTreeModel::FrontCover: case WizardTreeModel::BackCover: case WizardTreeModel::GeneralCover: mPicViewer->showPic(index.data(WizardTreeModel::FullPathRole).toString(), false); break; default: mPicViewer->setVisible(false); return; } mPicViewer->setVisible(true); mPicViewer->raise(); } MovieMappingPage::MovieMappingPage(const QString &table, QWidget *parent) : QWizardPage(parent){ QString title = QString(tr("Edit %1")).arg(table); QString subTitle = QString(tr("Edit %1 by adding them from the text field below")).arg(table); setTitle(title); setSubTitle(subTitle); mWidget = new MappingTableWidget(table); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(mWidget); setLayout(mainLayout); } void MovieMappingPage::initializePage(){ model()->setStringList(QStringList()); } WizardTreeModel::WizardTreeModel(QStringList &headers, QObject *parent) : SmTreeModel(headers, parent){ FilesTreeModel *filesModel = static_cast(SmGlobals::instance()->model("FilesModel")); mFileTypeMap = filesModel->fileTypes(); } Qt::ItemFlags WizardTreeModel::flags(const QModelIndex &index) const{ if(!index.parent().isValid()){ return Qt::ItemIsEnabled; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QHash WizardTreeModel::files() { QHash retval; mFilePartMap.clear(); SmTreeItem *rootItem = root(); for(int i = 0; i < rootItem->childCount(); ++i){ SmTreeItem *firstChild = rootItem->child(i); for(int j = 0; j < firstChild->childCount(); ++j){ SmTreeItem *secondChild = firstChild->child(j); retval.insert(secondChild->data(WizardTreeModel::FullPath).toString(), secondChild->data(WizardTreeModel::FileType).toInt()); if(secondChild->data(WizardTreeModel::FilePart).isValid()){ mFilePartMap.insert(secondChild->data(WizardTreeModel::FullPath).toString(), secondChild->data(WizardTreeModel::FilePart).toInt()); } } } return retval; } int WizardTreeModel::filesPart(const QString &fullPath) const{ if(mFilePartMap.contains(fullPath)){ return mFilePartMap.value(fullPath); } return -1; } QVariant WizardTreeModel::data(const QModelIndex &index, int role) const{ SmTreeItem *item = static_cast(index.internalPointer()); if(role == Qt::DisplayRole){ if(index.column() == FileSize){ if(item->parent() == root()){ return QVariant(); } QLocale l; return l.toString(item->data(FileSize).toLongLong()); } if(index.column() == FileType){ return mFileTypeMap.value(item->data(FileType).toInt()); } return item->data(index.column()); } if(role == Qt::TextAlignmentRole){ if(index.column() == FileSize){ return Qt::AlignRight; } return Qt::AlignLeft; } if(role == FileNameRole){ return item->data(FileName); } if(role == FileSizeRole){ if(item->parent() == root()){ return QVariant(); } return item->data(FileSize); } if(role == FileTypeRole){ return item->data(FileType); } if(role == FullPathRole){ return item->data(FullPath); } if(role == FilePartRole){ return item->data(FilePart); } if(role == Qt::DecorationRole){ if(index.column() == 0){ QSettings s; bool iconizeCover = s.value("ui/iconizecovers", false).toBool(); if(iconizeCover){ int fileType = item->data(FileType).toInt(); if((fileType == FrontCover) || (fileType == BackCover) || (fileType == GeneralCover)){ return QIcon(item->data(FullPath).toString()); } } } return SmTreeModel::data(index, role); } return QVariant(); } QStringList WizardTreeModel::types() const { return mFileTypeMap.values(); } int WizardTreeModel::typeId(const QString &value) const{ QHash::const_iterator it = mFileTypeMap.constBegin(); while(it != mFileTypeMap.constEnd()){ if(it.value() == value){ return it.key(); } ++it; } return -1; } QString WizardTreeModel::typeName(int typeId) const{ return mFileTypeMap.value(typeId); }