/* 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 "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" NewMovieWizard::NewMovieWizard(QWidget *parent) : QWizard(parent){ addPage(new MovieInfoPage); addPage(new MovieMappingPage("actors")); addPage(new MovieMappingPage("genres")); 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); //done emit seriesAdded(series, seriesno); QDialog::accept(); } MovieInfoPage::MovieInfoPage(QWidget *parent) : QWizardPage(parent){ 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))); //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); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mFileView); mainLayout->addLayout(fileButtonLayout); mainLayout->addLayout(movieTitleLayout); mainLayout->addLayout(numberLayout); mainLayout->addLayout(dvdLayout); setLayout(mainLayout); //expose data registerField("title*", mTitle); registerField("seriesNo", mSeriesNo); registerField("partNo", mPartno); registerField("quality", mQuality); registerField("dvdNo", mDvdNo); registerField("onDvd", mOnDvd); } void MovieInfoPage::initializePage(){ initModel(); mTitle->clear(); mSeriesNo->setValue(1); mPartno->setValue(1); mQuality->setValue(8); mOnDvd->setChecked(false); } void MovieInfoPage::addFiles(){ QSettings s; QString startDir = s.value("paths/selecteddir", QDir::homePath()).toString(); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files"), startDir); if(files.isEmpty()){ return; } foreach(QString f, files){ QFileInfo fi(f); 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{ 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::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); } } 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); } 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); }