This commit is contained in:
Luis Ángel San Martín 2018-04-14 10:24:19 +02:00
commit b41884d5db
161 changed files with 5930 additions and 2891 deletions

View File

@ -1683,6 +1683,7 @@ void MainWindowViewer::sendComic()
{
YACReaderLocalClient * client = new YACReaderLocalClient;
currentComicDB.info.hasBeenOpened = true;
currentComicDB.info.lastTimeOpened = QDateTime::currentSecsSinceEpoch();
viewer->updateComic(currentComicDB);
int retries = 1;
while(!client->sendComicInfo(libraryId,currentComicDB) && retries!=0)

View File

@ -1,317 +1,319 @@
TEMPLATE = app
TARGET = YACReaderLibrary
QMAKE_TARGET_BUNDLE_PREFIX = "com.yacreader"
DEPENDPATH += .
INCLUDEPATH += . \
../common \
./server \
./db \
../custom_widgets \
./comic_vine \
./comic_vine/model
DEFINES += SERVER_RELEASE NOMINMAX YACREADER_LIBRARY
QMAKE_MAC_SDK = macosx10.12
# load default build flags
include (../config.pri)
include (../dependencies/pdf_backend.pri)
unix:haiku {
DEFINES += _BSD_SOURCE
LIBS += -lnetwork -lbsd
}
INCLUDEPATH += ../common/gl
# there are two builds for Windows, Desktop OpenGL based and ANGLE OpenGL ES based
win32 {
CONFIG(force_angle) {
message("using ANGLE")
LIBS += -loleaut32 -lole32 -lshell32 -lopengl32 -lglu32 -luser32
# linking extra libs are necesary for a successful compilation, a better approach should be
# to remove any OpenGL (desktop) dependencies
# the OpenGL stuff should be migrated to OpenGL ES
DEFINES += FORCE_ANGLE
} else {
LIBS += -loleaut32 -lole32 -lshell32 -lopengl32 -lglu32 -luser32
}
QMAKE_CXXFLAGS_RELEASE += /MP /Ob2 /Oi /Ot /GT /GL
QMAKE_LFLAGS_RELEASE += /LTCG
CONFIG -= embed_manifest_exe
}
CONFIG(force_angle) {
contains(QMAKE_TARGET.arch, x86_64) {
Release:DESTDIR = ../release64_angle
Debug:DESTDIR = ../debug64_angle
} else {
Release:DESTDIR = ../release_angle
Debug:DESTDIR = ../debug_angle
}
} else {
contains(QMAKE_TARGET.arch, x86_64) {
Release:DESTDIR = ../release64
Debug:DESTDIR = ../debug64
} else {
Release:DESTDIR = ../release
Debug:DESTDIR = ../debug
}
}
unix:!macx:!CONFIG(no_opengl) {
LIBS += -lGLU
}
macx {
LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
CONFIG += objective_c
QT += macextras gui-private
}
unix:!macx {
CONFIG += c++11
}
#CONFIG += release
CONFIG -= flat
QT += sql network widgets script
!CONFIG(no_opengl) {
QT += opengl
}
# Input
HEADERS += comic_flow.h \
create_library_dialog.h \
library_creator.h \
library_window.h \
add_library_dialog.h \
rename_library_dialog.h \
properties_dialog.h \
options_dialog.h \
export_library_dialog.h \
import_library_dialog.h \
package_manager.h \
bundle_creator.h \
export_comics_info_dialog.h \
import_comics_info_dialog.h \
server_config_dialog.h \
comic_flow_widget.h \
db_helper.h \
./db/data_base_management.h \
./db/folder_item.h \
./db/folder_model.h \
./db/comic_model.h \
./db/comic_item.h \
../common/comic_db.h \
../common/folder.h \
../common/library_item.h \
../common/comic.h \
../common/bookmarks.h \
../common/pictureflow.h \
../common/custom_widgets.h \
../common/qnaturalsorting.h \
../common/yacreader_global.h \
../common/yacreader_global_gui.h \
../common/onstart_flow_selection_dialog.h \
../common/pdf_comic.h \
no_libraries_widget.h \
import_widget.h \
yacreader_local_server.h \
yacreader_main_toolbar.h \
comics_remover.h \
../common/http_worker.h \
yacreader_libraries.h \
../common/exit_check.h \
comics_view.h \
classic_comics_view.h \
empty_folder_widget.h \
no_search_results_widget.h \
comic_files_manager.h \
db/reading_list_model.h \
db/reading_list_item.h \
yacreader_folders_view.h \
yacreader_reading_lists_view.h \
add_label_dialog.h \
yacreader_history_controller.h \
yacreader_navigation_controller.h \
empty_label_widget.h \
empty_container_info.h \
empty_special_list.h \
empty_reading_list_widget.h \
../common/scroll_management.h \
../common/opengl_checker.h \
yacreader_comics_views_manager.h \
info_comics_view.h \
yacreader_comics_selection_helper.h \
yacreader_comic_info_helper.h
!CONFIG(no_opengl) {
HEADERS += ../common/gl/yacreader_flow_gl.h
}
SOURCES += comic_flow.cpp \
create_library_dialog.cpp \
library_creator.cpp \
library_window.cpp \
main.cpp \
add_library_dialog.cpp \
rename_library_dialog.cpp \
properties_dialog.cpp \
options_dialog.cpp \
export_library_dialog.cpp \
import_library_dialog.cpp \
package_manager.cpp \
bundle_creator.cpp \
export_comics_info_dialog.cpp \
import_comics_info_dialog.cpp \
server_config_dialog.cpp \
comic_flow_widget.cpp \
db_helper.cpp \
./db/data_base_management.cpp \
./db/folder_item.cpp \
./db/folder_model.cpp \
./db/comic_model.cpp \
./db/comic_item.cpp \
../common/comic_db.cpp \
../common/folder.cpp \
../common/library_item.cpp \
../common/comic.cpp \
../common/bookmarks.cpp \
../common/pictureflow.cpp \
../common/custom_widgets.cpp \
../common/qnaturalsorting.cpp \
../common/onstart_flow_selection_dialog.cpp \
no_libraries_widget.cpp \
import_widget.cpp \
yacreader_local_server.cpp \
yacreader_main_toolbar.cpp \
comics_remover.cpp \
../common/http_worker.cpp \
../common/yacreader_global.cpp \
../common/yacreader_global_gui.cpp \
yacreader_libraries.cpp \
../common/exit_check.cpp \
comics_view.cpp \
classic_comics_view.cpp \
empty_folder_widget.cpp \
no_search_results_widget.cpp \
comic_files_manager.cpp \
db/reading_list_model.cpp \
db/reading_list_item.cpp \
yacreader_folders_view.cpp \
yacreader_reading_lists_view.cpp \
add_label_dialog.cpp \
yacreader_history_controller.cpp \
yacreader_navigation_controller.cpp \
empty_label_widget.cpp \
empty_container_info.cpp \
empty_special_list.cpp \
empty_reading_list_widget.cpp \
../common/scroll_management.cpp \
../common/opengl_checker.cpp \
yacreader_comics_views_manager.cpp \
info_comics_view.cpp \
yacreader_comics_selection_helper.cpp \
yacreader_comic_info_helper.cpp
!CONFIG(no_opengl) {
SOURCES += ../common/gl/yacreader_flow_gl.cpp
}
include(./server/server.pri)
include(../custom_widgets/custom_widgets_yacreaderlibrary.pri)
CONFIG(7zip){
include(../compressed_archive/wrapper.pri)
} else:CONFIG(unarr) {
include(../compressed_archive/unarr/unarr-wrapper.pri)
} else {
error(No compression backend specified. Did you mess with the build system?)
}
include(./comic_vine/comic_vine.pri)
include(../QsLog/QsLog.pri)
include(../shortcuts_management/shortcuts_management.pri)
RESOURCES += images.qrc files.qrc
win32:RESOURCES += images_win.qrc
unix:!macx:RESOURCES += images_win.qrc
macx:RESOURCES += images_osx.qrc
RC_FILE = icon.rc
macx {
ICON = YACReaderLibrary.icns
}
TRANSLATIONS = yacreaderlibrary_es.ts \
yacreaderlibrary_ru.ts \
yacreaderlibrary_pt.ts \
yacreaderlibrary_fr.ts \
yacreaderlibrary_nl.ts \
yacreaderlibrary_tr.ts \
yacreaderlibrary_de.ts \
yacreaderlibrary_source.ts
#QML/GridView
QT += quick qml
HEADERS += grid_comics_view.h \
comics_view_transition.h
SOURCES += grid_comics_view.cpp \
comics_view_transition.cpp
RESOURCES += qml.qrc
win32:RESOURCES += qml_win.qrc
unix:!macx:RESOURCES += qml_win.qrc
macx:RESOURCES += qml_osx.qrc
unix:!macx {
#set install prefix if it's empty
isEmpty(PREFIX) {
PREFIX = /usr
}
isEmpty(BINDIR) {
BINDIR = $$PREFIX/bin
}
isEmpty(LIBDIR) {
LIBDIR = $$PREFIX/lib
}
isEmpty(DATADIR) {
DATADIR = $$PREFIX/share
}
DEFINES += "LIBDIR=\\\"$$LIBDIR\\\"" "DATADIR=\\\"$$DATADIR\\\""
DEFINES += "LIBDIR=\\\"$$LIBDIR\\\"" "DATADIR=\\\"$$DATADIR\\\"" "BINDIR=\\\"$$BINDIR\\\""
#MAKE INSTALL
INSTALLS += bin icon desktop server translation manpage
bin.path = $$BINDIR
isEmpty(DESTDIR) {
bin.files = YACReaderLibrary
} else {
bin.files = $$DESTDIR/YACReaderLibrary
}
server.path = $$DATADIR/yacreader
server.files = ../release/server
icon.path = $$DATADIR/icons/hicolor/scalable/apps
icon.files = ../YACReaderLibrary.svg
desktop.path = $$DATADIR/applications
desktop.files = ../YACReaderLibrary.desktop
translation.path = $$DATADIR/yacreader/languages
translation.files = ../release/languages/yacreaderlibrary_*
manpage.path = $$DATADIR/man/man1
manpage.files = ../YACReaderLibrary.1
}
TEMPLATE = app
TARGET = YACReaderLibrary
QMAKE_TARGET_BUNDLE_PREFIX = "com.yacreader"
DEPENDPATH += .
INCLUDEPATH += . \
../common \
./server \
./db \
../custom_widgets \
./comic_vine \
./comic_vine/model
DEFINES += SERVER_RELEASE NOMINMAX YACREADER_LIBRARY
QMAKE_MAC_SDK = macosx10.12
# load default build flags
include (../config.pri)
include (../dependencies/pdf_backend.pri)
unix:haiku {
DEFINES += _BSD_SOURCE
LIBS += -lnetwork -lbsd
}
INCLUDEPATH += ../common/gl
# there are two builds for Windows, Desktop OpenGL based and ANGLE OpenGL ES based
win32 {
CONFIG(force_angle) {
message("using ANGLE")
LIBS += -loleaut32 -lole32 -lshell32 -lopengl32 -lglu32 -luser32
# linking extra libs are necesary for a successful compilation, a better approach should be
# to remove any OpenGL (desktop) dependencies
# the OpenGL stuff should be migrated to OpenGL ES
DEFINES += FORCE_ANGLE
} else {
LIBS += -loleaut32 -lole32 -lshell32 -lopengl32 -lglu32 -luser32
}
QMAKE_CXXFLAGS_RELEASE += /MP /Ob2 /Oi /Ot /GT /GL
QMAKE_LFLAGS_RELEASE += /LTCG
CONFIG -= embed_manifest_exe
}
CONFIG(force_angle) {
contains(QMAKE_TARGET.arch, x86_64) {
Release:DESTDIR = ../release64_angle
Debug:DESTDIR = ../debug64_angle
} else {
Release:DESTDIR = ../release_angle
Debug:DESTDIR = ../debug_angle
}
} else {
contains(QMAKE_TARGET.arch, x86_64) {
Release:DESTDIR = ../release64
Debug:DESTDIR = ../debug64
} else {
Release:DESTDIR = ../release
Debug:DESTDIR = ../debug
}
}
unix:!macx:!CONFIG(no_opengl) {
LIBS += -lGLU
}
macx {
LIBS += -framework Foundation -framework ApplicationServices -framework AppKit
CONFIG += objective_c
QT += macextras gui-private
}
unix:!macx {
CONFIG += c++11
}
#CONFIG += release
CONFIG -= flat
QT += sql network widgets script
!CONFIG(no_opengl) {
QT += opengl
}
# Input
HEADERS += comic_flow.h \
create_library_dialog.h \
library_creator.h \
library_window.h \
add_library_dialog.h \
rename_library_dialog.h \
properties_dialog.h \
options_dialog.h \
export_library_dialog.h \
import_library_dialog.h \
package_manager.h \
bundle_creator.h \
export_comics_info_dialog.h \
import_comics_info_dialog.h \
server_config_dialog.h \
comic_flow_widget.h \
db_helper.h \
./db/data_base_management.h \
./db/folder_item.h \
./db/folder_model.h \
./db/comic_model.h \
./db/comic_item.h \
../common/comic_db.h \
../common/folder.h \
../common/library_item.h \
../common/comic.h \
../common/bookmarks.h \
../common/pictureflow.h \
../common/custom_widgets.h \
../common/qnaturalsorting.h \
../common/yacreader_global.h \
../common/yacreader_global_gui.h \
../common/onstart_flow_selection_dialog.h \
../common/pdf_comic.h \
no_libraries_widget.h \
import_widget.h \
yacreader_local_server.h \
yacreader_main_toolbar.h \
comics_remover.h \
../common/http_worker.h \
yacreader_libraries.h \
../common/exit_check.h \
comics_view.h \
classic_comics_view.h \
empty_folder_widget.h \
no_search_results_widget.h \
comic_files_manager.h \
db/reading_list_model.h \
db/reading_list_item.h \
yacreader_folders_view.h \
yacreader_reading_lists_view.h \
add_label_dialog.h \
yacreader_history_controller.h \
yacreader_navigation_controller.h \
empty_label_widget.h \
empty_container_info.h \
empty_special_list.h \
empty_reading_list_widget.h \
../common/scroll_management.h \
../common/opengl_checker.h \
yacreader_comics_views_manager.h \
info_comics_view.h \
yacreader_comics_selection_helper.h \
yacreader_comic_info_helper.h \
db/reading_list.h
!CONFIG(no_opengl) {
HEADERS += ../common/gl/yacreader_flow_gl.h
}
SOURCES += comic_flow.cpp \
create_library_dialog.cpp \
library_creator.cpp \
library_window.cpp \
main.cpp \
add_library_dialog.cpp \
rename_library_dialog.cpp \
properties_dialog.cpp \
options_dialog.cpp \
export_library_dialog.cpp \
import_library_dialog.cpp \
package_manager.cpp \
bundle_creator.cpp \
export_comics_info_dialog.cpp \
import_comics_info_dialog.cpp \
server_config_dialog.cpp \
comic_flow_widget.cpp \
db_helper.cpp \
./db/data_base_management.cpp \
./db/folder_item.cpp \
./db/folder_model.cpp \
./db/comic_model.cpp \
./db/comic_item.cpp \
../common/comic_db.cpp \
../common/folder.cpp \
../common/library_item.cpp \
../common/comic.cpp \
../common/bookmarks.cpp \
../common/pictureflow.cpp \
../common/custom_widgets.cpp \
../common/qnaturalsorting.cpp \
../common/onstart_flow_selection_dialog.cpp \
no_libraries_widget.cpp \
import_widget.cpp \
yacreader_local_server.cpp \
yacreader_main_toolbar.cpp \
comics_remover.cpp \
../common/http_worker.cpp \
../common/yacreader_global.cpp \
../common/yacreader_global_gui.cpp \
yacreader_libraries.cpp \
../common/exit_check.cpp \
comics_view.cpp \
classic_comics_view.cpp \
empty_folder_widget.cpp \
no_search_results_widget.cpp \
comic_files_manager.cpp \
db/reading_list_model.cpp \
db/reading_list_item.cpp \
yacreader_folders_view.cpp \
yacreader_reading_lists_view.cpp \
add_label_dialog.cpp \
yacreader_history_controller.cpp \
yacreader_navigation_controller.cpp \
empty_label_widget.cpp \
empty_container_info.cpp \
empty_special_list.cpp \
empty_reading_list_widget.cpp \
../common/scroll_management.cpp \
../common/opengl_checker.cpp \
yacreader_comics_views_manager.cpp \
info_comics_view.cpp \
yacreader_comics_selection_helper.cpp \
yacreader_comic_info_helper.cpp\
db/reading_list.cpp
!CONFIG(no_opengl) {
SOURCES += ../common/gl/yacreader_flow_gl.cpp
}
include(./server/server.pri)
include(../custom_widgets/custom_widgets_yacreaderlibrary.pri)
CONFIG(7zip){
include(../compressed_archive/wrapper.pri)
} else:CONFIG(unarr) {
include(../compressed_archive/unarr/unarr-wrapper.pri)
} else {
error(No compression backend specified. Did you mess with the build system?)
}
include(./comic_vine/comic_vine.pri)
include(../QsLog/QsLog.pri)
include(../shortcuts_management/shortcuts_management.pri)
RESOURCES += images.qrc files.qrc
win32:RESOURCES += images_win.qrc
unix:!macx:RESOURCES += images_win.qrc
macx:RESOURCES += images_osx.qrc
RC_FILE = icon.rc
macx {
ICON = YACReaderLibrary.icns
}
TRANSLATIONS = yacreaderlibrary_es.ts \
yacreaderlibrary_ru.ts \
yacreaderlibrary_pt.ts \
yacreaderlibrary_fr.ts \
yacreaderlibrary_nl.ts \
yacreaderlibrary_tr.ts \
yacreaderlibrary_de.ts \
yacreaderlibrary_source.ts
#QML/GridView
QT += quick qml
HEADERS += grid_comics_view.h \
comics_view_transition.h
SOURCES += grid_comics_view.cpp \
comics_view_transition.cpp
RESOURCES += qml.qrc
win32:RESOURCES += qml_win.qrc
unix:!macx:RESOURCES += qml_win.qrc
macx:RESOURCES += qml_osx.qrc
unix:!macx {
#set install prefix if it's empty
isEmpty(PREFIX) {
PREFIX = /usr
}
isEmpty(BINDIR) {
BINDIR = $$PREFIX/bin
}
isEmpty(LIBDIR) {
LIBDIR = $$PREFIX/lib
}
isEmpty(DATADIR) {
DATADIR = $$PREFIX/share
}
DEFINES += "LIBDIR=\\\"$$LIBDIR\\\"" "DATADIR=\\\"$$DATADIR\\\""
DEFINES += "LIBDIR=\\\"$$LIBDIR\\\"" "DATADIR=\\\"$$DATADIR\\\"" "BINDIR=\\\"$$BINDIR\\\""
#MAKE INSTALL
INSTALLS += bin icon desktop server translation manpage
bin.path = $$BINDIR
isEmpty(DESTDIR) {
bin.files = YACReaderLibrary
} else {
bin.files = $$DESTDIR/YACReaderLibrary
}
server.path = $$DATADIR/yacreader
server.files = ../release/server
icon.path = $$DATADIR/icons/hicolor/scalable/apps
icon.files = ../YACReaderLibrary.svg
desktop.path = $$DATADIR/applications
desktop.files = ../YACReaderLibrary.desktop
translation.path = $$DATADIR/yacreader/languages
translation.files = ../release/languages/yacreaderlibrary_*
manpage.path = $$DATADIR/man/man1
manpage.files = ../YACReaderLibrary.1
}

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

@ -582,7 +582,7 @@ void ComicModel::setupFavoritesModelData(const QString &databasePath)
"ORDER BY cdrl.ordering");
selectQuery.bindValue(":parentDefaultListId", 1);
selectQuery.exec();
setupModelData(selectQuery);
setupModelDataForList(selectQuery);
}
db.close();
QSqlDatabase::removeDatabase(_databasePath);
@ -607,9 +607,11 @@ void ComicModel::setupReadingModelData(const QString &databasePath)
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"WHERE ci.hasBeenOpened = 1 AND ci.read = 0 AND ci.currentPage != ci.numPages AND ci.currentPage != 1");
"WHERE ci.hasBeenOpened = 1 AND ci.read = 0 AND ci.currentPage != ci.numPages AND ci.currentPage != 1 "
"ORDER BY ci.lastTimeOpened DESC");
selectQuery.exec();
setupModelData(selectQuery);
setupModelDataForList(selectQuery);
}
db.close();
QSqlDatabase::removeDatabase(_databasePath);
@ -928,7 +930,7 @@ void ComicModel::removeInTransaction(int row)
endRemoveRows();
}
/*
void ComicModel::remove(ComicDB * comic, int row)
{
beginRemoveRows(QModelIndex(),row,row);
@ -944,7 +946,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

@ -3,7 +3,9 @@
#include <QtCore>
#include "library_creator.h"
#include "check_new_version.h"
#include "db_helper.h"
#include "QsLog.h"
static QString fields = "title ,"
@ -124,99 +126,105 @@ 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,"
//new 9.5 fields
"lastTimeOpened INTEGER,"
"coverSizeRatio REAL,"
"originalCoverSize STRING"//h/w
")");
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 9.5 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;
@ -317,7 +325,7 @@ void DataBaseManagement::exportComicsInfo(QString source, QString dest)
//QSqlDatabase sourceDB = loadDatabase(source);
QSqlDatabase destDB = loadDatabaseFromFile(dest);
//sourceDB.open();
{
{
QSqlQuery attach(destDB);
attach.prepare("ATTACH DATABASE '"+QDir().toNativeSeparators(dest) +"' AS dest;");
//attach.bindValue(":dest",QDir().toNativeSeparators(dest));
@ -415,7 +423,12 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
"edited = :edited,"
"comicVineID = :comicVineID"
"comicVineID = :comicVineID,"
"lastTimeOpened = :lastTimeOpened,"
"coverSizeRatio = :coverSizeRatio,"
"originalCoverSize = :originalCoverSize"
" WHERE hash = :hash ");
@ -449,6 +462,8 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
"read,"
"edited,"
"comicVineID,"
"lastTimeOpened,"
"coverSizeRatio,"
"hash)"
"VALUES (:title,"
@ -486,6 +501,11 @@ bool DataBaseManagement::importComicsInfo(QString source, QString dest)
":edited,"
":comicVineID,"
":lastTimeOpened,"
":coverSizeRatio,"
":originalCoverSize,"
":hash )");
QSqlRecord record = newInfo.record();
@ -596,6 +616,11 @@ void DataBaseManagement::bindValuesFromRecord(const QSqlRecord & record, QSqlQue
bindString("comicVineID",record,query);
bindString("lastTimeOpened",record,query);
bindDouble("coverSizeRatio",record,query);
bindString("originalCoverSize",record,query);
bindString("hash",record,query);
}
@ -609,13 +634,30 @@ bool DataBaseManagement::addColumns(const QString &tableName, const QStringList
QSqlQuery alterTable(db);
alterTable.prepare(sql.arg(tableName).arg(columnDef));
//alterTableComicInfo.bindValue(":column_def",columnDef);
alterTable.exec();
returnValue = returnValue && (alterTable.numRowsAffected() > 0);
bool exec = alterTable.exec();
returnValue = returnValue && exec;
if (!exec) {
QLOG_ERROR() << alterTable.lastError().text();
}
//returnValue = returnValue && (alterTable.numRowsAffected() > 0);
}
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())
@ -631,6 +673,14 @@ void DataBaseManagement::bindInt(const QString & name, const QSqlRecord & record
}
}
void DataBaseManagement::bindDouble(const QString & name, const QSqlRecord & record, QSqlQuery & query)
{
if(!record.value(name).isNull())
{
query.bindValue(":"+name,record.value(name).toDouble());
}
}
QString DataBaseManagement::checkValidDB(const QString & fullPath)
{
QSqlDatabase db = loadDatabaseFromFile(fullPath);
@ -681,11 +731,14 @@ int DataBaseManagement::compareVersions(const QString & v1, const QString v2)
return 0;
}
bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
bool DataBaseManagement::updateToCurrentVersion(const QString & path)
{
bool pre7 = false;
bool pre7_1 = false;
bool pre8 = false;
bool pre9_5 = false;
QString fullPath = path + "/library.ydb";
if(compareVersions(DataBaseManagement::checkValidDB(fullPath),"7.0.0")<0)
pre7 = true;
@ -693,6 +746,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),"9.5.0")<0)
pre9_5 = true;
QSqlDatabase db = loadDatabaseFromFile(fullPath);
bool returnValue = false;
@ -704,7 +759,7 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
updateVersion.bindValue(":version",VERSION);
updateVersion.exec();
if(updateVersion.numRowsAffected() > 0)
if(updateVersion.numRowsAffected() > 0)
returnValue = true;
if(pre7) //TODO: execute only if previous version was < 7.0
@ -721,7 +776,8 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
<< "contrast INTEGER DEFAULT -1"
<< "gamma INTEGER DEFAULT -1";
returnValue = returnValue && addColumns("comic_info", columnDefs, db);
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
returnValue = returnValue && successAddingColumns;
}
//TODO update hasBeenOpened value
@ -731,19 +787,78 @@ bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
QStringList columnDefs;
columnDefs << "finished BOOLEAN DEFAULT 0"
<< "completed BOOLEAN DEFAULT 1";
returnValue = returnValue && addColumns("folder", columnDefs, db);
bool successAddingColumns = addColumns("folder", columnDefs, db);
returnValue = returnValue && successAddingColumns;
}
{//comic_info
QStringList columnDefs;
columnDefs << "comicVineID TEXT DEFAULT NULL";
returnValue = returnValue && addColumns("comic_info", columnDefs, db);
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
returnValue = returnValue && successAddingColumns;
}
}
if(pre8)
{
returnValue = returnValue && createV8Tables(db);
bool successCreatingNewTables = createV8Tables(db);
returnValue = returnValue && successCreatingNewTables;
}
if(pre9_5)
{
{//folder
QStringList columnDefs;
//a full library update is needed after updating the table
columnDefs << "numChildren INTEGER";
columnDefs << "firstChildHash TEXT";
columnDefs << "customImage TEXT";
bool successAddingColumns = addColumns("folder", columnDefs, db);
returnValue = returnValue && successAddingColumns;
}
{//comic_info
QStringList columnDefs;
columnDefs << "lastTimeOpened INTEGER";
columnDefs << "coverSizeRatio REAL";
columnDefs << "originalCoverSize TEXT";
bool successAddingColumns = addColumns("comic_info", columnDefs, db);
returnValue = returnValue && successAddingColumns;
QSqlQuery queryIndexLastTimeOpened(db);
bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)");
returnValue = returnValue && successCreatingIndex;
}
//update folders info
{
DBHelper::updateChildrenInfo(db);
}
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT id, hash FROM comic_info");
selectQuery.exec();
db.transaction();
QSqlQuery updateCoverInfo(db);
updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id");
QImageReader thumbnail;
while (selectQuery.next())
{
thumbnail.setFileName(path % "/covers/" % selectQuery.value(1).toString() % ".jpg");
float coverSizeRatio = static_cast<float>(thumbnail.size().width()) / thumbnail.size().height();
updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio);
updateCoverInfo.bindValue(":id", selectQuery.value(0));
updateCoverInfo.exec();
}
db.commit();
}
}
}

View File

@ -35,9 +35,11 @@ private:
QList<QString> dataBasesList;
static void bindString(const QString & name, const QSqlRecord & record, QSqlQuery & query);
static void bindInt(const QString & name, const QSqlRecord & record, QSqlQuery & query);
static void bindDouble(const QString & name, const QSqlRecord & record, QSqlQuery & query);
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

@ -184,6 +184,9 @@ 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();
@ -315,7 +318,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);
QSqlRecord record = sqlquery.record();
@ -562,6 +565,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;
@ -600,11 +604,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

@ -0,0 +1,44 @@
#include "reading_list.h"
ReadingList::ReadingList(const QString &name, qulonglong id, int ordering)
:name(name), id(id), ordering(ordering)
{
}
qulonglong ReadingList::getId() const
{
return id;
}
QString ReadingList::getName() const
{
return name;
}
int ReadingList::getOrdering() const
{
return ordering;
}
Label::Label(const QString &name, qulonglong id, YACReader::LabelColors colorid)
:name(name), id(id), colorid(colorid)
{
}
YACReader::LabelColors Label::getColorID() const
{
return colorid;
}
QString Label::getName() const
{
return name;
}
qulonglong Label::getId() const
{
return id;
}

View File

@ -0,0 +1,36 @@
#ifndef READING_LIST_H
#define READING_LIST_H
#include "yacreader_global.h"
class ReadingList
{
public:
ReadingList(const QString &name, qulonglong id, int ordering);
qulonglong getId() const;
QString getName() const;
int getOrdering() const;
private:
QString name;
qulonglong id;
int ordering;
};
class Label
{
public:
Label(const QString &name, qulonglong id, YACReader::LabelColors colorid);
YACReader::LabelColors getColorID() const;
QString getName() const;
qulonglong getId() const;
private:
QString name;
qulonglong id;
YACReader::LabelColors colorid;
};
#endif // READING_LIST_H

View File

@ -14,6 +14,7 @@
#include <limits>
#include "reading_list.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);
@ -107,8 +140,7 @@ QString DBHelper::getFolderName(qulonglong libraryId, qulonglong id)
if(selectQuery.next())
{
QSqlRecord record = selectQuery.record();
name = record.value(0).toString();
name = selectQuery.value(0).toString();
}
}
@ -126,14 +158,223 @@ QString DBHelper::getLibraryName(int id)
{
return getLibraries().getName(id);
}
QList<ComicDB> DBHelper::getLabelComics(qulonglong libraryId, qulonglong labelId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QList<ComicDB> list;
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT c.id,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"INNER JOIN comic_label cl ON (c.id == cl.comic_id) "
"WHERE cl.label_id = :parentLabelId "
"ORDER BY cl.ordering");
selectQuery.bindValue(":parentLabelId", labelId);
selectQuery.exec();
while (selectQuery.next())
{
ComicDB comic;
comic.id = selectQuery.value(0).toULongLong();
comic.parentId = labelId;
comic.name = selectQuery.value(1).toString();
comic.info.title = selectQuery.value(2).toString();
comic.info.currentPage = selectQuery.value(3).toInt();
comic.info.numPages = selectQuery.value(4).toInt();
comic.info.hash = selectQuery.value(5).toString();
comic.info.read = selectQuery.value(6).toBool();
list.append(comic);
}
db.close();
}
return list;
}
QList<ComicDB> DBHelper::getFavorites(qulonglong libraryId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QList<ComicDB> list;
const int FAV_ID = 1;
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT c.id,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"INNER JOIN comic_default_reading_list cdrl ON (c.id == cdrl.comic_id) "
"WHERE cdrl.default_reading_list_id = :parentDefaultListId "
"ORDER BY cdrl.ordering");
selectQuery.bindValue(":parentDefaultListId", FAV_ID);
selectQuery.exec();
while (selectQuery.next())
{
ComicDB comic;
comic.id = selectQuery.value(0).toULongLong();
comic.parentId = FAV_ID;
comic.name = selectQuery.value(1).toString();
comic.info.title = selectQuery.value(2).toString();
comic.info.currentPage = selectQuery.value(3).toInt();
comic.info.numPages = selectQuery.value(4).toInt();
comic.info.hash = selectQuery.value(5).toString();
comic.info.read = selectQuery.value(6).toBool();
list.append(comic);
}
db.close();
}
return list;
}
QList<ComicDB> DBHelper::getReading(qulonglong libraryId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QList<ComicDB> list;
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT c.id,c.parentId,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"WHERE ci.hasBeenOpened = 1 AND ci.read = 0 AND ci.currentPage != ci.numPages AND ci.currentPage != 1 "
"ORDER BY ci.lastTimeOpened DESC");
selectQuery.exec();
while (selectQuery.next())
{
ComicDB comic;
comic.id = selectQuery.value(0).toULongLong();
comic.parentId = selectQuery.value(1).toULongLong();
comic.name = selectQuery.value(2).toString();
comic.info.title = selectQuery.value(3).toString();
comic.info.currentPage = selectQuery.value(4).toInt();
comic.info.numPages = selectQuery.value(5).toInt();
comic.info.hash = selectQuery.value(6).toString();
comic.info.read = selectQuery.value(7).toBool();
comic.info.coverSizeRatio = selectQuery.value(8).toFloat();
list.append(comic);
}
db.close();
}
return list;
}
QList<ReadingList> DBHelper::getReadingLists(qulonglong libraryId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QList<ReadingList> list;
QSqlQuery selectQuery("SELECT * from reading_list WHERE parentId IS NULL ORDER BY name DESC",db);
selectQuery.exec();
QSqlRecord record = selectQuery.record();
int name = record.indexOf("name");
int id = record.indexOf("id");
int ordering = record.indexOf("ordering");
while (selectQuery.next())
{
ReadingList item(selectQuery.value(name).toString(), selectQuery.value(id).toLongLong(),selectQuery.value(ordering).toInt());
if(list.isEmpty())
{
list.append(item);
}
else
{
int i= 0;
while(i<list.length() && naturalSortLessThanCI(list.at(i).getName(),item.getName()))
i++;
list.insert(i,item);
}
}
return list;
}
QList<ComicDB> DBHelper::getReadingListFullContent(qulonglong libraryId, qulonglong readingListId)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
QList<ComicDB> list;
{
QList<qulonglong> ids;
ids << readingListId;
QSqlQuery subfolders(db);
subfolders.prepare("SELECT id "
"FROM reading_list "
"WHERE parentId = :parentId "
"ORDER BY ordering ASC");
subfolders.bindValue(":parentId", readingListId);
subfolders.exec();
while(subfolders.next())
ids << subfolders.value(0).toULongLong();
foreach(qulonglong id, ids)
{
QSqlQuery selectQuery(db);
selectQuery.prepare("SELECT c.id,c.parentId,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read "
"FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) "
"INNER JOIN comic_reading_list crl ON (c.id == crl.comic_id) "
"WHERE crl.reading_list_id = :parentReadingList "
"ORDER BY crl.ordering");
selectQuery.bindValue(":parentReadingList", id);
selectQuery.exec();
while (selectQuery.next())
{
ComicDB comic;
comic.id = selectQuery.value(0).toULongLong();
comic.parentId = selectQuery.value(1).toULongLong();
comic.name = selectQuery.value(2).toString();
comic.info.title = selectQuery.value(3).toString();
comic.info.currentPage = selectQuery.value(4).toInt();
comic.info.numPages = selectQuery.value(5).toInt();
comic.info.hash = selectQuery.value(6).toString();
comic.info.read = selectQuery.value(7).toBool();
list.append(comic);
}
}
}
return list;
}
//objects management
//deletes
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)
{
@ -296,7 +537,13 @@ void DBHelper::update(ComicInfo * comicInfo, QSqlDatabase & db)
"rating = :rating,"
//new 7.1 fields
"comicVineID = :comicVineID"
"comicVineID = :comicVineID,"
//new 9.5 fields
"lastTimeOpened = :lastTimeOpened,"
"coverSizeRatio = :coverSizeRatio,"
"originalCoverSize = :originalCoverSize"
//--
" WHERE id = :id ");
@ -351,6 +598,11 @@ void DBHelper::update(ComicInfo * comicInfo, QSqlDatabase & db)
updateComicInfo.bindValue(":comicVineID", comicInfo->comicVineID);
updateComicInfo.bindValue(":lastTimeOpened", comicInfo->lastTimeOpened);
updateComicInfo.bindValue(":coverSizeRatio", comicInfo->coverSizeRatio);
updateComicInfo.bindValue(":originalCoverSize", comicInfo->originalCoverSize);
updateComicInfo.exec();
}
@ -379,6 +631,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.value(0).toULongLong(), db);
}
}
void DBHelper::updateProgress(qulonglong libraryId, const ComicInfo &comicInfo)
{
QString libraryPath = DBHelper::getLibraries().getPath(libraryId);
@ -402,12 +699,14 @@ void DBHelper::updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatab
"read = :read, "
"currentPage = :currentPage, "
"hasBeenOpened = :hasBeenOpened, "
"lastTimeOpened = :lastTimeOpened, "
"rating = :rating"
" WHERE id = :id ");
updateComicInfo.bindValue(":read", comicInfo.read?1:0);
updateComicInfo.bindValue(":currentPage", comicInfo.currentPage);
updateComicInfo.bindValue(":hasBeenOpened", comicInfo.hasBeenOpened?1:0);
updateComicInfo.bindValue(":lastTimeOpened", QDateTime::currentSecsSinceEpoch());
updateComicInfo.bindValue(":id", comicInfo.id);
updateComicInfo.bindValue(":rating", comicInfo.rating);
updateComicInfo.exec();
@ -492,7 +791,7 @@ void DBHelper::reasignOrderToComicsInFavorites(QList<qulonglong> comicIds, QSqlD
QSqlQuery updateOrdering(db);
updateOrdering.prepare("UPDATE comic_default_reading_list SET "
"ordering = :ordering "
"WHERE comic_id = :comic_id AND default_reading_list_id = 0");
"WHERE comic_id = :comic_id AND default_reading_list_id = 1");
db.transaction();
int order = 0;
foreach(qulonglong id, comicIds)
@ -554,6 +853,7 @@ qulonglong DBHelper::insert(Folder * folder, QSqlDatabase & db)
query.bindValue(":name", folder->name);
query.bindValue(":path", folder->path);
query.exec();
return query.lastInsertId().toULongLong();
}
@ -562,10 +862,12 @@ qulonglong DBHelper::insert(ComicDB * comic, QSqlDatabase & db)
if(!comic->info.existOnDb)
{
QSqlQuery comicInfoInsert(db);
comicInfoInsert.prepare("INSERT INTO comic_info (hash,numPages) "
"VALUES (:hash,:numPages)");
comicInfoInsert.prepare("INSERT INTO comic_info (hash,numPages,coverSizeRatio,originalCoverSize) "
"VALUES (:hash,:numPages,:coverSizeRatio,:originalCoverSize)");
comicInfoInsert.bindValue(":hash", comic->info.hash);
comicInfoInsert.bindValue(":numPages", comic->info.numPages);
comicInfoInsert.bindValue(":coverSizeRatio", comic->info.coverSizeRatio);
comicInfoInsert.bindValue(":originalCoverSize", comic->info.originalCoverSize);
comicInfoInsert.exec();
comic->info.id =comicInfoInsert.lastInsertId().toULongLong();
comic->_hasCover = false;
@ -581,6 +883,7 @@ qulonglong DBHelper::insert(ComicDB * comic, QSqlDatabase & db)
query.bindValue(":name", comic->name);
query.bindValue(":path", comic->path);
query.exec();
return query.lastInsertId().toULongLong();
}
@ -703,13 +1006,22 @@ QList<LibraryItem *> DBHelper::getFoldersFromParent(qulonglong parentId, QSqlDat
int name = record.indexOf("name");
int path = record.indexOf("path");
int id = record.indexOf("id");
int numChildren = record.indexOf("numChildren");
int firstChildHash = record.indexOf("firstChildHash");
int customImage = record.indexOf("customImage");
Folder * currentItem;
while (selectQuery.next())
{
//TODO sort by sort indicator and name
currentItem = new Folder(selectQuery.value(id).toULongLong(),parentId,selectQuery.value(name).toString(),selectQuery.value(path).toString());
int lessThan = 0;
currentItem = new Folder(selectQuery.value(id).toULongLong(),parentId,selectQuery.value(name).toString(),selectQuery.value(path).toString());
if(!selectQuery.value(numChildren).isNull() && selectQuery.value(numChildren).isValid())
currentItem->setNumChildren(selectQuery.value(numChildren).toInt());
currentItem->setFirstChildHash(selectQuery.value(firstChildHash).toString());
currentItem->setCustomImage(selectQuery.value(customImage).toString());
int lessThan = 0;
if(list.isEmpty() || !sort)
list.append(currentItem);
@ -721,7 +1033,7 @@ QList<LibraryItem *> DBHelper::getFoldersFromParent(qulonglong parentId, QSqlDat
QList<LibraryItem *>::iterator i;
i = list.end();
i--;
while ((0 > (lessThan = naturalSortLessThanCI(nameCurrent,nameLast))) && i != list.begin())
while ((0 > (lessThan = naturalCompare(nameCurrent,nameLast,Qt::CaseInsensitive))) && i != list.begin())
{
i--;
nameLast = (*i)->name;
@ -929,6 +1241,63 @@ QList<LibraryItem *> DBHelper::getComicsFromParent(qulonglong parentId, QSqlData
return list;
}
QList<Label> DBHelper::getLabels(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<Label> labels;
QSqlRecord record = selectQuery.record();
int name = record.indexOf("name");
int color = record.indexOf("color");
int id = record.indexOf("id");
int ordering = record.indexOf("ordering");
while(selectQuery.next())
{
Label item(selectQuery.value(name).toString(),
selectQuery.value(id).toLongLong(),
static_cast<YACReader::LabelColors>(selectQuery.value(color).toInt()));
if(labels.isEmpty())
{
labels << item;
}
else
{
int i = 0;
while (i < labels.count() && (labels.at(i).getColorID() < item.getColorID()) )
i++;
if(i < labels.count())
{
if(labels.at(i).getColorID() == item.getColorID()) //sort by name
{
while( i < labels.count() && labels.at(i).getColorID() == item.getColorID() && naturalSortLessThanCI(labels.at(i).getName(),item.getName()))
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)
{
@ -948,6 +1317,9 @@ Folder DBHelper::loadFolder(qulonglong id, QSqlDatabase & db)
int path = record.indexOf("path");
int finished = record.indexOf("finished");
int completed = record.indexOf("completed");
int numChildren = record.indexOf("numChildren");
int firstChildHash = record.indexOf("firstChildHash");
int customImage = record.indexOf("customImage");
if(query.next())
{
@ -955,9 +1327,16 @@ Folder DBHelper::loadFolder(qulonglong id, QSqlDatabase & db)
folder.name = query.value(name).toString();
folder.path = query.value(path).toString();
folder.knownId = true;
//new 7.1
folder.setFinished(query.value(finished).toBool());
folder.setCompleted(query.value(completed).toBool());
//new 9.5
if(!query.value(numChildren).isNull() && query.value(numChildren).isValid())
folder.setNumChildren(query.value(numChildren).toInt());
folder.setFirstChildHash(query.value(firstChildHash).toString());
folder.setCustomImage(query.value(customImage).toString());
}
return folder;
@ -980,6 +1359,9 @@ Folder DBHelper::loadFolder(const QString &folderName, qulonglong parentId, QSql
int path = record.indexOf("path");
int finished = record.indexOf("finished");
int completed = record.indexOf("completed");
int numChildren = record.indexOf("numChildren");
int firstChildHash = record.indexOf("firstChildHash");
int customImage = record.indexOf("customImage");
folder.parentId = parentId;
if(query.next())
@ -988,9 +1370,16 @@ Folder DBHelper::loadFolder(const QString &folderName, qulonglong parentId, QSql
folder.name = query.value(name).toString();
folder.path = query.value(path).toString();
folder.knownId = true;
//new 7.1
folder.setFinished(query.value(finished).toBool());
folder.setCompleted(query.value(completed).toBool());
//new 9.5
if(!query.value(numChildren).isNull() && query.value(numChildren).isValid())
folder.setNumChildren(query.value(numChildren).toInt());
folder.setFirstChildHash(query.value(firstChildHash).toString());
folder.setCustomImage(query.value(customImage).toString());
}
return folder;
@ -1108,6 +1497,11 @@ ComicInfo DBHelper::loadComicInfo(QString hash, QSqlDatabase & db)
int comicVineID = record.indexOf("comicVineID");
int lastTimeOpened = record.indexOf("lastTimeOpened");
int coverSizeRatio = record.indexOf("coverSizeRatio");
int originalCoverSize = record.indexOf("originalCoverSize");
if(findComicInfo.next())
{
comicInfo.hash = hash;
@ -1126,7 +1520,6 @@ ComicInfo DBHelper::loadComicInfo(QString hash, QSqlDatabase & db)
comicInfo.gamma = findComicInfo.value(gamma).toInt();
comicInfo.rating = findComicInfo.value(rating).toInt();
//--
comicInfo.title = findComicInfo.value(title);
comicInfo.numPages = findComicInfo.value(numPages);
@ -1162,6 +1555,13 @@ ComicInfo DBHelper::loadComicInfo(QString hash, QSqlDatabase & db)
comicInfo.comicVineID = findComicInfo.value(comicVineID);
//new 9.5 fields
comicInfo.lastTimeOpened = findComicInfo.value(lastTimeOpened);
comicInfo.coverSizeRatio = findComicInfo.value(coverSizeRatio);
comicInfo.originalCoverSize = findComicInfo.value(originalCoverSize);
//--
comicInfo.existOnDb = true;
}
else

View File

@ -9,11 +9,13 @@ class QString;
class ComicDB;
class Folder;
class LibraryItem;
class Label;
class QSqlDatabase;
class ComicInfo;
class QSqlRecord;
class QSqlQuery;
class YACReaderLibraries;
class ReadingList;
class DBHelper
{
@ -23,18 +25,24 @@ 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);
static QString getFolderName(qulonglong libraryId, qulonglong id);
static QList<QString> getLibrariesNames();
static QString getLibraryName(int id);
static QList<ComicDB> getLabelComics(qulonglong libraryId, qulonglong labelId);
static QList<ComicDB> getFavorites(qulonglong libraryId);
static QList<ComicDB> getReading(qulonglong libraryId);
static QList<ReadingList> getReadingLists(qulonglong libraryId);
static QList<ComicDB> getReadingListFullContent(qulonglong libraryId, qulonglong readingListId);
//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 +50,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 +64,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 +80,9 @@ 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<Label> getLabels(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

@ -42,8 +42,6 @@ YACReaderActivityIndicatorWidget::YACReaderActivityIndicatorWidget(QWidget * par
normal->setPixmap(line);
glow->setPixmap(glowLine);
QHBoxLayout * layout = new QHBoxLayout();
layout->addWidget(normal,0,Qt::AlignVCenter);
@ -155,6 +153,7 @@ ImportWidget::ImportWidget(QWidget *parent) :
QPushButton * stop = new QPushButton(tr("stop"));
stop->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
stopButton = stop;
QVBoxLayout * layout = new QVBoxLayout(this);
QHBoxLayout * buttonLayout = new QHBoxLayout();
@ -192,7 +191,7 @@ ImportWidget::ImportWidget(QWidget *parent) :
layout->addLayout(buttonLayout,0);
layout->addSpacing(10);
layout->addStretch();
portadasLabel = new QLabel("<font color=\"#565959\">"+tr("Some of the comics being added...")+"</font>");
coversLabel = new QLabel("<font color=\"#565959\">"+tr("Some of the comics being added...")+"</font>");
hideButton = new QToolButton(this);
hideButton->setFixedSize(25,18);
@ -202,7 +201,7 @@ ImportWidget::ImportWidget(QWidget *parent) :
connect(hideButton,SIGNAL(toggled(bool)),this,SLOT(showCovers(bool)));
layout->addWidget(portadasLabel,0,Qt::AlignHCenter);
layout->addWidget(coversLabel,0,Qt::AlignHCenter);
layout->addWidget(coversViewContainer);
//layout->addStretch();
layout->addWidget(currentComicLabel,0,Qt::AlignHCenter);
@ -346,6 +345,11 @@ void ImportWidget::setImportLook()
iconLabel->setPixmap(QPixmap(":/images/importingIcon.png"));
text->setText("<font color=\"#495252\">"+tr("Importing comics")+"</font>");
textDescription->setText("<font color=\"#565959\">"+tr("<p>YACReaderLibrary is now creating a new library.</p><p>Create a library could take several minutes. You can stop the process and update the library later for completing the task.</p>")+"</font>");
stopButton->setVisible(true);
coversLabel->setVisible(true);
coversViewContainer->setVisible(true);
hideButton->setVisible(true);
}
void ImportWidget::setUpdateLook()
@ -353,6 +357,23 @@ void ImportWidget::setUpdateLook()
iconLabel->setPixmap(QPixmap(":/images/updatingIcon.png"));
text->setText("<font color=\"#495252\">"+tr("Updating the library")+"</font>");
textDescription->setText("<font color=\"#565959\">"+tr("<p>The current library is being updated. For faster updates, please, update your libraries frequently.</p><p>You can stop the process and continue updating this library later.</p>")+"</font>");
stopButton->setVisible(true);
coversLabel->setVisible(true);
coversViewContainer->setVisible(true);
hideButton->setVisible(true);
}
void ImportWidget::setUpgradeLook()
{
iconLabel->setPixmap(QPixmap(":/images/updatingIcon.png"));
text->setText("<font color=\"#495252\">"+tr("Upgrading the library")+"</font>");
textDescription->setText("<font color=\"#565959\">"+tr("<p>The current library is being upgraded, please wait.</p>")+"</font>");
stopButton->setVisible(false);
coversLabel->setVisible(false);
coversViewContainer->setVisible(false);
hideButton->setVisible(false);
}
void ImportWidget::clearScene()
@ -363,7 +384,7 @@ void ImportWidget::clearScene()
void ImportWidget::showCovers(bool hide)
{
portadasLabel->setHidden(hide);
coversLabel->setHidden(hide);
coversViewContainer->setHidden(hide);
}

View File

@ -1,16 +1,9 @@
#ifndef IMPORT_WIDGET_H
#define IMPORT_WIDGET_H
#include <QWidget>
class QLabel;
class QGraphicsView;
class QGraphicsScene;
class QElapsedTimer;
class QVBoxLayout;
class QToolButton;
class QResizeEvent;
class QPropertyAnimation;
#include <QtWidgets>
class ImportWidget : public QWidget
{
@ -28,11 +21,12 @@ public slots:
void clearScene();
void setImportLook();
void setUpdateLook();
void setUpgradeLook();
void showCovers(bool hide);
private:
QLabel * currentComicLabel;
QLabel * portadasLabel;
QLabel * coversLabel;
QLabel * iconLabel;
QLabel * text;
QLabel * textDescription;
@ -40,6 +34,7 @@ private:
QGraphicsView * coversView;
QGraphicsScene * coversScene;
QPropertyAnimation * scrollAnimation;
QPushButton * stopButton;
int previousWidth;
bool updatingCovers;

View File

@ -150,6 +150,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());
@ -187,6 +190,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);
@ -231,7 +240,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
@ -300,12 +309,14 @@ void LibraryCreator::insertComic(const QString & relativePath,const QFileInfo &
QString hash = QString(crypto.result().toHex().constData()) + QString::number(fileInfo.size());
ComicDB comic = DBHelper::loadComic(fileInfo.fileName(),relativePath,hash,_database);
int numPages = 0;
QPair<int,int> originalCoverSize = {0,0};
bool exists = checkCover(hash);
if(! ( comic.hasCover() && exists))
{
ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+"/covers/"+hash+".jpg",comic.info.coverPage.toInt());
tc.create();
numPages = tc.getNumPages();
originalCoverSize = tc.getOriginalCoverSize();
if (numPages > 0)
{
emit(comicAdded(relativePath,_target+"/covers/"+hash+".jpg"));
@ -317,6 +328,12 @@ void LibraryCreator::insertComic(const QString & relativePath,const QFileInfo &
//en este punto sabemos que todos los folders que hay en _currentPath, deberían estar añadidos a la base de datos
insertFolders();
comic.info.numPages = numPages;
if(originalCoverSize.second > 0)
{
comic.info.originalCoverSize = QString("%1x%2").arg(originalCoverSize.first).arg(originalCoverSize.second);
comic.info.coverSizeRatio = static_cast<float>(originalCoverSize.first) / originalCoverSize.second;
}
comic.parentId = _currentPathFolders.last().id;
DBHelper::insert(&comic,_database);
}
@ -631,6 +648,7 @@ void ThumbnailCreator::create()
QImage p = pdfComic->page(_coverPage-1)->renderToImage(72,72);
#endif //
_cover = p;
_coverSize = QPair<int,int>(p.width(), p.height());
if(_target!="")
{
QImage scaled;
@ -642,7 +660,7 @@ void ThumbnailCreator::create()
{
scaled = p.scaledToWidth(480,Qt::SmoothTransformation);
}
scaled.save(_target,0,75);
scaled.save(_target,0,75);
}
else if(_target!="")
{
@ -708,6 +726,7 @@ void ThumbnailCreator::create()
QImage p;
if(p.loadFromData(archive.getRawDataAtIndex(index)))
{
_coverSize = QPair<int,int>(p.width(), p.height());
QImage scaled;
if(p.width()>p.height()) //landscape??
{

View File

@ -78,6 +78,7 @@
QString _target;
QString _currentName;
int _numPages;
QPair<int,int> _coverSize;
QImage _cover;
int _coverPage;
static bool crash;
@ -86,6 +87,7 @@
void create();
int getNumPages(){return _numPages;}
QPixmap getCover(){return QPixmap::fromImage(_cover);}
QPair<int,int> getOriginalCoverSize(){return _coverSize;}
signals:
void openingError(QProcess::ProcessError error);

View File

@ -19,6 +19,8 @@
#include <iterator>
#include <typeinfo>
#include <thread>
#include <future>
#include "data_base_management.h"
#include "yacreader_global.h"
@ -1124,6 +1126,15 @@ void LibraryWindow::createConnections()
//save covers
connect(saveCoversToAction,SIGNAL(triggered()),this,SLOT(saveSelectedCoversTo()));
//upgrade library
connect(this, SIGNAL(libraryUpgraded(QString)), this, SLOT(loadLibrary(QString)), Qt::QueuedConnection);
connect(this, SIGNAL(errorUpgradingLibrary(QString)), this, SLOT(showErrorUpgradingLibrary(QString)), Qt::QueuedConnection);
}
void LibraryWindow::showErrorUpgradingLibrary(const QString & path)
{
QMessageBox::critical(this,tr("Upgrade failed"), tr("There were errors during library upgrade in: ") + path+"/library.ydb");
}
void LibraryWindow::loadLibrary(const QString & name)
@ -1139,29 +1150,39 @@ void LibraryWindow::loadLibrary(const QString & name)
if(d.exists(path) && d.exists(path+"/library.ydb") && (dbVersion = DataBaseManagement::checkValidDB(path+"/library.ydb")) != "") //si existe en disco la biblioteca seleccionada, y es válida..
{
int comparation = DataBaseManagement::compareVersions(dbVersion,VERSION);
bool updated = false;
if(comparation < 0)
{
int ret = QMessageBox::question(this,tr("Update needed"),tr("This library was created with a previous version of YACReaderLibrary. It needs to be updated. Update now?"),QMessageBox::Yes,QMessageBox::No);
if(ret == QMessageBox::Yes)
{
updated = DataBaseManagement::updateToCurrentVersion(path+"/library.ydb");
if(!updated)
QMessageBox::critical(this,tr("Update failed"), tr("The current library can't be udpated. Check for write write permissions on: ") + path+"/library.ydb");
}
else
{
comicsViewsManager->comicsView->setModel(NULL);
foldersView->setModel(NULL);
listsView->setModel(NULL);
disableAllActions();//TODO comprobar que se deben deshabilitar
//será possible renombrar y borrar estas bibliotecas
renameLibraryAction->setEnabled(true);
removeLibraryAction->setEnabled(true);
}
}
if(comparation == 0 || updated) //en caso de que la versión se igual que la actual
if(comparation < 0)
{
int ret = QMessageBox::question(this,tr("Update needed"),tr("This library was created with a previous version of YACReaderLibrary. It needs to be updated. Update now?"),QMessageBox::Yes,QMessageBox::No);
if(ret == QMessageBox::Yes)
{
importWidget->setUpgradeLook();
showImportingWidget();
upgradeLibraryFuture = std::async(std::launch::async, [this, name, path] {
bool updated = DataBaseManagement::updateToCurrentVersion(path);
if(!updated)
emit errorUpgradingLibrary(path);
emit libraryUpgraded(name);
});
return;
}
else
{
comicsViewsManager->comicsView->setModel(NULL);
foldersView->setModel(NULL);
listsView->setModel(NULL);
disableAllActions();//TODO comprobar que se deben deshabilitar
//será possible renombrar y borrar estas bibliotecas
renameLibraryAction->setEnabled(true);
removeLibraryAction->setEnabled(true);
}
}
if(comparation == 0) //en caso de que la versión se igual que la actual
{
foldersModel->setupModelData(path);
foldersModelProxy->setSourceModel(foldersModel);
@ -1242,7 +1263,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);
@ -2487,7 +2508,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);
@ -2500,6 +2521,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

@ -12,6 +12,8 @@
#include "yacreader_navigation_controller.h"
#include <future>
#ifdef Q_OS_MAC
#include "yacreader_macosx_toolbar.h"
#endif
@ -286,6 +288,9 @@ protected:
public:
LibraryWindow();
signals:
void libraryUpgraded(const QString & libraryName);
void errorUpgradingLibrary(const QString & path);
public slots:
void loadLibrary(const QString & path);
void selectSubfolder(const QModelIndex & mi, int child);
@ -377,6 +382,7 @@ public slots:
void setToolbarTitle(const QModelIndex & modelIndex);
void saveSelectedCoversTo();
void checkMaxNumLibraries();
void showErrorUpgradingLibrary(const QString & path);
void changeEvent(QEvent *event);
@ -385,10 +391,11 @@ private:
Qt::WindowFlags previousWindowFlags;
QPoint previousPos;
QSize previousSize;
std::future<void> upgradeLibraryFuture;
QSystemTrayIcon trayIcon;
private slots:
void trayActivation(QSystemTrayIcon::ActivationReason reason);
};
#endif

View File

@ -757,15 +757,24 @@ void PropertiesDialog::save()
itr->info.edited = edited;
}
updateComics();
if(comics.count() == 1)
{
if(coverChanged)// && coverPageEdit->text().toInt() != *comics[0].info.coverPage)
{
ThumbnailCreator tc(basePath+comics[0].path,basePath+"/.yacreaderlibrary/covers/"+comics[0].info.hash+".jpg", comics[0].info.coverPage.toInt());
tc.create();
if(tc.getOriginalCoverSize().second > 0)
{
comics[0].info.originalCoverSize = QString("%1x%2").arg(tc.getOriginalCoverSize().first).arg(tc.getOriginalCoverSize().second);
comics[0].info.coverSizeRatio = static_cast<float>(tc.getOriginalCoverSize().first) / tc.getOriginalCoverSize().second;
}
}
}
updateComics();
close();
emit(accepted());
}

View File

@ -114,6 +114,8 @@ class QToolButton;
void updateCoverPageNumberLabel(int n);
bool coverChanged;
float coverSizeRatio;
QString originalCoverSize;
public:
PropertiesDialog(QWidget * parent = 0);

View File

@ -1,62 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "dumpcontroller.h"
#include <QVariant>
#include <QDateTime>
DumpController::DumpController(){}
void DumpController::service(HttpRequest& request, HttpResponse& response) {
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
response.setCookie(HttpCookie("firstCookie","hello",600));
response.setCookie(HttpCookie("secondCookie","world",600));
QByteArray body("<html><body>");
body.append("<b>Request:</b>");
body.append("<br>Method: ");
body.append(request.getMethod());
body.append("<br>Path: ");
body.append(request.getPath());
body.append("<br>Version: ");
body.append(request.getVersion());
body.append("<p><b>Headers:</b>");
QMapIterator<QByteArray,QByteArray> i(request.getHeaderMap());
while (i.hasNext()) {
i.next();
body.append("<br>");
body.append(i.key());
body.append("=");
body.append(i.value());
}
body.append("<p><b>Parameters:</b>");
i=QMapIterator<QByteArray,QByteArray>(request.getParameterMap());
while (i.hasNext()) {
i.next();
body.append("<br>");
body.append(i.key());
body.append("=");
body.append(i.value());
}
body.append("<p><b>Cookies:</b>");
i=QMapIterator<QByteArray,QByteArray>(request.getCookieMap());
while (i.hasNext()) {
i.next();
body.append("<br>");
body.append(i.key());
body.append("=");
body.append(i.value());
}
body.append("<p><b>Body:</b><br>");
body.append(request.getBody());
body.append("</body></html>");
response.write(body,true);
}

View File

@ -1,29 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef DUMPCONTROLLER_H
#define DUMPCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
This controller dumps the received HTTP request in the response.
*/
class DumpController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(DumpController);
public:
/** Constructor */
DumpController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // DUMPCONTROLLER_H

View File

@ -1,38 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "fileuploadcontroller.h"
FileUploadController::FileUploadController() {}
void FileUploadController::service(HttpRequest& request, HttpResponse& response) {
if (request.getParameter("action")=="show") {
response.setHeader("Content-Type", "image/jpeg");
QTemporaryFile* file=request.getUploadedFile("file1");
if (file) {
while (!file->atEnd() && !file->error()) {
QByteArray buffer=file->read(65536);
response.write(buffer);
}
}
else {
response.write("upload failed");
}
}
else {
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
response.write("<html><body>");
response.write("Upload a JPEG image file<p>");
response.write("<form method=\"post\" enctype=\"multipart/form-data\">");
response.write(" <input type=\"hidden\" name=\"action\" value=\"show\">");
response.write(" File: <input type=\"file\" name=\"file1\"><br>");
response.write(" <input type=\"submit\">");
response.write("</form>");
response.write("</body></html>",true);
}
}

View File

@ -1,30 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef FILEUPLOADCONTROLLER_H
#define FILEUPLOADCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
This controller displays a HTML form for file upload and recieved the file.
*/
class FileUploadController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(FileUploadController);
public:
/** Constructor */
FileUploadController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // FILEUPLOADCONTROLLER_H

View File

@ -1,64 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "formcontroller.h"
#include <QStringList>
FormController::FormController() {}
void FormController::service(HttpRequest& request, HttpResponse& response) {
response.setHeader("Content-Type", "text/html; charset=utf-8");
QString data(request.getBody());
QStringList list = data.split("\n");
response.write("<html><body>");
response.writeText("á é í ó ú ñ -> \\ /Device type: "+list.first());
//test background proccesing
/*int i=0;
int j=0;
while(i<1000000000)
{
if(request.getBody().length()>1)
j++;
else
i++;
if(i%1000000 == 0)
response.write("<p> lista </p>");
}*/
response.write("<p> lista </p>");
response.write("<ul>");
for(int i=1;i<list.length();i++)
{
response.writeText("<li>"+list.at(i)+"</li>");
}
response.write("</ul></body></html>",true);
/*if (request.getParameter("action")=="show") {
response.write("<html><body>");
response.write("Name = ");
response.write(request.getParameter("name"));
response.write("<br>City = ");
response.write(request.getParameter("city"));
response.write("</body></html>",true);
}
else {
response.write("<html><body>");
response.write("<form method=\"post\">");
response.write(" <input type=\"hidden\" name=\"action\" value=\"show\">");
response.write(" Name: <input type=\"text\" name=\"name\"><br>");
response.write(" City: <input type=\"text\" name=\"city\"><br>");
response.write(" <input type=\"submit\">");
response.write("</form>");
response.write("</body></html>",true);
}*/
}

View File

@ -1,40 +0,0 @@
#include "librariescontroller.h"
#include "db_helper.h" //get libraries
#include "yacreader_libraries.h"
#include "template.h"
#include "../static.h"
#include "QsLog.h"
LibrariesController::LibrariesController() {}
void LibrariesController::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
response.setHeader("Content-Type", "text/html; charset=utf-8");
response.setHeader("Connection","close");
session.clearNavigationPath();
Template t=Static::templateLoader->getTemplate("libraries_"+session.getDeviceType(),request.getHeader("Accept-Language"));
t.enableWarnings();
YACReaderLibraries libraries = DBHelper::getLibraries();
QList<QString> names = DBHelper::getLibrariesNames();
t.loop("library",names.length());
int currentId = 0;
int i = 0;
foreach (QString name,names) {
currentId = libraries.getId(name);
t.setVariable(QString("library%1.name").arg(i),QString::number(currentId));
t.setVariable(QString("library%1.label").arg(i),name);
i++;
}
response.setStatus(200,"OK");
response.writeText(t,true);
}

View File

@ -1,29 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef SESSIONCONTROLLER_H
#define SESSIONCONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
This controller demonstrates how to use sessions.
*/
class SessionController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(SessionController);
public:
/** Constructor */
SessionController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // SESSIONCONTROLLER_H

View File

@ -1,31 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "templatecontroller.h"
#include "template.h"
#include "../static.h"
TemplateController::TemplateController(){}
void TemplateController::service(HttpRequest& request, HttpResponse& response) {
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
Template t=Static::templateLoader->getTemplate("demo",request.getHeader("Accept-Language"));
t.enableWarnings();
t.setVariable("path",request.getPath());
QMap<QByteArray,QByteArray> headers=request.getHeaderMap();
QMapIterator<QByteArray,QByteArray> iterator(headers);
t.loop("header",headers.size());
int i=0;
while (iterator.hasNext()) {
iterator.next();
t.setVariable(QString("header%1.name").arg(i),QString(iterator.key()));
t.setVariable(QString("header%1.value").arg(i),QString(iterator.value()));
++i;
}
response.write(t.toLatin1(),true);
}

View File

@ -1,30 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef TEMPLATECONTROLLER_H
#define TEMPLATECONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
/**
This controller generates a website using the template engine.
It generates a Latin1 (ISO-8859-1) encoded website from a UTF-8 encoded template file.
*/
class TemplateController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(TemplateController);
public:
/** Constructor */
TemplateController();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // TEMPLATECONTROLLER_H

View File

@ -0,0 +1,124 @@
#include "comiccontroller.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "yacreader_http_session.h"
#include "template.h"
#include "../static.h"
#include "comic_db.h"
#include "comic.h"
#include "QsLog.h"
#include <typeinfo>
ComicController::ComicController() {}
void ComicController::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
qulonglong libraryId = pathElements.at(2).toLongLong();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong comicId = pathElements.at(4).toULongLong();
bool remoteComic = path.endsWith("remote");
//TODO
//if(pathElements.size() == 6)
//{
// QString action = pathElements.at(5);
// if(!action.isEmpty() && (action == "close"))
// {
// session.dismissCurrentComic();
// response.write("",true);
// return;
// }
//}
YACReaderLibraries libraries = DBHelper::getLibraries();
ComicDB comic = DBHelper::getComicInfo(libraryId, comicId);
if(!remoteComic)
ySession->setDownloadedComic(comic.info.hash);
Comic * comicFile = FactoryComic::newComic(libraries.getPath(libraryId)+comic.path);
if(comicFile != NULL)
{
QThread * thread = NULL;
thread = new QThread();
comicFile->moveToThread(thread);
connect(comicFile, SIGNAL(errorOpening()), thread, SLOT(quit()));
connect(comicFile, SIGNAL(errorOpening(QString)), thread, SLOT(quit()));
connect(comicFile, SIGNAL(imagesLoaded()), thread, SLOT(quit()));
connect(thread, SIGNAL(started()), comicFile, SLOT(process()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
comicFile->load(libraries.getPath(libraryId)+comic.path);
if(thread != NULL)
thread->start();
if(remoteComic)
{
QLOG_TRACE() << "remote comic requested";
ySession->setCurrentRemoteComic(comic.id, comicFile);
}
else
{
QLOG_TRACE() << "comic requested";
ySession->setCurrentComic(comic.id, comicFile);
}
response.setHeader("Content-Type", "text/plain; charset=utf-8");
//TODO this field is not used by the client!
response.write(QString("library:%1\r\n").arg(libraryName).toUtf8());
response.write(QString("libraryId:%1\r\n").arg(libraryId).toUtf8());
if(remoteComic) //send previous and next comics id
{
QList<LibraryItem *> siblings = DBHelper::getFolderComicsFromLibrary(libraryId, comic.parentId, true);
bool found = false;
int i;
for(i = 0; i < siblings.length(); i++)
{
if (siblings.at(i)->id == comic.id)
{
found = true;
break;
}
}
if(found)
{
if(i>0)
response.write(QString("previousComic:%1\r\n").arg(siblings.at(i-1)->id).toUtf8());
if(i<siblings.length()-1)
response.write(QString("nextComic:%1\r\n").arg(siblings.at(i+1)->id).toUtf8());
}
else
{
//ERROR
}
qDeleteAll(siblings);
}
response.write(comic.toTXT().toUtf8(),true);
}
else
{
//delete comicFile;
response.setStatus(404,"not found");
response.write("404 not found",true);
}
//response.write(t.toLatin1(),true);
}

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('/');
@ -21,6 +21,6 @@ void ComicDownloadInfoController::service(HttpRequest& request, HttpResponse& re
ComicDB comic = DBHelper::getComicInfo(libraryId, comicId);
//TODO: check if the comic wasn't found;
response.writeText(QString("fileName:%1\r\n").arg(comic.getFileName()));
response.writeText(QString("fileSize:%1\r\n").arg(comic.getFileSize()),true);
response.write(QString("fileName:%1\r\n").arg(comic.getFileName()).toUtf8());
response.write(QString("fileSize:%1\r\n").arg(comic.getFileSize()).toUtf8(),true);
}

View File

@ -0,0 +1,89 @@
#include "covercontroller.h"
#include "db_helper.h" //get libraries
#include "yacreader_libraries.h"
#include "yacreader_http_session.h"
#include "template.h"
#include "../static.h"
CoverController::CoverController() {}
void CoverController::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Connection","close");
//response.setHeader("Content-Type", "plain/text; charset=ISO-8859-1");
YACReaderLibraries libraries = DBHelper::getLibraries();
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
QString libraryName = DBHelper::getLibraryName(pathElements.at(2).toInt());
QString fileName = pathElements.at(4);
bool folderCover = request.getParameter("folderCover").length()>0;
//response.writeText(path+"<br/>");
//response.writeText(libraryName+"<br/>");
//response.writeText(libraries.value(libraryName)+"/.yacreaderlibrary/covers/"+fileName+"<br/>");
//QFile file(libraries.value(libraryName)+"/.yacreaderlibrary/covers/"+fileName);
//if (file.exists()) {
// if (file.open(QIODevice::ReadOnly))
// {
// qDebug("StaticFileController: Open file %s",qPrintable(file.fileName()));
// // Return the file content, do not store in cache
// while (!file.atEnd() && !file.error()) {
// response.write(file.read(131072));
// }
// }
// file.close();
//}
QImage img(libraries.getPath(libraryName)+"/.yacreaderlibrary/covers/"+fileName);
if (!img.isNull()) {
int width = 80, height = 120;
if(ySession->getDisplayType()=="@2x")
{
width = 160;
height = 240;
}
if(float(img.width())/img.height() < 0.66666)
img = img.scaledToWidth(width,Qt::SmoothTransformation);
else
img = img.scaledToHeight(height,Qt::SmoothTransformation);
QImage destImg(width,height,QImage::Format_RGB32);
destImg.fill(Qt::black);
QPainter p(&destImg);
p.drawImage((width-img.width())/2,(height-img.height())/2,img);
if(folderCover)
{
if(ySession->getDisplayType()=="@2x")
p.drawImage(0,0,QImage(":/images/f_overlayed_retina.png"));
else
p.drawImage(0,0,QImage(":/images/f_overlayed.png"));
}
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
destImg.save(&buffer, "JPG");
response.write(ba,true);
}
//DONE else, hay que devolver un 404
else
{
response.setStatus(404,"not found");
response.write("404 not found",true);
}
}

View File

@ -1,5 +1,7 @@
#include "foldercontroller.h"
#include "controllers/errorcontroller.h"
#include "controllers/v1/errorcontroller.h"
#include "yacreader_http_session.h"
#include "db_helper.h" //get libraries
#include "comic_db.h"
@ -32,6 +34,7 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
bool showlessInfoPerFolder = settings->value(REMOTE_BROWSE_PERFORMANCE_WORKAROUND,false).toBool();
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
response.setHeader("Content-Type", "text/html; charset=utf-8");
response.setHeader("Connection","close");
@ -39,7 +42,7 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
//QString y = session.get("xxx").toString();
//response.writeText(QString("session xxx : %1 <br/>").arg(y));
Template t=Static::templateLoader->getTemplate("folder_"+session.getDeviceType(),request.getHeader("Accept-Language"));
Template t=Static::templateLoader->getTemplate("folder_"+ySession->getDeviceType(),request.getHeader("Accept-Language"));
t.enableWarnings();
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
@ -91,17 +94,17 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
if(folderId == 1)
{
session.clearNavigationPath();
session.pushNavigationItem(QPair<qulonglong,quint32>(folderId,page));
ySession->clearNavigationPath();
ySession->pushNavigationItem(QPair<qulonglong,quint32>(folderId,page));
t.setVariable(QString("upurl"),"/");
}
else
{
if(fromUp)
session.popNavigationItem();
ySession->popNavigationItem();
else //drill down or direct access
{
QStack<QPair<qulonglong, quint32> > path = session.getNavigationPath();
QStack<QPair<qulonglong, quint32> > path = ySession->getNavigationPath();
bool found=false;
for(QStack<QPair<qulonglong, quint32> >::const_iterator itr = path.begin(); itr!=path.end(); itr++)
if(itr->first == folderId)
@ -112,16 +115,16 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
if(found)
{
while(session.topNavigationItem().first != folderId)
session.popNavigationItem();
while(ySession->topNavigationItem().first != folderId)
ySession->popNavigationItem();
session.updateTopItem(QPair<qulonglong,quint32>(folderId,page));
ySession->updateTopItem(QPair<qulonglong,quint32>(folderId,page));
}
else
session.pushNavigationItem(QPair<qulonglong,quint32>(folderId,page));
ySession->pushNavigationItem(QPair<qulonglong,quint32>(folderId,page));
}
QStack<QPair<qulonglong, quint32> > path = session.getNavigationPath();
QStack<QPair<qulonglong, quint32> > path = ySession->getNavigationPath();
if(path.count()>1)
{
QPair<qulonglong, quint32> parentItem = path.at(path.count()-2);
@ -152,7 +155,7 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
int numFoldersAtCurrentPage = qMax(0,qMin(numFolders - indexCurrentPage, elementsPerPage));
//PATH
QStack<QPair<qulonglong,quint32> > foldersPath = session.getNavigationPath();
QStack<QPair<qulonglong,quint32> > foldersPath = ySession->getNavigationPath();
t.setVariable(QString("library.name"),libraryName);
t.setVariable(QString("library.url"),QString("/library/%1/folder/1").arg(libraryId));
t.loop("path",foldersPath.count()-1);
@ -208,9 +211,9 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
const ComicDB * comic = (ComicDB *)item;
t.setVariable(QString("element%1.browse").arg(i),"");
//t.setVariable(QString("element%1.downloadurl").arg(i),"/library/"+libraryName+"/comic/"+QString("%1").arg(comic->id));
if(!session.isComicOnDevice(comic->info.hash) && !session.isComicDownloaded(comic->info.hash))
if(!ySession->isComicOnDevice(comic->info.hash) && !ySession->isComicDownloaded(comic->info.hash))
t.setVariable(QString("element%1.download").arg(i),QString("<a onclick=\"this.innerHTML='IMPORTING';this.className='importedButton';\" class =\"importButton\" href=\"%1\">IMPORT</a>").arg("/library/"+QString::number(libraryId)+"/comic/"+QString("%1").arg(comic->id)));
else if (session.isComicOnDevice(comic->info.hash))
else if (ySession->isComicOnDevice(comic->info.hash))
t.setVariable(QString("element%1.download").arg(i),QString("<div class=\"importedButton\">IMPORTED</div>"));
else
t.setVariable(QString("element%1.download").arg(i),QString("<div class=\"importedButton\">IMPORTING</div>"));
@ -329,6 +332,6 @@ void FolderController::service(HttpRequest& request, HttpResponse& response)
t.setVariable("page",QString("%1").arg(page+1));
t.setVariable("pages",QString("%1").arg(numPages));
response.writeText(t, true);
response.write(t.toUtf8(), true);
}

View File

@ -12,17 +12,17 @@ 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('/');
int libraryId = pathElements.at(2).toInt();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong parentId = pathElements.at(4).toULongLong();
QStringList pathElements = path.split('/');
int libraryId = pathElements.at(2).toInt();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong parentId = pathElements.at(4).toULongLong();
serviceComics(libraryId, parentId, response);
response.writeText("",true);
response.write("",true);
}
void FolderInfoController::serviceComics(const int &library, const qulonglong &folderId, HttpResponse &response)
@ -34,7 +34,7 @@ void FolderInfoController::serviceComics(const int &library, const qulonglong &f
for(QList<LibraryItem *>::const_iterator itr = folderComics.constBegin();itr!=folderComics.constEnd();itr++)
{
currentComic = (ComicDB *)(*itr);
response.writeText(QString("/library/%1/comic/%2:%3:%4\r\n").arg(library).arg(currentComic->id).arg(currentComic->getFileName()).arg(currentComic->getFileSize()));
response.write(QString("/library/%1/comic/%2:%3:%4\r\n").arg(library).arg(currentComic->id).arg(currentComic->getFileName()).arg(currentComic->getFileSize()).toUtf8());
delete currentComic;
}

View File

@ -0,0 +1,42 @@
#include "librariescontroller.h"
#include "db_helper.h" //get libraries
#include "yacreader_libraries.h"
#include "yacreader_http_session.h"
#include "template.h"
#include "../static.h"
#include "QsLog.h"
LibrariesController::LibrariesController() {}
void LibrariesController::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
response.setHeader("Content-Type", "text/html; charset=utf-8");
response.setHeader("Connection","close");
ySession->clearNavigationPath();
Template t=Static::templateLoader->getTemplate("libraries_"+ySession->getDeviceType(),request.getHeader("Accept-Language"));
t.enableWarnings();
YACReaderLibraries libraries = DBHelper::getLibraries();
QList<QString> names = DBHelper::getLibrariesNames();
t.loop("library",names.length());
int currentId = 0;
int i = 0;
foreach (QString name,names) {
currentId = libraries.getId(name);
t.setVariable(QString("library%1.name").arg(i),QString::number(currentId));
t.setVariable(QString("library%1.label").arg(i),name);
i++;
}
response.setStatus(200,"OK");
response.write(t.toUtf8(),true);
}

View File

@ -0,0 +1,99 @@
#include "pagecontroller.h"
#include "../static.h"
#include "comic.h"
#include "comiccontroller.h"
#include "yacreader_http_session.h"
#include <QDataStream>
#include <QPointer>
#include <QsLog.h>
#include "db_helper.h"
PageController::PageController() {}
void PageController::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
bool remote = path.endsWith("remote");
//QByteArray path2=request.getPath();
//qDebug("PageController: request to -> %s ",path2.data());
QStringList pathElements = path.split('/');
QString libraryName = DBHelper::getLibraryName(pathElements.at(2).toInt());
qulonglong comicId = pathElements.at(4).toULongLong();
unsigned int page = pathElements.at(6).toUInt();
//qDebug("lib name : %s",pathElements.at(2).data());
Comic * comicFile;
qulonglong currentComicId;
if(remote)
{
QLOG_TRACE() << "se recupera comic remoto para servir páginas";
comicFile = ySession->getCurrentRemoteComic();
currentComicId = ySession->getCurrentRemoteComicId();
}
else
{
QLOG_TRACE() << "se recupera comic para servir páginas";
comicFile = ySession->getCurrentComic();
currentComicId = ySession->getCurrentComicId();
}
if(currentComicId != 0 && !QPointer<Comic>(comicFile).isNull())
{
if(comicId == currentComicId && page < comicFile->numPages())
{
if(comicFile->pageIsLoaded(page))
{
//qDebug("PageController: La página estaba cargada -> %s ",path.data());
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Transfer-Encoding","chunked");
QByteArray pageData = comicFile->getRawPage(page);
QDataStream data(pageData);
char buffer[4096];
while (!data.atEnd()) {
int len = data.readRawData(buffer,4096);
response.write(QByteArray(buffer,len));
}
//response.write(pageData,true);
response.write(QByteArray(),true);
}
else
{
//qDebug("PageController: La página NO estaba cargada 404 -> %s ",path.data());
response.setStatus(404,"not found"); //TODO qué mensaje enviar
response.write("404 not found",true);
}
}
else
{
if(comicId != currentComicId)
{
//delete comicFile;
if(remote)
ySession->dismissCurrentRemoteComic();
else
ySession->dismissCurrentComic();
}
response.setStatus(404,"not found"); //TODO qué mensaje enviar
response.write("404 not found",true);
}
}
else
{
response.setStatus(404,"not found");
response.write("404 not found",true);
}
//response.write(t.toLatin1(),true);
}

View File

@ -55,7 +55,7 @@ void SyncController::service(HttpRequest &request, HttpResponse &response)
else
{
response.setStatus(412,"No comic info received");
response.writeText("",true);
response.write("",true);
return;
}

View File

@ -9,7 +9,7 @@
class SyncController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(SyncController);
Q_DISABLE_COPY(SyncController)
public:
/** Constructor */
SyncController();

View File

@ -38,7 +38,7 @@ void UpdateComicController::service(HttpRequest &request, HttpResponse &response
else
{
response.setStatus(412,"No comic info received");
response.writeText("",true);
response.write("",true);
return;
}

View File

@ -1,7 +1,8 @@
#include "comiccontroller.h"
#include "comiccontroller_v2.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "yacreader_http_session.h"
#include "template.h"
#include "../static.h"
@ -13,17 +14,18 @@
#include <typeinfo>
ComicController::ComicController() {}
ComicControllerV2::ComicControllerV2() {}
void ComicController::service(HttpRequest& request, HttpResponse& response)
void ComicControllerV2::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
qulonglong libraryId = pathElements.at(2).toLongLong();
qulonglong libraryId = pathElements.at(3).toLongLong();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong comicId = pathElements.at(4).toULongLong();
qulonglong comicId = pathElements.at(5).toULongLong();
bool remoteComic = path.endsWith("remote");
@ -44,7 +46,7 @@ void ComicController::service(HttpRequest& request, HttpResponse& response)
ComicDB comic = DBHelper::getComicInfo(libraryId, comicId);
if(!remoteComic)
session.setDownloadedComic(comic.info.hash);
ySession->setDownloadedComic(comic.info.hash);
Comic * comicFile = FactoryComic::newComic(libraries.getPath(libraryId)+comic.path);
@ -70,19 +72,19 @@ void ComicController::service(HttpRequest& request, HttpResponse& response)
if(remoteComic)
{
QLOG_TRACE() << "remote comic requested";
session.setCurrentRemoteComic(comic.id, comicFile);
ySession->setCurrentRemoteComic(comic.id, comicFile);
}
else
{
QLOG_TRACE() << "comic requested";
session.setCurrentComic(comic.id, comicFile);
ySession->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));
response.write(QString("library:%1\r\n").arg(libraryName).toUtf8());
response.write(QString("libraryId:%1\r\n").arg(libraryId).toUtf8());
if(remoteComic) //send previous and next comics id
{
QList<LibraryItem *> siblings = DBHelper::getFolderComicsFromLibrary(libraryId, comic.parentId, true);
@ -99,9 +101,9 @@ void ComicController::service(HttpRequest& request, HttpResponse& response)
if(found)
{
if(i>0)
response.writeText(QString("previousComic:%1\r\n").arg(siblings.at(i-1)->id));
response.write(QString("previousComic:%1\r\n").arg(siblings.at(i-1)->id).toUtf8());
if(i<siblings.length()-1)
response.writeText(QString("nextComic:%1\r\n").arg(siblings.at(i+1)->id));
response.write(QString("nextComic:%1\r\n").arg(siblings.at(i+1)->id).toUtf8());
}
else
{
@ -109,7 +111,7 @@ void ComicController::service(HttpRequest& request, HttpResponse& response)
}
qDeleteAll(siblings);
}
response.writeText(comic.toTXT(),true);
response.write(comic.toTXT().toUtf8(),true);
}
else
{

View File

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

View File

@ -0,0 +1,27 @@
#include "comicdownloadinfocontroller_v2.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "comic_db.h"
ComicDownloadInfoControllerV2::ComicDownloadInfoControllerV2() {}
void ComicDownloadInfoControllerV2::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('/');
qulonglong libraryId = pathElements.at(3).toLongLong();
qulonglong comicId = pathElements.at(5).toULongLong();
ComicDB comic = DBHelper::getComicInfo(libraryId, comicId);
//TODO: check if the comic wasn't found;
response.write(QString("fileName:%1\r\n").arg(comic.getFileName()).toUtf8());
response.write(QString("fileSize:%1\r\n").arg(comic.getFileSize()).toUtf8());
response.write(QString("hash:%1\r\n").arg(comic.info.hash).toUtf8(),true);
}

View File

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

View File

@ -1,16 +1,17 @@
#include "covercontroller.h"
#include "covercontroller_v2.h"
#include "db_helper.h" //get libraries
#include "yacreader_libraries.h"
#include "yacreader_http_session.h"
#include "template.h"
#include "../static.h"
CoverController::CoverController() {}
CoverControllerV2::CoverControllerV2() {}
void CoverController::service(HttpRequest& request, HttpResponse& response)
void CoverControllerV2::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
response.setHeader("Content-Type", "image/jpeg");
response.setHeader("Connection","close");
@ -20,8 +21,8 @@ void CoverController::service(HttpRequest& request, HttpResponse& response)
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
QString libraryName = DBHelper::getLibraryName(pathElements.at(2).toInt());
QString fileName = pathElements.at(4);
QString libraryName = DBHelper::getLibraryName(pathElements.at(3).toInt());
QString fileName = pathElements.at(5);
bool folderCover = request.getParameter("folderCover").length()>0;
@ -46,8 +47,8 @@ void CoverController::service(HttpRequest& request, HttpResponse& response)
QImage img(libraries.getPath(libraryName)+"/.yacreaderlibrary/covers/"+fileName);
if (!img.isNull()) {
int width = 80, height = 120;
if(session.getDisplayType()=="@2x")
/*int width = 80, height = 120;
if(ySession->getDisplayType()=="@2x")
{
width = 160;
height = 240;
@ -66,16 +67,16 @@ void CoverController::service(HttpRequest& request, HttpResponse& response)
if(folderCover)
{
if(session.getDisplayType()=="@2x")
if(ySession->getDisplayType()=="@2x")
p.drawImage(0,0,QImage(":/images/f_overlayed_retina.png"));
else
p.drawImage(0,0,QImage(":/images/f_overlayed.png"));
}
*/
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
destImg.save(&buffer, "JPG");
img.save(&buffer, "JPG");
response.write(ba,true);
}
//DONE else, hay que devolver un 404

View File

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

View File

@ -0,0 +1,26 @@
#include "errorcontroller_v2.h"
#include "template.h"
#include "../static.h"
ErrorControllerV2::ErrorControllerV2(int errorCode)
:error(errorCode)
{}
void ErrorControllerV2::service(HttpRequest& request, HttpResponse& response)
{
Q_UNUSED(request)
switch(error)
{
case 300:
response.setStatus(300,"redirect");
response.write("<html> <head> <meta http-equiv=\"refresh\" content=\"0; URL=/\"> </head> <body> </body> </html>", true);
break;
case 404:
response.setStatus(404,"not found");
response.write("404 not found",true);
break;
}
}

View File

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

View File

@ -0,0 +1,33 @@
#include "favoritescontroller_v2.h"
#include "db_helper.h"
#include "comic_db.h"
#include "yacreader_server_data_helper.h"
FavoritesControllerV2::FavoritesControllerV2() {}
void FavoritesControllerV2::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(3).toInt();
serviceContent(libraryId, response);
response.write("",true);
}
void FavoritesControllerV2::serviceContent(const int library, HttpResponse &response)
{
QList<ComicDB> tagComics = DBHelper::getFavorites(library);
for(const ComicDB &comic : tagComics)
{
response.write(YACReaderServerDataHelper::comicToYSFormat(library, comic).toUtf8());
}
}

View File

@ -0,0 +1,21 @@
#ifndef FAVORITESCONTROLLER_V2_H
#define FAVORITESCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class FavoritesControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(FavoritesControllerV2)
public:
FavoritesControllerV2();
void service(HttpRequest& request, HttpResponse& response);
private:
void serviceContent(const int library, HttpResponse &response);
};
#endif // FAVORITESCONTROLLER_H

View File

@ -0,0 +1,72 @@
#include "foldercontentcontroller_v2.h"
#include <QUrl>
#include "db_helper.h"
#include "comic_db.h"
#include "folder.h"
#include "yacreader_server_data_helper.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);
}
};
FolderContentControllerV2::FolderContentControllerV2() {}
void FolderContentControllerV2::service(HttpRequest& request, HttpResponse& response)
{
response.setHeader("Content-Type", "application/json");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
int libraryId = pathElements.at(3).toInt();
qulonglong parentId = pathElements.at(5).toULongLong();
serviceContent(libraryId, parentId, response);
response.setStatus(200,"OK");
response.write("",true);
}
void FolderContentControllerV2::serviceContent(const int &library, const qulonglong &folderId, HttpResponse &response)
{
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();
QJsonArray items;
ComicDB * currentComic;
Folder * currentFolder;
for(QList<LibraryItem *>::const_iterator itr = folderContent.constBegin();itr!=folderContent.constEnd();itr++)
{
if((*itr)->isDir())
{
currentFolder = (Folder *)(*itr);
items.append(YACReaderServerDataHelper::folderToJSON(library, *currentFolder));
}
else
{
currentComic = (ComicDB *)(*itr);
items.append(YACReaderServerDataHelper::comicToJSON(library, *currentComic));
}
}
QJsonDocument output(items);
response.write(output.toJson());
}

View File

@ -0,0 +1,22 @@
#ifndef FOLDERCONTENTCONTROLLER_V2_H
#define FOLDERCONTENTCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class FolderContentControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(FolderContentControllerV2)
public:
/** Constructor */
FolderContentControllerV2();
/** 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

@ -0,0 +1,55 @@
#include "folderinfocontroller_v2.h"
#include "db_helper.h" //get libraries
#include "folder.h"
#include "comic_db.h"
#include "template.h"
#include "../static.h"
FolderInfoControllerV2::FolderInfoControllerV2() {}
void FolderInfoControllerV2::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(3).toInt();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong parentId = pathElements.at(5).toULongLong();
serviceComics(libraryId, parentId, response);
response.write("",true);
}
void FolderInfoControllerV2::serviceComics(const int &library, const qulonglong &folderId, HttpResponse &response)
{
QList<LibraryItem *> folderContent = DBHelper::getFolderSubfoldersFromLibrary(library,folderId);
QList<LibraryItem *> folderComics = DBHelper::getFolderComicsFromLibrary(library,folderId);
ComicDB * currentComic;
for(QList<LibraryItem *>::const_iterator itr = folderComics.constBegin();itr!=folderComics.constEnd();itr++)
{
currentComic = (ComicDB *)(*itr);
response.write(QString("/library/%1/comic/%2:%3:%4:%5:%6\r\n")
.arg(library)
.arg(currentComic->id)
.arg(currentComic->getFileName())
.arg(currentComic->getFileSize())
.arg(currentComic->info.read ? 1 : 0)
.arg(currentComic->info.hash)
.toUtf8());
delete currentComic;
}
Folder * currentFolder;
for(QList<LibraryItem *>::const_iterator itr = folderContent.constBegin();itr!=folderContent.constEnd();itr++)
{
currentFolder = (Folder *)(*itr);
serviceComics(library, currentFolder->id, response);
delete currentFolder;
}
}

View File

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

View File

@ -0,0 +1,39 @@
#include "librariescontroller_v2.h"
#include "db_helper.h" //get libraries
#include "yacreader_libraries.h"
#include "template.h"
#include "../static.h"
#include "QsLog.h"
LibrariesControllerV2::LibrariesControllerV2() {}
void LibrariesControllerV2::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
response.setHeader("Content-Type", "application/json");
response.setHeader("Connection","close");
YACReaderLibraries libraries = DBHelper::getLibraries();
QList<QString> names = DBHelper::getLibrariesNames();
QJsonArray librariesJson;
int currentId = 0;
foreach (QString name,names) {
currentId = libraries.getId(name);
QJsonObject library;
library["name"] = name;
library["id"] = currentId;
librariesJson.append(library);
}
QJsonDocument output(librariesJson);
response.setStatus(200,"OK");
response.write(output.toJson(),true);
}

View File

@ -1,10 +1,5 @@
/**
@file
@author Stefan Frings
*/
#ifndef FORMCONTROLLER_H
#define FORMCONTROLLER_H
#ifndef LIBRARIESCONTROLLER_V2_H
#define LIBRARIESCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
@ -15,16 +10,16 @@
*/
class FormController : public HttpRequestHandler {
class LibrariesControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(FormController);
Q_DISABLE_COPY(LibrariesControllerV2)
public:
/** Constructor */
FormController();
LibrariesControllerV2();
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
};
#endif // FORMCONTROLLER_H
#endif // LIBRARIESCONTROLLER_H

View File

@ -1,9 +1,11 @@
#include "pagecontroller.h"
#include "pagecontroller_v2.h"
#include "../static.h"
#include "comic.h"
#include "comiccontroller.h"
#include "yacreader_http_session.h"
#include <QDataStream>
#include <QPointer>
@ -11,11 +13,12 @@
#include "db_helper.h"
PageController::PageController() {}
PageControllerV2::PageControllerV2() {}
void PageController::service(HttpRequest& request, HttpResponse& response)
void PageControllerV2::service(HttpRequest& request, HttpResponse& response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
bool remote = path.endsWith("remote");
@ -25,8 +28,8 @@ void PageController::service(HttpRequest& request, HttpResponse& response)
QStringList pathElements = path.split('/');
QString libraryName = DBHelper::getLibraryName(pathElements.at(2).toInt());
qulonglong comicId = pathElements.at(4).toULongLong();
unsigned int page = pathElements.at(6).toUInt();
qulonglong comicId = pathElements.at(5).toULongLong();
unsigned int page = pathElements.at(7).toUInt();
//qDebug("lib name : %s",pathElements.at(2).data());
@ -35,14 +38,14 @@ void PageController::service(HttpRequest& request, HttpResponse& response)
if(remote)
{
QLOG_TRACE() << "se recupera comic remoto para servir páginas";
comicFile = session.getCurrentRemoteComic();
currentComicId = session.getCurrentRemoteComicId();
comicFile = ySession->getCurrentRemoteComic();
currentComicId = ySession->getCurrentRemoteComicId();
}
else
{
QLOG_TRACE() << "se recupera comic para servir páginas";
comicFile = session.getCurrentComic();
currentComicId = session.getCurrentComicId();
comicFile = ySession->getCurrentComic();
currentComicId = ySession->getCurrentComicId();
}
if(currentComicId != 0 && !QPointer<Comic>(comicFile).isNull())
@ -77,9 +80,9 @@ void PageController::service(HttpRequest& request, HttpResponse& response)
{
//delete comicFile;
if(remote)
session.dismissCurrentRemoteComic();
ySession->dismissCurrentRemoteComic();
else
session.dismissCurrentComic();
ySession->dismissCurrentComic();
}
response.setStatus(404,"not found"); //TODO qué mensaje enviar
response.write("404 not found",true);

View File

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

View File

@ -0,0 +1,41 @@
#include "readingcomicscontroller_v2.h"
#include "db_helper.h"
#include "comic_db.h"
#include "yacreader_server_data_helper.h"
ReadingComicsControllerV2::ReadingComicsControllerV2()
{
}
void ReadingComicsControllerV2::service(HttpRequest &request, HttpResponse &response)
{
response.setHeader("Content-Type", "application/json");
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
int libraryId = pathElements.at(3).toInt();
serviceContent(libraryId, response);
response.setStatus(200,"OK");
response.write("",true);
}
void ReadingComicsControllerV2::serviceContent(const int &library, HttpResponse &response)
{
QList<ComicDB> readingComics = DBHelper::getReading(library);
QJsonArray comics;
for(const ComicDB &comic : readingComics)
{
comics.append(YACReaderServerDataHelper::comicToJSON(library, comic));
}
QJsonDocument output(comics);
response.write(output.toJson());
}

View File

@ -0,0 +1,20 @@
#ifndef READINGCOMICSCONTROLLER_V2_H
#define READINGCOMICSCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class ReadingComicsControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(ReadingComicsControllerV2)
public:
ReadingComicsControllerV2();
void service(HttpRequest& request, HttpResponse& response);
private:
void serviceContent(const int &library, HttpResponse &response);
};
#endif // READINGCOMICSCONTROLLER_H

View File

@ -0,0 +1,35 @@
#include "readinglistcontentcontroller_v2.h"
#include "db_helper.h"
#include "comic_db.h"
#include "yacreader_server_data_helper.h"
ReadingListContentControllerV2::ReadingListContentControllerV2()
{
}
void ReadingListContentControllerV2::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(3).toInt();
qulonglong readingListId = pathElements.at(5).toULongLong();
serviceContent(libraryId, readingListId, response);
response.write("",true);
}
void ReadingListContentControllerV2::serviceContent(const int &library, const qulonglong &readingListId, HttpResponse &response)
{
QList<ComicDB> comics = DBHelper::getReadingListFullContent(library, readingListId);
for(const ComicDB &comic : comics)
{
response.write(YACReaderServerDataHelper::comicToYSFormat(library, comic).toUtf8());
}
}

View File

@ -0,0 +1,20 @@
#ifndef READINGLISTCONTENTCONTROLLER_V2_H
#define READINGLISTCONTENTCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class ReadingListContentControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(ReadingListContentControllerV2)
public:
ReadingListContentControllerV2();
void service(HttpRequest& request, HttpResponse& response);
private:
void serviceContent(const int &library, const qulonglong &readingListId, HttpResponse &response);
};
#endif // READINGLISTCONTENTCONTROLLER_H

View File

@ -0,0 +1,32 @@
#include "readinglistscontroller_v2.h"
#include "db_helper.h"
#include "reading_list.h"
ReadingListsControllerV2::ReadingListsControllerV2()
{
}
void ReadingListsControllerV2::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(3).toInt();
serviceContent(libraryId, response);
response.write("",true);
}
void ReadingListsControllerV2::serviceContent(const int library, HttpResponse &response)
{
QList<ReadingList> readingLists = DBHelper::getReadingLists(library);
foreach(const ReadingList &item, readingLists)
{
response.write(QString("%1\t%2\t%3\r\n").arg(library).arg(item.getId()).arg(item.getName()).toUtf8());
}
}

View File

@ -0,0 +1,20 @@
#ifndef READINGLISTSCONTROLLER_V2_H
#define READINGLISTSCONTROLLER_V2_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
class ReadingListsControllerV2 : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(ReadingListsControllerV2)
public:
ReadingListsControllerV2();
void service(HttpRequest& request, HttpResponse& response);
private:
void serviceContent(const int library, HttpResponse &response);
};
#endif // READINGLISTSCONTROLLER_H

View File

@ -0,0 +1,64 @@
#include "synccontroller_v2.h"
#include "QsLog.h"
#include <QUrl>
#include "comic_db.h"
#include "db_helper.h"
SyncControllerV2::SyncControllerV2()
{
}
void SyncControllerV2::service(HttpRequest &request, HttpResponse &response)
{
QString postData = QString::fromUtf8(request.getBody());
QLOG_TRACE() << "POST DATA: " << postData;
if(postData.length()>0) {
QList<QString> data = postData.split("\n");
qulonglong libraryId;
qulonglong comicId;
int currentPage;
int currentRating;
QString hash;
foreach(QString comicInfo, data)
{
QList<QString> comicInfoProgress = comicInfo.split("\t");
if(comicInfoProgress.length() == 4 || comicInfoProgress.length() == 5)
{
libraryId = comicInfoProgress.at(0).toULongLong();
comicId = comicInfoProgress.at(1).toULongLong();
hash = comicInfoProgress.at(2);
currentPage = comicInfoProgress.at(3).toInt();
ComicInfo info;
info.currentPage = currentPage;
info.hash = hash; //TODO remove the hash check and add UUIDs for libraries
info.id = comicId;
//Client 2.1+ version
if(comicInfoProgress.length() > 4)
{
currentRating = comicInfoProgress.at(4).toInt();
info.rating = currentRating;
}
DBHelper::updateFromRemoteClient(libraryId,info);
}
}
}
else
{
response.setStatus(412,"No comic info received");
response.write("",true);
return;
}
response.write("OK",true);
}

View File

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

View File

@ -0,0 +1,37 @@
#include "tagcontentcontroller_v2.h"
#include "db_helper.h"
#include "comic_db.h"
#include "yacreader_server_data_helper.h"
#include <QUrl>
TagContentControllerV2::TagContentControllerV2()
{
}
void TagContentControllerV2::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(3).toInt();
qulonglong tagId = pathElements.at(5).toULongLong();
serviceContent(libraryId, tagId, response);
response.write("",true);
}
void TagContentControllerV2::serviceContent(const int &library, const qulonglong &tagId, HttpResponse &response)
{
QList<ComicDB> tagComics = DBHelper::getLabelComics(library, tagId);
for(const ComicDB &comic : tagComics)
{
response.write(YACReaderServerDataHelper::comicToYSFormat(library, comic).toUtf8());
}
}

View File

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

View File

@ -0,0 +1,30 @@
#include "tagscontroller_v2.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "reading_list.h"
#include "../static.h"
#include "yacreader_global.h"
#include "QsLog.h"
TagsControllerV2::TagsControllerV2() {}
void TagsControllerV2::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(3).toInt();
QList<Label> tags = DBHelper::getLabels(libraryId);
foreach(const Label &tag, tags)
{
response.write(QString("%1\t%2\t%3\t%4\r\n").arg(libraryId).arg(tag.getId()).arg(tag.getName()).arg(labelColorToRGBString(tag.getColorID())).toUtf8());
}
response.write("",true);
}

View File

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

View File

@ -0,0 +1,46 @@
#include "updatecomiccontroller_v2.h"
#include "db_helper.h"
#include "yacreader_libraries.h"
#include "template.h"
#include "../static.h"
#include "comic_db.h"
#include "comic.h"
#include "QsLog.h"
UpdateComicControllerV2::UpdateComicControllerV2(){}
void UpdateComicControllerV2::service(HttpRequest &request, HttpResponse &response)
{
HttpSession session=Static::sessionStore->getSession(request,response,false);
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
qulonglong libraryId = pathElements.at(3).toULongLong();
QString libraryName = DBHelper::getLibraryName(libraryId);
qulonglong comicId = pathElements.at(5).toULongLong();
QString postData = QString::fromUtf8(request.getBody());
QLOG_TRACE() << "POST DATA: " << postData;
if(postData.length()>0) {
QList<QString> data = postData.split("\n");
int currentPage = data.at(0).split(":").at(1).toInt();
ComicInfo info;
info.currentPage = currentPage;
info.id = comicId;
DBHelper::updateProgress(libraryId,info);
}
else
{
response.setStatus(412,"No comic info received");
response.write("",true);
return;
}
response.write("OK",true);
}

View File

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

View File

@ -0,0 +1,10 @@
#include "versioncontroller.h"
VersionController::VersionController() {}
void VersionController::service(HttpRequest& request, HttpResponse& response)
{
Q_UNUSED(request);
response.write(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

@ -1,12 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/httplistener.h $$PWD/httpconnectionhandler.h $$PWD/httpconnectionhandlerpool.h $$PWD/httprequest.h $$PWD/httpresponse.h $$PWD/httpcookie.h $$PWD/httprequesthandler.h
HEADERS += $$PWD/httpsession.h $$PWD/httpsessionstore.h
HEADERS += $$PWD/staticfilecontroller.h
SOURCES += $$PWD/httplistener.cpp $$PWD/httpconnectionhandler.cpp $$PWD/httpconnectionhandlerpool.cpp $$PWD/httprequest.cpp $$PWD/httpresponse.cpp $$PWD/httpcookie.cpp $$PWD/httprequesthandler.cpp
SOURCES += $$PWD/httpsession.cpp $$PWD/httpsessionstore.cpp
SOURCES += $$PWD/staticfilecontroller.cpp
OTHER_FILES += $$PWD/../doc/readme.txt

View File

@ -1,170 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "httpconnectionhandler.h"
#include "httpresponse.h"
#include <QTimer>
#include <QCoreApplication>
HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler)
: QThread()
{
Q_ASSERT(settings!=0);
Q_ASSERT(requestHandler!=0);
this->settings=settings;
this->requestHandler=requestHandler;
currentRequest=0;
busy = false;
// execute signals in my own thread
moveToThread(this);
socket.moveToThread(this);
readTimer.moveToThread(this);
connect(&socket, SIGNAL(readyRead()), SLOT(read()));
connect(&socket, SIGNAL(disconnected()), SLOT(disconnected()));
connect(&readTimer, SIGNAL(timeout()), SLOT(readTimeout()));
readTimer.setSingleShot(true);
qDebug("HttpConnectionHandler (%p): constructed", this);
this->start();
}
HttpConnectionHandler::~HttpConnectionHandler() {
socket.close();
quit();
wait();
qDebug("HttpConnectionHandler (%p): destroyed", this);
}
void HttpConnectionHandler::run() {
qDebug("HttpConnectionHandler (%p): thread started", this);
try {
exec();
}
catch (...) {
qCritical("HttpConnectionHandler (%p): an uncatched exception occured in the thread",this);
}
qDebug("HttpConnectionHandler (%p): thread stopped", this);
// Change to the main thread, otherwise deleteLater() would not work
moveToThread(QCoreApplication::instance()->thread());
}
void HttpConnectionHandler::handleConnection(tSocketDescriptor socketDescriptor) {
qDebug("HttpConnectionHandler (%p): handle new connection", this);
busy = true;
Q_ASSERT(socket.isOpen()==false); // if not, then the handler is already busy
if (!socket.setSocketDescriptor(socketDescriptor)) {
qCritical("HttpConnectionHandler (%p): cannot initialize socket: %s", this,qPrintable(socket.errorString()));
return;
}
// Start timer for read timeout
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
// delete previous request
delete currentRequest;
currentRequest=0;
}
bool HttpConnectionHandler::isBusy() {
return busy;
}
void HttpConnectionHandler::setBusy() {
this->busy = true;
}
void HttpConnectionHandler::readTimeout() {
qDebug("HttpConnectionHandler (%p): read timeout occured",this);
//Commented out because QWebView cannot handle this.
//socket.write("HTTP/1.1 408 request timeout\r\nConnection: close\r\n\r\n408 request timeout\r\n");
socket.disconnectFromHost();
delete currentRequest;
currentRequest=0;
}
void HttpConnectionHandler::disconnected() {
qDebug("HttpConnectionHandler (%p): disconnected", this);
socket.close();
readTimer.stop();
busy = false;
}
void HttpConnectionHandler::read() {
while (socket.bytesAvailable()) {
#ifdef SUPERVERBOSE
qDebug("HttpConnectionHandler (%p): read input",this);
#endif
// Create new HttpRequest object if necessary
if (!currentRequest) {
currentRequest=new HttpRequest(settings);
}
// Collect data for the request object
while (socket.bytesAvailable() && currentRequest->getStatus()!=HttpRequest::complete && currentRequest->getStatus()!=HttpRequest::abort) {
currentRequest->readFromSocket(socket);
if (currentRequest->getStatus()==HttpRequest::waitForBody) {
// Restart timer for read timeout, otherwise it would
// expire during large file uploads.
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
}
}
// If the request is aborted, return error message and close the connection
if (currentRequest->getStatus()==HttpRequest::abort) {
socket.write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
socket.disconnectFromHost();
delete currentRequest;
currentRequest=0;
return;
}
// If the request is complete, let the request mapper dispatch it
if (currentRequest->getStatus()==HttpRequest::complete) {
readTimer.stop();
qDebug("HttpConnectionHandler (%p): received request",this);
HttpResponse response(&socket);
//response.setHeader("Connection","close"); No funciona bien con NSURLConnection
try {
requestHandler->service(*currentRequest, response);
}
catch (...) {
qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",this);
}
// Finalize sending the response if not already done
if (!response.hasSentLastPart()) {
response.write(QByteArray(),true);
}
//socket.disconnectFromHost(); //CAMBIADO sólo se van a soportar conexiones NO persistentes
// Close the connection after delivering the response, if requested
if (QString::compare(currentRequest->getHeader("Connection"),"close",Qt::CaseInsensitive)==0) {
socket.disconnectFromHost();
}
else {
// Start timer for next request
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
}
// Prepare for next request
delete currentRequest;
currentRequest=0;
}
else
{
qDebug("HttpConnectionHandler (%p): received request",this);
}
}
}

View File

@ -1,64 +0,0 @@
#include "httpconnectionhandlerpool.h"
HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler)
: QObject()
{
Q_ASSERT(settings!=0);
this->settings=settings;
this->requestHandler=requestHandler;
cleanupTimer.start(settings->value("cleanupInterval",10000).toInt());
connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup()));
}
HttpConnectionHandlerPool::~HttpConnectionHandlerPool() {
foreach(HttpConnectionHandler* handler, pool) {
connect(handler,SIGNAL(finished()),handler,SLOT(deleteLater()));
handler->quit();
}
}
HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() {
HttpConnectionHandler* freeHandler=0;
mutex.lock();
// find a free handler in pool
foreach(HttpConnectionHandler* handler, pool) {
if (!handler->isBusy()) {
freeHandler=handler;
freeHandler->setBusy();
break;
}
}
// create a new handler, if necessary
if (!freeHandler) {
int maxConnectionHandlers=settings->value("maxThreads",1000).toInt();
if (pool.count()<maxConnectionHandlers) {
freeHandler=new HttpConnectionHandler(settings,requestHandler);
freeHandler->setBusy();
pool.append(freeHandler);
}
}
mutex.unlock();
return freeHandler;
}
void HttpConnectionHandlerPool::cleanup() {
int maxIdleHandlers=settings->value("minThreads",50).toInt();
int idleCounter=0;
mutex.lock();
foreach(HttpConnectionHandler* handler, pool) {
if (!handler->isBusy()) {
if (++idleCounter > maxIdleHandlers) {
pool.removeOne(handler);
qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %i",handler,pool.size());
connect(handler,SIGNAL(finished()),handler,SLOT(deleteLater()));
handler->quit();
break; // remove only one handler in each interval
}
}
}
mutex.unlock();
}

View File

@ -1,132 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "httpresponse.h"
HttpResponse::HttpResponse(QTcpSocket* socket) {
this->socket=socket;
statusCode=200;
statusText="OK";
sentHeaders=false;
sentLastPart=false;
}
void HttpResponse::setHeader(QByteArray name, QByteArray value) {
//Q_ASSERT(sentHeaders==false);
headers.insert(name,value);
}
void HttpResponse::setHeader(QByteArray name, int value) {
//Q_ASSERT(sentHeaders==false);
headers.insert(name,QByteArray::number(value));
}
QMap<QByteArray,QByteArray>& HttpResponse::getHeaders() {
return headers;
}
void HttpResponse::setStatus(int statusCode, QByteArray description) {
this->statusCode=statusCode;
statusText=description;
}
void HttpResponse::writeHeaders() {
//Q_ASSERT(sentHeaders==false);
QByteArray buffer;
buffer.append("HTTP/1.1 ");
buffer.append(QByteArray::number(statusCode));
buffer.append(' ');
buffer.append(statusText);
buffer.append("\r\n");
foreach(QByteArray name, headers.keys()) {
buffer.append(name);
buffer.append(": ");
buffer.append(headers.value(name));
buffer.append("\r\n");
}
foreach(HttpCookie cookie,cookies.values()) {
buffer.append("Set-Cookie: ");
buffer.append(cookie.toByteArray());
buffer.append("\r\n");
}
buffer.append("\r\n");
writeToSocket(buffer);
sentHeaders=true;
}
bool HttpResponse::writeToSocket(QByteArray data) {
int remaining=data.size();
char* ptr=data.data();
while (socket->isOpen() && remaining>0) {
// Wait until the previous buffer content is written out, otherwise it could become very large
socket->waitForBytesWritten(-1);
int written=socket->write(ptr,remaining);
if (written==-1) {
return false;
}
ptr+=written;
remaining-=written;
}
return true;
}
void HttpResponse::write(QByteArray data, bool lastPart) {
//Q_ASSERT(sentLastPart==false);
if (sentHeaders==false) {
QByteArray connectionMode=headers.value("Connection");
if (!headers.contains("Content-Length") && !headers.contains("Transfer-Encoding") && connectionMode!="close" && connectionMode!="Close") {
if (!lastPart) {
headers.insert("Transfer-Encoding","chunked");
}
else {
headers.insert("Content-Length",QByteArray::number(data.size()));
}
}
writeHeaders();
}
bool chunked=headers.value("Transfer-Encoding")=="chunked" || headers.value("Transfer-Encoding")=="Chunked";
if (chunked) {
if (data.size()>0) {
QByteArray buffer=QByteArray::number(data.size(),16);
buffer.append("\r\n");
writeToSocket(buffer);
writeToSocket(data);
writeToSocket("\r\n");
}
}
else {
writeToSocket(data);
}
if (lastPart) {
if (chunked) {
writeToSocket("0\r\n\r\n");
}
else if (!headers.contains("Content-Length")) {
socket->disconnectFromHost();
}
sentLastPart=true;
}
}
void HttpResponse::writeText(QString text, bool lastPart)
{
write(QByteArray(text.toUtf8()),lastPart);
}
bool HttpResponse::hasSentLastPart() const {
return sentLastPart;
}
void HttpResponse::setCookie(const HttpCookie& cookie) {
//Q_ASSERT(sentHeaders==false);
if (!cookie.getName().isEmpty()) {
cookies.insert(cookie.getName(),cookie);
}
}
QMap<QByteArray,HttpCookie>& HttpResponse::getCookies() {
return cookies;
}

View File

@ -1,135 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPRESPONSE_H
#define HTTPRESPONSE_H
#include <QMap>
#include <QString>
#include <QTcpSocket>
#include "httpcookie.h"
/**
This object represents a HTTP response, in particular the response headers.
<p>
Example code for proper response generation:
<code><pre>
response.setStatus(200,"OK"); // optional, because this is the default
response.writeBody("Hello");
response.writeBody("World!",true);
</pre></code>
<p>
Example how to return an error:
<code><pre>
response.setStatus(500,"server error");
response.write("The request cannot be processed because the servers is broken",true);
</pre></code>
<p>
For performance reason, writing a single or few large packets is better than writing
many small packets. In case of large responses (e.g. file downloads), a Content-Length
header should be set before calling write(). Web Browsers use that information to display
a progress bar.
*/
class HttpResponse {
Q_DISABLE_COPY(HttpResponse)
public:
/**
Constructor.
@param socket used to write the response
*/
HttpResponse(QTcpSocket* socket);
/**
Set a HTTP response header
@param name name of the header
@param value value of the header
*/
void setHeader(QByteArray name, QByteArray value);
/**
Set a HTTP response header
@param name name of the header
@param value value of the header
*/
void setHeader(QByteArray name, int value);
/** Get the map of HTTP response headers */
QMap<QByteArray,QByteArray>& getHeaders();
/** Get the map of cookies */
QMap<QByteArray,HttpCookie>& getCookies();
/**
Set status code and description. The default is 200,OK.
*/
void setStatus(int statusCode, QByteArray description=QByteArray());
/**
Write body data to the socket.
<p>
The HTTP status line and headers are sent automatically before the first
byte of the body gets sent.
<p>
If the response contains only a single chunk (indicated by lastPart=true),
the response is transferred in traditional mode with a Content-Length
header, which is automatically added if not already set before.
<p>
Otherwise, each part is transferred in chunked mode.
@param data Data bytes of the body
@param lastPart Indicator, if this is the last part of the response.
*/
void write(QByteArray data, bool lastPart=false);
void writeText(QString text, bool lastPart=false);
/**
Indicates wheter the body has been sent completely. Used by the connection
handler to terminate the body automatically when necessary.
*/
bool hasSentLastPart() const;
/**
Set a cookie. Cookies are sent together with the headers when the first
call to write() occurs.
*/
void setCookie(const HttpCookie& cookie);
private:
/** Request headers */
QMap<QByteArray,QByteArray> headers;
/** Socket for writing output */
QTcpSocket* socket;
/** HTTP status code*/
int statusCode;
/** HTTP status code description */
QByteArray statusText;
/** Indicator whether headers have been sent */
bool sentHeaders;
/** Indicator whether the body has been sent completely */
bool sentLastPart;
/** Cookies */
QMap<QByteArray,HttpCookie> cookies;
/** Write raw data to the socket. This method blocks until all bytes have been passed to the TCP buffer */
bool writeToSocket(QByteArray data);
/**
Write the response HTTP status and headers to the socket.
Calling this method is optional, because writeBody() calls
it automatically when required.
*/
void writeHeaders();
};
#endif // HTTPRESPONSE_H

View File

@ -1,383 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "httpsession.h"
#include <QDateTime>
#include <QUuid>
HttpSession::HttpSession(bool canStore) {
if (canStore) {
dataPtr=new HttpSessionData();
dataPtr->refCount=1;
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->id=QUuid::createUuid().toString().toLatin1();
dataPtr->yacreaderSessionData.comic = 0;
dataPtr->yacreaderSessionData.comicId = 0;
dataPtr->yacreaderSessionData.remoteComic = 0;
dataPtr->yacreaderSessionData.remoteComicId = 0;
#ifdef SUPERVERBOSE
qDebug("HttpSession: created new session data with id %s",dataPtr->id.data());
#endif
}
else {
dataPtr=0;
}
}
HttpSession::HttpSession(const HttpSession& other) {
dataPtr=other.dataPtr;
if (dataPtr) {
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
}
}
HttpSession& HttpSession::operator= (const HttpSession& other) {
HttpSessionData* oldPtr=dataPtr;
dataPtr=other.dataPtr;
if (dataPtr) {
dataPtr->lock.lockForWrite();
dataPtr->refCount++;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
if (oldPtr) {
int refCount;
oldPtr->lock.lockForRead();
refCount=oldPtr->refCount--;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount);
#endif
oldPtr->lock.unlock();
if (refCount==0) {
delete oldPtr;
}
}
return *this;
}
HttpSession::~HttpSession() {
if (dataPtr) {
int refCount;
dataPtr->lock.lockForRead();
refCount=--dataPtr->refCount;
#ifdef SUPERVERBOSE
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
#endif
dataPtr->lock.unlock();
if (refCount==0) {
qDebug("HttpSession: deleting data");
delete dataPtr;
}
}
}
QByteArray HttpSession::getId() const {
if (dataPtr) {
return dataPtr->id;
}
else {
return QByteArray();
}
}
bool HttpSession::isNull() const {
return dataPtr==0;
}
void HttpSession::set(const QByteArray& key, const QVariant& value) {
if (dataPtr) {
dataPtr->lock.lockForWrite();
dataPtr->values.insert(key,value);
dataPtr->lock.unlock();
}
}
void HttpSession::remove(const QByteArray& key) {
if (dataPtr) {
dataPtr->lock.lockForWrite();
dataPtr->values.remove(key);
dataPtr->lock.unlock();
}
}
QVariant HttpSession::get(const QByteArray& key) const {
QVariant value;
if (dataPtr) {
dataPtr->lock.lockForRead();
value=dataPtr->values.value(key);
dataPtr->lock.unlock();
}
return value;
}
bool HttpSession::contains(const QByteArray& key) const {
bool found=false;
if (dataPtr) {
dataPtr->lock.lockForRead();
found=dataPtr->values.contains(key);
dataPtr->lock.unlock();
}
return found;
}
QMap<QByteArray,QVariant> HttpSession::getAll() const {
QMap<QByteArray,QVariant> values;
if (dataPtr) {
dataPtr->lock.lockForRead();
values=dataPtr->values;
dataPtr->lock.unlock();
}
return values;
}
qint64 HttpSession::getLastAccess() const {
qint64 value=0;
if (dataPtr) {
dataPtr->lock.lockForRead();
value=dataPtr->lastAccess;
dataPtr->lock.unlock();
}
return value;
}
void HttpSession::setLastAccess() {
if (dataPtr) {
dataPtr->lock.lockForRead();
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->lock.unlock();
}
}
//AÑADIDO
//sets
bool HttpSession::isComicOnDevice(const QString & hash)
{
if(dataPtr)
return dataPtr->yacreaderSessionData.comicsOnDevice.contains(hash);
else
return false;
}
bool HttpSession::isComicDownloaded(const QString & hash)
{
if(dataPtr)
return dataPtr->yacreaderSessionData.downloadedComics.contains(hash);
else
return false;
}
void HttpSession::setComicOnDevice(const QString & hash)
{
if(dataPtr)
{
dataPtr->yacreaderSessionData.comicsOnDevice.insert(hash);
}
}
void HttpSession::setComicsOnDevice(const QSet<QString> & set)
{
if(dataPtr)
{
dataPtr->yacreaderSessionData.comicsOnDevice = set;
}
}
void HttpSession::setDownloadedComic(const QString & hash)
{
if(dataPtr)
{
dataPtr->yacreaderSessionData.downloadedComics.insert(hash);
}
}
QSet<QString> HttpSession::getComicsOnDevice()
{
if(dataPtr)
return dataPtr->yacreaderSessionData.comicsOnDevice ;
else
return QSet<QString>();
}
QSet<QString> HttpSession::getDownloadedComics()
{
if(dataPtr)
return dataPtr->yacreaderSessionData.downloadedComics ;
else
return QSet<QString>();
}
void HttpSession::clearComics()
{
if(dataPtr)
{
dataPtr->yacreaderSessionData.comicsOnDevice.clear();
dataPtr->yacreaderSessionData.downloadedComics.clear();
}
}
//current comic (import)
qulonglong HttpSession::getCurrentComicId()
{
if(dataPtr)
return dataPtr->yacreaderSessionData.comicId ;
else
return 0;
}
Comic* HttpSession::getCurrentComic()
{
if(dataPtr)
{
return dataPtr->yacreaderSessionData.comic ;
}
else
return 0;
}
void HttpSession::dismissCurrentComic()
{
if(dataPtr)
{
if(dataPtr->yacreaderSessionData.comic != 0)
{
dataPtr->yacreaderSessionData.comic->invalidate();
dataPtr->yacreaderSessionData.comic->deleteLater();
dataPtr->yacreaderSessionData.comic = 0;
}
dataPtr->yacreaderSessionData.comicId = 0;
}
}
void HttpSession::setCurrentComic(qulonglong id, Comic * comic)
{
if(dataPtr)
{
dismissCurrentComic();
dataPtr->yacreaderSessionData.comicId = id;
dataPtr->yacreaderSessionData.comic = comic;
}
}
//current comic (read)
qulonglong HttpSession::getCurrentRemoteComicId()
{
if(dataPtr)
return dataPtr->yacreaderSessionData.remoteComicId ;
else
return 0;
}
Comic* HttpSession::getCurrentRemoteComic()
{
if(dataPtr)
{
return dataPtr->yacreaderSessionData.remoteComic ;
}
else
return 0;
}
void HttpSession::dismissCurrentRemoteComic()
{
if(dataPtr)
{
if(dataPtr->yacreaderSessionData.remoteComic != 0)
{
dataPtr->yacreaderSessionData.remoteComic->invalidate();
dataPtr->yacreaderSessionData.remoteComic->deleteLater();
dataPtr->yacreaderSessionData.remoteComic = 0;
}
dataPtr->yacreaderSessionData.remoteComicId = 0;
}
}
void HttpSession::setCurrentRemoteComic(qulonglong id, Comic * comic)
{
if(dataPtr)
{
dismissCurrentRemoteComic();
dataPtr->yacreaderSessionData.remoteComicId = id;
dataPtr->yacreaderSessionData.remoteComic = comic;
}
}
QString HttpSession::getDeviceType()
{
if(dataPtr)
{
return dataPtr->yacreaderSessionData.device;
}
return "";
}
QString HttpSession::getDisplayType()
{
if(dataPtr)
{
return dataPtr->yacreaderSessionData.display;
}
return "";
}
void HttpSession::setDeviceType(const QString & device)
{
if(dataPtr)
{
//dataPtr->yacreaderSessionData.comicsOnDevice.clear(); //TODO crear un método clear que limpie la sesión completamente
//dataPtr->yacreaderSessionData.downloadedComics.clear();
dataPtr->yacreaderSessionData.device = device;
}
}
void HttpSession::setDisplayType(const QString & display)
{
if(dataPtr)
{
dataPtr->yacreaderSessionData.display = display;
}
}
void HttpSession::clearNavigationPath()
{
if(dataPtr)
dataPtr->yacreaderSessionData.navigationPath.clear();
}
QPair<qulonglong, quint32> HttpSession::popNavigationItem()
{
if(dataPtr && !(dataPtr->yacreaderSessionData.navigationPath.isEmpty()))
return dataPtr->yacreaderSessionData.navigationPath.pop();
return QPair<qulonglong, quint32>();
}
QPair<qulonglong, quint32> HttpSession::topNavigationItem()
{
if(dataPtr && !(dataPtr->yacreaderSessionData.navigationPath.isEmpty()))
return dataPtr->yacreaderSessionData.navigationPath.top();
return QPair<qulonglong, quint32>();
}
void HttpSession::pushNavigationItem(const QPair<qulonglong, quint32> &item)
{
if(dataPtr)
dataPtr->yacreaderSessionData.navigationPath.push(item);
}
void HttpSession::updateTopItem(const QPair<qulonglong, quint32> &item)
{
if(dataPtr && !(dataPtr->yacreaderSessionData.navigationPath.isEmpty()))
{
dataPtr->yacreaderSessionData.navigationPath.pop();
dataPtr->yacreaderSessionData.navigationPath.push(item);
} else if(dataPtr)
{
dataPtr->yacreaderSessionData.navigationPath.push(item);
}
}
QStack<QPair<qulonglong, quint32> > HttpSession::getNavigationPath()
{
if(dataPtr)
return dataPtr->yacreaderSessionData.navigationPath;
else
return QStack<QPair<qulonglong, quint32> >();
}

View File

@ -1,193 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef HTTPSESSION_H
#define HTTPSESSION_H
#include <QByteArray>
#include <QVariant>
#include <QReadWriteLock>
#include <QSet>
#include <QString>
#include "comic.h"
/**
This class stores data for a single HTTP session.
A session can store any number of key/value pairs. This class uses implicit
sharing for read and write access. This class is thread safe.
@see HttpSessionStore should be used to create and get instances of this class.
*/
class HttpSession {
public:
/**
Constructor.
@param canStore The session can store data, if this parameter is true.
Otherwise all calls to set() and remove() do not have any effect.
*/
HttpSession(bool canStore=false);
/**
Copy constructor. Creates another HttpSession object that shares the
data of the other object.
*/
HttpSession(const HttpSession& other);
/**
Copy operator. Detaches from the current shared data and attaches to
the data of the other object.
*/
HttpSession& operator= (const HttpSession& other);
/**
Destructor. Detaches from the shared data.
*/
virtual ~HttpSession();
/** Get the unique ID of this session. This method is thread safe. */
QByteArray getId() const;
/**
Null sessions cannot store data. All calls to set() and remove()
do not have any effect.This method is thread safe.
*/
bool isNull() const;
/** Set a value. This method is thread safe. */
void set(const QByteArray& key, const QVariant& value);
/** Remove a value. This method is thread safe. */
void remove(const QByteArray& key);
/** Get a value. This method is thread safe. */
QVariant get(const QByteArray& key) const;
/** Check if a key exists. This method is thread safe. */
bool contains(const QByteArray& key) const;
/**
Get a copy of all data stored in this session.
Changes to the session do not affect the copy and vice versa.
This method is thread safe.
*/
QMap<QByteArray,QVariant> getAll() const;
/**
Get the timestamp of last access. That is the time when the last
HttpSessionStore::getSession() has been called.
This method is thread safe.
*/
qint64 getLastAccess() const;
/**
Set the timestamp of last access, to renew the timeout period.
Called by HttpSessionStore::getSession().
This method is thread safe.
*/
void setLastAccess();
//AÑADIDO
//sets
void setComicsOnDevice(const QSet<QString> & set);
void setComicOnDevice(const QString & hash);
void setDownloadedComic(const QString & hash);
bool isComicOnDevice(const QString & hash);
bool isComicDownloaded(const QString & hash);
QSet<QString> getComicsOnDevice();
QSet<QString> getDownloadedComics();
void clearComics();
//current comic (import)
qulonglong getCurrentComicId();
Comic * getCurrentComic();
void dismissCurrentComic();
void setCurrentComic(qulonglong id, Comic * comic);
//current comic (read)
qulonglong getCurrentRemoteComicId();
Comic * getCurrentRemoteComic();
void dismissCurrentRemoteComic();
void setCurrentRemoteComic(qulonglong id, Comic * comic);
//device identification
QString getDeviceType();
QString getDisplayType();
void setDeviceType(const QString & device);
void setDisplayType(const QString & display);
/*int popPage();
void pushPage(int page);
int topPage();
void clearFoldersPath();
int popFolder();
void pushFolder(int page);
int topFolder();
QStack<int> getFoldersPath();*/
void clearNavigationPath();
QPair<qulonglong, quint32> popNavigationItem();
QPair<qulonglong, quint32> topNavigationItem();
void pushNavigationItem(const QPair<qulonglong, quint32> & item);
void updateTopItem(const QPair<qulonglong, quint32> & item);
//TODO replace QPair by a custom class for storing folderId, page and folderName(save some DB accesses)
QStack<QPair<qulonglong, quint32> > getNavigationPath();
private:
struct YACReaderSessionData {
//cómics disponibles en dispositivo
QSet<QString> comicsOnDevice;
//cómics que han sido descargados o están siendo descargados en esta sesión
QSet<QString> downloadedComics;
//cómic actual que está siendo descargado
QString device;
QString display;
qulonglong comicId;
qulonglong remoteComicId;
//folder_id, page_number
QStack<QPair<qulonglong, quint32> > navigationPath;
Comic * comic;
Comic * remoteComic;
};
struct HttpSessionData {
/** Unique ID */
QByteArray id;
/** Timestamp of last access, set by the HttpSessionStore */
qint64 lastAccess;
/** Reference counter */
int refCount;
/** Used to synchronize threads */
QReadWriteLock lock;
/** Storage for the key/value pairs; */
QMap<QByteArray,QVariant> values;
YACReaderSessionData yacreaderSessionData;
};
/** Pointer to the shared data. */
HttpSessionData* dataPtr;
};
#endif // HTTPSESSION_H

View File

@ -1,235 +0,0 @@
/**
@file
@author Stefan Frings
*/
#include "staticfilecontroller.h"
#include <QFileInfo>
#include <QDir>
#include <QDateTime>
#include "httpsession.h"
#include "static.h"
#include <QCoreApplication>
StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
:HttpRequestHandler(parent)
{
maxAge=settings->value("maxAge","60000").toInt();
encoding=settings->value("encoding","UTF-8").toString();
docroot=settings->value("path","./server/docroot").toString();
// Convert relative path to absolute, based on the directory of the config file.
#ifdef Q_OS_WIN32
if (QDir::isRelativePath(docroot) && settings->format()!=QSettings::NativeFormat)
#else
if (QDir::isRelativePath(docroot))
#endif
{
#if defined Q_OS_UNIX && ! defined Q_OS_MAC
QFileInfo configFile(QString(DATADIR)+"/yacreader");
docroot=QFileInfo(QString(DATADIR)+"/yacreader",docroot).absoluteFilePath();
#else
QFileInfo configFile(QCoreApplication::applicationDirPath());
docroot=QFileInfo(QCoreApplication::applicationDirPath(),docroot).absoluteFilePath();
#endif
}
qDebug("StaticFileController: docroot=%s, encoding=%s, maxAge=%i",qPrintable(docroot),qPrintable(encoding),maxAge);
maxCachedFileSize=settings->value("maxCachedFileSize","65536").toInt();
cache.setMaxCost(settings->value("cacheSize","1000000").toInt());
cacheTimeout=settings->value("cacheTime","60000").toInt();
qDebug("StaticFileController: cache timeout=%i, size=%i",cacheTimeout,cache.maxCost());
}
void StaticFileController::service(HttpRequest& request, HttpResponse& response) {
QByteArray path=request.getPath();
// Forbid access to files outside the docroot directory
if (path.startsWith("/..")) {
qWarning("StaticFileController: somebody attempted to access a file outside the docroot directory");
response.setStatus(403,"forbidden");
response.write("403 forbidden",true);
}
//TODO(DONE) carga sensible al dispositivo y a la localización
QString stringPath = path;
QStringList paths = QString(path).split('/');
QString fileName = paths.last();
stringPath.remove(fileName);
HttpSession session=Static::sessionStore->getSession(request,response,false);
QString device = session.getDeviceType();
QString display = session.getDisplayType();
if(fileName.endsWith(".png"))
fileName = getDeviceAwareFileName(fileName, device, display, request.getHeader("Accept-Language"), stringPath);
else
fileName = getDeviceAwareFileName(fileName, device, request.getHeader("Accept-Language"), stringPath);
QString newPath = stringPath.append(fileName);
path = newPath.toLocal8Bit();
//CAMBIADO
response.setHeader("Connection","close");
//END_TODO
// Check if we have the file in cache
//qint64 now=QDateTime::currentMSecsSinceEpoch();
// mutex.lock();
// CacheEntry* entry=cache.object(path);
//if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) {
// QByteArray document=entry->document; //copy the cached document, because other threads may destroy the cached entry immediately after mutex unlock.
// mutex.unlock();
// qDebug("StaticFileController: Cache hit for %s",path.data());
// setContentType(path,response);
// response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
// response.write(document);
//}
//else {
// mutex.unlock();
//qDebug("StaticFileController: Cache miss for %s",path.data());
// The file is not in cache.
// If the filename is a directory, append index.html.
if (QFileInfo(docroot+path).isDir()) {
path+="/index.html";
}
QFile file(docroot+path);
if (file.exists()) {
qDebug("StaticFileController: Open file %s",qPrintable(file.fileName()));
if (file.open(QIODevice::ReadOnly)) {
setContentType(path,response);
//response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
//if (file.size()<=maxCachedFileSize) {
// // Return the file content and store it also in the cache
// entry=new CacheEntry();
// while (!file.atEnd() && !file.error()) {
// QByteArray buffer=file.read(65536);
// response.write(buffer);
// entry->document.append(buffer);
// }
// entry->created=now;
// mutex.lock();
// cache.insert(request.getPath(),entry,entry->document.size());
// mutex.unlock();
//}
//else {
// Return the file content, do not store in cache*/
while (!file.atEnd() && !file.error()) {
response.write(file.read(131072));
//}
}
file.close();
}
else {
qWarning("StaticFileController: Cannot open existing file %s for reading",qPrintable(file.fileName()));
response.setStatus(403,"forbidden");
response.write("403 forbidden",true);
}
}
else {
response.setStatus(404,"not found");
response.write("404 not found",true);
}
//}
}
void StaticFileController::setContentType(QString fileName, HttpResponse& response) const {
if (fileName.endsWith(".png")) {
response.setHeader("Content-Type", "image/png");
}
else if (fileName.endsWith(".jpg")) {
response.setHeader("Content-Type", "image/jpeg");
}
else if (fileName.endsWith(".gif")) {
response.setHeader("Content-Type", "image/gif");
}
else if (fileName.endsWith(".pdf")) {
response.setHeader("Content-Type", "application/pdf");
}
else if (fileName.endsWith(".txt")) {
response.setHeader("Content-Type", qPrintable("text/plain; charset="+encoding));
}
else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
response.setHeader("Content-Type", qPrintable("text/html; charset="+encoding));
}
else if (fileName.endsWith(".css")) {
response.setHeader("Content-Type", "text/css");
}
else if (fileName.endsWith(".js")) {
response.setHeader("Content-Type", "text/javascript");
}
// Todo: add all of your content types
}
bool StaticFileController::exists(QString localizedName, QString path) const
{
QString fileName=docroot+"/"+path + localizedName;
QFile file(fileName);
return file.exists();
}
//retorna fileName si no se encontró alternativa traducida ó fileName-locale.extensión si se encontró
QString StaticFileController::getLocalizedFileName(QString fileName, QString locales, QString path) const
{
QSet<QString> tried; // used to suppress duplicate attempts
QStringList locs=locales.split(',',QString::SkipEmptyParts);
QStringList fileNameParts = fileName.split('.');
QString file = fileNameParts.first();
QString extension = fileNameParts.last();
// Search for exact match
foreach (QString loc,locs) {
loc.replace(QRegExp(";.*"),"");
loc.replace('-','_');
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
if (!tried.contains(localizedName)) {
if(exists(localizedName, path))
return localizedName;
tried.insert(localizedName);
}
}
// Search for correct language but any country
foreach (QString loc,locs) {
loc.replace(QRegExp("[;_-].*"),"");
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
if (!tried.contains(localizedName)) {
if(exists(localizedName, path))
return localizedName;
tried.insert(localizedName);
}
}
return fileName;
}
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const
{
QFileInfo fi(fileName);
QString baseName = fi.baseName();
QString extension = fi.completeSuffix();
QString completeFileName = getLocalizedFileName(baseName+"_"+device+"."+extension,locales,path);
if(QFile(docroot+"/"+path+completeFileName).exists())
return completeFileName; //existe un archivo específico para este dispositivo y locales
else
return getLocalizedFileName(fileName,locales,path); //no hay archivo específico para el dispositivo, pero puede haberlo para estas locales
}
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const
{
QFileInfo fi(fileName);
QString baseName = fi.baseName();
QString extension = fi.completeSuffix();
QString completeFileName = baseName+display+"."+extension;
if(QFile(docroot+"/"+path+completeFileName).exists())
return completeFileName;
else
{
completeFileName = baseName+"_"+device+display+"."+extension;
if((QFile(docroot+"/"+path+completeFileName).exists()))
return completeFileName;
}
return fileName;
}

View File

@ -1,92 +0,0 @@
/**
@file
@author Stefan Frings
*/
#ifndef STATICFILECONTROLLER_H
#define STATICFILECONTROLLER_H
#include "httprequest.h"
#include "httpresponse.h"
#include "httprequesthandler.h"
#include <QCache>
#include <QMutex>
/**
Delivers static files. It is usually called by the applications main request handler when
the caller request a path that is mapped to static files.
<p>
The following settings are required in the config file:
<code><pre>
path=docroot
encoding=UTF-8
maxAge=60000
cacheTime=60000
cacheSize=1000000
maxCachedFileSize=65536
</pre></code>
The path is relative to the directory of the config file. In case of windows, if the
settings are in the registry, the path is relative to the current working directory.
<p>
The encoding is sent to the web browser in case of text and html files.
<p>
The cache improves performance of small files when loaded from a network
drive. Large files are not cached. Files are cached as long as possible,
when cacheTime=0. The maxAge value (in msec!) controls the remote browsers cache.
<p>
Do not instantiate this class in each request, because this would make the file cache
useless. Better create one instance during start-up and call it when the application
received a related HTTP request.
*/
class StaticFileController : public HttpRequestHandler {
Q_OBJECT
Q_DISABLE_COPY(StaticFileController);
public:
/** Constructor */
StaticFileController(QSettings* settings, QObject* parent = 0);
/** Generates the response */
void service(HttpRequest& request, HttpResponse& response);
private:
/** Encoding of text files */
QString encoding;
/** Root directory of documents */
QString docroot;
/** Maximum age of files in the browser cache */
int maxAge;
struct CacheEntry {
QByteArray document;
qint64 created;
};
/** Timeout for each cached file */
int cacheTimeout;
/** Maximum size of files in cache, larger files are not cached */
int maxCachedFileSize;
/** Cache storage */
QCache<QString,CacheEntry> cache;
/** Used to synchronize cache access for threads */
QMutex mutex;
/** Set a content-type header in the response depending on the ending of the filename */
void setContentType(QString file, HttpResponse& response) const;
QString getLocalizedFileName(QString fileName, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const;
QString getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const;
bool exists(QString localizedName, QString path) const;
};
#endif // STATICFILECONTROLLER_H

View File

@ -1,5 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/logmessage.h $$PWD/logger.h $$PWD/filelogger.h $$PWD/dualfilelogger.h
SOURCES += $$PWD/logmessage.cpp $$PWD/logger.cpp $$PWD/filelogger.cpp $$PWD/dualfilelogger.cpp

View File

@ -1,7 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/template.h $$PWD/templateloader.h $$PWD/templatecache.h
SOURCES += $$PWD/template.cpp $$PWD/templateloader.cpp $$PWD/templatecache.cpp
OTHER_FILES += $$PWD/../doc/readme.txt

View File

@ -0,0 +1,275 @@
/**
@file
@author Stefan Frings
*/
#include "httpconnectionhandler.h"
#include "httpresponse.h"
HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration)
: QThread()
{
Q_ASSERT(settings!=0);
Q_ASSERT(requestHandler!=0);
this->settings=settings;
this->requestHandler=requestHandler;
this->sslConfiguration=sslConfiguration;
currentRequest=0;
busy=false;
// Create TCP or SSL socket
createSocket();
// execute signals in my own thread
moveToThread(this);
socket->moveToThread(this);
readTimer.moveToThread(this);
// Connect signals
connect(socket, SIGNAL(readyRead()), SLOT(read()));
connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
connect(&readTimer, SIGNAL(timeout()), SLOT(readTimeout()));
readTimer.setSingleShot(true);
qDebug("HttpConnectionHandler (%p): constructed", this);
this->start();
}
HttpConnectionHandler::~HttpConnectionHandler()
{
quit();
wait();
qDebug("HttpConnectionHandler (%p): destroyed", this);
}
void HttpConnectionHandler::createSocket()
{
// If SSL is supported and configured, then create an instance of QSslSocket
#ifndef QT_NO_OPENSSL
if (sslConfiguration)
{
QSslSocket* sslSocket=new QSslSocket();
sslSocket->setSslConfiguration(*sslConfiguration);
socket=sslSocket;
qDebug("HttpConnectionHandler (%p): SSL is enabled", this);
return;
}
#endif
// else create an instance of QTcpSocket
socket=new QTcpSocket();
}
void HttpConnectionHandler::run()
{
qDebug("HttpConnectionHandler (%p): thread started", this);
try
{
exec();
}
catch (...)
{
qCritical("HttpConnectionHandler (%p): an uncatched exception occured in the thread",this);
}
socket->close();
delete socket;
readTimer.stop();
qDebug("HttpConnectionHandler (%p): thread stopped", this);
}
void HttpConnectionHandler::handleConnection(tSocketDescriptor socketDescriptor)
{
qDebug("HttpConnectionHandler (%p): handle new connection", this);
busy = true;
Q_ASSERT(socket->isOpen()==false); // if not, then the handler is already busy
//UGLY workaround - we need to clear writebuffer before reusing this socket
//https://bugreports.qt-project.org/browse/QTBUG-28914
socket->connectToHost("",0);
socket->abort();
if (!socket->setSocketDescriptor(socketDescriptor))
{
qCritical("HttpConnectionHandler (%p): cannot initialize socket: %s", this,qPrintable(socket->errorString()));
return;
}
#ifndef QT_NO_OPENSSL
// Switch on encryption, if SSL is configured
if (sslConfiguration)
{
qDebug("HttpConnectionHandler (%p): Starting encryption", this);
((QSslSocket*)socket)->startServerEncryption();
}
#endif
// Start timer for read timeout
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
// delete previous request
delete currentRequest;
currentRequest=0;
}
bool HttpConnectionHandler::isBusy()
{
return busy;
}
void HttpConnectionHandler::setBusy()
{
this->busy = true;
}
void HttpConnectionHandler::readTimeout()
{
qDebug("HttpConnectionHandler (%p): read timeout occured",this);
//Commented out because QWebView cannot handle this.
//socket->write("HTTP/1.1 408 request timeout\r\nConnection: close\r\n\r\n408 request timeout\r\n");
socket->flush();
socket->disconnectFromHost();
delete currentRequest;
currentRequest=0;
}
void HttpConnectionHandler::disconnected()
{
qDebug("HttpConnectionHandler (%p): disconnected", this);
socket->close();
readTimer.stop();
busy = false;
}
void HttpConnectionHandler::read()
{
// The loop adds support for HTTP pipelinig
while (socket->bytesAvailable())
{
#ifdef SUPERVERBOSE
qDebug("HttpConnectionHandler (%p): read input",this);
#endif
// Create new HttpRequest object if necessary
if (!currentRequest)
{
currentRequest=new HttpRequest(settings);
}
// Collect data for the request object
while (socket->bytesAvailable() && currentRequest->getStatus()!=HttpRequest::complete && currentRequest->getStatus()!=HttpRequest::abort)
{
currentRequest->readFromSocket(socket);
if (currentRequest->getStatus()==HttpRequest::waitForBody)
{
// Restart timer for read timeout, otherwise it would
// expire during large file uploads.
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
}
}
// If the request is aborted, return error message and close the connection
if (currentRequest->getStatus()==HttpRequest::abort)
{
socket->write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
socket->flush();
socket->disconnectFromHost();
delete currentRequest;
currentRequest=0;
return;
}
// If the request is complete, let the request mapper dispatch it
if (currentRequest->getStatus()==HttpRequest::complete)
{
readTimer.stop();
qDebug("HttpConnectionHandler (%p): received request",this);
// Copy the Connection:close header to the response
HttpResponse response(socket);
bool closeConnection=QString::compare(currentRequest->getHeader("Connection"),"close",Qt::CaseInsensitive)==0;
if (closeConnection)
{
response.setHeader("Connection","close");
}
// In case of HTTP 1.0 protocol add the Connection:close header.
// This ensures that the HttpResponse does not activate chunked mode, which is not spported by HTTP 1.0.
else
{
bool http1_0=QString::compare(currentRequest->getVersion(),"HTTP/1.0",Qt::CaseInsensitive)==0;
if (http1_0)
{
closeConnection=true;
response.setHeader("Connection","close");
}
}
// Call the request mapper
try
{
requestHandler->service(*currentRequest, response);
}
catch (...)
{
qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",this);
}
// Finalize sending the response if not already done
if (!response.hasSentLastPart())
{
response.write(QByteArray(),true);
}
qDebug("HttpConnectionHandler (%p): finished request",this);
// Find out whether the connection must be closed
if (!closeConnection)
{
// Maybe the request handler or mapper added a Connection:close header in the meantime
bool closeResponse=QString::compare(response.getHeaders().value("Connection"),"close",Qt::CaseInsensitive)==0;
if (closeResponse==true)
{
closeConnection=true;
}
else
{
// If we have no Content-Length header and did not use chunked mode, then we have to close the
// connection to tell the HTTP client that the end of the response has been reached.
bool hasContentLength=response.getHeaders().contains("Content-Length");
if (!hasContentLength)
{
bool hasChunkedMode=QString::compare(response.getHeaders().value("Transfer-Encoding"),"chunked",Qt::CaseInsensitive)==0;
if (!hasChunkedMode)
{
closeConnection=true;
}
}
}
}
// Close the connection or prepare for the next request on the same connection.
if (closeConnection)
{
socket->flush();
socket->disconnectFromHost();
}
else
{
// Start timer for next request
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
}
delete currentRequest;
currentRequest=0;
}
}
}

Some files were not shown because too many files have changed in this diff Show More