#include #include #include #include "comic_item.h" #include "comic_model.h" #include "data_base_management.h" #include "qnaturalsorting.h" #include "comic_db.h" #include "db_helper.h" //ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read #include "QsLog.h" ComicModel::ComicModel(QObject *parent) : QAbstractItemModel(parent) { connect(this,SIGNAL(beforeReset()),this,SIGNAL(modelAboutToBeReset())); connect(this,SIGNAL(reset()),this,SIGNAL(modelReset())); } ComicModel::ComicModel( QSqlQuery &sqlquery, QObject *parent) : QAbstractItemModel(parent) { setupModelData(sqlquery); } ComicModel::~ComicModel() { qDeleteAll(_data); } int ComicModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) if(_data.isEmpty()) return 0; return _data.first()->columnCount(); } bool ComicModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const { Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); Q_UNUSED(parent); if(!enableResorting) return false; return data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat); } //TODO: optimize this method (seriously) bool ComicModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { QAbstractItemModel::dropMimeData(data,action,row,column,parent); QLOG_TRACE() << ">>>>>>>>>>>>>>dropMimeData ComicModel<<<<<<<<<<<<<<<<<"<< parent << row << "," << column; if(!data->formats().contains(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat)) return false; QList comicIds = YACReader::mimeDataToComicsIds(data); QList currentIndexes; int i; foreach(qulonglong id, comicIds) { i = 0; foreach (ComicItem *item, _data) { if(item->data(Id)==id) { currentIndexes << i; break; } i++; } } std::sort(currentIndexes.begin(), currentIndexes.end()); QList resortedData; if(currentIndexes.contains(row))//no resorting return false; ComicItem * destinationItem; if(row == -1 || row >= _data.length()) destinationItem = 0; else destinationItem = _data.at(row); QList newSorting; i = 0; foreach (ComicItem *item, _data) { if(!currentIndexes.contains(i)) { if(item == destinationItem) { foreach(int index, currentIndexes) { resortedData << _data.at(index); newSorting << index; } } resortedData << item; newSorting << i; } i++; } if(destinationItem == 0) { foreach(int index, currentIndexes) { resortedData << _data.at(index); newSorting << index; } } QLOG_TRACE() << newSorting; int tempRow = row; if(tempRow < 0) tempRow = _data.count(); foreach(qulonglong id, comicIds) { int i = 0; foreach (ComicItem *item, _data) { if(item->data(Id) == id) { beginMoveRows(parent,i,i,parent,tempRow); bool skipElement = i == tempRow || i + 1 == tempRow; if(!skipElement) { if(i > tempRow) _data.move(i, tempRow); else _data.move(i, tempRow - 1); } endMoveRows(); if(i > tempRow) tempRow++; break; } i++; } } //TODO fix selection QList allComicIds; foreach (ComicItem *item, _data) { allComicIds << item->data(Id).toULongLong(); } QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); switch (mode) { case Favorites: DBHelper::reasignOrderToComicsInFavorites(allComicIds,db); break; case Label: DBHelper::reasignOrderToComicsInLabel(sourceId,allComicIds,db); break; case ReadingList: DBHelper::reasignOrderToComicsInReadingList(sourceId,allComicIds,db); break; } QSqlDatabase::removeDatabase(_databasePath); //endMoveRows(); emit resortedIndexes(newSorting); int destSelectedIndex = row<0?_data.length():row; if(destSelectedIndex>currentIndexes.at(0)) emit newSelectedIndex(index(qMax(0,destSelectedIndex-1),0,parent)); else emit newSelectedIndex(index(qMax(0,destSelectedIndex),0,parent)); return true; } bool ComicModel::canBeResorted() { return enableResorting; } QMimeData *ComicModel::mimeData(const QModelIndexList &indexes) const { //custom model data //application/yacreader-comics-ids + list of ids in a QByteArray QList ids; foreach(QModelIndex index, indexes) { QLOG_DEBUG() << "dragging : " << index.data(IdRole).toULongLong(); ids << index.data(IdRole).toULongLong(); } QByteArray data; QDataStream out(&data,QIODevice::WriteOnly); out << ids; //serialize the list of identifiers QMimeData * mimeData = new QMimeData(); mimeData->setData(YACReader::YACReaderLibrarComiscSelectionMimeDataFormat, data); return mimeData; } QStringList ComicModel::mimeTypes() const { QLOG_DEBUG() << "mimeTypes"; QStringList list; list << YACReader::YACReaderLibrarComiscSelectionMimeDataFormat; return list; } QHash ComicModel::roleNames() const { QHash roles; roles[NumberRole] = "number"; roles[TitleRole] = "title"; roles[FileNameRole] = "file_name"; roles[NumPagesRole] = "num_pages"; roles[IdRole] = "id"; roles[Parent_IdRole] = "parent_id"; roles[PathRole] = "path"; roles[HashRole] = "hash"; roles[ReadColumnRole] = "read_column"; roles[IsBisRole] = "is_bis"; roles[CurrentPageRole] = "current_page"; roles[RatingRole] = "rating"; roles[HasBeenOpenedRole] = "has_been_opened"; roles[CoverPathRole] = "cover_path"; return roles; } QVariant ComicModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); /*if (index.column() == TableModel::Rating && role == Qt::DecorationRole) { TableItem *item = static_cast(index.internalPointer()); return QPixmap(QString(":/images/rating%1.png").arg(item->data(index.column()).toInt())); }*/ if (role == Qt::DecorationRole) { return QVariant(); } if (role == Qt::TextAlignmentRole) { switch(index.column())//TODO obtener esto de la query { case ComicModel::Number: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::NumPages: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::Hash: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::CurrentPage: return QVariant(Qt::AlignRight | Qt::AlignVCenter); default: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } } //TODO check here if any view is asking for TableModel::Roles //these roles will be used from QML/GridView ComicItem *item = static_cast(index.internalPointer()); if (role == NumberRole) return item->data(Number); else if (role == TitleRole) return item->data(Title).isNull()?item->data(FileName):item->data(Title); else if (role == FileNameRole) return item->data(FileName); else if (role == RatingRole) return item->data(Rating); else if (role == CoverPathRole) return QUrl("file:"+_databasePath+"/covers/"+item->data(Hash).toString()+".jpg"); else if (role == NumPagesRole) return item->data(NumPages); else if (role == CurrentPageRole) return item->data(CurrentPage); else if (role == ReadColumnRole) return item->data(ReadColumn).toBool(); else if (role == HasBeenOpenedRole) return item->data(ComicModel::HasBeenOpened); else if (role == IdRole) return item->data(Id); if (role != Qt::DisplayRole) return QVariant(); if(index.column() == ComicModel::Hash) return QString::number(item->data(index.column()).toString().right(item->data(index.column()).toString().length()-40).toInt()/1024.0/1024.0,'f',2)+"Mb"; if(index.column() == ComicModel::ReadColumn) return (item->data(ComicModel::CurrentPage).toInt()==item->data(ComicModel::NumPages).toInt() || item->data(ComicModel::ReadColumn).toBool())?QVariant(tr("yes")):QVariant(tr("no")); if(index.column() == ComicModel::CurrentPage) return item->data(ComicModel::HasBeenOpened).toBool()?item->data(index.column()):QVariant("-"); if (index.column() == ComicModel::Rating) return QVariant(); return item->data(index.column()); } Qt::ItemFlags ComicModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; if(index.column() == ComicModel::Rating) return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled ; } QVariant ComicModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { switch(section)//TODO obtener esto de la query { case ComicModel::Number: return QVariant(QString("#")); case ComicModel::Title: return QVariant(QString(tr("Title"))); case ComicModel::FileName: return QVariant(QString(tr("File Name"))); case ComicModel::NumPages: return QVariant(QString(tr("Pages"))); case ComicModel::Hash: return QVariant(QString(tr("Size"))); case ComicModel::ReadColumn: return QVariant(QString(tr("Read"))); case ComicModel::CurrentPage: return QVariant(QString(tr("Current Page"))); case ComicModel::Rating: return QVariant(QString(tr("Rating"))); } } if (orientation == Qt::Horizontal && role == Qt::TextAlignmentRole) { switch(section)//TODO obtener esto de la query { case ComicModel::Number: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::NumPages: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::Hash: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::CurrentPage: return QVariant(Qt::AlignRight | Qt::AlignVCenter); default: return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } } if(orientation == Qt::Vertical && role == Qt::DecorationRole) { QString fileName = _data.value(section)->data(ComicModel::FileName).toString(); QFileInfo fi(fileName); QString ext = fi.suffix(); if (ext.compare("cbr",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/comicRar.png")); else if (ext.compare("cbz",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/comicZip.png")); else if(ext.compare("pdf",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/pdf.png")); else if (ext.compare("tar",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/tar.png")); else if(ext.compare("zip",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/zip.png")); else if(ext.compare("rar",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/rar.png")); #ifndef use_unarr else if (ext.compare("7z",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/7z.png")); else if (ext.compare("cb7",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/comic7z.png")); #endif else if (ext.compare("cbt",Qt::CaseInsensitive) == 0) return QVariant(QIcon(":/images/comicTar.png")); } return QVariant(); } QModelIndex ComicModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); return createIndex(row, column, _data.at(row)); } QModelIndex ComicModel::parent(const QModelIndex &index) const { Q_UNUSED(index) return QModelIndex(); } int ComicModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) return 0; if (!parent.isValid()) return _data.count(); return 0; } QStringList ComicModel::getPaths(const QString & _source) { QStringList paths; QString source = _source + "/.yacreaderlibrary/covers/"; QList::ConstIterator itr; for(itr = _data.constBegin();itr != _data.constEnd();itr++) { QString hash = (*itr)->data(ComicModel::Hash).toString(); paths << source+ hash +".jpg"; } return paths; } void ComicModel::setupFolderModelData(unsigned long long int folderId,const QString & databasePath) { enableResorting = false; mode = Folder; sourceId=folderId; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE c.parentId = :parentId"); selectQuery.bindValue(":parentId", folderId); selectQuery.exec(); setupModelData(selectQuery); } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); /*if(_data.length()==0) emit isEmpty();*/ } void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QString &databasePath) { enableResorting = true; mode = Label; sourceId = parentLabel; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "INNER JOIN comic_label cl ON (c.id == cl.comic_id) " "WHERE cl.label_id = :parentLabelId " "ORDER BY cl.ordering"); selectQuery.bindValue(":parentLabelId", parentLabel); selectQuery.exec(); setupModelDataForList(selectQuery); } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); /*if(_data.length()==0) emit isEmpty();*/ } void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, const QString &databasePath) { mode = ReadingList; sourceId = parentReadingList; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { QList ids; ids << parentReadingList; QSqlQuery subfolders(db); subfolders.prepare("SELECT id " "FROM reading_list " "WHERE parentId = :parentId " "ORDER BY ordering ASC"); subfolders.bindValue(":parentId", parentReadingList); subfolders.exec(); while(subfolders.next()) ids << subfolders.record().value(0).toULongLong(); enableResorting = ids.length()==1;//only resorting if no sublists exist foreach(qulonglong id, ids) { QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "INNER JOIN comic_reading_list crl ON (c.id == crl.comic_id) " "WHERE crl.reading_list_id = :parentReadingList " "ORDER BY crl.ordering"); selectQuery.bindValue(":parentReadingList", id); selectQuery.exec(); //TODO, extra information is needed (resorting) QList tempData = _data; _data.clear(); setupModelDataForList(selectQuery); _data = tempData << _data; } } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); } void ComicModel::setupFavoritesModelData(const QString &databasePath) { enableResorting = true; mode = Favorites; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "INNER JOIN comic_default_reading_list cdrl ON (c.id == cdrl.comic_id) " "WHERE cdrl.default_reading_list_id = :parentDefaultListId " "ORDER BY cdrl.ordering"); selectQuery.bindValue(":parentDefaultListId", 1); selectQuery.exec(); setupModelData(selectQuery); } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); /*if(_data.length()==0) emit isEmpty();*/ } void ComicModel::setupReadingModelData(const QString &databasePath) { enableResorting = false; mode = Reading; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { QSqlQuery selectQuery(db); selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE ci.hasBeenOpened = 1 AND ci.read = 0 AND ci.currentPage != ci.numPages AND ci.currentPage != 1"); selectQuery.exec(); setupModelData(selectQuery); } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); /*if(_data.length()==0) emit isEmpty();*/ } void ComicModel::setupModelData(const SearchModifiers modifier, const QString &filter, const QString &databasePath) { //QFile f(QCoreApplication::applicationDirPath()+"/performance.txt"); //f.open(QIODevice::Append); beginResetModel(); //QElapsedTimer timer; //timer.start(); qDeleteAll(_data); _data.clear(); //QTextStream txtS(&f); //txtS << "TABLEMODEL: Tiempo de borrado: " << timer.elapsed() << "ms\r\n"; _databasePath = databasePath; QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); { //crear la consulta //timer.restart(); QSqlQuery selectQuery(db); switch (modifier) { case YACReader::NoModifiers: selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter) LIMIT :limit"); selectQuery.bindValue(":filter", "%%"+filter+"%%"); selectQuery.bindValue(":limit",500); //TODO, load this value from settings break; case YACReader::OnlyRead: selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE (UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter)) AND ci.read = 1 LIMIT :limit"); selectQuery.bindValue(":filter", "%%"+filter+"%%"); selectQuery.bindValue(":limit",500); //TODO, load this value from settings break; case YACReader::OnlyUnread: selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE (UPPER(ci.title) LIKE UPPER(:filter) OR UPPER(c.fileName) LIKE UPPER(:filter)) AND ci.read = 0 LIMIT :limit"); selectQuery.bindValue(":filter", "%%"+filter+"%%"); selectQuery.bindValue(":limit",500); //TODO, load this value from settings break; default: QLOG_ERROR() << "not implemented"; break; } selectQuery.exec(); QLOG_DEBUG() << selectQuery.lastError() << "--"; //txtS << "TABLEMODEL: Tiempo de consulta: " << timer.elapsed() << "ms\r\n"; //timer.restart(); setupModelData(selectQuery); //txtS << "TABLEMODEL: Tiempo de creaci�n del modelo: " << timer.elapsed() << "ms\r\n"; //selectQuery.finish(); } db.close(); QSqlDatabase::removeDatabase(_databasePath); endResetModel(); emit searchNumResults(_data.length()); } QString ComicModel::getComicPath(QModelIndex mi) { if(mi.isValid()) return _data.at(mi.row())->data(ComicModel::Path).toString(); return ""; } void ComicModel::setupModelData(QSqlQuery &sqlquery) { int numColumns = sqlquery.record().count(); while (sqlquery.next()) { QList data; for(int i=0;idata(ComicModel::Number).isNull() && c2->data(ComicModel::Number).isNull()) { return naturalSortLessThanCI(c1->data(ComicModel::FileName).toString(), c2->data(ComicModel::FileName).toString()); } else { if (c1->data(ComicModel::Number).isNull() == false && c2->data(ComicModel::Number).isNull() == false) { return c1->data(ComicModel::Number).toInt() < c2->data(ComicModel::Number).toInt(); } else { return c2->data(ComicModel::Number).isNull(); } } }); } //comics are sorted by "ordering", the sorting is done in the sql query void ComicModel::setupModelDataForList(QSqlQuery &sqlquery) { int numColumns = sqlquery.record().count(); while (sqlquery.next()) { QList data; for(int i=0;idata(ComicModel::Id).toULongLong(),db); db.close(); QSqlDatabase::removeDatabase(_databasePath); return c; } ComicDB ComicModel::_getComic(const QModelIndex & mi) { QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); ComicDB c = DBHelper::loadComic(_data.at(mi.row())->data(ComicModel::Id).toULongLong(),db); db.close(); QSqlDatabase::removeDatabase(_databasePath); return c; } QVector ComicModel::getReadList() { int numComics = _data.count(); QVector readList(numComics); for(int i=0;idata(ComicModel::ReadColumn).toBool()) readList[i] = YACReader::Read; else if (_data.value(i)->data(ComicModel::CurrentPage).toInt() == _data.value(i)->data(ComicModel::NumPages).toInt()) readList[i] = YACReader::Read; else if (_data.value(i)->data(ComicModel::HasBeenOpened).toBool()) readList[i] = YACReader::Opened; else readList[i] = YACReader::Unread; } return readList; } //TODO untested, this method is no longer used QVector ComicModel::setAllComicsRead(YACReaderComicReadStatus read) { return setComicsRead(persistentIndexList(),read); } QList ComicModel::getAllComics() { QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); db.transaction(); QList comics; int numComics = _data.count(); for(int i=0;idata(ComicModel::Id).toULongLong(),db)); } db.commit(); db.close(); QSqlDatabase::removeDatabase(_databasePath); return comics; } QList ComicModel::getComics(QList list) { QList comics; QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); db.transaction(); QList::const_iterator itr; for(itr = list.constBegin(); itr!= list.constEnd();itr++) { comics.append(_getComic(*itr)); } db.commit(); db.close(); QSqlDatabase::removeDatabase(_databasePath); return comics; } //TODO QVector ComicModel::setComicsRead(QList list,YACReaderComicReadStatus read) { QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); db.transaction(); foreach (QModelIndex mi, list) { if(read == YACReader::Read) { _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(true)); ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(),db); c.info.read = true; DBHelper::update(&(c.info),db); } if(read == YACReader::Unread) { _data.value(mi.row())->setData(ComicModel::ReadColumn, QVariant(false)); _data.value(mi.row())->setData(ComicModel::CurrentPage, QVariant(1)); _data.value(mi.row())->setData(ComicModel::HasBeenOpened, QVariant(false)); ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(),db); c.info.read = false; c.info.currentPage = 1; c.info.hasBeenOpened = false; DBHelper::update(&(c.info),db); } } db.commit(); db.close(); QSqlDatabase::removeDatabase(_databasePath); emit dataChanged(index(list.first().row(),ComicModel::ReadColumn),index(list.last().row(),ComicModel::HasBeenOpened),QVector() << ReadColumnRole << CurrentPageRole << HasBeenOpenedRole); return getReadList(); } qint64 ComicModel::asignNumbers(QList list,int startingNumber) { QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); db.transaction(); qint64 idFirst = _data.value(list[0].row())->data(ComicModel::Id).toULongLong(); int i = 0; foreach (QModelIndex mi, list) { ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(),db); c.info.number = startingNumber+i; c.info.edited = true; DBHelper::update(&(c.info),db); i++; } db.commit(); db.close(); QSqlDatabase::removeDatabase(_databasePath); //emit dataChanged(index(0,ComicModel::Number),index(_data.count()-1,ComicModel::HasBeenOpened)); return idFirst; } QModelIndex ComicModel::getIndexFromId(quint64 id) { QList::ConstIterator itr; int i=0; for(itr = _data.constBegin();itr != _data.constEnd();itr++) { if((*itr)->data(ComicModel::Id).toULongLong() == id) break; i++; } return index(i,0); } //TODO completely inefficiently QList ComicModel::getIndexesFromIds(const QList &comicIds) { QList comicsIndexes; foreach(qulonglong id,comicIds) comicsIndexes << getIndexFromId(id); return comicsIndexes; } void ComicModel::startTransaction() { dbTransaction = DataBaseManagement::loadDatabase(_databasePath); dbTransaction.transaction(); } void ComicModel::finishTransaction() { dbTransaction.commit(); dbTransaction.close(); QSqlDatabase::removeDatabase(_databasePath); } void ComicModel::removeInTransaction(int row) { ComicDB c = DBHelper::loadComic(_data.at(row)->data(ComicModel::Id).toULongLong(),dbTransaction); DBHelper::removeFromDB(&c,dbTransaction); beginRemoveRows(QModelIndex(),row,row); removeRow(row); delete _data.at(row); _data.removeAt(row); endRemoveRows(); } void ComicModel::remove(ComicDB * comic, int row) { beginRemoveRows(QModelIndex(),row,row); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::removeFromDB(comic,db); removeRow(row); delete _data.at(row); _data.removeAt(row); db.close(); QSqlDatabase::removeDatabase(_databasePath); endRemoveRows(); } /*ComicDB TableModel::getComic(int row) { return getComic(index(row,0)); }*/ void ComicModel::remove(int row) { removeInTransaction(row); } void ComicModel::reload(const ComicDB & comic) { int row = 0; bool found = false; foreach(ComicItem * item,_data) { if(item->data(ComicModel::Id).toULongLong() == comic.id) { found = true; item->setData(ComicModel::ReadColumn,comic.info.read); item->setData(ComicModel::CurrentPage,comic.info.currentPage); item->setData(ComicModel::HasBeenOpened,true); break; } row++; } if(found) emit dataChanged(index(row,ReadColumn),index(row,HasBeenOpened), QVector() << ReadColumnRole << CurrentPageRole << HasBeenOpenedRole); } void ComicModel::resetComicRating(const QModelIndex &mi) { ComicDB comic = getComic(mi); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); comic.info.rating = 0; _data[mi.row()]->setData(ComicModel::Rating,0); DBHelper::update(&(comic.info),db); emit dataChanged(mi,mi); db.close(); QSqlDatabase::removeDatabase(_databasePath); } void ComicModel::addComicsToFavorites(const QList &comicIds) { addComicsToFavorites(getIndexesFromIds(comicIds)); } void ComicModel::addComicsToFavorites(const QList & comicsList) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::insertComicsInFavorites(comics,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); } void ComicModel::addComicsToLabel(const QList &comicIds, qulonglong labelId) { addComicsToLabel(getIndexesFromIds(comicIds),labelId); } void ComicModel::addComicsToLabel(const QList &comicsList, qulonglong labelId) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::insertComicsInLabel(comics,labelId,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); } void ComicModel::addComicsToReadingList(const QList &comicIds, qulonglong readingListId) { addComicsToReadingList(getIndexesFromIds(comicIds),readingListId); } void ComicModel::addComicsToReadingList(const QList &comicsList, qulonglong readingListId) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::insertComicsInReadingList(comics,readingListId,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); } void ComicModel::deleteComicsFromFavorites(const QList &comicsList) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::deleteComicsFromFavorites(comics,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); if(mode == Favorites) deleteComicsFromModel(comicsList); } void ComicModel::deleteComicsFromLabel(const QList &comicsList, qulonglong labelId) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::deleteComicsFromLabel(comics,labelId,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); deleteComicsFromModel(comicsList); } void ComicModel::deleteComicsFromReadingList(const QList &comicsList, qulonglong readingListId) { QList comics = getComics(comicsList); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); DBHelper::deleteComicsFromReadingList(comics,readingListId,db); db.close(); QSqlDatabase::removeDatabase(_databasePath); deleteComicsFromModel(comicsList); } void ComicModel::deleteComicsFromModel(const QList &comicsList) { QListIterator it(comicsList); it.toBack(); while(it.hasPrevious()) { int row = it.previous().row(); beginRemoveRows(QModelIndex(),row,row); _data.removeAt(row); endRemoveRows(); } if(_data.isEmpty()) emit isEmpty(); } bool ComicModel::isFavorite(const QModelIndex &index) { bool isFavorite; QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); isFavorite = DBHelper::isFavoriteComic(_data[index.row()]->data(Id).toLongLong(),db); db.close(); QSqlDatabase::removeDatabase(_databasePath); return isFavorite; } void ComicModel::updateRating(int rating, QModelIndex mi) { ComicDB comic = getComic(mi); QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); //TODO optimize update comic.info.rating = rating; _data[mi.row()]->setData(ComicModel::Rating,rating); DBHelper::update(&(comic.info),db); emit dataChanged(mi,mi); db.close(); QSqlDatabase::removeDatabase(_databasePath); }