Add new fields to the DB and make then available to be used in the apps

This commit is contained in:
Luis Ángel San Martín
2023-05-12 16:59:23 +02:00
parent 830d8d911f
commit f2bf53ce5b
23 changed files with 957 additions and 591 deletions

View File

@ -239,6 +239,7 @@ QHash<int, QByteArray> ComicModel::roleNames() const
roles[CoverPathRole] = "cover_path";
roles[PublicationDate] = "date";
roles[ReadableTitle] = "readable_title";
roles[Added] = "added_date";
return roles;
}
@ -301,6 +302,10 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const
return item->data(Id);
else if (role == PublicationDateRole)
return QVariant(localizedDate(item->data(PublicationDate).toString()));
else if (role == AddedRole)
return item->data(Added);
else if (role == TypeRole)
return item->data(Type);
if (role != Qt::DisplayRole)
return QVariant();
@ -443,6 +448,8 @@ QStringList ComicModel::getPaths(const QString &_source)
return paths;
}
#define COMIC_MODEL_QUERY_FIELDS "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,ci.date,ci.added,ci.type"
void ComicModel::setupFolderModelData(unsigned long long int folderId, const QString &databasePath)
{
enableResorting = false;
@ -458,7 +465,7 @@ void ComicModel::setupFolderModelData(unsigned long long int folderId, const QSt
{
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,ci.date "
selectQuery.prepare("SELECT " COMIC_MODEL_QUERY_FIELDS " "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"WHERE c.parentId = :parentId");
selectQuery.bindValue(":parentId", folderId);
@ -485,7 +492,7 @@ void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QStri
{
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,ci.date "
selectQuery.prepare("SELECT " COMIC_MODEL_QUERY_FIELDS " "
"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 "
@ -529,7 +536,7 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList,
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,ci.date "
selectQuery.prepare("SELECT " COMIC_MODEL_QUERY_FIELDS " "
"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 "
@ -566,7 +573,7 @@ void ComicModel::setupFavoritesModelData(const QString &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,ci.date "
selectQuery.prepare("SELECT " COMIC_MODEL_QUERY_FIELDS " "
"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 "
@ -595,7 +602,7 @@ void ComicModel::setupReadingModelData(const QString &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,ci.date "
selectQuery.prepare("SELECT " COMIC_MODEL_QUERY_FIELDS " "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"WHERE ci.hasBeenOpened = 1 AND ci.read = 0 "
"ORDER BY ci.lastTimeOpened DESC");
@ -652,7 +659,7 @@ void ComicModel::setupModelData(QSqlQuery &sqlquery)
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();
return naturalSortLessThanCI(c1->data(ComicModel::Number).toString(), c2->data(ComicModel::Number).toString());
} else {
return c2->data(ComicModel::Number).isNull();
}
@ -794,7 +801,7 @@ QVector<YACReaderComicReadStatus> ComicModel::setComicsRead(QList<QModelIndex> l
return getReadList();
}
void ComicModel::setComicsManga(QList<QModelIndex> list, bool isManga)
void ComicModel::setComicsType(QList<QModelIndex> list, FileType type)
{
QString connectionName = "";
{
@ -803,7 +810,7 @@ void ComicModel::setComicsManga(QList<QModelIndex> list, bool isManga)
foreach (QModelIndex mi, list) {
bool found;
ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ComicModel::Id).toULongLong(), db, found);
c.info.manga = isManga;
c.info.type = QVariant::fromValue(type);
DBHelper::update(&(c.info), db);
}
db.commit();

View File

@ -31,11 +31,13 @@ public:
Path = 6,
Hash = 7,
ReadColumn = 8,
IsBis = 9,
IsBis = 9, // TODO_METADATA: Remove this column
CurrentPage = 10,
Rating = 11,
HasBeenOpened = 12,
PublicationDate = 13,
Added = 14,
Type = 15,
};
enum Roles {
@ -55,6 +57,8 @@ public:
CoverPathRole,
PublicationDateRole,
ReadableTitle,
AddedRole,
TypeRole,
};
enum Mode {
@ -107,7 +111,7 @@ public:
// setComicInfoForAllComics(); --> inserta la información común a todos los cómics de una sola vez.
// setComicInfoForSelectedComis(QList<QModelIndex> list); -->inserta la información común para los comics seleccionados
QVector<YACReaderComicReadStatus> setComicsRead(QList<QModelIndex> list, YACReaderComicReadStatus read);
void setComicsManga(QList<QModelIndex> list, bool isManga);
void setComicsType(QList<QModelIndex> list, FileType type);
qint64 asignNumbers(QList<QModelIndex> list, int startingNumber);
// void remove(ComicDB * comic, int row);
void removeInTransaction(int row);

View File

@ -64,23 +64,29 @@ static QString fields = "title,"
//"coverSizeRatio," cover may have changed since the info was exported...
//"originalCoverSize," // h/w
// new 9.8 fields
"manga";
"manga,"
// new 9.13 fields
"added,"
"type,"
"editor,"
"imprint,"
"teams,"
"locations,"
"series,"
"alternateSeries,"
"alternateNumber,"
"alternateCount,"
"languageISO,"
"seriesGroup,"
"mainCharacterOrTeam,"
"review,"
"tags";
DataBaseManagement::DataBaseManagement()
: QObject(), dataBasesList()
{
}
/*TreeModel * DataBaseManagement::newTreeModel(QString path)
{
//la consulta se ejecuta...
QSqlQuery selectQuery(loadDatabase(path));
selectQuery.setForwardOnly(true);
selectQuery.exec("select * from folder order by parentId,name");
//selectQuery.finish();
return new TreeModel(selectQuery);
}*/
QSqlDatabase DataBaseManagement::createDatabase(QString name, QString path)
{
return createDatabase(QDir::cleanPath(path) + "/" + name + ".ydb");
@ -106,8 +112,6 @@ QSqlDatabase DataBaseManagement::createDatabase(QString dest)
"VALUES (1,'root', '/')",
db);
}
// query.finish();
// db.close();
return db;
}
@ -156,13 +160,13 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
"coverPage INTEGER DEFAULT 1,"
"numPages INTEGER,"
"number INTEGER,"
"number TEXT," // changed to text from INTEGER (9.13)
"isBis BOOLEAN,"
"count INTEGER,"
"volume TEXT,"
"storyArc TEXT,"
"arcNumber INTEGER,"
"arcNumber TEXT," // changed to text from INTEGER (9.13)
"arcCount INTEGER,"
"genere TEXT,"
@ -174,7 +178,7 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
"letterer TEXT,"
"coverArtist TEXT,"
"date TEXT," // dd/mm/yyyy --> se mostrará en 3 campos diferentes
"date TEXT," // publication date dd/mm/yyyy --> se mostrará en 3 campos diferentes
"publisher TEXT,"
"format TEXT,"
"color BOOLEAN,"
@ -190,7 +194,7 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
// new 7.0 fields
"hasBeenOpened BOOLEAN DEFAULT 0,"
"rating INTEGER DEFAULT 0,"
"rating INTEGER DEFAULT 0," // TODO_METADATA change type to REAL with two decimals
"currentPage INTEGER DEFAULT 1, "
"bookmark1 INTEGER DEFAULT -1, "
"bookmark2 INTEGER DEFAULT -1, "
@ -205,8 +209,23 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
"coverSizeRatio REAL,"
"originalCoverSize STRING," // h/w
// new 9.8 fields
"manga BOOLEAN DEFAULT 0"
"manga BOOLEAN DEFAULT 0," // deprecated 9.13
// new 9.13 fields
"added INTEGER,"
"type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma
"editor TEXT,"
"imprint TEXT,"
"teams TEXT,"
"locations TEXT,"
"series TEXT,"
"alternateSeries TEXT,"
"alternateNumber TEXT,"
"alternateCount INTEGER,"
"languageISO TEXT,"
"seriesGroup TEXT,"
"mainCharacterOrTeam TEXT,"
"review TEXT,"
"tags TEXT"
")");
success = success && queryComicInfo.exec();
// queryComicInfo.finish();
@ -226,7 +245,11 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
"firstChildHash TEXT,"
"customImage TEXT,"
// new 9.8 fields
"manga BOOLEAN DEFAULT 0,"
"manga BOOLEAN DEFAULT 0," // deprecated 9.13
// new 9.13 fields
"type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma
"added INTEGER,"
"updated INTEGER," // updated when the folder gets new content
"FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE)");
success = success && queryFolder.exec();
@ -460,7 +483,25 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
//--
// new 9.8 fields
"manga = :manga"
"manga = :manga,"
// new 9.13 fields
"added = :added,"
"type = :type," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic,
"editor = :editor,"
"imprint = :imprint,"
"teams = :teams,"
"locations = :locations,"
"series = :series,"
"alternateSeries = :alternateSeries,"
"alternateNumber = :alternateNumber,"
"alternateCount = :alternateCount,"
"languageISO = :languageISO,"
"seriesGroup = :seriesGroup,"
"mainCharacterOrTeam = :mainCharacterOrTeam,"
"review = :review,"
"tags = :tags"
//--
" WHERE hash = :hash ");
@ -496,6 +537,21 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
"comicVineID,"
"lastTimeOpened,"
"coverSizeRatio,"
"manga,"
"added,"
"type,"
"editor,"
"imprint,"
"teams,"
"locations,"
"series,"
"alternateSeries,"
"alternateNumber,"
"alternateCount,"
"languageISO,"
"seriesGroup,"
"mainCharacterOrTeam,"
"review,"
"hash)"
"VALUES (:title,"
@ -539,6 +595,23 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
":coverSizeRatio,"
":originalCoverSize,"
":manga,"
":added,"
":type,"
":editor,"
":imprint,"
":teams,"
":locations,"
":series,"
":alternateSeries,"
":alternateNumber,"
":alternateCount,"
":languageISO,"
":seriesGroup,"
":mainCharacterOrTeam,"
":review,"
":tags,"
":hash )");
QSqlRecord record = newInfo.record();
@ -596,6 +669,8 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
return b;
}
// TODO: update fields
// TODO fix these bindings
void DataBaseManagement::bindValuesFromRecord(const QSqlRecord &record, QSqlQuery &query)
{
@ -654,6 +729,22 @@ void DataBaseManagement::bindValuesFromRecord(const QSqlRecord &record, QSqlQuer
bindValue("coverSizeRatio", record, query);
bindValue("originalCoverSize", record, query);
bindValue("added", record, query);
bindValue("type", record, query);
bindValue("editor", record, query);
bindValue("imprint", record, query);
bindValue("teams", record, query);
bindValue("locations", record, query);
bindValue("series", record, query);
bindValue("alternateSeries", record, query);
bindValue("alternateNumber", record, query);
bindValue("alternateCount", record, query);
bindValue("languageISO", record, query);
bindValue("seriesGroup", record, query);
bindValue("mainCharacterOrTeam", record, query);
bindValue("review", record, query);
bindValue("tags", record, query);
bindValue("hash", record, query);
}
@ -757,6 +848,7 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
bool pre8 = false;
bool pre9_5 = false;
bool pre9_8 = false;
bool pre9_13 = false;
QString fullPath = path + "/library.ydb";
@ -770,6 +862,8 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
pre9_5 = true;
if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.8.0") < 0)
pre9_8 = true;
if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.13.0") < 0)
pre9_13 = true;
QString connectionName = "";
bool returnValue = false;
@ -895,6 +989,53 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
returnValue = returnValue && successAddingColumns;
}
}
if (pre9_13) {
{ // comic_info
QStringList columnDefs;
columnDefs << "added INTEGER";
columnDefs << "type INTEGER DEFAULT 0"; // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic,
columnDefs << "editor TEXT";
columnDefs << "imprint TEXT";
columnDefs << "teams TEXT";
columnDefs << "locations TEXT";
columnDefs << "series TEXT";
columnDefs << "alternateSeries TEXT";
columnDefs << "alternateNumber TEXT";
columnDefs << "alternateCount INTEGER";
columnDefs << "languageISO TEXT";
columnDefs << "seriesGroup TEXT";
columnDefs << "mainCharacterOrTeam TEXT";
columnDefs << "review TEXT";
columnDefs << "tags TEXT";
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
returnValue = returnValue && successAddingColumns;
QSqlQuery updateTypeQueryToManga(db);
updateTypeQueryToManga.prepare("UPDATE comic_info SET type = manga");
bool successMigratingManga = updateTypeQueryToManga.exec();
returnValue = returnValue && successMigratingManga;
QSqlQuery updateNumberQueryToBis(db);
updateNumberQueryToBis.prepare("UPDATE comic_info SET number = number + 0.5 WHERE isBis = 1");
bool successMigratingBis = updateNumberQueryToBis.exec();
returnValue = returnValue && successMigratingBis;
}
{ // folder
QStringList columnDefs;
columnDefs << "added INTEGER";
columnDefs << "updated INTEGER";
columnDefs << "type INTEGER DEFAULT 0";
bool successAddingColumns = addColumns("folder", columnDefs, db);
returnValue = returnValue && successAddingColumns;
QSqlQuery updateTypeQueryToManga(db);
updateTypeQueryToManga.prepare("UPDATE folder SET type = manga");
bool successMigratingManga = updateTypeQueryToManga.exec();
returnValue = returnValue && successMigratingManga;
}
}
}
connectionName = db.connectionName();
}

View File

@ -42,7 +42,6 @@ private:
public:
DataBaseManagement();
// TreeModel * newTreeModel(QString path);
// crea una base de datos y todas sus tablas
static QSqlDatabase createDatabase(QString name, QString path);
static QSqlDatabase createDatabase(QString dest);

View File

@ -6,8 +6,6 @@
#include "db_helper.h"
#include "qnaturalsorting.h"
#include "yacreader_global_gui.h"
#include "QsLog.h"
#include "query_parser.h"
#include <QtGui>
@ -61,14 +59,12 @@ FolderModel::FolderModel(QObject *parent)
FolderModel::FolderModel(QSqlQuery &sqlquery, QObject *parent)
: QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr)
{
// lo m<>s probable es que el nodo ra<72>z no necesite tener informaci<63>n
QList<QVariant> rootData;
rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
rootData << "root"; // id 1, parent 1, title "root"
rootItem = new FolderItem(rootData);
rootItem->id = ROOT;
rootItem->parentItem = nullptr;
setupModelData(sqlquery, rootItem);
// sqlquery.finish();
}
FolderModel::~FolderModel()
@ -98,7 +94,11 @@ QHash<int, QByteArray> FolderModel::roleNames() const
roles[IdRole] = "id";
roles[MangaRole] = "is_manga";
roles[CoverPathRole] = "cover_path";
roles[FolderName] = "name";
roles[FolderNameRole] = "name";
roles[NumChildrenRole] = "num_children";
roles[TypeRole] = "type";
roles[AddedRole] = "added";
roles[UpdatedRole] = "type";
return roles;
}
@ -150,7 +150,7 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
#endif
}
if (role == FolderModel::FolderName) {
if (role == FolderModel::FolderNameRole) {
return item->data(FolderModel::Name);
}
@ -169,6 +169,18 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
if (role == FolderModel::CoverPathRole)
return getCoverUrlPathForComicHash(item->data(FirstChildHash).toString());
if (role == FolderModel::NumChildrenRole)
return item->data(NumChildren);
if (role == FolderModel::TypeRole)
return item->data(Type);
if (role == FolderModel::AddedRole)
return item->data(Added);
if (role == FolderModel::UpdatedRole)
return item->data(Updated);
if (role != Qt::DisplayRole)
return QVariant();
@ -323,65 +335,39 @@ void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
int manga = record.indexOf("manga");
int id = record.indexOf("id");
int parentId = record.indexOf("parentId");
int numChildren = record.indexOf("numChildren");
int firstChildHash = record.indexOf("firstChildHash");
int customImage = record.indexOf("customImage");
int type = record.indexOf("type");
int added = record.indexOf("added");
int updated = record.indexOf("updated");
while (sqlquery.next()) {
QList<QVariant> data;
data << sqlquery.value(name).toString();
data << sqlquery.value(path).toString();
data << sqlquery.value(finished).toBool();
data << sqlquery.value(completed).toBool();
data << sqlquery.value(manga).toBool();
data << sqlquery.value(firstChildHash).toString();
data << sqlquery.value(name);
data << sqlquery.value(path);
data << sqlquery.value(finished);
data << sqlquery.value(completed);
data << sqlquery.value(manga);
data << sqlquery.value(numChildren);
data << sqlquery.value(firstChildHash);
data << sqlquery.value(customImage);
data << sqlquery.value(type);
data << sqlquery.value(added);
data << sqlquery.value(updated);
auto item = new FolderItem(data);
item->id = sqlquery.value(id).toULongLong();
// la inserci<63>n de hijos se hace de forma ordenada
FolderItem *parent = items.value(sqlquery.value(parentId).toULongLong());
// if(parent !=0) //TODO if parent==0 the parent of item was removed from the DB and delete on cascade didn't work, ERROR.
parent->appendChild(item);
// se a<>ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
items.insert(item->id, item);
}
}
void FolderModel::updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent)
{
Q_UNUSED(parent);
QSqlRecord record = sqlquery.record();
int name = record.indexOf("name");
int path = record.indexOf("path");
int finished = record.indexOf("finished");
int completed = record.indexOf("completed");
int manga = record.indexOf("manga");
int id = record.indexOf("id");
int parentId = record.indexOf("parentId");
int firstChildHash = record.indexOf("firstChildHash");
while (sqlquery.next()) {
QList<QVariant> data;
data << sqlquery.value(name).toString();
data << sqlquery.value(path).toString();
data << sqlquery.value(finished).toBool();
data << sqlquery.value(completed).toBool();
data << sqlquery.value(manga).toBool();
data << sqlquery.value(firstChildHash).toString();
auto item = new FolderItem(data);
item->id = sqlquery.value(id).toULongLong();
// la inserci<63>n de hijos se hace de forma ordenada
FolderItem *parent = items.value(sqlquery.value(parentId).toULongLong());
if (parent != 0) // TODO if parent==0 the parent of item was removed from the DB and delete on cascade didn't work, ERROR.
parent->appendChild(item);
// se a<>ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
items.insert(item->id, item);
}
}
QString FolderModel::getDatabase()
{
return _databasePath;
@ -406,7 +392,7 @@ void FolderModel::updateFolderCompletedStatus(const QModelIndexList &list, bool
if (!isSubfolder) {
Folder f = DBHelper::loadFolder(item->id, db);
f.setCompleted(status);
f.completed = status;
DBHelper::update(f, db);
}
}
@ -430,7 +416,7 @@ void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool s
if (!isSubfolder) {
Folder f = DBHelper::loadFolder(item->id, db);
f.setFinished(status);
f.finished = status;
DBHelper::update(f, db);
}
}
@ -439,10 +425,10 @@ void FolderModel::updateFolderFinishedStatus(const QModelIndexList &list, bool s
}
QSqlDatabase::removeDatabase(connectionName);
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::FirstChildHash));
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Updated));
}
void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
void FolderModel::updateFolderType(const QModelIndexList &list, YACReader::FileType type)
{
QString connectionName = "";
{
@ -451,19 +437,19 @@ void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
foreach (QModelIndex mi, list) {
auto item = static_cast<FolderItem *>(mi.internalPointer());
std::function<void(FolderItem *, bool)> setManga;
setManga = [&setManga](FolderItem *item, bool manga) -> void {
item->setData(FolderModel::Manga, manga);
std::function<void(FolderItem *, YACReader::FileType)> setType;
setType = [&setType](FolderItem *item, YACReader::FileType type) -> void {
item->setData(FolderModel::Type, QVariant::fromValue(type));
for (auto child : item->children()) {
setManga(child, manga);
setType(child, type);
}
};
setManga(item, manga);
setType(item, type);
if (!isSubfolder) {
DBHelper::updateFolderTreeManga(item->id, db, manga);
DBHelper::updateFolderTreeType(item->id, db, type);
}
}
db.commit();
@ -471,7 +457,7 @@ void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga)
}
QSqlDatabase::removeDatabase(connectionName);
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::FirstChildHash));
emit dataChanged(index(list.first().row(), FolderModel::Name), index(list.last().row(), FolderModel::Updated));
}
QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi)
@ -552,7 +538,13 @@ Folder FolderModel::getFolder(const QModelIndex &mi)
folderItem->parent()->data(Columns::Path).toString() + "/" + name,
folderItem->data(Columns::Completed).toBool(),
folderItem->data(Columns::Finished).toBool(),
folderItem->data(Columns::Manga).toBool());
folderItem->data(Columns::Manga).toBool(),
folderItem->data(Columns::NumChildren).toInt(),
folderItem->data(Columns::FirstChildHash).toString(),
folderItem->data(Columns::CustomImage).toString(),
folderItem->data(Columns::Type).value<YACReader::FileType>(),
folderItem->data(Columns::Added).toLongLong(),
folderItem->data(Columns::Updated).toLongLong());
return folder;
}
@ -589,74 +581,6 @@ QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIn
return QModelIndex();
}
void FolderModel::fetchMoreFromDB(const QModelIndex &parent)
{
FolderItem *item;
if (parent.isValid())
item = static_cast<FolderItem *>(parent.internalPointer());
else
item = rootItem;
// Remove all children
if (item->childCount() > 0) {
beginRemoveRows(parent, 0, item->childCount() - 1);
item->clearChildren();
endRemoveRows();
}
QString connectionName = "";
{
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
QList<FolderItem *> items;
QList<FolderItem *> nextLevelItems;
QSqlQuery selectQuery(db);
selectQuery.prepare("select * from folder where id <> 1 and parentId = :parentId order by parentId,name");
items << item;
bool firstLevelUpdated = false;
while (items.size() > 0) {
nextLevelItems.clear();
foreach (FolderItem *item, items) {
QLOG_DEBUG() << "ID " << item->id;
selectQuery.bindValue(":parentId", item->id);
selectQuery.exec();
if (!firstLevelUpdated) {
// NO size support
int numResults = 0;
while (selectQuery.next())
numResults++;
if (!selectQuery.seek(-1))
selectQuery.exec();
// END no size support
beginInsertRows(parent, 0, numResults - 1);
}
updateFolderModelData(selectQuery, item);
if (!firstLevelUpdated) {
endInsertRows();
firstLevelUpdated = true;
}
nextLevelItems << item->children();
}
items.clear();
items = nextLevelItems;
}
connectionName = db.connectionName();
}
QLOG_DEBUG() << "item->childCount()-1" << item->childCount() - 1;
QSqlDatabase::removeDatabase(connectionName);
}
QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QModelIndex &parent)
{
FolderItem *parentItem;
@ -670,7 +594,9 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod
newFolder.name = folderName;
newFolder.parentId = parentItem->id;
newFolder.path = parentItem->data(Columns::Path).toString() + "/" + folderName;
newFolder.setManga(parentItem->data(Columns::Manga).toBool());
newFolder.manga = parentItem->data(Columns::Manga).toBool();
newFolder.type = parentItem->data(Columns::Type).value<YACReader::FileType>();
QString connectionName = "";
{
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
@ -687,7 +613,13 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod
data << newFolder.path;
data << false; // finished
data << true; // completed
data << newFolder.isManga();
data << newFolder.manga;
data << 0; // numChildren
data << QVariant(); // first child hash, new folder is empty
data << QVariant(); // custom cover
data << QVariant::fromValue(newFolder.type);
data << newFolder.added;
data << newFolder.updated;
auto item = new FolderItem(data);
item->id = newFolder.id;

View File

@ -66,13 +66,10 @@ public:
void setupModelData(QString path);
QString getDatabase();
QString getFolderPath(const QModelIndex &folder);
// QModelIndex indexFromItem(FolderItem * item, int column);
// bool isFilterEnabled(){return filterEnabled;};
void updateFolderCompletedStatus(const QModelIndexList &list, bool status);
void updateFolderFinishedStatus(const QModelIndexList &list, bool status);
void updateFolderManga(const QModelIndexList &list, bool manga);
void updateFolderType(const QModelIndexList &list, YACReader::FileType type);
QStringList getSubfoldersNames(const QModelIndex &mi);
FolderModel *getSubfoldersModel(const QModelIndex &mi);
@ -80,28 +77,35 @@ public:
Folder getFolder(const QModelIndex &mi);
QModelIndex getIndexFromFolder(const Folder &folder, const QModelIndex &parent = QModelIndex());
void fetchMoreFromDB(const QModelIndex &parent);
QModelIndex addFolderAtParent(const QString &folderName, const QModelIndex &parent);
Q_INVOKABLE QUrl getCoverUrlPathForComicHash(const QString &hash) const;
enum Columns {
Name = 0,
Path = 1,
Finished = 2,
Completed = 3,
Manga = 4,
FirstChildHash = 5
}; // id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, name TEXT NOT NULL, path TEXT NOT NULL
Path,
Finished,
Completed,
Manga, // deprecated
NumChildren,
FirstChildHash,
CustomImage,
Type, // FileType
Added,
Updated,
};
enum Roles {
FinishedRole = Qt::UserRole + 1,
CompletedRole,
IdRole,
MangaRole,
MangaRole, // deprecated
CoverPathRole,
FolderName,
FolderNameRole,
NumChildrenRole,
TypeRole,
AddedRole,
UpdatedRole,
};
bool isSubfolder;
@ -112,9 +116,7 @@ public slots:
private:
void fullSetup(QSqlQuery &sqlquery, FolderItem *parent);
void setupModelData(QSqlQuery &sqlquery, FolderItem *parent);
void updateFolderModelData(QSqlQuery &sqlquery, FolderItem *parent);
FolderItem *rootItem; // el árbol
QMap<unsigned long long int, FolderItem *> items; // relación entre folders

View File

@ -5,14 +5,17 @@
#include <numeric>
#include <stdexcept>
#include <QsLog.h>
const std::map<QueryParser::FieldType, std::vector<std::string>> QueryParser::fieldNames {
{ FieldType::numeric, { "numpages", "number", "count", "arcnumber", "arccount" } },
{ FieldType::text, { "title", "volume", "storyarc", "genere", "writer", "penciller", "inker", "colorist", "letterer", "coverartist", "publisher", "format", "agerating", "synopsis", "characters", "notes" } },
{ FieldType::boolean, { "isbis", "color", "read", "manga" } },
{ FieldType::date, { "date" } },
{ FieldType::numeric, { "numpages", "count", "arccount", "alternateCount" } },
{ FieldType::text, { "number", "arcnumber", "title", "volume", "storyarc", "genere", "writer", "penciller", "inker", "colorist", "letterer", "coverartist", "publisher", "format", "agerating", "synopsis", "characters", "notes", "editor", "imprint", "teams", "locations", "series", "alternateSeries", "alternateNumber", "languageISO", "seriesGroup", "mainCharacterOrTeam", "review", "tags" } },
{ FieldType::boolean, { "isbis", "color", "read" } },
{ FieldType::date, { "date", "added", "lastTimeOpened" } },
{ FieldType::filename, { "filename" } },
{ FieldType::folder, { "folder" } },
{ FieldType::booleanFolder, { "completed", "finished" } },
{ FieldType::booleanFolder, { "completed", "finished" } }, // TODO_METADTA include new folder fields, e.g. type
{ FieldType::enumField, { "type" } }
};
int QueryParser::TreeNode::buildSqlString(std::string &sqlString, int bindPosition) const
@ -26,7 +29,7 @@ int QueryParser::TreeNode::buildSqlString(std::string &sqlString, int bindPositi
}
sqlString += "UPPER(c.filename) LIKE UPPER(:bindPosition" + std::to_string(bindPosition) + ") OR ";
sqlString += "UPPER(f.name) LIKE UPPER(:bindPosition" + std::to_string(bindPosition) + ")) ";
} else if (isIn(fieldType(children[0].t), { FieldType::numeric, FieldType::boolean })) {
} else if (isIn(fieldType(children[0].t), { FieldType::numeric, FieldType::boolean, FieldType::enumField })) {
sqlString += "ci." + children[0].t + " = :bindPosition" + std::to_string(bindPosition) + " ";
} else if (fieldType(children[0].t) == FieldType::filename) {
sqlString += "(UPPER(c." + children[0].t + ") LIKE UPPER(:bindPosition" + std::to_string(bindPosition) + ")) ";
@ -67,6 +70,24 @@ int QueryParser::TreeNode::bindValues(QSqlQuery &selectQuery, int bindPosition)
} else {
selectQuery.bindValue(QString::fromStdString(bind_string), std::stoi(value));
}
} else if ((isIn(fieldType(children[0].t), { FieldType::enumField }))) {
auto enumType = children[0].t;
auto value = toLower(children[1].t);
if (enumType == "type") {
if (value == "comic") {
selectQuery.bindValue(QString::fromStdString(bind_string), 0);
} else if (value == "manga") {
selectQuery.bindValue(QString::fromStdString(bind_string), 1);
} else if (value == "westernmanga") {
selectQuery.bindValue(QString::fromStdString(bind_string), 2);
} else if (value == "webcomic" || value == "web") {
selectQuery.bindValue(QString::fromStdString(bind_string), 3);
} else if (value == "4koma" || value == "yonkoma") {
selectQuery.bindValue(QString::fromStdString(bind_string), 4);
}
} else {
selectQuery.bindValue(QString::fromStdString(bind_string), std::stoi(children[1].t));
}
} else {
selectQuery.bindValue(QString::fromStdString(bind_string), QString::fromStdString("%%" + children[1].t + "%%"));
}
@ -232,6 +253,7 @@ QueryParser::TreeNode QueryParser::baseToken()
return TreeNode("token", { TreeNode("all", {}), TreeNode(token(true), {}) });
}
// TODO ":" should come from the lexer as a token
auto words(split(token(true), ':'));
if (words.size() > 1 && fieldType(words[0].toStdString()) != FieldType::unknown) {

View File

@ -85,7 +85,8 @@ private:
date,
folder,
booleanFolder,
filename };
filename,
enumField };
static FieldType fieldType(const std::string &str);
static std::string join(const QStringList &strings, const std::string &delim);