/* 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 "seriestreemodel.h" #include "smtreeitem.h" #include "helper.h" SeriesTreeModel::SeriesTreeModel(QStringList &headers, QObject *parent) : SmTreeModel(headers, parent){ mDb = QSqlDatabase::database("treedb"); mSeriesPartsQuery = new QSqlQuery(mDb); mSeriesPartsQuery->prepare("SELECT iseriesparts_id, iseriespart FROM seriesparts WHERE iseries_id = :id ORDER BY iseriespart"); mUpdateSeriesIdQuery = new QSqlQuery(mDb); mUpdateSeriesIdQuery->prepare("UPDATE seriesparts SET iseries_id = :newid WHERE iseries_id = :oldid"); mUpdateSeriesNameQuery = new QSqlQuery(mDb); mUpdateSeriesNameQuery->prepare("UPDATE series SET tseries_name = :newname WHERE iseries_id = :id"); mDeleteSeriesQuery = new QSqlQuery(mDb); mDeleteSeriesQuery->prepare("DELETE FROM series where iseries_id = :id"); mDeleteSeriesPartQuery = new QSqlQuery(mDb); mDeleteSeriesPartQuery->prepare("DELETE FROM seriesparts WHERE iseriesparts_id = :id"); mSeriesInsertQuery = new QSqlQuery(mDb); mSeriesInsertQuery->prepare("INSERT INTO series(tseries_name) VALUES(:name)"); mSeriesFilesQuery = new QSqlQuery(mDb); mSeriesFilesQuery->prepare("SELECT files.tfilename, files.cmd5sum FROM series, seriesparts, files WHERE series.iseries_id = :id AND series.iseries_id = seriesparts.iseries_id AND seriesparts.iseriesparts_id = files.iseriespart_id"); mSeriesPartFilesQuery = new QSqlQuery(mDb); mSeriesPartFilesQuery->prepare("SELECT files.tfilename, files.cmd5sum FROM seriesparts, files WHERE seriesparts.iseriesparts_id = :id AND seriesparts.iseriesparts_id = files.iseriespart_id"); mSortedMovieListQuery = new QSqlQuery(mDb); mSortedMovieListQuery->prepare("SELECT files.tfilename, files.cmd5sum FROM series, seriesparts, files WHERE series.iseries_id = :id AND seriesparts.iseries_id = series.iseries_id AND seriesparts.iseriesparts_id = files.iseriespart_id AND files.sifiletype = 1 ORDER BY seriesparts.iseriespart, files.sifileno"); populate(); } SeriesTreeModel::~SeriesTreeModel(){ delete mSeriesPartsQuery; delete mUpdateSeriesIdQuery; delete mUpdateSeriesNameQuery; delete mDeleteSeriesQuery; delete mSeriesInsertQuery; delete mSeriesFilesQuery; delete mSeriesPartFilesQuery; mDb.close(); mDb = QSqlDatabase(); } Qt::ItemFlags SeriesTreeModel::flags(const QModelIndex &index) const{ if(!index.isValid()){ return 0; } Qt::ItemFlags retval = Qt::ItemIsEnabled | Qt::ItemIsSelectable; if(index.data(TypeRole).toInt() == Series || index.data(TypeRole).toInt() == NewSeries){ return retval | Qt::ItemIsEditable; } return retval; } QVariant SeriesTreeModel::data(const QModelIndex &index, int role) const{ if(!index.isValid()){ return QVariant(); } SmTreeItem *item = static_cast(index.internalPointer()); if(role == Qt::DisplayRole){ if(index.column() == Name){ int type = index.data(TypeRole).toInt(); if(type == Series || type == NewSeries){ return item->data(Name); }else if(type == Part){ QString retval = QString("%1 %2").arg(item->data(Name).toString()).arg(item->data(SeriesPart).toInt()); return retval; }else{ return QVariant(); } }else{ return item->data(index.column()); } } if(role == Qt::DecorationRole){ if(index.column() == 0){ return QIcon(":/dildo.png"); } } if(role == Qt::EditRole){ if(index.data(TypeRole) == Series || index.data(TypeRole) == NewSeries){ if(index.column() == 0){ return item->data(Name); } } } if(role == NameRole){ return item->data(Name); } if(role == SeriesIdRole){ return item->data(SeriesId); } if(role == SeriesPartIdRole){ return item->data(SeriesPartId); } if(role == SeriesPartRole){ return item->data(SeriesPart); } if(role == TypeRole){ return item->data(Type); } return QVariant(); } bool SeriesTreeModel::setData(const QModelIndex &index, const QVariant &value, int role){ if(!index.isValid()){ return false; } if(role == Qt::EditRole){ if(index.data(TypeRole).toInt() == Series){ //change of series name if(index.column() == Name){ QModelIndex newSeries = findValue(value, index.parent(), index.column()); if(newSeries == index){ //no change made, exit gracefully return false; } //int oldSeriesId = index.data(SeriesIdRole).toInt(); if(newSeries != QModelIndex()){ //series already exists, merge return mergeSeries(index, newSeries); }else{ //rename series return renameSeries(index, value); } } }else if(index.data(TypeRole).toInt() == NewSeries){ return setNewSeries(index, value); } } return false; } QList SeriesTreeModel::childrenColumnList(const QModelIndex &parent, int column) const{ if(!parent.isValid()){ return QList(); } SmTreeItem *item = static_cast(parent.internalPointer()); QList retval; for(int i = 0; i < item->childCount(); ++i){ SmTreeItem *child = item->child(i); retval << child->data(column); } return retval; } QModelIndex SeriesTreeModel::findValue(const QVariant &value, const QModelIndex &parent, int column) const{ SmTreeItem *parentItem = root(); if(parent != QModelIndex()){ parentItem = static_cast(parent.internalPointer()); } for(int i = 0; i < parentItem->childCount(); ++i){ SmTreeItem *childItem = parentItem->child(i); if(value == childItem->data(column)){ return createIndex(i, column, childItem); } } return QModelIndex(); } QFileInfoList SeriesTreeModel::findFiles(const QModelIndex &where) const{ int type = where.data(TypeRole).toInt(); QFileInfoList retval; QSqlQuery *query = 0; if(type == Series){ query = mSeriesFilesQuery; query->bindValue(":id", where.data(SeriesIdRole)); }else if(type == Part){ query = mSeriesPartFilesQuery; query->bindValue(":id", where.data(SeriesPartIdRole)); } if(query){ if(query->exec()){ while(query->next()){ QString path = Helper::createArchivePath(query->value(0).toString(), query->value(1).toString()); retval << QFileInfo(path); } } } return retval; } QFileInfoList SeriesTreeModel::findMovies(const QModelIndexList &from) const{ if(from.isEmpty()){ return QFileInfoList(); } QFileInfoList retval; foreach(QModelIndex idx, from){ QFileInfoList files = findFiles(idx); foreach(QFileInfo fi, files){ QString mime = Helper::mimeType(fi.absoluteFilePath()); if(mime.startsWith("video")){ if(!retval.contains(fi)){ retval << fi; } } } } return retval; } QFileInfoList SeriesTreeModel::findSortedMovies(const QModelIndex &from) const{ if(!from.isValid()){ return QFileInfoList(); } QFileInfoList retval; int seriesId = from.data(SeriesIdRole).toInt(); mSortedMovieListQuery->bindValue(":id", seriesId); if(mSortedMovieListQuery->exec()){ while(mSortedMovieListQuery->next()){ QString path = Helper::createArchivePath(mSortedMovieListQuery->value(0).toString(), mSortedMovieListQuery->value(1).toString()); retval << QFileInfo(path); } } return retval; } bool SeriesTreeModel::deleteFromSeries(const QModelIndex &what){ int nodeType = what.data(TypeRole).toInt(); QSqlQuery *query = 0; if(nodeType == Series || nodeType == NewSeries){ query = mDeleteSeriesQuery; query->bindValue(":id", what.data(SeriesIdRole)); }else if(nodeType == Part){ query = mDeleteSeriesPartQuery; query->bindValue(":id", what.data(SeriesPartIdRole)); } if(query){ QFileInfoList files = findFiles(what); if(query->exec()){ foreach(QFileInfo fi, files){ QFile::remove(fi.absoluteFilePath()); } removeRows(what.row(), 1, what.parent()); return true; } } return false; } void SeriesTreeModel::populate(){ QSqlQuery seriesQuery = QSqlQuery("SELECT iseries_id, tseries_name FROM series ORDER BY tseries_name", mDb); SmTreeItem *rootItem = new SmTreeItem(5); while(seriesQuery.next()){ QList seriesData; seriesData << seriesQuery.value(1) << seriesQuery.value(0) << QVariant() << QVariant() << Series; SmTreeItem *seriesItem = new SmTreeItem(seriesData, rootItem); rootItem->appendChild(seriesItem); mSeriesPartsQuery->bindValue(":id", seriesData.at(1)); mSeriesPartsQuery->exec(); while(mSeriesPartsQuery->next()){ QList partData; partData << seriesData.at(Name) << seriesData.at(SeriesId) << mSeriesPartsQuery->value(0) << mSeriesPartsQuery->value(1) << Part; SmTreeItem *partItem = new SmTreeItem(partData, seriesItem); seriesItem->appendChild(partItem); } } setRoot(rootItem); } bool SeriesTreeModel::mergeSeries(const QModelIndex &from, const QModelIndex &to){ //new series name already exists int oldSeriesId = from.data(SeriesIdRole).toInt(); int newSeriesId = to.data(SeriesIdRole).toInt(); mUpdateSeriesIdQuery->bindValue(":oldid", oldSeriesId); mUpdateSeriesIdQuery->bindValue(":newid", newSeriesId); if(mUpdateSeriesIdQuery->exec()){ SmTreeItem *oldParent = static_cast(from.internalPointer()); SmTreeItem *newParent = static_cast(to.internalPointer()); //reparent items to new series for(int i = oldParent->childCount() - 1; i > -1; --i){ SmTreeItem *curItem = oldParent->child(i); curItem->setParent(newParent); curItem->setData(Name, to.data(NameRole)); newParent->appendChild(curItem); oldParent->removeChild(i, false); } mDeleteSeriesQuery->bindValue(":id", oldSeriesId); if(mDeleteSeriesQuery->exec()){ //series has to be empty root()->removeChild(from.row()); } reset(); return true; } return false; } bool SeriesTreeModel::renameSeries(const QModelIndex &source, const QVariant &value){ int oldSeriesId = source.data(SeriesIdRole).toInt(); mUpdateSeriesNameQuery->bindValue(":newname", value); mUpdateSeriesNameQuery->bindValue(":id", oldSeriesId); if(mUpdateSeriesNameQuery->exec()){ SmTreeItem *curItem = static_cast(source.internalPointer()); curItem->setData(Name, value); emit dataChanged(source, source); emit needResort(); return true; } return false; } bool SeriesTreeModel::setNewSeries(const QModelIndex &source, const QVariant &value){ QString newName = value.toString(); if(newName.isEmpty()){ return false; } SmTreeItem *item = static_cast(source.internalPointer()); mDb.transaction(); mSeriesInsertQuery->bindValue(":name", value); if(mSeriesInsertQuery->exec()){ QSqlQuery lastId("SELECT currval('series_iseries_id__seq')", mDb); if(lastId.next()){ int newId = lastId.value(0).toInt(); item->setData(Name, value); item->setData(SeriesId, newId); item->setData(Type, Series); QModelIndex end = index(source.row(), item->childCount() - 1, source.parent()); emit dataChanged(source, end); emit needResort(); mDb.commit(); return true; } } mDb.rollback(); return false; }