diff options
author | Arno <am@disconnect.de> | 2010-06-26 15:24:00 +0200 |
---|---|---|
committer | Arno <am@disconnect.de> | 2010-06-26 15:24:00 +0200 |
commit | 0b807eba97e65bf9e25f83387826ef2579b79c90 (patch) | |
tree | 9a86166a4ebd77d95e9a26b723c49ebab417e337 | |
parent | 6567a92bec5ca8b2bc6b7156bddc5ba8508f31b3 (diff) | |
download | SheMov-0b807eba97e65bf9e25f83387826ef2579b79c90.tar.gz SheMov-0b807eba97e65bf9e25f83387826ef2579b79c90.tar.bz2 SheMov-0b807eba97e65bf9e25f83387826ef2579b79c90.zip |
Actors and genre edit
Implemented widgets for actor and genre editing of movies. Created new
MappingTableWidget for both genres and actors and revamped
ArchiveTreeView to show 2 widgets below the FilesTreeView separated by a
splitter.
While testing the new setup several bugs were fixed:
-an SQL syntax error in FilesTreeModel
-fixed SmModelSingleton to properly work with table names
I also changed the signature of MappingTableModel::addMapping for the
ease of use and added MappingTableModel::removeMapping.
MappingTableModel got 2 new convenience functions:
1. bool contains(QString) to check if an item is already present
2. QModelIndex find() to get the index of a specific value from the
model.
-rw-r--r-- | archivetreeview.cpp | 48 | ||||
-rw-r--r-- | archivetreeview.h | 10 | ||||
-rw-r--r-- | filestreemodel.cpp | 2 | ||||
-rw-r--r-- | mappingtablemodel.cpp | 52 | ||||
-rw-r--r-- | mappingtablemodel.h | 6 | ||||
-rw-r--r-- | mappingtablewidget.cpp | 146 | ||||
-rw-r--r-- | mappingtablewidget.h | 59 | ||||
-rw-r--r-- | shemov.pro | 6 | ||||
-rw-r--r-- | smmodelsingleton.cpp | 4 |
9 files changed, 313 insertions, 20 deletions
diff --git a/archivetreeview.cpp b/archivetreeview.cpp index 211aa37..d77f8e3 100644 --- a/archivetreeview.cpp +++ b/archivetreeview.cpp @@ -20,8 +20,14 @@ #include "filestreewidget.h" #include "filestreemodel.h" #include "seriestreemodel.h" +#include "mappingtablewidget.h" +#include "mappingtablemodel.h" ArchiveTreeView::ArchiveTreeView(QWidget *parent) : QWidget(parent){ + // models + mActorsModel = static_cast<MappingTableModel*>(SmModelSingleton::instance()->model("actors")); + mGenresModel = static_cast<MappingTableModel*>(SmModelSingleton::instance()->model("genres")); + // series view mSeriesWidget = new SeriesTreeWidget; QItemSelectionModel *selModel = mSeriesWidget->seriesTree()->selectionModel(); @@ -36,11 +42,29 @@ ArchiveTreeView::ArchiveTreeView(QWidget *parent) : QWidget(parent){ mFilesWidget->filesTree()->setColumnHidden(i, true); } + // actors and genre + QWidget *genreActorWidget = new QWidget; + QHBoxLayout *genreActorLayout = new QHBoxLayout; + mActorsWidget = new MappingTableWidget("actors"); + mGenresWidget = new MappingTableWidget("genres"); + genreActorLayout->addWidget(mActorsWidget); + genreActorLayout->addWidget(mGenresWidget); + genreActorWidget->setLayout(genreActorLayout); + + // fileview, actors and genres + QSplitter *verticalSplitter = new QSplitter(Qt::Vertical); + verticalSplitter->addWidget(mFilesWidget); + verticalSplitter->addWidget(genreActorWidget); + verticalSplitter->setStretchFactor(0, 3); + verticalSplitter->setStretchFactor(1, 1); + // layout QHBoxLayout *mainLayout = new QHBoxLayout; QSplitter *splitter = new QSplitter; splitter->addWidget(mSeriesWidget); - splitter->addWidget(mFilesWidget); + splitter->addWidget(verticalSplitter); + splitter->setStretchFactor(0, 2); + splitter->setStretchFactor(1, 3); mainLayout->addWidget(splitter); setLayout(mainLayout); } @@ -83,4 +107,26 @@ void ArchiveTreeView::currentChanged(const QItemSelection &selected, const QItem mFilesWidget->filesTree()->resizeColumnToContents(1); mFilesWidget->filesTree()->resizeColumnToContents(2); mFilesWidget->filesTree()->resizeColumnToContents(3); + setMappingItems(selectedPartIds, mActorsModel, mActorsWidget); + setMappingItems(selectedPartIds, mGenresModel, mGenresWidget); +} + +void ArchiveTreeView::setMappingItems(QList<int>seriesPartIds, MappingTableModel *model, MappingTableWidget *widget){ + QStringList items; + foreach(int id, seriesPartIds){ + QList<QVariant> actorNames = model->mappings(id); + foreach(QVariant v, actorNames){ + if(!items.contains(v.toString())){ + items << v.toString(); + } + } + } + qSort(items); + widget->setStringList(items); + widget->setEditEnabled(seriesPartIds.count() == 1); + if(seriesPartIds.count() == 1){ + widget->setCurrentId(seriesPartIds.at(0)); + }else{ + widget->setCurrentId(-1); + } } diff --git a/archivetreeview.h b/archivetreeview.h index 9958138..13dc88a 100644 --- a/archivetreeview.h +++ b/archivetreeview.h @@ -10,12 +10,15 @@ #include <QWidget> #include <QModelIndexList> +#include <QList> class SmUberModel; class SeriesTreeWidget; class FilesTreeWidget; class FilesTreeModel; class SeriesTreeModel; +class MappingTableWidget; +class MappingTableModel; class QItemSelection; class ArchiveTreeView : public QWidget @@ -28,13 +31,20 @@ class ArchiveTreeView : public QWidget private slots: void currentChanged(const QItemSelection &selected, const QItemSelection &deselected); + void setMappingItems(const QList<int> seriesPartIds, MappingTableModel *model, MappingTableWidget *widget); private: //widgets SeriesTreeWidget *mSeriesWidget; FilesTreeWidget *mFilesWidget; + MappingTableWidget *mActorsWidget; + MappingTableWidget *mGenresWidget; + + //models FilesTreeModel *mFilesModel; SeriesTreeModel *mSeriesModel; + MappingTableModel *mActorsModel; + MappingTableModel *mGenresModel; //lists QModelIndexList mSelectedItems; diff --git a/filestreemodel.cpp b/filestreemodel.cpp index 973e7a6..cbfbd24 100644 --- a/filestreemodel.cpp +++ b/filestreemodel.cpp @@ -18,7 +18,7 @@ FilesTreeModel::FilesTreeModel(QStringList &headers, QObject *parent) : SmTreeMo mUpdateDvdQuery = new QSqlQuery(mDb); mUpdateDvdQuery->prepare("UPDATE files SET idvd = :dvd WHERE ifiles_id = :id"); mUpdateQualityQuery = new QSqlQuery(mDb); - mUpdateQualityQuery->prepare("UPDATE files SET iquality = :quality WHERE ifiles_id = :id"); + mUpdateQualityQuery->prepare("UPDATE files SET siquality = :quality WHERE ifiles_id = :id"); } FilesTreeModel::~FilesTreeModel(){ diff --git a/mappingtablemodel.cpp b/mappingtablemodel.cpp index 84c242a..ad569ee 100644 --- a/mappingtablemodel.cpp +++ b/mappingtablemodel.cpp @@ -33,7 +33,10 @@ MappingTableModel::MappingTableModel(QStringList &headers, const QString &table, QString addMappingQuery = QString("INSERT INTO %1 (iseriesparts_id, %2) VALUES (:id1, :id2)").arg(mMappingTable).arg(mIdColumnName); mAddMappingQuery = new QSqlQuery(mDb); mAddMappingQuery->prepare(addMappingQuery); - QString mappingQuery = QString("SELECT %1 FROM %2, %3 WHERE %1.%4 = %3.%4 AND %3.iseriesparts_id = :id").arg(mNameColumnName).arg(mTable).arg(mMappingTable).arg(mIdColumnName); + QString removeMappingQuery = QString("DELETE FROM %1 WHERE iseriesparts_id = :id1 AND %2 = :id2").arg(mMappingTable).arg(mIdColumnName); + mRemoveMappingQuery = new QSqlQuery(mDb); + mRemoveMappingQuery->prepare(removeMappingQuery); + QString mappingQuery = QString("SELECT %1 FROM %2, %3 WHERE %2.%4 = %3.%4 AND %3.iseriesparts_id = :id").arg(mNameColumnName).arg(mTable).arg(mMappingTable).arg(mIdColumnName); mMappingQuery = new QSqlQuery(mDb); mMappingQuery->prepare(mappingQuery); @@ -46,6 +49,7 @@ MappingTableModel::~MappingTableModel(){ delete mInsertItemQuery; delete mDeleteItemQuery; delete mAddMappingQuery; + delete mRemoveMappingQuery; delete mMappingQuery; mDb = QSqlDatabase(); } @@ -98,6 +102,24 @@ bool MappingTableModel::setData(const QModelIndex &index, const QVariant &value, return false; } +bool MappingTableModel::contains(const QString &value) const{ + return mItemNames.contains(value); +} + +QModelIndex MappingTableModel::find(const QVariant &value, int column, const QModelIndex &parent) const{ + SmTreeItem *parentItem = root(); + if(parent.isValid()){ + parentItem = static_cast<SmTreeItem*>(parent.internalPointer()); + } + for(int i = 0; i < parentItem->childCount(); ++i){ + SmTreeItem *cur = parentItem->child(i); + if(cur->data(column) == value){ + return index(i, column, parent); + } + } + return QModelIndex(); +} + bool MappingTableModel::addItem(const QVariant &name){ QString newValue = name.toString().toLower().trimmed(); if(mItemNames.contains(newValue)){ @@ -138,22 +160,24 @@ bool MappingTableModel::removeItem(const QModelIndex &idx){ return false; } -bool MappingTableModel::addMapping(int seriesId, const QList<int> &itemIds){ - if(itemIds.isEmpty()){ - return false; - } +bool MappingTableModel::addMapping(int seriesId, int itemId){ mDb.transaction(); - foreach(int id, itemIds){ - mAddMappingQuery->bindValue(":id1", seriesId); - mAddMappingQuery->bindValue(":id2", id); - if(!mAddMappingQuery->exec()){ - mDb.rollback(); - return false; - } + mAddMappingQuery->bindValue(":id1", seriesId); + mAddMappingQuery->bindValue(":id2", itemId); + if(!mAddMappingQuery->exec()){ + mDb.rollback(); + return false; } + mDb.commit(); return true; } +bool MappingTableModel::removeMapping(int seriesId, int itemId){ + mRemoveMappingQuery->bindValue(":id1", seriesId); + mRemoveMappingQuery->bindValue(":id2", itemId); + return mRemoveMappingQuery->exec(); +} + QList<QVariant> MappingTableModel::mappings(int seriesId){ QList<QVariant> retval; mMappingQuery->bindValue(":id", seriesId); @@ -167,7 +191,9 @@ QList<QVariant> MappingTableModel::mappings(int seriesId){ void MappingTableModel::populate(){ QString query = QString("SELECT %1, %2 FROM %3 ORDER BY %2").arg(mIdColumnName).arg(mNameColumnName).arg(mTable); - SmTreeItem *root = new SmTreeItem(2); + QList<QVariant> rootData; + rootData << QString(tr("%1 name")).arg(mTable) << tr("Id"); + SmTreeItem *root = new SmTreeItem(rootData); QSqlQuery dataQuery(query, mDb); while(dataQuery.next()){ QList<QVariant> data; diff --git a/mappingtablemodel.h b/mappingtablemodel.h index f624bff..d600437 100644 --- a/mappingtablemodel.h +++ b/mappingtablemodel.h @@ -29,13 +29,16 @@ class MappingTableModel : public SmTreeModel{ virtual Qt::ItemFlags flags(const QModelIndex &index) const; virtual QVariant data(const QModelIndex &index, int role) const; virtual bool setData(const QModelIndex &index, const QVariant &value, int role); + bool contains(const QString &value) const; + QModelIndex find(const QVariant &value, int column = 0, const QModelIndex &parent = QModelIndex()) const; //add and remove items bool addItem(const QVariant &name); bool removeItem(const QModelIndex &idx); //mappings - bool addMapping(int seriesId, const QList<int> &itemIds); + bool addMapping(int seriesId, int itemId); + bool removeMapping(int seriesId, int itemId); QList<QVariant> mappings(int seriesId); signals: @@ -56,6 +59,7 @@ class MappingTableModel : public SmTreeModel{ QSqlQuery *mInsertItemQuery; QSqlQuery *mDeleteItemQuery; QSqlQuery *mAddMappingQuery; + QSqlQuery *mRemoveMappingQuery; QSqlQuery *mMappingQuery; }; diff --git a/mappingtablewidget.cpp b/mappingtablewidget.cpp new file mode 100644 index 0000000..e4a177c --- /dev/null +++ b/mappingtablewidget.cpp @@ -0,0 +1,146 @@ +/* + 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 <QIcon> +#include <QTreeView> +#include <QPushButton> +#include <QLineEdit> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QLabel> +#include <QCompleter> +#include <QGroupBox> + +#include "mappingtablewidget.h" +#include "mappingtablemodel.h" +#include "smmodelsingleton.h" + +MappingTableWidget::MappingTableWidget(const QString &table, QWidget *parent) : QWidget(parent), mTable(table), mCurrentId(-1){ + //the view + mView = new QTreeView; + mView->setHeaderHidden(true); + mModel = new MappingTableItemModel(this); + mModel->setHeaderData(0, Qt::Horizontal, mTable); + mView->setModel(mModel); + + //mapping model + mMappingModel = static_cast<MappingTableModel*>(SmModelSingleton::instance()->model(mTable)); + + //editor + QHBoxLayout *itemEditLayout = new QHBoxLayout; + QString l1Text = QString(tr("&Edit %1")).arg(mTable); + QLabel *l1 = new QLabel(l1Text); + mItemEdit = new QLineEdit; + QCompleter *completer = new QCompleter(this); + completer->setModel(mMappingModel); + mItemEdit->setCompleter(completer); + l1->setBuddy(mItemEdit); + itemEditLayout->addWidget(l1); + itemEditLayout->addWidget(mItemEdit); + connect(mItemEdit, SIGNAL(returnPressed()), this, SLOT(addItem())); + + //buttons + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + mAddItem = new QPushButton(tr("Add item")); + mRemoveItem = new QPushButton(tr("Remove item")); + buttonLayout->addWidget(mAddItem); + buttonLayout->addWidget(mRemoveItem); + connect(mAddItem, SIGNAL(clicked()), this, SLOT(addItem())); + connect(mRemoveItem, SIGNAL(clicked()), this, SLOT(removeItem())); + + //layout + QVBoxLayout *groupBoxLayout = new QVBoxLayout; + groupBoxLayout->addWidget(mView); + groupBoxLayout->addLayout(itemEditLayout); + groupBoxLayout->addLayout(buttonLayout); + QString gbCaption = QString(tr("Edit %1")).arg(mTable); + QGroupBox *gb = new QGroupBox(gbCaption); + gb->setLayout(groupBoxLayout); + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(gb); + setLayout(mainLayout); + setContentsMargins(0, 0, 0, 0); +} + +void MappingTableWidget::setStringList(const QStringList &list){ + mModel->setStringList(list); +} + +void MappingTableWidget::setEditEnabled(bool enabled){ + mAddItem->setEnabled(enabled); + mRemoveItem->setEnabled(enabled); + mItemEdit->setEnabled(enabled); +} +void MappingTableWidget::addItem(){ + QString value = mItemEdit->text().toLower().trimmed(); + if(mModel->stringList().contains(value)){ + return; + } + if(!mMappingModel->contains(value)){ + mMappingModel->addItem(value); + } + int row = mModel->lowerBound(value); + if(mModel->insertRows(row, 1)){ + QModelIndex idx = mModel->index(row, 0); + mModel->setData(idx, value); + QModelIndex mapIndex = mMappingModel->find(value, 0, QModelIndex()); + if(mapIndex.isValid()){ + int id = mapIndex.data(MappingTableModel::ItemIdRole).toInt(); + mMappingModel->addMapping(mCurrentId, id); + } + } +} + +void MappingTableWidget::removeItem(){ + QModelIndexList selected = mView->selectionModel()->selectedRows(); + if(selected.isEmpty()){ + return; + } + foreach(QPersistentModelIndex i, selected){ + QString item = i.data().toString(); + mModel->removeRows(i.column(), 1); + QModelIndex itemIdx = mMappingModel->find(item); + if(itemIdx.isValid()){ + mMappingModel->removeMapping(mCurrentId, itemIdx.data(MappingTableModel::ItemIdRole).toInt()); + } + } +} + +MappingTableItemModel::MappingTableItemModel(QObject *parent) : QStringListModel(parent) {} + +QVariant MappingTableItemModel::data(const QModelIndex &index, int role) const{ + if(role == Qt::DecorationRole){ + return QIcon(":/dildo.png"); + } + return QStringListModel::data(index, role); +} + +Qt::ItemFlags MappingTableItemModel::flags(const QModelIndex &index) const{ + Q_UNUSED(index); + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +int MappingTableItemModel::lowerBound(const QString &value) const{ + int retval = 0; + for(int i = 0; i < stringList().count(); ++i){ + if(value < stringList().at(i)){ + ++retval; + }else{ + break; + } + } + return retval; +} + +QModelIndex MappingTableItemModel::find(const QString &value) const{ + int row = stringList().indexOf(value); + if(row == -1){ + return QModelIndex(); + } + return index(row, 0); +} diff --git a/mappingtablewidget.h b/mappingtablewidget.h new file mode 100644 index 0000000..d6df991 --- /dev/null +++ b/mappingtablewidget.h @@ -0,0 +1,59 @@ +/* + 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. +*/ + +#ifndef MAPPINGTABLEWIDGET_H +#define MAPPINGTABLEWIDGET_H + +#include <QWidget> +#include <QStringListModel> + +class QTreeView; +class QLineEdit; +class QPushButton; +class MappingTableItemModel; +class MappingTableModel; + +class MappingTableWidget : public QWidget{ + Q_OBJECT + public: + explicit MappingTableWidget(const QString &table, QWidget *parent = 0); + + public slots: + void setStringList(const QStringList &list); + void setEditEnabled(bool enabled); + void setCurrentId(int id) { mCurrentId = id; } + + private slots: + void addItem(); + void removeItem(); + + private: + QTreeView *mView; + QPushButton *mAddItem; + QPushButton *mRemoveItem; + QLineEdit *mItemEdit; + MappingTableItemModel *mModel; + MappingTableModel *mMappingModel; + const QString mTable; + int mCurrentId; +}; + +class MappingTableItemModel : public QStringListModel { + Q_OBJECT + public: + explicit MappingTableItemModel(QObject *parent = 0); + + //data + flags + virtual QVariant data(const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + + //find + int lowerBound(const QString &value) const; + QModelIndex find(const QString &value) const; +}; + +#endif // MAPPINGTABLEWIDGET_H @@ -54,7 +54,8 @@ SOURCES = main.cpp \ seriestreemodel.cpp \ filestreemodel.cpp \ filestreewidget.cpp \ - mappingtablemodel.cpp + mappingtablemodel.cpp \ + mappingtablewidget.cpp HEADERS = listitem.h \ listmodel.h \ movieitem.h \ @@ -104,6 +105,7 @@ HEADERS = listitem.h \ seriestreemodel.h \ filestreemodel.h \ filestreewidget.h \ - mappingtablemodel.h + mappingtablemodel.h \ + mappingtablewidget.h LIBS += -lmagic RESOURCES = shemov.qrc diff --git a/smmodelsingleton.cpp b/smmodelsingleton.cpp index 2ee5623..7425aeb 100644 --- a/smmodelsingleton.cpp +++ b/smmodelsingleton.cpp @@ -51,13 +51,13 @@ QAbstractItemModel *SmModelSingleton::model(const QString &which){ FilesTreeModel *model = new FilesTreeModel(headers); mModels.insert(which, model); } - }else if(which == "ActorsModel"){ + }else if(which == "actors"){ if(!mModels.contains(which)){ QStringList headers = QStringList() << tr("Actor") << tr("Id"); MappingTableModel *model = new MappingTableModel(headers, "actors"); mModels.insert(which, model); } - }else if(which == "GenresModel"){ + }else if(which == "genres"){ if(!mModels.contains(which)){ QStringList headers = QStringList() << tr("Genre") << tr("Id"); MappingTableModel *model = new MappingTableModel(headers, "genres"); |