mirror of
https://github.com/YACReader/yacreader
synced 2025-07-14 02:54:46 -04:00
Add new fields to the DB and make then available to be used in the apps
This commit is contained in:
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user