/* 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 #include #include "archiveview.h" #include "archivecontroller.h" #include "mappingtablewidget.h" #include "delegates.h" #include "smglobals.h" #include "helper.h" #include "delegates.h" #include "smdialog.h" ArchiveView::ArchiveView(QWidget *parent) : QWidget(parent) { QSettings s; mArchiveModel = static_cast(SmGlobals::instance()->model("ArchiveModel")); connect(mArchiveModel, SIGNAL(needRefresh()), this, SLOT(refreshArchive())); connect(mArchiveModel, SIGNAL(databaseError(QString)), this, SLOT(showDatabaseError(QString))); mProxy = new ArchiveProxy; mProxy->setSourceModel(mArchiveModel); mTree = new ArchiveTree; mTree->setModel(mProxy); mTree->setColumnHidden(ArchiveModel::GenericId, true); mTree->setColumnHidden(ArchiveModel::SeriesPartId, true); mTree->setColumnHidden(ArchiveModel::SeriesPart, true); mTree->setColumnHidden(ArchiveModel::Type, true); mTree->setColumnHidden(ArchiveModel::Favorite, true); mTree->setColumnHidden(ArchiveModel::Subtitle, true); mTree->setColumnHidden(ArchiveModel::Count, true); mTree->resizeColumnToContents(ArchiveModel::Name); mTree->setSortingEnabled(true); mTree->setEditTriggers(QAbstractItemView::NoEditTriggers); connect(mTree, SIGNAL(expanded(QModelIndex)), this, SLOT(expandItem(QModelIndex))); connect(mTree, SIGNAL(collapsed(QModelIndex)), this, SLOT(collapseItem(QModelIndex))); mTree->sortByColumn(0, Qt::AscendingOrder); QString sortOrderName = s.value("archivemodel/sortorder", "Series Name").toString(); mSortOrder = new QComboBox; mSortOrder->addItems(mArchiveModel->availableOrders()); mSortOrder->setCurrentText(sortOrderName); // this is _not_ redundant! when sortOrderName is the first // item in the list, nothing will happen otherwise! mArchiveModel->setOrder(sortOrderName); connect(mSortOrder, SIGNAL(currentIndexChanged(QString)), mArchiveModel, SLOT(setOrder(QString))); connect(mArchiveModel, SIGNAL(modelReset()), this, SLOT(doSelection())); QLabel *l1 = new QLabel(tr("Filter")); mFilter = new QLineEdit; QString savedFilter = s.value("archivemodel/filter", QString()).toString(); connect(mFilter, SIGNAL(returnPressed()), this, SLOT(setFilter())); QPushButton *filter = new QPushButton(tr("Filter")); connect(filter, SIGNAL(clicked()), this, SLOT(setFilter())); QPushButton *clear = new QPushButton(tr("Clear")); mFilter->setText(savedFilter); connect(clear, SIGNAL(clicked()), this, SLOT(clearFilter())); mProxy->setFilter(savedFilter, currentSortOrder()); QHBoxLayout *filterLayout = new QHBoxLayout; filterLayout->addWidget(l1); filterLayout->addWidget(mFilter); filterLayout->addWidget(filter); filterLayout->addWidget(clear); QVBoxLayout *treeLayout = new QVBoxLayout; treeLayout->addWidget(mSortOrder); treeLayout->addLayout(filterLayout); treeLayout->addWidget(mTree); QWidget *treeWidget = new QWidget; treeWidget->setLayout(treeLayout); mToolBar = new QToolBar; mToolBar->setIconSize(QSize(16,16)); mFiles = new ArchiveFiles; mFiles->setItemDelegateForColumn(ArchiveFilesModel::FileType, new FileTypeDelegate(this)); mFiles->setItemDelegateForColumn(ArchiveFilesModel::DvdNo, new DvdNoDelegate(this)); mFiles->setItemDelegateForColumn(ArchiveFilesModel::Size, new SizeDelegate(this)); mFiles->setItemDelegateForColumn(ArchiveFilesModel::SizeDur, new DurationDelegate(this)); mFiles->setItemDelegateForColumn(ArchiveFilesModel::FileNumber, new EmptyDelegate(this)); mFiles->setSelectionMode(QAbstractItemView::ExtendedSelection); mFiles->setSelectionBehavior(QAbstractItemView::SelectRows); mFilesModel = new ArchiveFilesModel(QStringList() << QChar(0x26A7) << tr("Seriespartid") << tr("Filename") << tr("Md5Sum") << tr("Size") << tr("Dvd") << tr("Type") << tr("No") << tr("Q") << tr("Fileid") << tr("S/Dur") << tr("Full Path") << tr("Series Name") << tr("Series Part") << tr("Subtitle "), this); mFilesProxy = new ArchiveFilesProxy; mFilesProxy->setSourceModel(mFilesModel); mFiles->setModel(mFilesProxy); mFiles->setSourceModel(mFilesModel); mActorView = new SmTreeView; mActorView->setHeaderHidden(true); mActorModel = new QStandardItemModel(this); mActorView->setModel(mActorModel); QGroupBox *actorBox = new QGroupBox(tr("Actors")); QHBoxLayout *actorLayout = new QHBoxLayout; actorLayout->addWidget(mActorView); actorBox->setLayout(actorLayout); mGenreView = new SmTreeView; mGenreView->setHeaderHidden(true); mGenreModel = new QStandardItemModel(this); mGenreView->setModel(mGenreModel); QGroupBox *genreBox = new QGroupBox(tr("Genres")); QHBoxLayout *genreLayout = new QHBoxLayout; genreLayout->addWidget(mGenreView); genreBox->setLayout(genreLayout); QGroupBox *metadataBox = new QGroupBox("Metadata/Comment"); QVBoxLayout *metadataLayout = new QVBoxLayout; mMeta = new QTextEdit; mMeta->setReadOnly(true); metadataLayout->addWidget(mMeta); metadataBox->setLayout(metadataLayout); QHBoxLayout *bottomRightLayout = new QHBoxLayout; bottomRightLayout->addWidget(actorBox, 1); bottomRightLayout->addWidget(genreBox, 1); bottomRightLayout->addWidget(metadataBox, 2); QWidget *bottomRightWidget = new QWidget; bottomRightWidget->setLayout(bottomRightLayout); QVBoxLayout *topRightLayout = new QVBoxLayout; topRightLayout->addWidget(mToolBar); topRightLayout->addWidget(mFiles); QWidget *topRightWidget = new QWidget; topRightWidget->setLayout(topRightLayout); mRightSplitter = new QSplitter(Qt::Vertical); mRightSplitter->addWidget(topRightWidget); mRightSplitter->addWidget(bottomRightWidget); mRightSplitter->setStretchFactor(0, 4); mTreeSplitter = new QSplitter(Qt::Horizontal); mTreeSplitter->addWidget(treeWidget); mTreeSplitter->addWidget(mRightSplitter); mTreeSplitter->setStretchFactor(0, 1); mTreeSplitter->setStretchFactor(1, 4); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(mTreeSplitter); setLayout(mainLayout); initController(); } int ArchiveView::currentSortOrder() const { return mArchiveModel->availableOrdersHash().value(mSortOrder->currentText()); } void ArchiveView::readSettings(){ QSettings s; QVariantList list; list = s.value("archivemodel/expandedgenres").toList(); mExpandedItems[ArchiveModel::Genre] = list; list = s.value("archivemodel/expandedactors").toList(); mExpandedItems[ArchiveModel::Actor] = list; list = s.value("archivemodel/expandedseries").toList(); mExpandedItems[ArchiveModel::SeriesName] = list; list = s.value("archivemodel/expandedlocalfiles").toList(); mExpandedItems[ArchiveModel::Local] = list; list = s.value("archivemodel/expandedfavorites").toList(); mExpandedItems[ArchiveModel::FavoriteOrder] = list; mCurrentArchivePath = s.value("archivemodel/selectedseries").toStringList(); QByteArray splitterState = s.value("archivemodel/vsplitter").toByteArray(); mTreeSplitter->restoreState(splitterState); QByteArray hSplitterState = s.value("archivemodel/hsplitter").toByteArray(); mRightSplitter->restoreState(hSplitterState); doSelection(); mFiles->readHeaderConfig(); mFiles->setSortingEnabled(true); } void ArchiveView::writeSettings() { QSettings s; s.setValue("archivemodel/sortorder", mSortOrder->currentText()); s.setValue("archivemodel/filter", mFilter->text()); s.setValue("archivemodel/expandedgenres", mExpandedItems.value(ArchiveModel::Genre)); s.setValue("archivemodel/expandedactors", mExpandedItems.value(ArchiveModel::Actor)); s.setValue("archivemodel/expandedseries", mExpandedItems.value(ArchiveModel::SeriesName)); s.setValue("archivemodel/expandedlocalfiles", mExpandedItems.value(ArchiveModel::Local)); s.setValue("archivemodel/expandedfavorites", mExpandedItems.value(ArchiveModel::FavoriteOrder)); s.setValue("archivemodel/selectedseries", mCurrentArchivePath); s.setValue("archivemodel/vsplitter", mTreeSplitter->saveState()); s.setValue("archivemodel/hsplitter", mRightSplitter->saveState()); mFiles->writeHeaderConfig(); } void ArchiveView::refreshArchive(){ writeSettings(); mArchiveModel->refresh(); doSelection(); } void ArchiveView::doSelection(){ QVariantList list = mExpandedItems.value(currentSortOrder()); foreach(QVariant p, list){ QStringList path = p.toStringList(); QModelIndexList expand = mArchiveModel->pathToIndex(path); foreach(QModelIndex idx, expand){ mTree->setExpanded(mProxy->mapFromSource(idx), true); } } if(!mCurrentArchivePath.isEmpty()){ QModelIndexList l = mArchiveModel->pathToIndex(mCurrentArchivePath); if(!l.isEmpty()){ QModelIndex sel = mProxy->mapFromSource(l.last()); mTree->selectionModel()->select(sel, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); } } } void ArchiveView::setFilter(){ QString filter = mFilter->text(); mProxy->setFilter(filter, currentSortOrder()); mTree->expandAll(); } void ArchiveView::clearFilter(){ mFilter->clear(); mProxy->setFilter(QString(), currentSortOrder()); mTree->collapseAll(); } void ArchiveView::showDatabaseError(const QString &errorMsg){ QMessageBox::critical(this, tr("Database Error"), errorMsg); } void ArchiveView::expandItem(const QModelIndex &idx){ QModelIndex realIdx = mProxy->mapToSource(idx); if(realIdx.isValid()){ QStringList path = mArchiveModel->indexToPath(realIdx); QVariantList list = mExpandedItems.value(currentSortOrder()); if(!list.contains(path)){ list << mArchiveModel->indexToPath(realIdx); } mExpandedItems[currentSortOrder()] = list; } } void ArchiveView::collapseItem(const QModelIndex &idx){ QModelIndex realIdx = mProxy->mapToSource(idx); if(realIdx.isValid()){ QVariantList list = mExpandedItems.value(currentSortOrder()); list.removeAll(mArchiveModel->indexToPath(realIdx)); mExpandedItems[currentSortOrder()] = list; } } void ArchiveView::initController(){ mController = new ArchiveController(this); mController->setArchiveView(this); mController->setArchiveTree(mTree, mProxy); mController->setArchiveFiles(mFiles, mFilesProxy); mController->setModels(mArchiveModel, mFilesModel); mController->setMappingModels(mActorModel, mGenreModel); mController->setMetadata(mMeta); mController->init(); SmGlobals::instance()->setArchiveController(mController); } ArchiveTree::ArchiveTree(QWidget *parent) : SmTreeView(parent) { setAcceptDrops(true); } void ArchiveTree::setModel(ArchiveProxy *model){ mProxy = model; mModel = qobject_cast(mProxy->sourceModel()); QTreeView::setModel(model); } void ArchiveTree::edit(){ QModelIndex idx = firstSelected(); if(idx.isValid()){ QString currentName = idx.data(ArchiveModel::NameRole).toString(); QString question = QString(tr("Rename %1 to:")).arg(currentName); QString newName = QInputDialog::getText(this, tr("Rename"), question, QLineEdit::Normal, currentName); if(!newName.isEmpty()){ QModelIndex realIdx = mProxy->mapToSource(idx); mModel->setData(realIdx, newName, Qt::EditRole); } } } void ArchiveTree::remove(){ QModelIndex idx = firstSelected(); if(idx.isValid()){ QString warningMsg = QString("Really remove %1?").arg(idx.data().toString()); int retval = QMessageBox::warning(this, tr("Question"), warningMsg, QMessageBox::Yes | QMessageBox::No); if(retval == QMessageBox::Yes){ QModelIndex realIdx = mProxy->mapToSource(idx); if(!mModel->removeNode(realIdx)){ impossible(); } } } } void ArchiveTree::editActors(){ MappingEditor e(tr("Actors"), this); QStringList actors = mModel->allActors(); e.widget()->fillCompleter(actors); QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } int pId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); QStringList curActors = mModel->actors(QSet() << pId); e.widget()->setDecorationItem(SmGlobals::instance()->iconFor("actor")); e.widget()->setCurrentItems(curActors); int res = e.exec(); if(res == QDialog::Accepted){ QStringList selActors = e.widget()->items(); mModel->setActors(pId, selActors); ArchiveController *c = SmGlobals::instance()->archiveController(); c->treeSelectionChanged(QItemSelection(), QItemSelection()); } } void ArchiveTree::editGenres(){ MappingEditor e(tr("Genres"), this); QStringList genres = mModel->allGenres(); e.widget()->fillCompleter(genres); QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } int pId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); QStringList curGenres = mModel->genres(QSet() << pId); e.widget()->setDecorationItem(SmGlobals::instance()->iconFor("genre")); e.widget()->setCurrentItems(curGenres); int res = e.exec(); if(res == QDialog::Accepted){ QStringList selGenres = e.widget()->items(); mModel->setGenres(pId, selGenres); ArchiveController *c = SmGlobals::instance()->archiveController(); c->treeSelectionChanged(QItemSelection(), QItemSelection()); } } void ArchiveTree::editMetadata(){ QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } MetadataEditor e(this); ArchiveController *c = SmGlobals::instance()->archiveController(); int pId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); QList curMetadata = c->archiveTreeModel()->metadataList(pId); e.widget()->setMetadata(curMetadata); int res = e.exec(); if(res == QDialog::Accepted){ QList data = e.widget()->metadata(); mModel->setMetadata(pId, data); c->treeSelectionChanged(QItemSelection(), QItemSelection()); } } void ArchiveTree::editSeriesPart(){ QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } int curPart = idx.data(ArchiveModel::SeriesPartRole).toInt(); QString subtitle = idx.data(ArchiveModel::SubtitleRole).toString(); PartEditor e(this); e.setPartNo(curPart); e.setSubtitle(subtitle); int res = e.exec(); if(res == QDialog::Accepted){ int pId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); ArchiveController *c = SmGlobals::instance()->archiveController(); c->archiveTreeModel()->setPartNo(pId, e.partNo(), e.subtitle()); mModel->refresh(); } } void ArchiveTree::markAsFavorite(){ QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } int pId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); bool fav = idx.data(ArchiveModel::FavoriteRole).toBool(); ArchiveController *c = SmGlobals::instance()->archiveController(); c->archiveTreeModel()->setFavorite(pId, !fav); } void ArchiveTree::deleteFromTree(){ QModelIndex idx = firstSelected(); if(!idx.isValid()){ return; } int type = idx.data(ArchiveModel::TypeRole).toInt(); ArchiveController *c = SmGlobals::instance()->archiveController(); ArchiveFilesModel *fm = c->archiveFilesModel(); ArchiveModel *am = c->archiveTreeModel(); if(type == ArchiveModel::SeriesPartNode){ int seriesPartId = idx.data(ArchiveModel::SeriesPartIdRole).toInt(); QStringList files = fm->filesForSeriespart(seriesPartId); if(!files.isEmpty()){ QString msg = tr("This action will permanently delete the following files:
    "); foreach(QString f, files){ QString fli = QString("
  • %1
  • ").arg(f); msg.append(fli); } msg.append("
"); msg.append(tr("

Continue?

")); int answer = QMessageBox::warning(0, tr("Question"), msg, QMessageBox::Yes | QMessageBox::No); if(answer == QMessageBox::Yes){ am->deleteSeriesPart(seriesPartId); } }else{ am->deleteSeriesPart(seriesPartId); } am->refresh(); } if(type == ArchiveModel::SeriesNode){ if(mProxy->hasChildren(idx)){ QMessageBox::critical(0, tr("Critical"), tr("Series is not empty!"), QMessageBox::Ok); return; } int seriesId = idx.data(ArchiveModel::GenericIdRole).toInt(); if(seriesId > 0){ QString msg = QString(tr("Really delete series %1?")).arg(idx.data(ArchiveModel::NameRole).toString()); int retval = QMessageBox::question(0, tr("Question"), msg, QMessageBox::Ok | QMessageBox::Cancel); if(retval == QMessageBox::Ok){ am->deleteSeries(seriesId); am->refresh(); } } } } void ArchiveTree::newPart(){ SeriesPartsDialog pDlg(this); int retval = pDlg.exec(); if(retval == QDialog::Accepted){ QString subtitle = pDlg.subtitle(); int partno = pDlg.partNo(); QModelIndex sel = firstSelected(); QModelIndex rSel = mProxy->mapToSource(sel); mModel->addSeriesPart(partno, subtitle, rSel); mModel->refresh(); } } void ArchiveTree::dragEnterEvent(QDragEnterEvent *e){ if(e->mimeData()->hasFormat("application/x-shemov-file")){ e->acceptProposedAction(); }else{ e->ignore(); } } void ArchiveTree::dragMoveEvent(QDragMoveEvent *e){ QModelIndex idx = indexAt(e->pos()); if(idx.isValid()){ int flags = idx.flags(); if(flags & Qt::ItemIsDropEnabled){ e->acceptProposedAction(); return; } } e->ignore(); return; } void ArchiveTree::dropEvent(QDropEvent *e){ QDataStream stream(e->mimeData()->data("application/x-shemov-file")); int size; stream >> size; QString question = QString(tr("Really move %1 items?")).arg(QString::number(size)); int retval = QMessageBox::question(this, tr("Question"), question); if(retval == QMessageBox::Yes){ QModelIndex dropIdx = indexAt(e->pos()); if(dropIdx.isValid()){ int newPartId = dropIdx.data(ArchiveModel::SeriesPartIdRole).toInt(); ArchiveController *c = SmGlobals::instance()->archiveController(); QStringList md5Sums; for(int i = 0; i < size; ++i){ QVariant md5; stream >> md5; md5Sums << md5.toString(); } c->moveFilesToSeriespart(md5Sums, newPartId); c->archiveFiles()->expandAll(); e->accept(); return; } } e->ignore(); } void ArchiveTree::impossible(const QString msg){ QMessageBox::critical(this, tr("Error"), msg); } QModelIndex ArchiveTree::firstSelected(){ QModelIndexList idxs = selectionModel()->selectedRows(); if(idxs.isEmpty()){ return QModelIndex(); } return idxs.first(); } ArchiveFiles::ArchiveFiles(const QString &headerSettings, QWidget *parent) : SmTreeView(headerSettings, parent){ setEditTriggers(QAbstractItemView::NoEditTriggers); setDragEnabled(true); } void ArchiveFiles::deleteFromFiles(){ QModelIndexList selected = selectionModel()->selectedRows(); QString msg = tr("This action will permanently delete the following files:
    "); QList fileIds; foreach(QModelIndex idx, selected){ QString a = QString("
  • %1
  • ").arg(idx.data(ArchiveFilesModel::FullPathRole).toString()); msg.append(a); fileIds << idx.data(ArchiveFilesModel::FileIdRole).toInt(); } msg.append("
"); msg.append(tr("

Continue?

")); int answer = QMessageBox::warning(0, tr("Question"), msg, QMessageBox::Yes | QMessageBox::No); if(answer == QMessageBox::Yes){ ArchiveController *c = SmGlobals::instance()->archiveController(); c->archiveTreeModel()->removeFiles(fileIds); c->archiveTreeModel()->refresh(); } } void ArchiveFiles::mousePressEvent(QMouseEvent *e){ if(e->button() == Qt::LeftButton){ mDragStartPos = e->pos(); } return SmTreeView::mousePressEvent(e); } void ArchiveFiles::mouseMoveEvent(QMouseEvent *e){ if(!(e->buttons() & Qt::LeftButton)){ return; } if((e->pos() - mDragStartPos).manhattanLength() < qApp->startDragDistance()){ return; } QModelIndexList sel = selectionModel()->selectedRows(); if(sel.isEmpty()){ return; } QString files("
    "); QByteArray dataBuf; QDataStream stream(&dataBuf, QIODevice::WriteOnly); stream << sel.size(); foreach(QModelIndex i, sel){ files.append("
  • "); files.append(i.data(ArchiveFilesModel::FilenameRole).toString()); stream << i.data(ArchiveFilesModel::Md5SumRole); files.append("
  • "); } files.append("
"); QLabel dragLabel(files); QPixmap dragPixmap(dragLabel.size()); dragLabel.render(&dragPixmap); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setData("application/x-shemov-file", dataBuf); drag->setMimeData(mimeData); drag->setPixmap(dragPixmap); drag->exec(Qt::MoveAction | Qt::CopyAction); } ArchiveProxy::ArchiveProxy(QObject *parent) : QSortFilterProxyModel(parent) {} void ArchiveProxy::setFilter(const QString &filter, int sortOrder){ mFilter = QRegExp(filter); mSortOrder = sortOrder; invalidateFilter(); } bool ArchiveProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { if(mFilter.isEmpty()){ return true; } QModelIndex nameIdx = sourceModel()->index(sourceRow, ArchiveModel::Name, sourceParent); ArchiveModel *model = qobject_cast(sourceModel()); return model->matchRecursive(nameIdx, mFilter); } bool ArchiveProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const{ QString l = left.data().toString(); QString r = right.data().toString(); QRegExp nrRex("( \\d+$)"); int lPos = nrRex.indexIn(l); if(lPos != -1){ int lNum = nrRex.cap(0).toInt(); int rPos = nrRex.indexIn(r); int rNum = -1; if(rPos != -1){ rNum = nrRex.cap(0).toInt(); } if(lNum > -1 && rNum > -1){ QString lNoNum = l.mid(0, lPos); QString rNoNum = r.mid(0, rPos); if(lNoNum == rNoNum){ return lNum < rNum; } } } return l < r; } ArchiveFilesProxy::ArchiveFilesProxy(QObject *parent) : QSortFilterProxyModel(parent) {} /* Mapping Editor Widget */ MappingEditorWidget::MappingEditorWidget(const QString &caption, bool showClearButton, QWidget *parent) : QWidget(parent), mCaption(caption){ // the view mModel = new QStandardItemModel(this); mModel->setHorizontalHeaderItem(0, new QStandardItem(mCaption)); mProxy = new QSortFilterProxyModel(this); mProxy->setSourceModel(mModel); QVBoxLayout *viewLayout = new QVBoxLayout; mView = new SmTreeView; viewLayout->addWidget(mView); mView->setModel(mProxy); mView->setSortingEnabled(true); // line editor QHBoxLayout *editLayout = new QHBoxLayout; QLabel *l2 = new QLabel(tr("Add:")); mEditor = new QLineEdit; mCompleter = new QCompleter(this); mCompleterModel = new QStringListModel(this); mCompleter->setModel(mCompleterModel); mEditor->setCompleter(mCompleter); editLayout->addWidget(l2); editLayout->addWidget(mEditor); // edit buttons QHBoxLayout *editButtonLayout = new QHBoxLayout; editButtonLayout->addStretch(); mClear = new QPushButton(tr("Clear")); connect(mClear, SIGNAL(clicked()), this, SLOT(clear())); if(showClearButton){ editButtonLayout->addWidget(mClear); } mRemove = new QPushButton(tr("&Remove")); connect(mRemove, SIGNAL(clicked()), this, SLOT(removeItem())); editButtonLayout->addWidget(mRemove); mAdd = new QPushButton(tr("&Add")); connect(mAdd, SIGNAL(clicked()), this, SLOT(addItem())); editButtonLayout->addWidget(mAdd); // main layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(viewLayout); mainLayout->addLayout(editLayout); mainLayout->addLayout(editButtonLayout); setLayout(mainLayout); } void MappingEditorWidget::fillCompleter(const QStringList &completions){ mCompleterModel->setStringList(completions); } void MappingEditorWidget::setCurrentItems(const QStringList &items){ foreach(QString i, items){ QStandardItem *item = new QStandardItem(i); item->setIcon(mDecorationIcon); mModel->appendRow(item); } } QStringList MappingEditorWidget::items() const{ QStringList retval; for(int i = 0; i < mModel->rowCount(); ++i){ QStandardItem *item = mModel->item(i); retval << item->text(); } return retval; } void MappingEditorWidget::clear(){ mModel->clear(); mModel->setHorizontalHeaderItem(0, new QStandardItem(mCaption)); mEditor->clear(); } void MappingEditorWidget::addItem(){ QString itemName = mEditor->text(); if(itemName.isEmpty()){ return; } QList found = mModel->findItems(itemName, Qt::MatchFixedString); if(found.size()){ return; } QStandardItem *newItem = new QStandardItem(itemName); newItem->setIcon(mDecorationIcon); mModel->appendRow(newItem); mProxy->sort(0, mProxy->sortOrder()); mEditor->clear(); } void MappingEditorWidget::removeItem(){ QModelIndexList sel = mView->selectionModel()->selectedRows(); if(sel.isEmpty()){ return; } QModelIndex real = mProxy->mapToSource(sel.first()); mModel->removeRow(real.row()); } /* Mapping Editor */ MappingEditor::MappingEditor(const QString &caption, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) { // Mapping Editor Widget mWidget = new MappingEditorWidget(caption); // buttons QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); mCancel = new QPushButton(tr("Cancel")); connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); buttonLayout->addWidget(mCancel); mAccept = new QPushButton(tr("Accept")); connect(mAccept, SIGNAL(clicked()), this, SLOT(accept())); buttonLayout->addWidget(mAccept); // dialog layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mWidget); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); setMinimumWidth(300); } /* Metadata Editor Widget */ MetadataEditorWidget::MetadataEditorWidget(QWidget *parent) : QWidget(parent){ QLabel *captionL = new QLabel(tr("Edit Metadata")); QGroupBox *genGB = new QGroupBox(tr("General")); QFormLayout *genGBL = new QFormLayout; mReleaseYear = new QSpinBox; mReleaseYear->setMinimum(1900); mReleaseYear->setMaximum(3000); mReleaseYear->setValue(QDate::currentDate().year()); genGBL->addRow(tr("&Release Year"), mReleaseYear); mSubject = new QLineEdit; genGBL->addRow(tr("Name/Sub&ject"), mSubject); genGB->setLayout(genGBL); QGroupBox *srcGB = new QGroupBox(tr("Source")); QHBoxLayout *srcGBL = new QHBoxLayout; mTorrent = new QRadioButton(tr("BitTorrent")); mTorrent->toggle(); mUsenet = new QRadioButton(tr("Usenet")); srcGBL->addWidget(mTorrent); srcGBL->addWidget(mUsenet); srcGBL->addStretch(); srcGB->setLayout(srcGBL); QGroupBox *reasonGB = new QGroupBox(tr("Reencode reason")); QHBoxLayout *reasonGBL = new QHBoxLayout; mReencReason = new QComboBox; QStringList reasons = SmGlobals::instance()->reencReasons(); mReencReason->addItems(reasons); connect(mReencReason, SIGNAL(currentIndexChanged(QString)), this, SLOT(addToComment(QString))); reasonGBL->addWidget(mReencReason); reasonGB->setLayout(reasonGBL); QHBoxLayout *srcReasonL = new QHBoxLayout; srcReasonL->addWidget(srcGB); srcReasonL->addWidget(reasonGB); //comment QGroupBox *commentGB = new QGroupBox(tr("Comment")); mComment = new QTextEdit; QHBoxLayout *commentGBL = new QHBoxLayout; commentGBL->addWidget(mComment); commentGB->setLayout(commentGBL); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(captionL); mainLayout->addWidget(genGB); mainLayout->addLayout(srcReasonL); mainLayout->addWidget(commentGB); setLayout(mainLayout); } void MetadataEditorWidget::setMetadata(const QList &data){ mReleaseYear->setValue(data.at(ArchiveModel::ReleaseYear).toInt()); QString src = data.at(ArchiveModel::Source).toString(); if(src == "torrent"){ mTorrent->toggle(); }else{ mUsenet->toggle(); } mSubject->setText(data.at(ArchiveModel::Subject).toString()); mComment->setText(data.at(ArchiveModel::Comment).toString()); mAdded = data.at(ArchiveModel::Added).toDate(); } QList MetadataEditorWidget::metadata() const{ QList retval; for(int i = 0; i < ArchiveModel::MetadataNumFields; ++i){ retval << QVariant(); } retval[ArchiveModel::ReleaseYear] = mReleaseYear->value(); QString source = "torrent"; if(mUsenet->isChecked()){ source = "Usenet"; } retval[ArchiveModel::Source] = source; retval[ArchiveModel::Subject] = mSubject->text(); retval[ArchiveModel::Comment] = mComment->toPlainText(); retval[ArchiveModel::Added] = mAdded; return retval; } void MetadataEditorWidget::addToComment(const QString &reason){ mComment->append(reason); } /* Metadata Editor */ MetadataEditor::MetadataEditor(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){ mWidget = new MetadataEditorWidget; QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); mCancel = new QPushButton(tr("Cancel")); connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); buttonLayout->addWidget(mCancel); mAccept = new QPushButton(tr("Accept")); connect(mAccept, SIGNAL(clicked()), this, SLOT(accept())); buttonLayout->addWidget(mAccept); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(mWidget); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); setMinimumWidth(400); } /* Part Editor */ PartEditor::PartEditor(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){ QLabel *captionL = new QLabel(tr("Edit part")); QFormLayout *editLayout = new QFormLayout; // part no mPartNo = new QSpinBox; mPartNo->setMinimum(0); mPartNo->setMaximum(1024); editLayout->addRow(tr("Part &no"), mPartNo); // subtitle mSubtitle = new QLineEdit; editLayout->addRow(tr("&Subtitle"), mSubtitle); // buttons QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(); mCancel = new QPushButton(tr("Cancel")); connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); mAccept = new QPushButton(tr("Accept")); connect(mAccept, SIGNAL(clicked()), this, SLOT(accept())); buttonLayout->addWidget(mCancel); buttonLayout->addWidget(mAccept); // main layout QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(captionL); mainLayout->addLayout(editLayout); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); } void PartEditor::setPartNo(int partNo){ mPartNo->setValue(partNo); } int PartEditor::partNo() const { return mPartNo->value(); } void PartEditor::setSubtitle(const QString &subtitle){ mSubtitle->setText(subtitle); } QString PartEditor::subtitle() const { return mSubtitle->text(); }