merged develop

This commit is contained in:
Luis Ángel San Martín 2016-04-19 23:19:39 +02:00
commit 581592909d
30 changed files with 638 additions and 125 deletions

View File

@ -5,8 +5,8 @@
#include "QsLog.h"
ComicsRemover::ComicsRemover(QModelIndexList & il, QList<QString> & ps, QObject *parent)
:QObject(parent),indexList(il), paths(ps)
ComicsRemover::ComicsRemover(QModelIndexList & il, QList<QString> & ps, qulonglong parentId, QObject *parent)
:QObject(parent),indexList(il), paths(ps), parentId(parentId)
{
}
@ -29,6 +29,7 @@ void ComicsRemover::process()
}
emit finished();
emit removedItemsFromFolder(parentId);
}

View File

@ -10,12 +10,13 @@ class ComicsRemover : public QObject
{
Q_OBJECT
public:
explicit ComicsRemover(QModelIndexList & indexList, QList<QString> & paths, QObject *parent = 0);
explicit ComicsRemover(QModelIndexList & indexList, QList<QString> & paths, qulonglong parentId, QObject *parent = 0);
signals:
void remove(int);
void removeError();
void finished();
void removedItemsFromFolder(qulonglong);
public slots:
void process();
@ -23,6 +24,7 @@ public slots:
private:
QModelIndexList indexList;
QList<QString> paths;
qulonglong parentId;
};
class FoldersRemover : public QObject

View File

@ -981,7 +981,7 @@ void ComicModel::removeInTransaction(int row)
endRemoveRows();
}
/*
void ComicModel::remove(ComicDB * comic, int row)
{
beginRemoveRows(QModelIndex(),row,row);
@ -997,7 +997,7 @@ void ComicModel::remove(ComicDB * comic, int row)
QSqlDatabase::removeDatabase(_databasePath);
endRemoveRows();
}
*/
/*ComicDB TableModel::getComic(int row)
{
return getComic(index(row,0));

View File

@ -65,7 +65,7 @@ public:
//setComicInfoForSelectedComis(QList<QModelIndex> list); -->inserta la información común para los comics seleccionados
QVector<YACReaderComicReadStatus> setComicsRead(QList<QModelIndex> list,YACReaderComicReadStatus read);
qint64 asignNumbers(QList<QModelIndex> list,int startingNumber);
void remove(ComicDB * comic, int row);
//void remove(ComicDB * comic, int row);
void removeInTransaction(int row);
void reload(const ComicDB & comic);
void resetComicRating(const QModelIndex & mi);

View File

@ -124,99 +124,101 @@ QSqlDatabase DataBaseManagement::loadDatabaseFromFile(QString filePath)
bool DataBaseManagement::createTables(QSqlDatabase & database)
{
bool success = true;
bool success = true;
//FOLDER (representa una carpeta en disco)
{
QSqlQuery queryFolder(database);
queryFolder.prepare("CREATE TABLE folder ("
"id INTEGER PRIMARY KEY,"
"parentId INTEGER NOT NULL,"
"name TEXT NOT NULL,"
"path TEXT NOT NULL,"
//new 7.1 fields
"finished BOOLEAN DEFAULT 0," //reading
"completed BOOLEAN DEFAULT 1," //collecting
//--
"FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE)");
success = success && queryFolder.exec();
{
//COMIC INFO (representa la información de un cómic, cada cómic tendrá un idéntificador único formado por un hash sha1'de los primeros 512kb' + su tamaño en bytes)
QSqlQuery queryComicInfo(database);
queryComicInfo.prepare("CREATE TABLE comic_info ("
"id INTEGER PRIMARY KEY,"
"title TEXT,"
//COMIC INFO (representa la información de un cómic, cada cómic tendrá un idéntificador único formado por un hash sha1'de los primeros 512kb' + su tamaño en bytes)
QSqlQuery queryComicInfo(database);
queryComicInfo.prepare("CREATE TABLE comic_info ("
"id INTEGER PRIMARY KEY,"
"title TEXT,"
"coverPage INTEGER DEFAULT 1,"
"numPages INTEGER,"
"coverPage INTEGER DEFAULT 1,"
"numPages INTEGER,"
"number INTEGER,"
"isBis BOOLEAN,"
"count INTEGER,"
"number INTEGER,"
"isBis BOOLEAN,"
"count INTEGER,"
"volume TEXT,"
"storyArc TEXT,"
"arcNumber INTEGER,"
"arcCount INTEGER,"
"volume TEXT,"
"storyArc TEXT,"
"arcNumber INTEGER,"
"arcCount INTEGER,"
"genere TEXT,"
"genere TEXT,"
"writer TEXT,"
"penciller TEXT,"
"inker TEXT,"
"colorist TEXT,"
"letterer TEXT,"
"coverArtist TEXT,"
"writer TEXT,"
"penciller TEXT,"
"inker TEXT,"
"colorist TEXT,"
"letterer TEXT,"
"coverArtist TEXT,"
"date TEXT," //dd/mm/yyyy --> se mostrará en 3 campos diferentes
"publisher TEXT,"
"format TEXT,"
"color BOOLEAN,"
"ageRating BOOLEAN,"
"date TEXT," //dd/mm/yyyy --> se mostrará en 3 campos diferentes
"publisher TEXT,"
"format TEXT,"
"color BOOLEAN,"
"ageRating BOOLEAN,"
"synopsis TEXT,"
"characters TEXT,"
"notes TEXT,"
"synopsis TEXT,"
"characters TEXT,"
"notes TEXT,"
"hash TEXT UNIQUE NOT NULL,"
"edited BOOLEAN DEFAULT 0,"
"read BOOLEAN DEFAULT 0,"
//new 7.0 fields
"hash TEXT UNIQUE NOT NULL,"
"edited BOOLEAN DEFAULT 0,"
"read BOOLEAN DEFAULT 0,"
//new 7.0 fields
"hasBeenOpened BOOLEAN DEFAULT 0,"
"rating INTEGER DEFAULT 0,"
"currentPage INTEGER DEFAULT 1, "
"bookmark1 INTEGER DEFAULT -1, "
"bookmark2 INTEGER DEFAULT -1, "
"bookmark3 INTEGER DEFAULT -1, "
"brightness INTEGER DEFAULT -1, "
"contrast INTEGER DEFAULT -1, "
"gamma INTEGER DEFAULT -1, "
//new 7.1 fields
"comicVineID TEXT"
"hasBeenOpened BOOLEAN DEFAULT 0,"
"rating INTEGER DEFAULT 0,"
"currentPage INTEGER DEFAULT 1, "
"bookmark1 INTEGER DEFAULT -1, "
"bookmark2 INTEGER DEFAULT -1, "
"bookmark3 INTEGER DEFAULT -1, "
"brightness INTEGER DEFAULT -1, "
"contrast INTEGER DEFAULT -1, "
"gamma INTEGER DEFAULT -1, "
//new 7.1 fields
"comicVineID TEXT"
")");
success = success && queryComicInfo.exec();
//queryComicInfo.finish();
")");
success = success && queryComicInfo.exec();
//queryComicInfo.finish();
//COMIC (representa un cómic en disco, contiene el nombre de fichero)
QSqlQuery queryComic(database);
queryComic.prepare("CREATE TABLE comic (id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, comicInfoId INTEGER NOT NULL, fileName TEXT NOT NULL, path TEXT, FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE, FOREIGN KEY(comicInfoId) REFERENCES comic_info(id))");
success = success && queryComic.exec();
//queryComic.finish();
//DB INFO
QSqlQuery queryDBInfo(database);
queryDBInfo.prepare("CREATE TABLE db_info (version TEXT NOT NULL)");
success = success && queryDBInfo.exec();
//queryDBInfo.finish();
//FOLDER (representa una carpeta en disco)
QSqlQuery queryFolder(database);
queryFolder.prepare("CREATE TABLE folder ("
"id INTEGER PRIMARY KEY,"
"parentId INTEGER NOT NULL,"
"name TEXT NOT NULL,"
"path TEXT NOT NULL,"
//new 7.1 fields
"finished BOOLEAN DEFAULT 0," //reading
"completed BOOLEAN DEFAULT 1," //collecting
//new 8.6 fields
"numChildren INTEGER,"
"firstChildHash TEXT,"
"customImage TEXT,"
"FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE)");
success = success && queryFolder.exec();
QSqlQuery query("INSERT INTO db_info (version) "
"VALUES ('" VERSION "')",database);
//query.finish();
//COMIC (representa un cómic en disco, contiene el nombre de fichero)
QSqlQuery queryComic(database);
queryComic.prepare("CREATE TABLE comic (id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, comicInfoId INTEGER NOT NULL, fileName TEXT NOT NULL, path TEXT, FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE, FOREIGN KEY(comicInfoId) REFERENCES comic_info(id))");
success = success && queryComic.exec();
//queryComic.finish();
//DB INFO
QSqlQuery queryDBInfo(database);
queryDBInfo.prepare("CREATE TABLE db_info (version TEXT NOT NULL)");
success = success && queryDBInfo.exec();
//queryDBInfo.finish();
//8.0> tables
success = success && DataBaseManagement::createV8Tables(database);
QSqlQuery query("INSERT INTO db_info (version) "
"VALUES ('" VERSION "')",database);
//query.finish();
//8.0> tables
success = success && DataBaseManagement::createV8Tables(database);
}
return success;
@ -616,6 +618,19 @@ bool DataBaseManagement::addColumns(const QString &tableName, const QStringList
return returnValue;
}
bool DataBaseManagement::addConstraint(const QString &tableName, const QString &constraint, const QSqlDatabase &db)
{
QString sql = "ALTER TABLE %1 ADD %2";
bool returnValue = true;
QSqlQuery alterTable(db);
alterTable.prepare(sql.arg(tableName).arg(constraint));
alterTable.exec();
returnValue = returnValue && (alterTable.numRowsAffected() > 0);
return returnValue;
}
void DataBaseManagement::bindString(const QString & name, const QSqlRecord & record, QSqlQuery & query)
{
if(!record.value(name).isNull())
@ -686,6 +701,7 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
bool pre7 = false;
bool pre7_1 = false;
bool pre8 = false;
bool pre8_6 = false;
if(compareVersions(DataBaseManagement::checkValidDB(fullPath),"7.0.0")<0)
pre7 = true;
@ -693,6 +709,8 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
pre7_1 = true;
if(compareVersions(DataBaseManagement::checkValidDB(fullPath),"8.0.0")<0)
pre8 = true;
if(compareVersions(DataBaseManagement::checkValidDB(fullPath),"8.6.0")<0)
pre8_6 = true;
QSqlDatabase db = loadDatabaseFromFile(fullPath);
bool returnValue = false;
@ -745,6 +763,16 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
{
returnValue = returnValue && createV8Tables(db);
}
if(pre8_6)
{
QStringList columnDefs;
//TODO
columnDefs << "numChildren INTEGER";
columnDefs << "firstChildHash TEXT";
columnDefs << "customImage TEXT";
//returnValue = returnValue && addColumns("folder", columnDefs, db);
}
}
db.close();

View File

@ -38,6 +38,7 @@ private:
static void bindValuesFromRecord(const QSqlRecord & record, QSqlQuery & query);
static bool addColumns(const QString & tableName, const QStringList & columnDefs, const QSqlDatabase & db);
static bool addConstraint(const QString &tableName, const QString & constraint, const QSqlDatabase & db);
public:
DataBaseManagement();

View File

@ -172,11 +172,12 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
if(role == FolderModel::FinishedRole)
return item->data(FolderModel::Finished);
if(role == FolderModel::IdRole)
return item->id;
if (role != Qt::DisplayRole)
return QVariant();
return item->data(index.column());
}
//! [3]
@ -305,7 +306,7 @@ void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent)
//el diccionario permitir<69> encontrar cualquier nodo del <20>rbol r<>pidamente, de forma que a<>adir un hijo a un padre sea O(1)
items.clear();
//se a<>ade el nodo 0
items.insert(parent->id,parent);
items.insert(parent->id,parent);
while (sqlquery.next()) {
QList<QVariant> data;
@ -537,6 +538,7 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
newFolder.id = DBHelper::insert(&newFolder, db);
DBHelper::updateChildrenInfo(parentItem->id, db);
QSqlDatabase::removeDatabase(_databasePath);
int destRow = 0;
@ -575,11 +577,18 @@ void FolderModel::deleteFolder(const QModelIndex &mi)
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
DBHelper::removeFromDB(&f,db);
DBHelper::updateChildrenInfo(item->parent()->id, db);
QSqlDatabase::removeDatabase(_databasePath);
endRemoveRows();
}
void FolderModel::updateFolderChildrenInfo(qulonglong folderId)
{
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
DBHelper::updateChildrenInfo(folderId, db);
QSqlDatabase::removeDatabase(_databasePath);
}
//PROXY

View File

@ -127,11 +127,13 @@ public:
enum Roles {
FinishedRole = Qt::UserRole + 1,
CompletedRole
CompletedRole,
IdRole
};
public slots:
void deleteFolder(const QModelIndex & mi);
void updateFolderChildrenInfo(qulonglong folderId);
private:
void setupModelData( QSqlQuery &sqlquery, FolderItem *parent);

View File

@ -14,6 +14,7 @@
#include <limits>
#include "reading_list_item.h"
#include "library_item.h"
#include "comic_db.h"
#include "data_base_management.h"
@ -58,6 +59,38 @@ QList<LibraryItem *> DBHelper::getFolderComicsFromLibrary(qulonglong libraryId,
QSqlDatabase::removeDatabase(libraryPath);
return list;
}
quint32 DBHelper::getNumChildrenFromFolder(qulonglong libraryId, qulonglong folderId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
quint32 result = 0;
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT count(*) FROM folder WHERE parentId = :parentId and id <> 1");
selectQuery.bindValue(":parentId", folderId);
selectQuery.exec();
result += selectQuery.record().value(0).toULongLong();
}
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT count(*) FROM comic c WHERE c.parentId = :parentId");
selectQuery.bindValue(":parentId", folderId);
selectQuery.exec();
result += selectQuery.record().value(0).toULongLong();
}
db.close();
QSqlDatabase::removeDatabase(libraryPath);
return result;
}
qulonglong DBHelper::getParentFromComicFolderId(qulonglong libraryId, qulonglong id)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
@ -131,9 +164,9 @@ QString DBHelper::getLibraryName(int id)
void DBHelper::removeFromDB(LibraryItem * item, QSqlDatabase & db)
{
if(item->isDir())
DBHelper::removeFromDB(dynamic_cast<Folder *>(item),db);
DBHelper::removeFromDB(dynamic_cast<Folder *>(item),db);
else
DBHelper::removeFromDB(dynamic_cast<ComicDB *>(item),db);
DBHelper::removeFromDB(dynamic_cast<ComicDB *>(item),db);
}
void DBHelper::removeFromDB(Folder * folder, QSqlDatabase & db)
{
@ -376,6 +409,51 @@ void DBHelper::update(const Folder & folder, QSqlDatabase &db)
updateFolderInfo.exec();
}
void DBHelper::updateChildrenInfo(const Folder & folder, QSqlDatabase & db)
{
QSqlQuery updateFolderInfo(db);
updateFolderInfo.prepare("UPDATE folder SET "
"numChildren = :numChildren, "
"firstChildHash = :firstChildHash "
"WHERE id = :id ");
updateFolderInfo.bindValue(":numChildren", folder.getNumChildren());
updateFolderInfo.bindValue(":firstChildHash", folder.getFirstChildHash());
updateFolderInfo.bindValue(":id", folder.id);
updateFolderInfo.exec();
}
void DBHelper::updateChildrenInfo(qulonglong folderId, QSqlDatabase & db)
{
QList<LibraryItem *> subfolders = DBHelper::getFoldersFromParent(folderId,db,false);
QList<LibraryItem *> comics = DBHelper::getComicsFromParent(folderId,db,true);
ComicDB * firstComic = NULL;
if(comics.count() > 0)
firstComic = static_cast<ComicDB *>(comics.first());
QSqlQuery updateFolderInfo(db);
updateFolderInfo.prepare("UPDATE folder SET "
"numChildren = :numChildren, "
"firstChildHash = :firstChildHash "
"WHERE id = :id ");
updateFolderInfo.bindValue(":numChildren", subfolders.count() + comics.count());
updateFolderInfo.bindValue(":firstChildHash", firstComic != NULL ? firstComic->info.hash : "");
updateFolderInfo.bindValue(":id", folderId);
updateFolderInfo.exec();
}
void DBHelper::updateChildrenInfo(QSqlDatabase & db)
{
QSqlQuery selectQuery(db); //TODO check
selectQuery.prepare("SELECT id FROM folder");
selectQuery.exec();
while (selectQuery.next())
{
DBHelper::updateChildrenInfo(selectQuery.record().value(0).toULongLong(), db);
}
}
void DBHelper::updateProgress(qulonglong libraryId, const ComicInfo &comicInfo)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
@ -548,6 +626,7 @@ qulonglong DBHelper::insert(Folder * folder, QSqlDatabase & db)
query.bindValue(":name", folder->name);
query.bindValue(":path", folder->path);
query.exec();
return query.lastInsertId().toULongLong();
}
@ -575,6 +654,7 @@ qulonglong DBHelper::insert(ComicDB * comic, QSqlDatabase & db)
query.bindValue(":name", comic->name);
query.bindValue(":path", comic->path);
query.exec();
return query.lastInsertId().toULongLong();
}
@ -701,7 +781,13 @@ QList<LibraryItem *> DBHelper::getFoldersFromParent(qulonglong parentId, QSqlDat
data << record.value(i);
//TODO sort by sort indicator and name
currentItem = new Folder(record.value("id").toULongLong(),record.value("parentId").toULongLong(),record.value("name").toString(),record.value("path").toString());
int lessThan = 0;
if(!record.value("numChildren").isNull() && record.value("numChildren").isValid())
currentItem->setNumChildren(record.value("numChildren").toInt());
currentItem->setFirstChildHash(record.value("firstChildHash").toString());
currentItem->setCustomImage(record.value("customImage").toString());
int lessThan = 0;
if(list.isEmpty() || !sort)
list.append(currentItem);
@ -876,6 +962,59 @@ QList<LibraryItem *> DBHelper::getComicsFromParent(qulonglong parentId, QSqlData
return list;
}
QList<LabelItem *> DBHelper::getLabelItems(qulonglong libraryId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QSqlQuery selectQuery("SELECT * FROM label ORDER BY ordering,name",db); //TODO add some kind of
QList<LabelItem *> labels;
while(selectQuery.next())
{
QSqlRecord record = selectQuery.record();
LabelItem *item = new LabelItem(QList<QVariant>()
<< record.value("name")
<< record.value("color")
<< record.value("id")
<< record.value("ordering"));
if(labels.isEmpty())
{
labels << item;
}
else
{
int i = 0;
while (i < labels.count() && (labels.at(i)->colorid() < item->colorid()) )
i++;
if(i < labels.count())
{
if(labels.at(i)->colorid() == item->colorid()) //sort by name
{
while( i < labels.count() && labels.at(i)->colorid() == item->colorid() && naturalSortLessThanCI(labels.at(i)->name(),item->name()))
i++;
}
}
if(i >= labels.count())
{
labels << item;
}
else
{
labels.insert(i,item);
}
}
}
db.close();
QSqlDatabase::removeDatabase(libraryPath);
return labels;
}
//loads
Folder DBHelper::loadFolder(qulonglong id, QSqlDatabase & db)
{
@ -897,6 +1036,11 @@ Folder DBHelper::loadFolder(qulonglong id, QSqlDatabase & db)
//new 7.1
folder.setFinished(record.value("finished").toBool());
folder.setCompleted(record.value("completed").toBool());
//new 8.6
if(!record.value("numChildren").isNull() && record.value("numChildren").isValid())
folder.setNumChildren(record.value("numChildren").toInt());
folder.setFirstChildHash(record.value("firstChildHash").toString());
folder.setCustomImage(record.value("customImage").toString());
}
return folder;
@ -925,6 +1069,12 @@ Folder DBHelper::loadFolder(const QString &folderName, qulonglong parentId, QSql
//new 7.1
folder.setFinished(record.value("finished").toBool());
folder.setCompleted(record.value("completed").toBool());
//new 8.6
if(!record.value("numChildren").isNull() && record.value("numChildren").isValid())
folder.setNumChildren(record.value("numChildren").toInt());
folder.setFirstChildHash(record.value("firstChildHash").toString());
folder.setCustomImage(record.value("customImage").toString());
QLOG_DEBUG() << "FOUND!!";
}

View File

@ -9,6 +9,7 @@ class QString;
class ComicDB;
class Folder;
class LibraryItem;
class LabelItem;
class QSqlDatabase;
class ComicInfo;
class QSqlRecord;
@ -23,6 +24,7 @@ public:
static QList<LibraryItem *> getFolderSubfoldersFromLibrary(qulonglong libraryId, qulonglong folderId);
static QList<LibraryItem *> getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId);
static QList<LibraryItem *> getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId, bool sort);
static quint32 getNumChildrenFromFolder(qulonglong libraryId, qulonglong folderId);
static qulonglong getParentFromComicFolderId(qulonglong libraryId, qulonglong id);
static ComicDB getComicInfo(qulonglong libraryId, qulonglong id);
static QList<ComicDB> getSiblings(qulonglong libraryId, qulonglong parentId);
@ -32,9 +34,9 @@ public:
//objects management
//deletes
static void removeFromDB(LibraryItem * item, QSqlDatabase & db);
static void removeFromDB(Folder * folder, QSqlDatabase & db);
static void removeFromDB(ComicDB * comic, QSqlDatabase & db);
static void removeFromDB(LibraryItem * item, QSqlDatabase & db);
static void removeFromDB(Folder * folder, QSqlDatabase & db);
static void removeFromDB(ComicDB * comic, QSqlDatabase & db);
static void removeLabelFromDB(qulonglong id, QSqlDatabase & db);
static void removeListFromDB(qulonglong id, QSqlDatabase & db);
//logic deletes
@ -42,8 +44,8 @@ public:
static void deleteComicsFromLabel(const QList<ComicDB> & comicsList, qulonglong labelId, QSqlDatabase & db);
static void deleteComicsFromReadingList(const QList<ComicDB> & comicsList, qulonglong readingListId, QSqlDatabase & db);
//inserts
static qulonglong insert(Folder * folder, QSqlDatabase & db);
static qulonglong insert(ComicDB * comic, QSqlDatabase & db);
static qulonglong insert(Folder * folder, QSqlDatabase & db);
static qulonglong insert(ComicDB * comic, QSqlDatabase & db);
static qulonglong insertLabel(const QString & name, YACReader::LabelColors color , QSqlDatabase & db);
static qulonglong insertReadingList(const QString & name, QSqlDatabase & db);
static qulonglong insertReadingSubList(const QString & name, qulonglong parentId, int ordering, QSqlDatabase & db);
@ -56,6 +58,9 @@ public:
static void update(ComicInfo * comicInfo, QSqlDatabase & db);
static void updateRead(ComicInfo * comicInfo, QSqlDatabase & db);
static void update(const Folder & folder, QSqlDatabase & db);
static void updateChildrenInfo(const Folder & folder, QSqlDatabase & db);
static void updateChildrenInfo(qulonglong folderId, QSqlDatabase & db);
static void updateChildrenInfo(QSqlDatabase & db);
static void updateProgress(qulonglong libraryId,const ComicInfo & comicInfo);
static void updateReadingRemoteProgress(const ComicInfo & comicInfo, QSqlDatabase & db);
static void updateFromRemoteClient(qulonglong libraryId,const ComicInfo & comicInfo);
@ -69,7 +74,8 @@ public:
static QList<LibraryItem *> getFoldersFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
static QList<ComicDB> getSortedComicsFromParent(qulonglong parentId, QSqlDatabase & db);
static QList<LibraryItem *> getComicsFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
//load
static QList<LabelItem *> getLabelItems(qulonglong libraryId);
//load
static Folder loadFolder(qulonglong id, QSqlDatabase & db);
static Folder loadFolder(const QString & folderName, qulonglong parentId, QSqlDatabase & db);
static ComicDB loadComic(qulonglong id, QSqlDatabase & db);

View File

@ -9,6 +9,8 @@
#include "console_ui_library_creator.h"
#include <iostream>
#include "QsLog.h"
#include "QsLogDest.h"
@ -118,7 +120,7 @@ int main( int argc, char ** argv )
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::tr("\nYACReaderLibraryServer is the headless (no gui) version of YACReaderLibrary"));
parser.addHelpOption();
parser.addVersionOption();
const QCommandLineOption versionOption = parser.addVersionOption();
parser.addPositionalArgument("command", "The command to execute. [start, create-library, update-library, add-library, remove-library, list-libraries]");
parser.parse(QCoreApplication::arguments());
@ -126,6 +128,13 @@ int main( int argc, char ** argv )
const QStringList args = parser.positionalArguments();
const QString command = args.isEmpty() ? QString() : args.first();
if(parser.isSet(versionOption))
{
qout << "YACReaderLibraryServer" << " " << VERSION << endl;
return 0;
}
if(command == "start")
{
QString destLog = YACReader::getSettingsPath()+"/yacreaderlibrary.log";

View File

@ -162,6 +162,9 @@ void LibraryCreator::run()
_database.transaction();
//se crea la librería
create(QDir(_source));
DBHelper::updateChildrenInfo(_database);
_database.commit();
_database.close();
QSqlDatabase::removeDatabase(_database.connectionName());
@ -199,6 +202,12 @@ void LibraryCreator::run()
{
update(QDir(_source));
}
if(partialUpdate)
DBHelper::updateChildrenInfo(folderDestinationModelIndex.data(FolderModel::IdRole).toULongLong(),_database);
else
DBHelper::updateChildrenInfo(_database);
_database.commit();
_database.close();
QSqlDatabase::removeDatabase(_target);
@ -243,7 +252,7 @@ qulonglong LibraryCreator::insertFolders()
if(!(i->knownId))
{
i->setFather(currentId);
currentId = DBHelper::insert(&(*i),_database);//insertFolder(currentId,*i);
currentId = DBHelper::insert(&(*i),_database);//insertFolder(currentId,*i);
i->setId(currentId);
}
else

View File

@ -1233,7 +1233,7 @@ void LibraryWindow::loadLibrary(const QString & name)
if(d.exists(path+"/library.ydb"))
{
QSqlDatabase db = DataBaseManagement::loadDatabase(path);
QSqlDatabase db = DataBaseManagement::loadDatabase(path);
manageOpeningLibraryError(db.lastError().databaseText() + "-" + db.lastError().driverText());
//será possible renombrar y borrar estas bibliotecas
renameLibraryAction->setEnabled(true);
@ -2420,7 +2420,7 @@ void LibraryWindow::deleteComicsFromDisk()
QLOG_TRACE() << comic.parentId;
}
ComicsRemover * remover = new ComicsRemover(indexList,paths);
ComicsRemover * remover = new ComicsRemover(indexList,paths,comics.at(0).parentId);
QThread * thread = NULL;
thread = new QThread(this);
@ -2433,6 +2433,8 @@ void LibraryWindow::deleteComicsFromDisk()
connect(remover, SIGNAL(remove(int)), comicsModel, SLOT(remove(int)));
connect(remover, SIGNAL(removeError()),this,SLOT(setRemoveError()));
connect(remover, SIGNAL(finished()), comicsModel, SLOT(finishTransaction()));
connect(remover, SIGNAL(finished()), comicsModel, SLOT(finishTransaction()));
connect(remover, SIGNAL(removedItemsFromFolder(qulonglong)), foldersModel, SLOT(updateFolderChildrenInfo(qulonglong)));
connect(remover, SIGNAL(finished()),this,SLOT(checkEmptyFolder()));
connect(remover, SIGNAL(finished()),this,SLOT(checkRemoveError()));

View File

@ -79,7 +79,7 @@ void ComicController::service(HttpRequest& request, HttpResponse& response)
session.setCurrentComic(comic.id, comicFile);
}
response.setHeader("Content-Type", "plain/text; charset=utf-8");
response.setHeader("Content-Type", "text/plain; charset=utf-8");
//TODO this field is not used by the client!
response.writeText(QString("library:%1\r\n").arg(libraryName));
response.writeText(QString("libraryId:%1\r\n").arg(libraryId));

View File

@ -10,7 +10,7 @@ ComicDownloadInfoController::ComicDownloadInfoController() {}
void ComicDownloadInfoController::service(HttpRequest& request, HttpResponse& response)
{
response.setHeader("Content-Type", "plain/text; charset=utf-8");
response.setHeader("Content-Type", "text/plain; charset=utf-8");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');

View File

@ -0,0 +1,70 @@
#include "foldercontentcontroller.h"
#include <QUrl>
#include "db_helper.h"
#include "comic_db.h"
#include "folder.h"
#include "qnaturalsorting.h"
#include <ctime>
using namespace std;
struct LibraryItemSorter
{
bool operator()(const LibraryItem * a,const LibraryItem * b) const
{
return naturalSortLessThanCI(a->name,b->name);
}
};
FolderContentController::FolderContentController() {}
void FolderContentController::service(HttpRequest& request, HttpResponse& response)
{
response.setHeader("Content-Type", "text/plain; charset=utf-8");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
int libraryId = pathElements.at(2).toInt();
qulonglong parentId = pathElements.at(4).toULongLong();
serviceContent(libraryId, parentId, response);
response.writeText("",true);
}
void FolderContentController::serviceContent(const int &library, const qulonglong &folderId, HttpResponse &response)
{
clock_t begin = clock();
QList<LibraryItem *> folderContent = DBHelper::getFolderSubfoldersFromLibrary(library,folderId);
QList<LibraryItem *> folderComics = DBHelper::getFolderComicsFromLibrary(library,folderId);
folderContent.append(folderComics);
qSort(folderContent.begin(),folderContent.end(),LibraryItemSorter());
folderComics.clear();
ComicDB * currentComic;
Folder * currentFolder;
for(QList<LibraryItem *>::const_iterator itr = folderContent.constBegin();itr!=folderContent.constEnd();itr++)
{
if((*itr)->isDir())
{
currentFolder = (Folder *)(*itr);
response.writeText(QString("f\t%1\t%2\t%3\t%4\t%5\r\n").arg(library).arg(currentFolder->id).arg(currentFolder->name).arg(currentFolder->getNumChildren()).arg(currentFolder->getFirstChildHash()));
}
else
{
currentComic = (ComicDB *)(*itr);
response.writeText(QString("c\t%1\t%2\t%3\t%4\t%5\r\n").arg(library).arg(currentComic->id).arg(currentComic->getFileName()).arg(currentComic->getFileSize()).arg(currentComic->info.hash));
}
}
clock_t end = clock();
double msecs = double(end - begin);
response.writeText(QString("%1ms").arg(msecs));
}

View File

@ -0,0 +1,22 @@
#ifndef FOLDERCONTENTCONTROLLER_H
#define FOLDERCONTENTCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class FolderContentController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(FolderContentController);
public:
/** Constructor */
FolderContentController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
private:
void serviceContent(const int &library, const qulonglong &folderId, HttpResponse &response);
};
#endif // FOLDERCONTENTCONTROLLER_H

View File

@ -167,11 +167,11 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
{
t.setVariable(QString("element%1.class").arg(i),"folder");
QList<LibraryItem *> children = DBHelper::getFolderComicsFromLibrary(libraryId, item->id);
if(children.length()>0)
const Folder * folder = static_cast<Folder*>(item);
if(folder->getFirstChildHash().length()>0)
{
const ComicDB * comic = static_cast<ComicDB*>(children.at(0));
t.setVariable(QString("element%1.image.url").arg(i),QString("/library/%1/cover/%2.jpg?folderCover=true").arg(libraryId).arg(comic->info.hash));
t.setVariable(QString("element%1.image.url").arg(i),QString("/library/%1/cover/%2.jpg?folderCover=true").arg(libraryId).arg(folder->getFirstChildHash()));
}
else
t.setVariable(QString("element%1.image.url").arg(i),"/images/f.png");

View File

@ -12,7 +12,7 @@ FolderInfoController::FolderInfoController() {}
void FolderInfoController::service(HttpRequest& request, HttpResponse& response)
{
response.setHeader("Content-Type", "plain/text; charset=utf-8");
response.setHeader("Content-Type", "text/plain; charset=utf-8");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');

View File

@ -0,0 +1,30 @@
#include "tagscontroller.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "reading_list_item.h"
#include "../static.h"
#include "yacreader_global.h"
#include "QsLog.h"
TagsController::TagsController() {}
void TagsController::service(HttpRequest& request, HttpResponse& response)
{
response.setHeader("Content-Type", "text/plain; charset=utf-8");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
int libraryId = pathElements.at(2).toInt();
QList<LabelItem *> tags = DBHelper::getLabelItems(libraryId);
foreach(LabelItem * tag, tags)
{
response.writeText(QString("%1\t%2\t%3\r\n").arg(tag->getId()).arg(tag->name()).arg(labelColorToRGBString(tag->colorid())));
}
response.writeText("",true);
}

View File

@ -0,0 +1,22 @@
#ifndef TAGSCONTROLLER_H
#define TAGSCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class TagsController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(TagsController)
public:
/** Constructor */
TagsController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // TAGSCONTROLLER_H

View File

@ -0,0 +1,10 @@
#include "versioncontroller.h"
VersionController::VersionController() {}
void VersionController::service(HttpRequest& request, HttpResponse& response)
{
Q_UNUSED(request);
response.writeText(SERVER_VERSION_NUMBER,true);
}

View File

@ -0,0 +1,21 @@
#ifndef VERSIONCONTROLLER_H
#define VERSIONCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
#include <QThread>
class VersionController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(VersionController);
public:
/** Constructor */
VersionController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // VERSIONCONTROLLER_H

View File

@ -22,6 +22,9 @@
#include "controllers/errorcontroller.h"
#include "controllers/comicdownloadinfocontroller.h"
#include "controllers/synccontroller.h"
#include "controllers/versioncontroller.h"
#include "controllers/foldercontentcontroller.h"
#include "controllers/tagscontroller.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
@ -105,6 +108,9 @@ void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
QRegExp cover("/library/.+/cover/[0-9a-f]+.jpg"); //get comic cover (navigation)
QRegExp comicPage("/library/.+/comic/[0-9]+/page/[0-9]+/?"); //get comic page
QRegExp comicPageRemote("/library/.+/comic/[0-9]+/page/[0-9]+/remote?"); //get comic page (remote reading)
QRegExp serverVersion("/version/?");
QRegExp folderContent("/library/.+/folder/[0-9]+/content/?");
QRegExp tags("/library/.+/tags/?");
QRegExp sync("/sync");
@ -122,8 +128,14 @@ void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
}
else
{
if(sync.exactMatch(path))
if(serverVersion.exactMatch(path))
{
VersionController().service(request, response);
}
else if(sync.exactMatch(path))
{
SyncController().service(request, response);
}
else
{
//se comprueba que la sesión sea la correcta con el fin de evitar accesos no autorizados
@ -161,6 +173,14 @@ void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
{
UpdateComicController().service(request, response);
}
else if(folderContent.exactMatch(path))
{
FolderContentController().service(request, response);
}
else if(tags.exactMatch(path))
{
TagsController().service(request, response);
}
}
else
{

View File

@ -15,7 +15,11 @@ HEADERS += \
$$PWD/controllers/covercontroller.h \
$$PWD/controllers/updatecomiccontroller.h \
$$PWD/controllers/comicdownloadinfocontroller.h \
$$PWD/controllers/synccontroller.h
$$PWD/controllers/synccontroller.h \
#v2
$$PWD/controllers/versioncontroller.h \
$$PWD/controllers/foldercontentcontroller.h \
$$PWD/controllers/tagscontroller.h
SOURCES += \
$$PWD/static.cpp \
@ -31,8 +35,14 @@ SOURCES += \
$$PWD/controllers/covercontroller.cpp \
$$PWD/controllers/updatecomiccontroller.cpp \
$$PWD/controllers/comicdownloadinfocontroller.cpp \
$$PWD/controllers/synccontroller.cpp
$$PWD/controllers/synccontroller.cpp \
#v2
$$PWD/controllers/versioncontroller.cpp \
$$PWD/controllers/foldercontentcontroller.cpp \
$$PWD/controllers/tagscontroller.cpp
include(lib/bfLogging/bfLogging.pri)
include(lib/bfHttpServer/bfHttpServer.pri)
include(lib/bfTemplateEngine/bfTemplateEngine.pri)
DEFINES += SERVER_VERSION_NUMBER=\\\"2.0\\\"

View File

@ -16,7 +16,7 @@ ComicDB::ComicDB(const ComicDB &comicDB)
operator=(comicDB);
}
bool ComicDB::isDir()
bool ComicDB::isDir() const
{
return false;
}

View File

@ -210,7 +210,7 @@ public:
ComicDB();
ComicDB(const ComicDB & comicDB);
bool isDir();
bool isDir() const;
bool _hasCover;

View File

@ -1,6 +1,23 @@
#include "folder.h"
Folder::Folder()
:knownParent(false),
knownId(false),
numChildren(-1)
{}
Folder::Folder(qulonglong folderId, qulonglong parentId, const QString &folderName, const QString &folderPath)
:knownParent(true),
knownId(true),
numChildren(-1)
{
this->id = folderId;
this->parentId = parentId;
this->name = folderName;
this->path = folderPath;
}
Folder::Folder(const Folder &folder)
{
operator=(folder);
@ -17,3 +34,11 @@ Folder &Folder::operator =(const Folder &other)
return *this;
}
Folder::Folder(const QString & folderName, const QString & folderPath)
:knownParent(false),
knownId(false),
numChildren(-1)
{
this->name = folderName;
this->path = folderPath;
}

View File

@ -11,22 +11,86 @@ public:
bool knownParent;
bool knownId;
Folder():knownParent(false), knownId(false){}
Folder(qulonglong sid, qulonglong pid,QString fn, QString fp):knownParent(true), knownId(true){id = sid; parentId = pid;name = fn; path = fp;}
Folder(QString fn, QString fp):knownParent(false), knownId(false){name = fn; path = fp;}
Folder();
Folder(qulonglong folderId, qulonglong parentId,const QString & folderName, const QString & folderPath);
Folder(const QString & folderName, const QString & folderPath);
Folder(const Folder &folder);
Folder &operator =(const Folder & other);
void setId(qulonglong sid){id = sid;knownId = true;}
void setFather(qulonglong pid){parentId = pid;knownParent = true;}
bool isDir() {return true;}
bool isFinished() const {return finished;}
bool isCompleted() const {return completed;}
void setFinished(bool b) {finished = b;}
void setCompleted(bool b) {completed = b;}
inline void setId(qulonglong sid)
{
id = sid;
knownId = true;
}
inline void setFather(qulonglong pid)
{
parentId = pid;
knownParent = true;
}
inline bool isDir() const
{
return true;
}
inline bool isFinished() const
{
return finished;
}
inline bool isCompleted() const
{
return completed;
}
inline void setFinished(bool b)
{
finished = b;
}
inline void setCompleted(bool b)
{
completed = b;
}
inline qint32 getNumChildren() const
{
return numChildren;
}
inline void setNumChildren(const qint32 v)
{
numChildren = v;
}
inline QString getFirstChildHash() const
{
return firstChildHash;
}
inline void setFirstChildHash(const QString & v)
{
firstChildHash = v;
}
inline QString getCustomImage() const
{
return customImage;
}
inline void setCustomImage(const QString & s)
{
customImage = s;
}
private:
bool finished;
bool completed;
qint32 numChildren; //-1 for unknown number of children
QString firstChildHash; //empty for unknown first child
QString customImage; //empty for none custom image
};
#endif

View File

@ -7,7 +7,7 @@ class LibraryItem : public QObject
{
Q_OBJECT
public:
virtual bool isDir() = 0;
virtual bool isDir() const = 0;
LibraryItem & operator=(const LibraryItem & other);
QString name;
QString path;