mirror of
https://github.com/YACReader/yacreader
synced 2026-03-20 04:29:47 -04:00
corregida toolbar en macosx
This commit is contained in:
BIN
YACReaderLibrary/YACReaderLibrary.icns
Normal file
BIN
YACReaderLibrary/YACReaderLibrary.icns
Normal file
Binary file not shown.
141
YACReaderLibrary/YACReaderLibrary.pro
Normal file
141
YACReaderLibrary/YACReaderLibrary.pro
Normal file
@ -0,0 +1,141 @@
|
||||
######################################################################
|
||||
# Automatically generated by qmake (2.01a) dom 12. oct 20:47:48 2008
|
||||
######################################################################
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET =
|
||||
DEPENDPATH += .
|
||||
INCLUDEPATH += .
|
||||
INCLUDEPATH += ../common \
|
||||
./server \
|
||||
./db \
|
||||
../YACReader \
|
||||
../custom_widgets
|
||||
|
||||
DEFINES += SERVER_RELEASE
|
||||
|
||||
win32 {
|
||||
INCLUDEPATH += ../dependencies/poppler/include
|
||||
LIBS += -L../dependencies/poppler/lib -lpoppler-qt4
|
||||
QMAKE_CXXFLAGS_RELEASE += /MP /Ob2 /Oi /Ot /GT /GL
|
||||
QMAKE_LFLAGS_RELEASE += /LTCG
|
||||
CONFIG -= embed_manifest_exe
|
||||
}
|
||||
|
||||
unix:!macx{
|
||||
INCLUDEPATH += /usr/include/poppler/qt4
|
||||
LIBS += -L/usr/lib -lpoppler-qt4
|
||||
LIBS += -lGLU
|
||||
}
|
||||
|
||||
macx{
|
||||
#INCLUDEPATH += "/Volumes/Mac OS X Lion/usr/X11/include"
|
||||
INCLUDEPATH += /usr/local/include/poppler/qt4
|
||||
LIBS += -L/usr/local/lib -lpoppler-qt4
|
||||
}
|
||||
|
||||
CONFIG += release
|
||||
CONFIG -= flat
|
||||
QT += sql network 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/treeitem.h \
|
||||
./db/treemodel.h \
|
||||
./db/tablemodel.h \
|
||||
./db/tableitem.h \
|
||||
../common/comic_db.h \
|
||||
../common/folder.h \
|
||||
../common/library_item.h \
|
||||
../YACReader/comic.h \
|
||||
../YACReader/bookmarks.h \
|
||||
../common/pictureflow.h \
|
||||
../common/custom_widgets.h \
|
||||
../common/qnaturalsorting.h \
|
||||
../common/yacreader_flow_gl.h \
|
||||
../common/yacreader_global.h \
|
||||
../common/onstart_flow_selection_dialog.h \
|
||||
no_libraries_widget.h \
|
||||
import_widget.h \
|
||||
yacreader_local_server.h \
|
||||
yacreader_main_toolbar.h \
|
||||
comics_remover.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/treeitem.cpp \
|
||||
./db/treemodel.cpp \
|
||||
./db/tablemodel.cpp \
|
||||
./db/tableitem.cpp \
|
||||
../common/comic_db.cpp \
|
||||
../common/folder.cpp \
|
||||
../common/library_item.cpp \
|
||||
../YACReader/comic.cpp \
|
||||
../YACReader/bookmarks.cpp \
|
||||
../common/pictureflow.cpp \
|
||||
../common/custom_widgets.cpp \
|
||||
../common/qnaturalsorting.cpp \
|
||||
../common/yacreader_flow_gl.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
|
||||
|
||||
|
||||
include(./server/server.pri)
|
||||
include(../custom_widgets/custom_widgets.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
|
||||
|
||||
Release:DESTDIR = ../release
|
||||
Debug:DESTDIR = ../debug
|
||||
|
||||
125
YACReaderLibrary/add_library_dialog.cpp
Normal file
125
YACReaderLibrary/add_library_dialog.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include "add_library_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
|
||||
|
||||
AddLibraryDialog::AddLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void AddLibraryDialog::setupUI()
|
||||
{
|
||||
textLabel = new QLabel(tr("Comics folder : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
connect(path,SIGNAL(textChanged(QString)),this,SLOT(pathSetted(QString)));
|
||||
|
||||
nameLabel = new QLabel(tr("Library Name : "));
|
||||
nameEdit = new QLineEdit;
|
||||
nameLabel->setBuddy(nameEdit);
|
||||
connect(nameEdit,SIGNAL(textChanged(QString)),this,SLOT(nameSetted(QString)));
|
||||
|
||||
accept = new QPushButton(tr("Add"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(add()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/comicFolder.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
QGridLayout * content = new QGridLayout;
|
||||
|
||||
content->addWidget(nameLabel,0,0);
|
||||
content->addWidget(nameEdit,0,1);
|
||||
|
||||
content->addWidget(textLabel,1,0);
|
||||
content->addWidget(path,1,1);
|
||||
content->addWidget(find,1,2);
|
||||
content->setColumnStretch(2,0);
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(content);
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/openLibrary.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);//,0,Qt::AlignTop);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Add an existing library"));
|
||||
}
|
||||
|
||||
void AddLibraryDialog::add()
|
||||
{
|
||||
//accept->setEnabled(false);
|
||||
emit(addLibrary(QDir::cleanPath(path->text()),nameEdit->text()));
|
||||
close();
|
||||
}
|
||||
|
||||
void AddLibraryDialog::nameSetted(const QString & text)
|
||||
{
|
||||
if(!text.isEmpty())
|
||||
{
|
||||
if(!path->text().isEmpty())
|
||||
{
|
||||
QFileInfo fi(path->text());
|
||||
if(fi.isDir())
|
||||
accept->setEnabled(true);
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void AddLibraryDialog::pathSetted(const QString & text)
|
||||
{
|
||||
QFileInfo fi(text);
|
||||
if(fi.isDir())
|
||||
{
|
||||
if(!nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void AddLibraryDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getExistingDirectory(0,"Comics directory",".");
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
if(!nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void AddLibraryDialog::close()
|
||||
{
|
||||
path->clear();
|
||||
nameEdit->clear();
|
||||
accept->setEnabled(false);
|
||||
QDialog::close();
|
||||
}
|
||||
35
YACReaderLibrary/add_library_dialog.h
Normal file
35
YACReaderLibrary/add_library_dialog.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __ADD_LIBRARY_DIALOG_H
|
||||
#define __ADD_LIBRARY_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QThread>
|
||||
|
||||
class AddLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AddLibraryDialog(QWidget * parent = 0);
|
||||
private:
|
||||
QLabel * nameLabel;
|
||||
QLabel * textLabel;
|
||||
QLineEdit * path;
|
||||
QLineEdit * nameEdit;
|
||||
QPushButton * find;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
void setupUI();
|
||||
public slots:
|
||||
void add();
|
||||
void findPath();
|
||||
void close();
|
||||
void nameSetted(const QString & text);
|
||||
void pathSetted(const QString & text);
|
||||
signals:
|
||||
void addLibrary(QString target, QString name);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
13
YACReaderLibrary/bundle_creator.cpp
Normal file
13
YACReaderLibrary/bundle_creator.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "bundle_creator.h"
|
||||
|
||||
|
||||
BundleCreator::BundleCreator(void)
|
||||
:QObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
BundleCreator::~BundleCreator(void)
|
||||
{
|
||||
}
|
||||
14
YACReaderLibrary/bundle_creator.h
Normal file
14
YACReaderLibrary/bundle_creator.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __BUNDLE_CREATOR_H
|
||||
#define __BUNDLE_CREATOR_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class BundleCreator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BundleCreator(void);
|
||||
~BundleCreator(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
221
YACReaderLibrary/comic_flow.cpp
Normal file
221
YACReaderLibrary/comic_flow.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
#include "comic_flow.h"
|
||||
#include "qnaturalsorting.h"
|
||||
|
||||
#include "yacreader_global.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QMutex>
|
||||
#include <QImageReader>
|
||||
#include <QTimer>
|
||||
|
||||
ComicFlow::ComicFlow(QWidget* parent,FlowType flowType)
|
||||
:YACReaderFlow(parent,flowType)
|
||||
{
|
||||
updateTimer = new QTimer;
|
||||
connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateImageData()));
|
||||
|
||||
worker = new ImageLoader;
|
||||
connect(this, SIGNAL(centerIndexChanged(int)), this, SLOT(preload()));
|
||||
connect(this, SIGNAL(centerIndexChangedSilent(int)), this, SLOT(preload()));
|
||||
|
||||
setReflectionEffect(PlainReflection);
|
||||
}
|
||||
|
||||
ComicFlow::~ComicFlow()
|
||||
{
|
||||
delete worker;
|
||||
delete updateTimer;
|
||||
}
|
||||
|
||||
void ComicFlow::setImagePaths(const QStringList& paths)
|
||||
{
|
||||
clear();
|
||||
|
||||
//imagePath = path;
|
||||
imageFiles = paths;
|
||||
imagesLoaded.clear();
|
||||
imagesLoaded.fill(false,imageFiles.size());
|
||||
numImagesLoaded = 0;
|
||||
|
||||
imagesSetted.clear();
|
||||
imagesSetted.fill(false,imageFiles.size());
|
||||
|
||||
// populate with empty images
|
||||
QImage img; //TODO remove
|
||||
QString s;
|
||||
for(int i = 0; i < (int)imageFiles.size(); i++)
|
||||
{
|
||||
addSlide(img);
|
||||
s = imageFiles.at(i);
|
||||
s.remove(s.size()-4,4);
|
||||
if(QFileInfo(s+".r").exists())
|
||||
markSlide(i);
|
||||
}
|
||||
|
||||
setCenterIndex(0);
|
||||
worker->reset();
|
||||
preload();
|
||||
}
|
||||
|
||||
void ComicFlow::preload()
|
||||
{
|
||||
if(numImagesLoaded < imagesLoaded.size())
|
||||
updateTimer->start(30); //TODO comprobar rendimiento, originalmente era 70
|
||||
}
|
||||
|
||||
void ComicFlow::updateImageData()
|
||||
{
|
||||
// can't do anything, wait for the next possibility
|
||||
if(worker->busy())
|
||||
return;
|
||||
|
||||
// set image of last one
|
||||
int idx = worker->index();
|
||||
if( idx >= 0 && !worker->result().isNull())
|
||||
{
|
||||
if(!imagesSetted[idx])
|
||||
{
|
||||
setSlide(idx, worker->result());
|
||||
imagesSetted[idx] = true;
|
||||
numImagesLoaded++;
|
||||
imagesLoaded[idx]=true;
|
||||
}
|
||||
}
|
||||
|
||||
// try to load only few images on the left and right side
|
||||
// i.e. all visible ones plus some extra
|
||||
#define COUNT 8
|
||||
int indexes[2*COUNT+1];
|
||||
int center = centerIndex();
|
||||
indexes[0] = center;
|
||||
for(int j = 0; j < COUNT; j++)
|
||||
{
|
||||
indexes[j*2+1] = center+j+1;
|
||||
indexes[j*2+2] = center-j-1;
|
||||
}
|
||||
for(int c = 0; c < 2*COUNT+1; c++)
|
||||
{
|
||||
int i = indexes[c];
|
||||
if((i >= 0) && (i < slideCount()))
|
||||
if(!imagesLoaded[i])//slide(i).isNull())
|
||||
{
|
||||
// schedule thumbnail generation
|
||||
QString fname = imageFiles[i];
|
||||
|
||||
|
||||
worker->generate(i, fname, slideSize());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no need to generate anything? stop polling...
|
||||
updateTimer->stop();
|
||||
}
|
||||
|
||||
void ComicFlow::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
PictureFlow::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void ComicFlow::wheelEvent(QWheelEvent * event)
|
||||
{
|
||||
if(event->delta()<0)
|
||||
showNext();
|
||||
else
|
||||
showPrevious();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void ComicFlow::removeSlide(int cover)
|
||||
{
|
||||
imageFiles.removeAt(cover);
|
||||
if(imagesLoaded[cover])
|
||||
numImagesLoaded--;
|
||||
imagesLoaded.remove(cover);
|
||||
imagesSetted.remove(cover);
|
||||
|
||||
YACReaderFlow::removeSlide(cover);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
//ImageLoader
|
||||
//-----------------------------------------------------------------------------
|
||||
static QImage loadImage(const QString& fileName)
|
||||
{
|
||||
QImage image;
|
||||
bool result = image.load(fileName);
|
||||
|
||||
if(!result)
|
||||
return QImage();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
ImageLoader::ImageLoader():
|
||||
QThread(), restart(false), working(false), idx(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ImageLoader::~ImageLoader()
|
||||
{
|
||||
mutex.lock();
|
||||
condition.wakeOne();
|
||||
mutex.unlock();
|
||||
wait();
|
||||
}
|
||||
|
||||
bool ImageLoader::busy() const
|
||||
{
|
||||
return isRunning() ? working : false;
|
||||
}
|
||||
|
||||
void ImageLoader::generate(int index, const QString& fileName, QSize size)
|
||||
{
|
||||
mutex.lock();
|
||||
this->idx = index;
|
||||
this->fileName = fileName;
|
||||
this->size = size;
|
||||
this->img = QImage();
|
||||
mutex.unlock();
|
||||
|
||||
if (!isRunning())
|
||||
start();
|
||||
else
|
||||
{
|
||||
// already running, wake up whenever ready
|
||||
restart = true;
|
||||
condition.wakeOne();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageLoader::run()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
// copy necessary data
|
||||
mutex.lock();
|
||||
this->working = true;
|
||||
QString fileName = this->fileName;
|
||||
mutex.unlock();
|
||||
|
||||
QImage image = loadImage(fileName);
|
||||
|
||||
// let everyone knows it is ready
|
||||
mutex.lock();
|
||||
this->working = false;
|
||||
this->img = image;
|
||||
mutex.unlock();
|
||||
|
||||
// put to sleep
|
||||
mutex.lock();
|
||||
if (!this->restart)
|
||||
condition.wait(&mutex);
|
||||
restart = false;
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
QImage ImageLoader::result()
|
||||
{
|
||||
return img;
|
||||
}
|
||||
75
YACReaderLibrary/comic_flow.h
Normal file
75
YACReaderLibrary/comic_flow.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef __COMICFLOW_H
|
||||
#define __COMICFLOW_H
|
||||
|
||||
#include "yacreader_flow.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QImage>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QString>
|
||||
#include <QWheelEvent>
|
||||
|
||||
class ImageLoader;
|
||||
class ComicFlow : public YACReaderFlow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComicFlow(QWidget* parent = 0,FlowType flowType = CoverFlowLike);
|
||||
virtual ~ComicFlow();
|
||||
|
||||
void setImagePaths(const QStringList& paths);
|
||||
//bool eventFilter(QObject *target, QEvent *event);
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void removeSlide(int cover);
|
||||
|
||||
private slots:
|
||||
void preload();
|
||||
void updateImageData();
|
||||
|
||||
private:
|
||||
//QString imagePath;
|
||||
QStringList imageFiles;
|
||||
QVector<bool> imagesLoaded;
|
||||
QVector<bool> imagesSetted;
|
||||
uint numImagesLoaded;
|
||||
QTimer* updateTimer;
|
||||
ImageLoader* worker;
|
||||
virtual void wheelEvent(QWheelEvent * event);
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Source code of ImageLoader class was modified from http://code.google.com/p/photoflow/
|
||||
//------------------------------------------------------------------------------
|
||||
class ImageLoader : public QThread
|
||||
{
|
||||
public:
|
||||
ImageLoader();
|
||||
~ImageLoader();
|
||||
// returns FALSE if worker is still busy and can't take the task
|
||||
bool busy() const;
|
||||
void generate(int index, const QString& fileName, QSize size);
|
||||
void reset(){idx = -1;};
|
||||
int index() const { return idx; };
|
||||
QImage result();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private:
|
||||
QMutex mutex;
|
||||
QWaitCondition condition;
|
||||
|
||||
bool restart;
|
||||
bool working;
|
||||
int idx;
|
||||
QString fileName;
|
||||
QSize size;
|
||||
QImage img;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
344
YACReaderLibrary/comic_flow_widget.cpp
Normal file
344
YACReaderLibrary/comic_flow_widget.cpp
Normal file
@ -0,0 +1,344 @@
|
||||
#include "comic_flow_widget.h"
|
||||
|
||||
ComicFlowWidget::ComicFlowWidget(QWidget * parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ComicFlowWidgetSW::ComicFlowWidgetSW(QWidget * parent)
|
||||
:ComicFlowWidget(parent)
|
||||
{
|
||||
flow = new ComicFlow(parent);
|
||||
|
||||
connect(flow,SIGNAL(centerIndexChanged(int)),this,SIGNAL(centerIndexChanged(int)));
|
||||
connect(flow,SIGNAL(selected(unsigned int)),this,SIGNAL(selected(unsigned int)));
|
||||
|
||||
QVBoxLayout * l = new QVBoxLayout;
|
||||
l->addWidget(flow);
|
||||
setLayout(l);
|
||||
|
||||
//TODO eleminar "padding"
|
||||
QPalette Pal(palette());
|
||||
// set black background
|
||||
Pal.setColor(QPalette::Background, Qt::black);
|
||||
setAutoFillBackground(true);
|
||||
setPalette(Pal);
|
||||
|
||||
//config
|
||||
QMatrix m;
|
||||
m.rotate(-90);
|
||||
m.scale(-1,1);
|
||||
QImage image(":/images/setRead.png");
|
||||
QImage imageTransformed = image.transformed(m,Qt::SmoothTransformation);
|
||||
setMarkImage(imageTransformed);
|
||||
}
|
||||
|
||||
QSize ComicFlowWidgetSW::minimumSizeHint() const
|
||||
{
|
||||
return flow->minimumSizeHint();
|
||||
}
|
||||
QSize ComicFlowWidgetSW::sizeHint() const
|
||||
{
|
||||
return flow->sizeHint();
|
||||
}
|
||||
|
||||
void ComicFlowWidgetSW::setShowMarks(bool value)
|
||||
{
|
||||
flow->setShowMarks(value);
|
||||
}
|
||||
void ComicFlowWidgetSW::setMarks(QVector<bool> marks)
|
||||
{
|
||||
flow->setMarks(marks);
|
||||
}
|
||||
void ComicFlowWidgetSW::setMarkImage(QImage & image)
|
||||
{
|
||||
flow->setMarkImage(image);
|
||||
}
|
||||
void ComicFlowWidgetSW::markSlide(int index)
|
||||
{
|
||||
flow->markSlide(index);
|
||||
}
|
||||
void ComicFlowWidgetSW::unmarkSlide(int index)
|
||||
{
|
||||
flow->unmarkSlide(index);
|
||||
}
|
||||
void ComicFlowWidgetSW::setSlideSize(QSize size)
|
||||
{
|
||||
flow->setSlideSize(size);
|
||||
}
|
||||
void ComicFlowWidgetSW::clear()
|
||||
{
|
||||
flow->clear();
|
||||
}
|
||||
void ComicFlowWidgetSW::setImagePaths(QStringList paths)
|
||||
{
|
||||
flow->setImagePaths(paths);
|
||||
}
|
||||
void ComicFlowWidgetSW::setCenterIndex(int index)
|
||||
{
|
||||
flow->setCenterIndex(index);
|
||||
}
|
||||
void ComicFlowWidgetSW::showSlide(int index)
|
||||
{
|
||||
flow->showSlide(index);
|
||||
}
|
||||
int ComicFlowWidgetSW::centerIndex()
|
||||
{
|
||||
return flow->centerIndex();
|
||||
}
|
||||
void ComicFlowWidgetSW::updateMarks()
|
||||
{
|
||||
flow->updateMarks();
|
||||
}
|
||||
void ComicFlowWidgetSW::setFlowType(FlowType flowType)
|
||||
{
|
||||
flow->setFlowType(flowType);
|
||||
}
|
||||
void ComicFlowWidgetSW::render()
|
||||
{
|
||||
flow->render();
|
||||
}
|
||||
void ComicFlowWidgetSW::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
flow->keyPressEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetSW::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
flow->paintEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetSW::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
flow->mousePressEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetSW::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
flow->resizeEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetSW::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
flow->mouseDoubleClickEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetSW::updateConfig(QSettings * settings)
|
||||
{
|
||||
switch (settings->value(FLOW_TYPE_SW).toInt())
|
||||
{
|
||||
case 0:
|
||||
flow->setFlowType(CoverFlowLike);
|
||||
return;
|
||||
case 1:
|
||||
flow->setFlowType(Strip);
|
||||
return;
|
||||
case 2:
|
||||
flow->setFlowType(StripOverlapped);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ComicFlowWidgetSW::remove(int cover)
|
||||
{
|
||||
flow->removeSlide(cover);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
///OpenGL ComicFlow
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ComicFlowWidgetGL::ComicFlowWidgetGL(QWidget * parent)
|
||||
:ComicFlowWidget(parent)
|
||||
{
|
||||
flow = new YACReaderComicFlowGL(parent);
|
||||
|
||||
connect(flow,SIGNAL(centerIndexChanged(int)),this,SIGNAL(centerIndexChanged(int)));
|
||||
connect(flow,SIGNAL(selected(unsigned int)),this,SIGNAL(selected(unsigned int)));
|
||||
|
||||
QVBoxLayout * l = new QVBoxLayout;
|
||||
l->addWidget(flow);
|
||||
l->setContentsMargins(0,0,0,0);
|
||||
setLayout(l);
|
||||
|
||||
//TODO eleminar "padding"
|
||||
QPalette Pal(palette());
|
||||
// set black background
|
||||
Pal.setColor(QPalette::Background, Qt::black);
|
||||
setAutoFillBackground(true);
|
||||
setPalette(Pal);
|
||||
}
|
||||
|
||||
QSize ComicFlowWidgetGL::minimumSizeHint() const
|
||||
{
|
||||
return flow->minimumSizeHint();
|
||||
}
|
||||
QSize ComicFlowWidgetGL::sizeHint() const
|
||||
{
|
||||
return flow->sizeHint();
|
||||
}
|
||||
|
||||
void ComicFlowWidgetGL::setShowMarks(bool value)
|
||||
{
|
||||
flow->setShowMarks(value);
|
||||
}
|
||||
void ComicFlowWidgetGL::setMarks(QVector<bool> marks)
|
||||
{
|
||||
flow->setMarks(marks);
|
||||
}
|
||||
void ComicFlowWidgetGL::setMarkImage(QImage & image)
|
||||
{
|
||||
flow->setMarkImage(image);
|
||||
}
|
||||
void ComicFlowWidgetGL::markSlide(int index)
|
||||
{
|
||||
flow->markSlide(index);
|
||||
}
|
||||
void ComicFlowWidgetGL::unmarkSlide(int index)
|
||||
{
|
||||
flow->unmarkSlide(index);
|
||||
}
|
||||
void ComicFlowWidgetGL::setSlideSize(QSize size)
|
||||
{
|
||||
flow->setSlideSize(size);
|
||||
}
|
||||
void ComicFlowWidgetGL::clear()
|
||||
{
|
||||
flow->clear();
|
||||
}
|
||||
void ComicFlowWidgetGL::setImagePaths(QStringList paths)
|
||||
{
|
||||
flow->setImagePaths(paths);
|
||||
}
|
||||
void ComicFlowWidgetGL::setCenterIndex(int index)
|
||||
{
|
||||
flow->setCenterIndex(index);
|
||||
}
|
||||
void ComicFlowWidgetGL::showSlide(int index)
|
||||
{
|
||||
flow->showSlide(index);
|
||||
}
|
||||
int ComicFlowWidgetGL::centerIndex()
|
||||
{
|
||||
return flow->centerIndex();
|
||||
}
|
||||
void ComicFlowWidgetGL::updateMarks()
|
||||
{
|
||||
flow->updateMarks();
|
||||
}
|
||||
void ComicFlowWidgetGL::setFlowType(FlowType flowType)
|
||||
{
|
||||
if(flowType == CoverFlowLike)
|
||||
flow->setPreset(presetYACReaderFlowClassicConfig);
|
||||
else if(flowType == Strip)
|
||||
flow->setPreset(presetYACReaderFlowStripeConfig);
|
||||
else if(flowType == StripOverlapped)
|
||||
flow->setPreset(presetYACReaderFlowOverlappedStripeConfig);
|
||||
else
|
||||
flow->setPreset(defaultYACReaderFlowConfig);
|
||||
}
|
||||
void ComicFlowWidgetGL::render()
|
||||
{
|
||||
flow->render();
|
||||
}
|
||||
void ComicFlowWidgetGL::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
flow->keyPressEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetGL::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
//flow->paintEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetGL::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
flow->mousePressEvent(event);
|
||||
}
|
||||
void ComicFlowWidgetGL::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
flow->resizeGL(event->size().width(),event->size().height());
|
||||
}
|
||||
void ComicFlowWidgetGL::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
flow->mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void ComicFlowWidgetGL::updateConfig(QSettings * settings)
|
||||
{
|
||||
Performance performance = medium;
|
||||
|
||||
switch (settings->value(PERFORMANCE).toInt())
|
||||
{
|
||||
case 0:
|
||||
performance = low;
|
||||
break;
|
||||
case 1:
|
||||
performance = medium;
|
||||
break;
|
||||
case 2:
|
||||
performance = high;
|
||||
break;
|
||||
case 3:
|
||||
performance = ultraHigh;
|
||||
break;
|
||||
}
|
||||
|
||||
flow->setPerformance(performance);
|
||||
if(!settings->contains(V_SYNC))
|
||||
flow->useVSync(false);
|
||||
else
|
||||
flow->useVSync(settings->value(V_SYNC).toBool());
|
||||
|
||||
switch (settings->value(FLOW_TYPE_GL).toInt())
|
||||
{
|
||||
case 0:
|
||||
flow->setPreset(presetYACReaderFlowClassicConfig);
|
||||
return;
|
||||
case 1:
|
||||
flow->setPreset(presetYACReaderFlowStripeConfig);
|
||||
return;
|
||||
case 2:
|
||||
flow->setPreset(presetYACReaderFlowOverlappedStripeConfig);
|
||||
return;
|
||||
case 3:
|
||||
flow->setPreset(defaultYACReaderFlowConfig);
|
||||
return;
|
||||
case 4:
|
||||
flow->setPreset(pressetYACReaderFlowDownConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//custom config
|
||||
|
||||
flow->setCF_RX(settings->value(X_ROTATION).toInt());
|
||||
flow->setCF_Y(settings->value(Y_POSITION).toInt());
|
||||
flow->setX_Distance(settings->value(COVER_DISTANCE).toInt());
|
||||
flow->setCenter_Distance(settings->value(CENTRAL_DISTANCE).toInt());
|
||||
flow->setCF_Z(settings->value(ZOOM_LEVEL).toInt());
|
||||
flow->setY_Distance(settings->value(Y_COVER_OFFSET).toInt());
|
||||
flow->setZ_Distance(settings->value(Z_COVER_OFFSET).toInt());
|
||||
flow->setRotation(settings->value(COVER_ROTATION).toInt());
|
||||
flow->setFadeOutDist(settings->value(FADE_OUT_DIST).toInt());
|
||||
flow->setLightStrenght(settings->value(LIGHT_STRENGTH).toInt());
|
||||
flow->setMaxAngle(settings->value(MAX_ANGLE).toInt());
|
||||
|
||||
/* flow->setVisibility(settings->value("visibilityDistance").toInt());
|
||||
flow->setLightStrenght(settings->value("lightStrength").toInt())*/;
|
||||
|
||||
}
|
||||
|
||||
void ComicFlowWidgetGL::remove(int cover)
|
||||
{
|
||||
flow->remove(cover);
|
||||
}
|
||||
|
||||
//void ComicFlowWidgetGL::setCF_RX(int value){ flow->setCF_RX(value);}
|
||||
//void ComicFlowWidgetGL::setCF_RY(int value){ flow->setCF_RY(value);}
|
||||
//void ComicFlowWidgetGL::setCF_RZ(int value){ flow->setCF_RZ(value);}
|
||||
//void ComicFlowWidgetGL::setZoom(int zoom){ flow->setZoom(zoom);}
|
||||
//void ComicFlowWidgetGL::setRotation(int angle){ flow->setRotation(angle);}
|
||||
//void ComicFlowWidgetGL::setX_Distance(int distance){ flow->setX_Distance(distance);}
|
||||
//void ComicFlowWidgetGL::setCenter_Distance(int distance){ flow->setCenter_Distance(distance);}
|
||||
//void ComicFlowWidgetGL::setZ_Distance(int distance){ flow->setZ_Distance(distance);}
|
||||
//void ComicFlowWidgetGL::setCF_Y(int value){ flow->setCF_Y(value);}
|
||||
//void ComicFlowWidgetGL::setY_Distance(int value){ flow->setY_Distance(value);}
|
||||
//void ComicFlowWidgetGL::setPreset(const Preset & p){ flow->setPreset(p);}
|
||||
128
YACReaderLibrary/comic_flow_widget.h
Normal file
128
YACReaderLibrary/comic_flow_widget.h
Normal file
@ -0,0 +1,128 @@
|
||||
#ifndef __COMIC_FLOW_WIDGET_H
|
||||
#define __COMIC_FLOW_WIDGET_H
|
||||
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "pictureflow.h"
|
||||
#include "comic_flow.h"
|
||||
#include "yacreader_flow_gl.h"
|
||||
|
||||
class ComicFlowWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComicFlowWidget(QWidget * paret = 0);
|
||||
|
||||
public slots:
|
||||
virtual void setShowMarks(bool value) = 0;
|
||||
virtual void setMarks(QVector<bool> marks) = 0;
|
||||
virtual void setMarkImage(QImage & image) = 0;
|
||||
virtual void markSlide(int index) = 0;
|
||||
virtual void unmarkSlide(int index) = 0;
|
||||
virtual void setSlideSize(QSize size) = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual void setImagePaths(QStringList paths) = 0;
|
||||
virtual void setCenterIndex(int index) = 0;
|
||||
virtual void showSlide(int index) = 0;
|
||||
virtual int centerIndex() = 0;
|
||||
virtual void updateMarks() = 0;
|
||||
virtual void setFlowType(FlowType flowType) = 0;
|
||||
virtual void render() = 0;
|
||||
virtual void updateConfig(QSettings * settings) = 0;
|
||||
virtual void remove(int cover) = 0;
|
||||
signals:
|
||||
void centerIndexChanged(int);
|
||||
void selected(unsigned int);
|
||||
};
|
||||
|
||||
|
||||
class ComicFlowWidgetSW : public ComicFlowWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
ComicFlow * flow;
|
||||
public:
|
||||
ComicFlowWidgetSW(QWidget * parent = 0);
|
||||
|
||||
void setShowMarks(bool value);
|
||||
void setMarks(QVector<bool> marks);
|
||||
void setMarkImage(QImage & image);
|
||||
void markSlide(int index);
|
||||
void unmarkSlide(int index);
|
||||
void setSlideSize(QSize size);
|
||||
void clear();
|
||||
void setImagePaths(QStringList paths);
|
||||
void setCenterIndex(int index);
|
||||
void showSlide(int index);
|
||||
int centerIndex();
|
||||
void updateMarks();
|
||||
void setFlowType(FlowType flowType);
|
||||
void render();
|
||||
void updateConfig(QSettings * settings);
|
||||
void remove(int cover);
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
QSize minimumSizeHint() const;
|
||||
QSize sizeHint() const;
|
||||
QSize slideSizeW;
|
||||
QSize slideSizeF;
|
||||
};
|
||||
|
||||
class ComicFlowWidgetGL : public ComicFlowWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
YACReaderComicFlowGL * flow;
|
||||
public:
|
||||
ComicFlowWidgetGL(QWidget * parent = 0);
|
||||
|
||||
void setShowMarks(bool value);
|
||||
void setMarks(QVector<bool> marks);
|
||||
void setMarkImage(QImage & image);
|
||||
void markSlide(int index);
|
||||
void unmarkSlide(int index);
|
||||
void setSlideSize(QSize size);
|
||||
void clear();
|
||||
void setImagePaths(QStringList paths);
|
||||
void setCenterIndex(int index);
|
||||
void showSlide(int index);
|
||||
int centerIndex();
|
||||
void updateMarks();
|
||||
void setFlowType(FlowType flowType);
|
||||
void render();
|
||||
void updateConfig(QSettings * settings);
|
||||
void remove(int cover);
|
||||
//public slots:
|
||||
// void setCF_RX(int value);
|
||||
// //the Y Rotation of the Coverflow
|
||||
// void setCF_RY(int value);
|
||||
// //the Z Rotation of the Coverflow
|
||||
// void setCF_RZ(int value);
|
||||
// //perspective
|
||||
// void setZoom(int zoom);
|
||||
// void setRotation(int angle);
|
||||
// //sets the distance between the covers
|
||||
// void setX_Distance(int distance);
|
||||
// //sets the distance between the centered and the non centered covers
|
||||
// void setCenter_Distance(int distance);
|
||||
// //sets the pushback amount
|
||||
// void setZ_Distance(int distance);
|
||||
// void setCF_Y(int value);
|
||||
// void setY_Distance(int value);
|
||||
// void setPreset(const Preset & p);
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
QSize minimumSizeHint() const;
|
||||
QSize sizeHint() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
29
YACReaderLibrary/comics_remover.cpp
Normal file
29
YACReaderLibrary/comics_remover.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include "comics_remover.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
ComicsRemover::ComicsRemover(QModelIndexList & il, QList<QString> & ps, QObject *parent) :
|
||||
QThread(parent),indexList(il), paths(ps)
|
||||
{
|
||||
}
|
||||
|
||||
void ComicsRemover::run()
|
||||
{
|
||||
QString currentComicPath;
|
||||
QListIterator<QModelIndex> i(indexList);
|
||||
QListIterator<QString> i2(paths);
|
||||
i.toBack();
|
||||
i2.toBack();
|
||||
|
||||
while (i.hasPrevious() && i2.hasPrevious())
|
||||
{
|
||||
QModelIndex mi = i.previous();
|
||||
currentComicPath = i2.previous();
|
||||
if(QFile::remove(currentComicPath))
|
||||
{
|
||||
emit remove(mi.row());
|
||||
}
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
||||
27
YACReaderLibrary/comics_remover.h
Normal file
27
YACReaderLibrary/comics_remover.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef COMICS_REMOVER_H
|
||||
#define COMICS_REMOVER_H
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <comic_db.h>
|
||||
|
||||
class ComicsRemover : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ComicsRemover(QModelIndexList & indexList, QList<QString> & paths, QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
void remove(int);
|
||||
void finished();
|
||||
|
||||
private:
|
||||
void run();
|
||||
|
||||
private:
|
||||
QModelIndexList indexList;
|
||||
QList<QString> paths;
|
||||
};
|
||||
|
||||
#endif // COMICS_REMOVER_H
|
||||
235
YACReaderLibrary/create_library_dialog.cpp
Normal file
235
YACReaderLibrary/create_library_dialog.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include "create_library_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QSizePolicy>
|
||||
#include <QMessageBox>
|
||||
|
||||
CreateLibraryDialog::CreateLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::setupUI()
|
||||
{
|
||||
textLabel = new QLabel(tr("Comics folder : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
connect(path,SIGNAL(textChanged(QString)),this,SLOT(pathSetted(QString)));
|
||||
|
||||
nameLabel = new QLabel(tr("Library Name : "));
|
||||
nameEdit = new QLineEdit;
|
||||
nameLabel->setBuddy(nameEdit);
|
||||
connect(nameEdit,SIGNAL(textChanged(QString)),this,SLOT(nameSetted(QString)));
|
||||
|
||||
accept = new QPushButton(tr("Create"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(create()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SIGNAL(cancelCreate()));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/comicFolder.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
QGridLayout * content = new QGridLayout;
|
||||
|
||||
//QHBoxLayout *nameLayout = new QHBoxLayout;
|
||||
|
||||
content->addWidget(nameLabel,0,0);
|
||||
content->addWidget(nameEdit,0,1);
|
||||
|
||||
//QHBoxLayout *libraryLayout = new QHBoxLayout;
|
||||
|
||||
content->addWidget(textLabel,1,0);
|
||||
content->addWidget(path,1,1);
|
||||
content->addWidget(find,1,2);
|
||||
content->setColumnMinimumWidth(2,0); //TODO
|
||||
|
||||
QHBoxLayout *middleLayout = new QHBoxLayout;
|
||||
|
||||
progressBar = new QProgressBar(this);
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setTextVisible(false);
|
||||
progressBar->hide();
|
||||
|
||||
currentFileLabel = new QLabel("");
|
||||
currentFileLabel->setWordWrap(true);
|
||||
middleLayout->addWidget(currentFileLabel);
|
||||
middleLayout->addStretch();
|
||||
middleLayout->setSizeConstraint(QLayout::SetMaximumSize);
|
||||
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addWidget(message = new QLabel(tr("Create a library could take several minutes. You can stop the process and update the library later for completing the task.")));
|
||||
message->setWordWrap(true);
|
||||
//message->hide();
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(content);
|
||||
|
||||
mainLayout->addLayout(middleLayout);
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addWidget(progressBar);
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/new.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Create new library"));
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::create()
|
||||
{
|
||||
|
||||
QFileInfo f(path->text());
|
||||
if(f.exists() && f.isDir() && f.isWritable())
|
||||
{
|
||||
progressBar->show();
|
||||
message->show();
|
||||
currentFileLabel->setText("Importing : \n\n\n\n\n");
|
||||
this->adjustSize();
|
||||
accept->setEnabled(false);
|
||||
emit(createLibrary(QDir::cleanPath(path->text()),QDir::cleanPath(path->text())+"/.yacreaderlibrary",nameEdit->text()));
|
||||
close();
|
||||
}
|
||||
else
|
||||
QMessageBox::critical(NULL,tr("Path not found"),tr("The selected path does not exist or is not a valid path. Be sure that you have write access to this folder"));
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::showCurrentFile(QString file)
|
||||
{
|
||||
currentFileLabel->setText(tr("Importing : \n") + file);
|
||||
currentFileLabel->update();
|
||||
//this->adjustSize();
|
||||
//is->update();
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::nameSetted(const QString & text)
|
||||
{
|
||||
if(!text.isEmpty())
|
||||
{
|
||||
if(!path->text().isEmpty())
|
||||
{
|
||||
QFileInfo fi(path->text());
|
||||
if(fi.isDir())
|
||||
accept->setEnabled(true);
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::pathSetted(const QString & text)
|
||||
{
|
||||
QFileInfo fi(text);
|
||||
if(fi.isDir())
|
||||
{
|
||||
if(!nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getExistingDirectory(0,"Comics directory",".");
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
if(!nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::close()
|
||||
{
|
||||
progressBar->hide();
|
||||
path->clear();
|
||||
nameEdit->clear();
|
||||
currentFileLabel->setText("");
|
||||
this->adjustSize();
|
||||
accept->setEnabled(false);
|
||||
QDialog::close();
|
||||
}
|
||||
|
||||
void CreateLibraryDialog::setDataAndStart(QString name, QString path)
|
||||
{
|
||||
this->path->setText(path);
|
||||
this->nameEdit->setText(name);
|
||||
show();
|
||||
create();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// UpdateLibraryDialog
|
||||
//-----------------------------------------------------------------------------
|
||||
UpdateLibraryDialog::UpdateLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
QVBoxLayout * mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(message = new QLabel(tr("Updating....")));
|
||||
mainLayout->addWidget(currentFileLabel = new QLabel("\n\n\n\n"));
|
||||
currentFileLabel->setWordWrap(true);
|
||||
|
||||
QHBoxLayout * bottom = new QHBoxLayout;
|
||||
bottom->addStretch();
|
||||
bottom->addWidget(cancel = new QPushButton(tr("Cancel")));
|
||||
|
||||
connect(cancel,SIGNAL(clicked()),this,SIGNAL(cancelUpdate()));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
|
||||
mainLayout->addStretch();
|
||||
|
||||
progressBar = new QProgressBar(this);
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setTextVisible(false);
|
||||
|
||||
mainLayout->addWidget(progressBar);
|
||||
mainLayout->addLayout(bottom);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/updateLibrary.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Update library"));
|
||||
}
|
||||
|
||||
void UpdateLibraryDialog::showCurrentFile(QString file)
|
||||
{
|
||||
currentFileLabel->setText(file);
|
||||
currentFileLabel->update();
|
||||
this->update();
|
||||
}
|
||||
|
||||
void UpdateLibraryDialog::close()
|
||||
{
|
||||
currentFileLabel->setText("");
|
||||
this->adjustSize();
|
||||
QDialog::close();
|
||||
}
|
||||
58
YACReaderLibrary/create_library_dialog.h
Normal file
58
YACReaderLibrary/create_library_dialog.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef __CREATE_LIBRARY_DIALOG_H
|
||||
#define __CREATE_LIBRARY_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QThread>
|
||||
#include <QProgressBar>
|
||||
|
||||
class CreateLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CreateLibraryDialog(QWidget * parent = 0);
|
||||
private:
|
||||
QLabel * nameLabel;
|
||||
QLabel * textLabel;
|
||||
QLabel * message;
|
||||
QProgressBar *progressBar;
|
||||
QLabel * currentFileLabel;
|
||||
QLineEdit * path;
|
||||
QLineEdit * nameEdit;
|
||||
QPushButton * find;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
void setupUI();
|
||||
public slots:
|
||||
void create();
|
||||
void findPath();
|
||||
void showCurrentFile(QString file);
|
||||
void close();
|
||||
void setDataAndStart(QString name, QString paht);
|
||||
void nameSetted(const QString & text);
|
||||
void pathSetted(const QString & text);
|
||||
signals:
|
||||
void createLibrary(QString source, QString target, QString name);
|
||||
void cancelCreate();
|
||||
};
|
||||
|
||||
class UpdateLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
UpdateLibraryDialog(QWidget * parent = 0);
|
||||
private:
|
||||
QLabel * message;
|
||||
QLabel * currentFileLabel;
|
||||
QProgressBar *progressBar;
|
||||
QPushButton * cancel;
|
||||
public slots:
|
||||
void showCurrentFile(QString file);
|
||||
void close();
|
||||
signals:
|
||||
void cancelUpdate();
|
||||
};
|
||||
|
||||
#endif
|
||||
591
YACReaderLibrary/db/data_base_management.cpp
Normal file
591
YACReaderLibrary/db/data_base_management.cpp
Normal file
@ -0,0 +1,591 @@
|
||||
#include "data_base_management.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include "library_creator.h"
|
||||
#include "check_new_version.h"
|
||||
|
||||
static QString fields = "title ,"
|
||||
|
||||
"coverPage,"
|
||||
"numPages,"
|
||||
|
||||
"number,"
|
||||
"isBis,"
|
||||
"count,"
|
||||
|
||||
"volume,"
|
||||
"storyArc,"
|
||||
"arcNumber,"
|
||||
"arcCount,"
|
||||
|
||||
"genere,"
|
||||
|
||||
"writer,"
|
||||
"penciller,"
|
||||
"inker,"
|
||||
"colorist,"
|
||||
"letterer,"
|
||||
"coverArtist,"
|
||||
|
||||
"date,"
|
||||
"publisher,"
|
||||
"format,"
|
||||
"color,"
|
||||
"ageRating,"
|
||||
|
||||
"synopsis,"
|
||||
"characters,"
|
||||
"notes,"
|
||||
|
||||
"hash";
|
||||
|
||||
DataBaseManagement::DataBaseManagement()
|
||||
:QObject(),dataBasesList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*TreeModel * DataBaseManagement::newTreeModel(QString path)
|
||||
{
|
||||
//la consulta se ejecuta...
|
||||
QSqlQuery selectQuery(loadDatabase(path));
|
||||
selectQuery.setForwardOnly(true);
|
||||
selectQuery.exec("select * from folder order by parentId,name");
|
||||
//selectQuery.finish();
|
||||
return new TreeModel(selectQuery);
|
||||
}*/
|
||||
|
||||
QSqlDatabase DataBaseManagement::createDatabase(QString name, QString path)
|
||||
{
|
||||
return createDatabase(QDir::cleanPath(path) + "/" + name + ".ydb");
|
||||
}
|
||||
|
||||
QSqlDatabase DataBaseManagement::createDatabase(QString dest)
|
||||
{
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",dest);
|
||||
db.setDatabaseName(dest);
|
||||
if (!db.open())
|
||||
qDebug() << db.lastError();
|
||||
else {
|
||||
qDebug() << db.tables();
|
||||
}
|
||||
|
||||
{
|
||||
QSqlQuery pragma("PRAGMA foreign_keys = ON",db);
|
||||
//pragma.finish();
|
||||
DataBaseManagement::createTables(db);
|
||||
|
||||
QSqlQuery query("INSERT INTO folder (parentId, name, path) "
|
||||
"VALUES (1,'root', '/')",db);
|
||||
}
|
||||
//query.finish();
|
||||
//db.close();
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
QSqlDatabase DataBaseManagement::loadDatabase(QString path)
|
||||
{
|
||||
//TODO check path
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",path);
|
||||
db.setDatabaseName(path+"/library.ydb");
|
||||
if (!db.open()) {
|
||||
//se devuelve una base de datos vac<61>a e inv<6E>lida
|
||||
|
||||
return QSqlDatabase();
|
||||
}
|
||||
QSqlQuery pragma("PRAGMA foreign_keys = ON",db);
|
||||
//pragma.finish();
|
||||
//devuelve la base de datos
|
||||
return db;
|
||||
}
|
||||
|
||||
QSqlDatabase DataBaseManagement::loadDatabaseFromFile(QString filePath)
|
||||
{
|
||||
//TODO check path
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",filePath);
|
||||
db.setDatabaseName(filePath);
|
||||
if (!db.open()) {
|
||||
//se devuelve una base de datos vac<61>a e inv<6E>lida
|
||||
|
||||
return QSqlDatabase();
|
||||
}
|
||||
{
|
||||
QSqlQuery pragma("PRAGMA foreign_keys = ON",db);
|
||||
}
|
||||
//pragma.finish();
|
||||
//devuelve la base de datos
|
||||
return db;
|
||||
}
|
||||
|
||||
bool DataBaseManagement::createTables(QSqlDatabase & database)
|
||||
{
|
||||
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, FOREIGN KEY(parentId) REFERENCES folder(id) ON DELETE CASCADE)");
|
||||
success = success && queryFolder.exec();
|
||||
//queryFolder.finish();
|
||||
//COMIC INFO (representa la informaci<63>n de un c<>mic, cada c<>mic tendr<64> un id<69>ntificador <20>nico formado por un hash sha1'de los primeros 512kb' + su tama<6D>o en bytes)
|
||||
QSqlQuery queryComicInfo(database);
|
||||
queryComicInfo.prepare("CREATE TABLE comic_info ("
|
||||
"id INTEGER PRIMARY KEY,"
|
||||
"title TEXT,"
|
||||
|
||||
"coverPage INTEGER DEFAULT 1,"
|
||||
"numPages INTEGER,"
|
||||
|
||||
"number INTEGER,"
|
||||
"isBis BOOLEAN,"
|
||||
"count INTEGER,"
|
||||
|
||||
"volume TEXT,"
|
||||
"storyArc TEXT,"
|
||||
"arcNumber INTEGER,"
|
||||
"arcCount INTEGER,"
|
||||
|
||||
"genere TEXT,"
|
||||
|
||||
"writer TEXT,"
|
||||
"penciller TEXT,"
|
||||
"inker TEXT,"
|
||||
"colorist TEXT,"
|
||||
"letterer TEXT,"
|
||||
"coverArtist TEXT,"
|
||||
|
||||
"date TEXT," //dd/mm/yyyy --> se mostrar<61> en 3 campos diferentes
|
||||
"publisher TEXT,"
|
||||
"format TEXT,"
|
||||
"color BOOLEAN,"
|
||||
"ageRating BOOLEAN,"
|
||||
|
||||
"synopsis TEXT,"
|
||||
"characters TEXT,"
|
||||
"notes TEXT,"
|
||||
|
||||
"hash TEXT UNIQUE NOT NULL,"
|
||||
"edited BOOLEAN DEFAULT 0,"
|
||||
"read BOOLEAN DEFAULT 0)");
|
||||
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();
|
||||
|
||||
QSqlQuery query("INSERT INTO db_info (version) "
|
||||
"VALUES ('"VERSION"')",database);
|
||||
//query.finish();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
#include <qmessagebox.h>
|
||||
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));
|
||||
attach.exec();
|
||||
//attach.finish();
|
||||
|
||||
QSqlQuery attach2(destDB);
|
||||
attach2.prepare("ATTACH DATABASE '"+QDir().toNativeSeparators(source) +"' AS source;");
|
||||
attach2.exec();
|
||||
//attach2.finish();
|
||||
|
||||
//sourceDB.close();
|
||||
QSqlQuery queryDBInfo(destDB);
|
||||
queryDBInfo.prepare("CREATE TABLE dest.db_info (version TEXT NOT NULL)");
|
||||
queryDBInfo.exec();
|
||||
//queryDBInfo.finish();
|
||||
|
||||
/*QSqlQuery queryComicsInfo(sourceDB);
|
||||
queryComicsInfo.prepare("CREATE TABLE dest.comic_info (id INTEGER PRIMARY KEY, hash TEXT NOT NULL, edited BOOLEAN DEFAULT FALSE, title TEXT, read BOOLEAN)");
|
||||
queryComicsInfo.exec();*/
|
||||
|
||||
QSqlQuery query("INSERT INTO dest.db_info (version) "
|
||||
"VALUES ('"VERSION"')",destDB);
|
||||
//query.finish();
|
||||
|
||||
QSqlQuery exportData(destDB);
|
||||
exportData.prepare("create table dest.comic_info as select " + fields +
|
||||
" from source.comic_info where source.comic_info.edited = 1");
|
||||
exportData.exec();
|
||||
//exportData.finish();
|
||||
}
|
||||
|
||||
//sourceDB.close();
|
||||
destDB.close();
|
||||
QSqlDatabase::removeDatabase(dest);
|
||||
|
||||
}
|
||||
|
||||
bool DataBaseManagement::importComicsInfo(QString source, QString dest)
|
||||
{
|
||||
QString error;
|
||||
QString driver;
|
||||
QStringList hashes;
|
||||
|
||||
bool b = false;
|
||||
|
||||
QSqlDatabase sourceDB = loadDatabaseFromFile(source);
|
||||
QSqlDatabase destDB = loadDatabaseFromFile(dest);
|
||||
|
||||
{
|
||||
QSqlQuery pragma("PRAGMA synchronous=OFF",destDB);
|
||||
|
||||
|
||||
QSqlQuery newInfo(sourceDB);
|
||||
newInfo.prepare("SELECT * FROM comic_info");
|
||||
newInfo.exec();
|
||||
destDB.transaction();
|
||||
int cp;
|
||||
while (newInfo.next()) //cada tupla deber<65> ser insertada o actualizada
|
||||
{
|
||||
QSqlQuery update(destDB);
|
||||
update.prepare("UPDATE comic_info SET "
|
||||
"title = :title,"
|
||||
|
||||
"coverPage = :coverPage,"
|
||||
"numPages = :numPages,"
|
||||
|
||||
"number = :number,"
|
||||
"isBis = :isBis,"
|
||||
"count = :count,"
|
||||
|
||||
"volume = :volume,"
|
||||
"storyArc = :storyArc,"
|
||||
"arcNumber = :arcNumber,"
|
||||
"arcCount = :arcCount,"
|
||||
|
||||
"genere = :genere,"
|
||||
|
||||
"writer = :writer,"
|
||||
"penciller = :penciller,"
|
||||
"inker = :inker,"
|
||||
"colorist = :colorist,"
|
||||
"letterer = :letterer,"
|
||||
"coverArtist = :coverArtist,"
|
||||
|
||||
"date = :date,"
|
||||
"publisher = :publisher,"
|
||||
"format = :format,"
|
||||
"color = :color,"
|
||||
"ageRating = :ageRating,"
|
||||
|
||||
"synopsis = :synopsis,"
|
||||
"characters = :characters,"
|
||||
"notes = :notes,"
|
||||
|
||||
"edited = :edited"
|
||||
|
||||
" WHERE hash = :hash ");
|
||||
|
||||
QSqlQuery insert(destDB);
|
||||
insert.prepare("INSERT INTO comic_info "
|
||||
"(title,"
|
||||
"coverPage,"
|
||||
"numPages,"
|
||||
"number,"
|
||||
"isBis,"
|
||||
"count,"
|
||||
"volume,"
|
||||
"storyArc,"
|
||||
"arcNumber,"
|
||||
"arcCount,"
|
||||
"genere,"
|
||||
"writer,"
|
||||
"penciller,"
|
||||
"inker,"
|
||||
"colorist,"
|
||||
"letterer,"
|
||||
"coverArtist,"
|
||||
"date,"
|
||||
"publisher,"
|
||||
"format,"
|
||||
"color,"
|
||||
"ageRating,"
|
||||
"synopsis,"
|
||||
"characters,"
|
||||
"notes,"
|
||||
"read,"
|
||||
"edited,"
|
||||
"hash)"
|
||||
|
||||
"VALUES (:title,"
|
||||
":coverPage,"
|
||||
":numPages,"
|
||||
":number,"
|
||||
":isBis,"
|
||||
":count,"
|
||||
|
||||
":volume,"
|
||||
":storyArc,"
|
||||
":arcNumber,"
|
||||
":arcCount,"
|
||||
|
||||
":genere,"
|
||||
|
||||
":writer,"
|
||||
":penciller,"
|
||||
":inker,"
|
||||
":colorist,"
|
||||
":letterer,"
|
||||
":coverArtist,"
|
||||
|
||||
":date,"
|
||||
":publisher,"
|
||||
":format,"
|
||||
":color,"
|
||||
":ageRating,"
|
||||
|
||||
":synopsis,"
|
||||
":characters,"
|
||||
":notes,"
|
||||
|
||||
":read,"
|
||||
":edited,"
|
||||
|
||||
":hash )");
|
||||
|
||||
QSqlRecord record = newInfo.record();
|
||||
cp = record.value("coverPage").toInt();
|
||||
if(cp>1)
|
||||
{
|
||||
QSqlQuery checkCoverPage(destDB);
|
||||
checkCoverPage.prepare("SELECT coverPage FROM comic_info where hash = :hash");
|
||||
checkCoverPage.bindValue(":hash",record.value("hash").toString());
|
||||
checkCoverPage.exec();
|
||||
bool extract = false;
|
||||
if(checkCoverPage.next())
|
||||
{
|
||||
extract = checkCoverPage.record().value("coverPage").toInt() != cp;
|
||||
}
|
||||
if(extract)
|
||||
hashes.append(record.value("hash").toString());
|
||||
}
|
||||
|
||||
bindValuesFromRecord(record,update);
|
||||
|
||||
update.bindValue(":edited",1);
|
||||
|
||||
|
||||
update.exec();
|
||||
|
||||
if(update.numRowsAffected() == 0)
|
||||
{
|
||||
|
||||
bindValuesFromRecord(record,insert);
|
||||
insert.bindValue(":edited",1);
|
||||
insert.bindValue(":read",0);
|
||||
|
||||
insert.exec();
|
||||
|
||||
QString error1 = insert.lastError().databaseText();
|
||||
QString error2 = insert.lastError().driverText();
|
||||
|
||||
//QMessageBox::critical(NULL,"db",error1);
|
||||
//QMessageBox::critical(NULL,"driver",error2);
|
||||
}
|
||||
//update.finish();
|
||||
//insert.finish();
|
||||
}
|
||||
}
|
||||
|
||||
destDB.commit();
|
||||
QString hash;
|
||||
foreach(hash, hashes)
|
||||
{
|
||||
QSqlQuery getComic(destDB);
|
||||
getComic.prepare("SELECT c.path,ci.coverPage FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) where ci.hash = :hash");
|
||||
getComic.bindValue(":hash",hash);
|
||||
getComic.exec();
|
||||
if(getComic.next())
|
||||
{
|
||||
QString basePath = QString(dest).remove("/.yacreaderlibrary/library.ydb");
|
||||
QString path = basePath + getComic.record().value("path").toString();
|
||||
int coverPage = getComic.record().value("coverPage").toInt();
|
||||
ThumbnailCreator tc(path,basePath+"/.yacreaderlibrary/covers/"+hash+".jpg",coverPage);
|
||||
tc.create();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
destDB.close();
|
||||
sourceDB.close();
|
||||
QSqlDatabase::removeDatabase(source);
|
||||
QSqlDatabase::removeDatabase(dest);
|
||||
return b;
|
||||
|
||||
}
|
||||
|
||||
void DataBaseManagement::bindValuesFromRecord(const QSqlRecord & record, QSqlQuery & query)
|
||||
{
|
||||
bindString("title",record,query);
|
||||
|
||||
bindInt("coverPage",record,query);
|
||||
bindInt("numPages",record,query);
|
||||
|
||||
bindInt("number",record,query);
|
||||
bindInt("isBis",record,query);
|
||||
bindInt("count",record,query);
|
||||
|
||||
bindString("volume",record,query);
|
||||
bindString("storyArc",record,query);
|
||||
bindInt("arcNumber",record,query);
|
||||
bindInt("arcCount",record,query);
|
||||
|
||||
bindString("genere",record,query);
|
||||
|
||||
bindString("writer",record,query);
|
||||
bindString("penciller",record,query);
|
||||
bindString("inker",record,query);
|
||||
bindString("colorist",record,query);
|
||||
bindString("letterer",record,query);
|
||||
bindString("coverArtist",record,query);
|
||||
|
||||
bindString("date",record,query);
|
||||
bindString("publisher",record,query);
|
||||
bindString("format",record,query);
|
||||
bindInt("color",record,query);
|
||||
bindString("ageRating",record,query);
|
||||
|
||||
bindString("synopsis",record,query);
|
||||
bindString("characters",record,query);
|
||||
bindString("notes",record,query);
|
||||
|
||||
bindString("hash",record,query);
|
||||
}
|
||||
|
||||
void DataBaseManagement::bindString(const QString & name, const QSqlRecord & record, QSqlQuery & query)
|
||||
{
|
||||
if(!record.value(name).isNull())
|
||||
{
|
||||
query.bindValue(":"+name,record.value(name).toString());
|
||||
}
|
||||
}
|
||||
void DataBaseManagement::bindInt(const QString & name, const QSqlRecord & record, QSqlQuery & query)
|
||||
{
|
||||
if(!record.value(name).isNull())
|
||||
{
|
||||
query.bindValue(":"+name,record.value(name).toInt());
|
||||
}
|
||||
}
|
||||
|
||||
QString DataBaseManagement::checkValidDB(const QString & fullPath)
|
||||
{
|
||||
QSqlDatabase db = loadDatabaseFromFile(fullPath);
|
||||
QString versionString = "";
|
||||
if(db.isValid() && db.isOpen())
|
||||
{
|
||||
QSqlQuery version(db);
|
||||
version.prepare("SELECT * FROM db_info");
|
||||
version.exec();
|
||||
|
||||
if(version.next())
|
||||
versionString = version.record().value("version").toString();
|
||||
}
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(fullPath);
|
||||
return versionString;
|
||||
}
|
||||
|
||||
int DataBaseManagement::compareVersions(const QString & v1, const QString v2)
|
||||
{
|
||||
QStringList v1l = v1.split('.');
|
||||
QStringList v2l = v2.split('.');
|
||||
QList<int> v1il;
|
||||
QList<int> v2il;
|
||||
|
||||
foreach(QString s, v1l)
|
||||
v1il.append(s.toInt());
|
||||
|
||||
foreach(QString s,v2l)
|
||||
v2il.append(s.toInt());
|
||||
|
||||
for(int i=0;i<qMin(v1il.length(),v2il.length());i++)
|
||||
{
|
||||
if(v1il[i]<v2il[i])
|
||||
return -1;
|
||||
if(v1il[i]>v2il[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(v1il.length() < v2il.length())
|
||||
return -1;
|
||||
if(v1il.length() == v2il.length())
|
||||
return 0;
|
||||
if(v1il.length() > v2il.length())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DataBaseManagement::updateToCurrentVersion(const QString & fullPath)
|
||||
{
|
||||
QSqlDatabase db = loadDatabaseFromFile(fullPath);
|
||||
bool returnValue = false;
|
||||
if(db.isValid() && db.isOpen())
|
||||
{
|
||||
QSqlQuery updateVersion(db);
|
||||
updateVersion.prepare("UPDATE db_info SET "
|
||||
"version = :version");
|
||||
updateVersion.bindValue(":version",VERSION);
|
||||
updateVersion.exec();
|
||||
|
||||
if(updateVersion.numRowsAffected() > 0)
|
||||
returnValue = true;
|
||||
}
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(fullPath);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
//COMICS_INFO_EXPORTER
|
||||
ComicsInfoExporter::ComicsInfoExporter()
|
||||
:QThread()
|
||||
{
|
||||
}
|
||||
|
||||
void ComicsInfoExporter::exportComicsInfo(QSqlDatabase & source, QSqlDatabase & dest)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ComicsInfoExporter::run()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//COMICS_INFO_IMPORTER
|
||||
ComicsInfoImporter::ComicsInfoImporter()
|
||||
:QThread()
|
||||
{
|
||||
}
|
||||
|
||||
void ComicsInfoImporter::importComicsInfo(QSqlDatabase & source, QSqlDatabase & dest)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ComicsInfoImporter::run()
|
||||
{
|
||||
|
||||
}
|
||||
59
YACReaderLibrary/db/data_base_management.h
Normal file
59
YACReaderLibrary/db/data_base_management.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef __DATA_BASE_MANAGEMENT_H
|
||||
#define __DATA_BASE_MANAGEMENT_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtSql>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "treemodel.h"
|
||||
|
||||
class ComicsInfoExporter : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComicsInfoExporter();
|
||||
void exportComicsInfo(QSqlDatabase & source, QSqlDatabase & dest);
|
||||
private:
|
||||
void run();
|
||||
};
|
||||
|
||||
class ComicsInfoImporter : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ComicsInfoImporter();
|
||||
void importComicsInfo(QSqlDatabase & source, QSqlDatabase & dest);
|
||||
private:
|
||||
void run();
|
||||
|
||||
};
|
||||
|
||||
class DataBaseManagement : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
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 bindValuesFromRecord(const QSqlRecord & record, QSqlQuery & query);
|
||||
|
||||
public:
|
||||
DataBaseManagement();
|
||||
//TreeModel * newTreeModel(QString path);
|
||||
//crea una base de datos y todas sus tablas
|
||||
static QSqlDatabase createDatabase(QString name, QString path);
|
||||
static QSqlDatabase createDatabase(QString dest);
|
||||
//carga una base de datos desde la ruta path
|
||||
static QSqlDatabase loadDatabase(QString path);
|
||||
static QSqlDatabase loadDatabaseFromFile(QString path);
|
||||
static bool createTables(QSqlDatabase & database);
|
||||
|
||||
static void exportComicsInfo(QString source, QString dest);
|
||||
static bool importComicsInfo(QString source, QString dest);
|
||||
|
||||
static QString checkValidDB(const QString & fullPath); //retorna "" si la DB es inv<6E>lida <20> la versi<73>n si es v<>lida.
|
||||
static int compareVersions(const QString & v1, const QString v2); //retorna <0 si v1 < v2, 0 si v1 = v2 y >0 si v1 > v2
|
||||
static bool updateToCurrentVersion(const QString & path);
|
||||
};
|
||||
|
||||
#endif
|
||||
47
YACReaderLibrary/db/tableitem.cpp
Normal file
47
YACReaderLibrary/db/tableitem.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "tableitem.h"
|
||||
|
||||
//! [0]
|
||||
TableItem::TableItem(const QList<QVariant> &data)
|
||||
|
||||
{
|
||||
itemData = data;
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
TableItem::~TableItem()
|
||||
{
|
||||
|
||||
}
|
||||
//! [1]
|
||||
|
||||
|
||||
//! [5]
|
||||
int TableItem::columnCount() const
|
||||
{
|
||||
return itemData.count();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QVariant TableItem::data(int column) const
|
||||
{
|
||||
return itemData.value(column);
|
||||
}
|
||||
//! [6]
|
||||
|
||||
void TableItem::setData(int column,const QVariant & value)
|
||||
{
|
||||
itemData[column] = value;
|
||||
}
|
||||
|
||||
//! [8]
|
||||
int TableItem::row() const
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
//! [8]
|
||||
27
YACReaderLibrary/db/tableitem.h
Normal file
27
YACReaderLibrary/db/tableitem.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef TABLEITEM_H
|
||||
#define TABLEITEM_H
|
||||
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
|
||||
//! [0]
|
||||
class TableItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TableItem(const QList<QVariant> &data);
|
||||
~TableItem();
|
||||
int columnCount() const;
|
||||
QVariant data(int column) const;
|
||||
void setData(int column,const QVariant & value);
|
||||
int row() const;
|
||||
unsigned long long int id; //TODO sustituir por una clase adecuada
|
||||
//Comic comic;
|
||||
private:
|
||||
QList<QVariant> itemData;
|
||||
|
||||
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
||||
491
YACReaderLibrary/db/tablemodel.cpp
Normal file
491
YACReaderLibrary/db/tablemodel.cpp
Normal file
@ -0,0 +1,491 @@
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "tableitem.h"
|
||||
#include "tablemodel.h"
|
||||
#include "data_base_management.h"
|
||||
#include "qnaturalsorting.h"
|
||||
#include "comic_db.h"
|
||||
#include "db_helper.h"
|
||||
|
||||
//ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read
|
||||
#define NUMBER 0
|
||||
#define TITLE 1
|
||||
#define FILE_NAME 2
|
||||
#define NUM_PAGES 3
|
||||
#define ID 4
|
||||
#define PARENT_ID 5
|
||||
#define PATH 6
|
||||
#define HASH 7
|
||||
#define READ 8
|
||||
#define IS_BIS 9
|
||||
|
||||
TableModel::TableModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
connect(this,SIGNAL(beforeReset()),this,SIGNAL(modelAboutToBeReset()));
|
||||
connect(this,SIGNAL(reset()),this,SIGNAL(modelReset()));
|
||||
}
|
||||
|
||||
//! [0]
|
||||
TableModel::TableModel( QSqlQuery &sqlquery, QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
setupModelData(sqlquery);
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
TableModel::~TableModel()
|
||||
{
|
||||
qDeleteAll(_data);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
int TableModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(_data.isEmpty())
|
||||
return 0;
|
||||
return _data.first()->columnCount();
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QVariant TableModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DecorationRole)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
TableItem *item = static_cast<TableItem*>(index.internalPointer());
|
||||
if(index.column() == HASH)
|
||||
return QString::number(item->data(index.column()).toString().right(item->data(index.column()).toString().length()-40).toInt()/1024.0/1024.0,'f',2)+"Mb";
|
||||
if(index.column() == READ)
|
||||
return item->data(index.column()).toBool()?QVariant(tr("yes")):QVariant(tr("no"));
|
||||
return item->data(index.column());
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
QVariant TableModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
switch(section)//TODO obtener esto de la query
|
||||
{
|
||||
case 0:
|
||||
return QVariant(QString("#"));
|
||||
case 1:
|
||||
return QVariant(QString(tr("Title")));
|
||||
case 2:
|
||||
return QVariant(QString(tr("File Name")));
|
||||
case 3:
|
||||
return QVariant(QString(tr("Pages")));
|
||||
case 7:
|
||||
return QVariant(QString(tr("Size")));
|
||||
case 8:
|
||||
return QVariant(QString(tr("Read")));
|
||||
}
|
||||
}
|
||||
|
||||
if(orientation == Qt::Vertical && role == Qt::DecorationRole)
|
||||
{
|
||||
QString fileName = _data.value(section)->data(FILE_NAME).toString();
|
||||
QFileInfo fi(fileName);
|
||||
QString ext = fi.suffix();
|
||||
|
||||
if (ext.compare("cbr",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/comicRar.png"));
|
||||
else if (ext.compare("cbz",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/comicZip.png"));
|
||||
else if(ext.compare("pdf",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/pdf.png"));
|
||||
else if (ext.compare("tar",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/tar.png"));
|
||||
else if(ext.compare("zip",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/zip.png"));
|
||||
else if(ext.compare("rar",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/rar.png"));
|
||||
else if (ext.compare("7z",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/7z.png"));
|
||||
else if (ext.compare("cb7",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/comic7z.png"));
|
||||
else if (ext.compare("cb7",Qt::CaseInsensitive) == 0)
|
||||
return QVariant(QIcon(":/images/comicTar.png"));
|
||||
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QModelIndex TableModel::index(int row, int column, const QModelIndex &parent)
|
||||
const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(row, column, _data.at(row));
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
QModelIndex TableModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
int TableModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
TreeItem *parentItem;
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
if (!parent.isValid())
|
||||
return _data.count();
|
||||
|
||||
return 0;
|
||||
}
|
||||
//! [8]
|
||||
|
||||
QStringList TableModel::getPaths(const QString & _source)
|
||||
{
|
||||
QStringList paths;
|
||||
QString source = _source + "/.yacreaderlibrary/covers/";
|
||||
QList<TableItem *>::ConstIterator itr;
|
||||
for(itr = _data.constBegin();itr != _data.constEnd();itr++)
|
||||
{
|
||||
QString hash = (*itr)->data(HASH).toString();
|
||||
paths << source+ hash +".jpg";
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
void TableModel::setupModelData(unsigned long long int folderId,const QString & databasePath)
|
||||
{
|
||||
//QFile f(QCoreApplication::applicationDirPath()+"/performance.txt");
|
||||
//f.open(QIODevice::Append);
|
||||
beginResetModel();
|
||||
//QElapsedTimer timer;
|
||||
//timer.start();
|
||||
qDeleteAll(_data);
|
||||
_data.clear();
|
||||
|
||||
//QTextStream txtS(&f);
|
||||
//txtS << "TABLEMODEL: Tiempo de borrado: " << timer.elapsed() << "ms\r\n";
|
||||
_databasePath = databasePath;
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath);
|
||||
{
|
||||
//crear la consulta
|
||||
//timer.restart();
|
||||
QSqlQuery selectQuery(db); //TODO check
|
||||
selectQuery.prepare("select ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis from comic c inner join comic_info ci on (c.comicInfoId = ci.id) where c.parentId = :parentId");
|
||||
selectQuery.bindValue(":parentId", folderId);
|
||||
selectQuery.exec();
|
||||
//txtS << "TABLEMODEL: Tiempo de consulta: " << timer.elapsed() << "ms\r\n";
|
||||
//timer.restart();
|
||||
setupModelData(selectQuery);
|
||||
//txtS << "TABLEMODEL: Tiempo de creaci<63>n del modelo: " << timer.elapsed() << "ms\r\n";
|
||||
//selectQuery.finish();
|
||||
}
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
endResetModel();
|
||||
//f.close();
|
||||
}
|
||||
|
||||
QString TableModel::getComicPath(QModelIndex mi)
|
||||
{
|
||||
if(mi.isValid())
|
||||
return _data.at(mi.row())->data(PATH).toString();
|
||||
return "";
|
||||
}
|
||||
#define NUMBER_MAX 99999999
|
||||
void TableModel::setupModelData(QSqlQuery &sqlquery)
|
||||
{
|
||||
TableItem * currentItem;
|
||||
while (sqlquery.next())
|
||||
{
|
||||
QList<QVariant> data;
|
||||
QSqlRecord record = sqlquery.record();
|
||||
for(int i=0;i<record.count();i++)
|
||||
data << record.value(i);
|
||||
|
||||
currentItem = new TableItem(data);
|
||||
bool lessThan = false;
|
||||
if(_data.isEmpty())
|
||||
_data.append(currentItem);
|
||||
else
|
||||
{
|
||||
TableItem * last = _data.back();
|
||||
QString nameLast = last->data(FILE_NAME).toString();
|
||||
QString nameCurrent = currentItem->data(FILE_NAME).toString();
|
||||
int numberLast,numberCurrent;
|
||||
numberLast = numberCurrent = NUMBER_MAX; //TODO change by std limit
|
||||
|
||||
if(!last->data(NUMBER).isNull())
|
||||
numberLast = last->data(NUMBER).toInt();
|
||||
|
||||
if(!currentItem->data(NUMBER).isNull())
|
||||
numberCurrent = currentItem->data(NUMBER).toInt();
|
||||
|
||||
QList<TableItem *>::iterator i;
|
||||
i = _data.end();
|
||||
i--;
|
||||
|
||||
if(numberCurrent != NUMBER_MAX)
|
||||
{
|
||||
while ((lessThan =numberCurrent < numberLast) && i != _data.begin())
|
||||
{
|
||||
i--;
|
||||
numberLast = NUMBER_MAX; //TODO change by std limit
|
||||
|
||||
if(!(*i)->data(NUMBER).isNull())
|
||||
numberLast = (*i)->data(NUMBER).toInt();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((lessThan = naturalSortLessThanCI(nameCurrent,nameLast)) && i != _data.begin() && numberLast == 99999999)
|
||||
{
|
||||
i--;
|
||||
nameLast = (*i)->data(FILE_NAME).toString();
|
||||
numberLast = NUMBER_MAX; //TODO change by std limit
|
||||
|
||||
if(!(*i)->data(NUMBER).isNull())
|
||||
numberLast = (*i)->data(NUMBER).toInt();
|
||||
}
|
||||
|
||||
}
|
||||
if(!lessThan) //si se ha encontrado un elemento menor que current, se inserta justo despu<70>s
|
||||
{
|
||||
if(numberCurrent != NUMBER_MAX)
|
||||
{
|
||||
if(numberCurrent == numberLast)
|
||||
if(currentItem->data(IS_BIS).toBool())
|
||||
{
|
||||
_data.insert(++i,currentItem);
|
||||
}
|
||||
else
|
||||
_data.insert(i,currentItem);
|
||||
else
|
||||
_data.insert(++i,currentItem);
|
||||
}
|
||||
else
|
||||
_data.insert(++i,currentItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_data.insert(i,currentItem);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComicDB TableModel::getComic(const QModelIndex & mi)
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
ComicDB c = DBHelper::loadComic(_data.at(mi.row())->data(ID).toULongLong(),db);
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
ComicDB TableModel::_getComic(const QModelIndex & mi)
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
ComicDB c = DBHelper::loadComic(_data.at(mi.row())->data(ID).toULongLong(),db);
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
QVector<bool> TableModel::getReadList()
|
||||
{
|
||||
int numComics = _data.count();
|
||||
QVector<bool> readList(numComics);
|
||||
for(int i=0;i<numComics;i++)
|
||||
{
|
||||
readList[i] = _data.value(i)->data(READ).toBool();
|
||||
}
|
||||
return readList;
|
||||
}
|
||||
|
||||
QVector<bool> TableModel::setAllComicsRead(bool read)
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
db.transaction();
|
||||
int numComics = _data.count();
|
||||
QVector<bool> readList(numComics);
|
||||
for(int i=0;i<numComics;i++)
|
||||
{
|
||||
readList[i] = read;
|
||||
_data.value(i)->setData(READ,QVariant(read));
|
||||
ComicDB c = DBHelper::loadComic(_data.value(i)->data(ID).toULongLong(),db);
|
||||
c.info.read = read;
|
||||
DBHelper::update(&(c.info),db);
|
||||
}
|
||||
db.commit();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
emit dataChanged(index(0,READ),index(numComics-1,READ));
|
||||
|
||||
return readList;
|
||||
}
|
||||
|
||||
QList<ComicDB> TableModel::getComics(QList<QModelIndex> list)
|
||||
{
|
||||
QList<ComicDB> comics;
|
||||
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
db.transaction();
|
||||
QList<QModelIndex>::const_iterator itr;
|
||||
for(itr = list.constBegin(); itr!= list.constEnd();itr++)
|
||||
{
|
||||
comics.append(_getComic(*itr));
|
||||
}
|
||||
db.commit();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
return comics;
|
||||
}
|
||||
|
||||
QVector<bool> TableModel::setComicsRead(QList<QModelIndex> list,bool read)
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
db.transaction();
|
||||
foreach (QModelIndex mi, list)
|
||||
{
|
||||
_data.value(mi.row())->setData(READ, QVariant(read));
|
||||
ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ID).toULongLong(),db);
|
||||
c.info.read = read;
|
||||
DBHelper::update(&(c.info),db);
|
||||
}
|
||||
db.commit();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
emit dataChanged(index(list.first().row(),READ),index(list.last().row(),READ));
|
||||
|
||||
return getReadList();
|
||||
}
|
||||
qint64 TableModel::asignNumbers(QList<QModelIndex> list,int startingNumber)
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
db.transaction();
|
||||
qint64 idFirst = _data.value(list[0].row())->data(ID).toULongLong();
|
||||
int i = 0;
|
||||
foreach (QModelIndex mi, list)
|
||||
{
|
||||
ComicDB c = DBHelper::loadComic(_data.value(mi.row())->data(ID).toULongLong(),db);
|
||||
c.info.setNumber(startingNumber+i);
|
||||
c.info.edited = true;
|
||||
DBHelper::update(&(c.info),db);
|
||||
i++;
|
||||
}
|
||||
|
||||
db.commit();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
//emit dataChanged(index(list.first().row(),READ),index(list.last().row(),READ));
|
||||
|
||||
return idFirst;
|
||||
}
|
||||
QModelIndex TableModel::getIndexFromId(quint64 id)
|
||||
{
|
||||
QList<TableItem *>::ConstIterator itr;
|
||||
int i=0;
|
||||
for(itr = _data.constBegin();itr != _data.constEnd();itr++)
|
||||
{
|
||||
if((*itr)->data(ID).toULongLong() == id)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return index(i,0);
|
||||
}
|
||||
|
||||
void TableModel::startTransaction()
|
||||
{
|
||||
|
||||
dbTransaction = DataBaseManagement::loadDatabase(_databasePath);
|
||||
dbTransaction.transaction();
|
||||
}
|
||||
|
||||
void TableModel::finishTransaction()
|
||||
{
|
||||
dbTransaction.commit();
|
||||
dbTransaction.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TableModel::removeInTransaction(int row)
|
||||
{
|
||||
ComicDB c = DBHelper::loadComic(_data.at(row)->data(ID).toULongLong(),dbTransaction);
|
||||
|
||||
DBHelper::removeFromDB(&c,dbTransaction);
|
||||
beginRemoveRows(QModelIndex(),row,row);
|
||||
removeRow(row);
|
||||
delete _data.at(row);
|
||||
_data.removeAt(row);
|
||||
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void TableModel::remove(ComicDB * comic, int row)
|
||||
{
|
||||
beginRemoveRows(QModelIndex(),row,row);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
|
||||
DBHelper::removeFromDB(comic,db);
|
||||
|
||||
removeRow(row);
|
||||
delete _data.at(row);
|
||||
_data.removeAt(row);
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
ComicDB TableModel::getComic(int row)
|
||||
{
|
||||
return getComic(index(row,0));
|
||||
}
|
||||
|
||||
void TableModel::remove(int row)
|
||||
{
|
||||
removeInTransaction(row);
|
||||
}
|
||||
73
YACReaderLibrary/db/tablemodel.h
Normal file
73
YACReaderLibrary/db/tablemodel.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef TABLEMODEL_H
|
||||
#define TABLEMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
class ComicDB;
|
||||
|
||||
class TableItem;
|
||||
|
||||
//! [0]
|
||||
class TableModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TableModel(QObject *parent = 0);
|
||||
TableModel( QSqlQuery &sqlquery, QObject *parent = 0);
|
||||
~TableModel();
|
||||
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
void setupModelData(unsigned long long int parentFolder,const QString & databasePath);
|
||||
|
||||
//M<>todos de conveniencia
|
||||
QStringList getPaths(const QString & _source);
|
||||
QString getComicPath(QModelIndex mi);
|
||||
ComicDB getComic(const QModelIndex & mi); //--> para la edici<63>n
|
||||
ComicDB getComic(int row);
|
||||
QVector<bool> getReadList();
|
||||
QVector<bool> setAllComicsRead(bool read);
|
||||
QList<ComicDB> getComics(QList<QModelIndex> list); //--> recupera la informaci<63>n com<6F>n a los comics seleccionados
|
||||
QModelIndex getIndexFromId(quint64 id);
|
||||
//setcomicInfo(QModelIndex & mi); --> inserta en la base datos
|
||||
//setComicInfoForAllComics(); --> inserta la informaci<63>n com<6F>n a todos los c<>mics de una sola vez.
|
||||
//setComicInfoForSelectedComis(QList<QModelIndex> list); -->inserta la informaci<63>n com<6F>n para los comics seleccionados
|
||||
QVector<bool> setComicsRead(QList<QModelIndex> list,bool read);
|
||||
qint64 asignNumbers(QList<QModelIndex> list,int startingNumber);
|
||||
void remove(ComicDB * comic, int row);
|
||||
void removeInTransaction(int row);
|
||||
|
||||
public slots:
|
||||
void remove(int row);
|
||||
void startTransaction();
|
||||
void finishTransaction();
|
||||
|
||||
private:
|
||||
void setupModelData( QSqlQuery &sqlquery);
|
||||
ComicDB _getComic(const QModelIndex & mi);
|
||||
QList<TableItem *> _data;
|
||||
|
||||
QString _databasePath;
|
||||
|
||||
QSqlDatabase dbTransaction;
|
||||
|
||||
signals:
|
||||
void beforeReset();
|
||||
void reset();
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
||||
147
YACReaderLibrary/db/treeitem.cpp
Normal file
147
YACReaderLibrary/db/treeitem.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
treeitem.cpp
|
||||
|
||||
A container for items of data supplied by the simple tree model.
|
||||
*/
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "treeitem.h"
|
||||
#include "qnaturalsorting.h"
|
||||
|
||||
//! [0]
|
||||
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
|
||||
{
|
||||
parentItem = parent;
|
||||
itemData = data;
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
TreeItem::~TreeItem()
|
||||
{
|
||||
qDeleteAll(childItems);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
void TreeItem::appendChild(TreeItem *item)
|
||||
{
|
||||
item->parentItem = this;
|
||||
//TODO insertar odernado
|
||||
if(childItems.isEmpty())
|
||||
childItems.append(item);
|
||||
else
|
||||
{
|
||||
TreeItem * last = childItems.back();
|
||||
QString nameLast = last->data(1).toString(); //TODO usar info name si est<73> disponible, sino el nombre del fichero.....
|
||||
QString nameCurrent = item->data(1).toString();
|
||||
QList<TreeItem *>::iterator i;
|
||||
i = childItems.end();
|
||||
i--;
|
||||
while (naturalSortLessThanCI(nameCurrent,nameLast) && i != childItems.begin())
|
||||
{
|
||||
i--;
|
||||
nameLast = (*i)->data(1).toString();
|
||||
}
|
||||
if(!naturalSortLessThanCI(nameCurrent,nameLast)) //si se ha encontrado un elemento menor que current, se inserta justo despu<70>s
|
||||
childItems.insert(++i,item);
|
||||
else
|
||||
childItems.insert(i,item);
|
||||
|
||||
}
|
||||
|
||||
//childItems.append(item);
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
TreeItem *TreeItem::child(int row)
|
||||
{
|
||||
return childItems.value(row);
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
int TreeItem::childCount() const
|
||||
{
|
||||
return childItems.count();
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
int TreeItem::columnCount() const
|
||||
{
|
||||
return itemData.count();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QVariant TreeItem::data(int column) const
|
||||
{
|
||||
return itemData.value(column);
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
TreeItem *TreeItem::parent()
|
||||
{
|
||||
return parentItem;
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
int TreeItem::row() const
|
||||
{
|
||||
if (parentItem)
|
||||
return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
|
||||
|
||||
return 0;
|
||||
}
|
||||
//! [8]
|
||||
|
||||
|
||||
QList<QVariant> TreeItem::getData() const
|
||||
{
|
||||
return itemData;
|
||||
}
|
||||
78
YACReaderLibrary/db/treeitem.h
Normal file
78
YACReaderLibrary/db/treeitem.h
Normal file
@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TREEITEM_H
|
||||
#define TREEITEM_H
|
||||
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QModelIndex>
|
||||
|
||||
//! [0]
|
||||
class TreeItem
|
||||
{
|
||||
public:
|
||||
TreeItem(const QList<QVariant> &data, TreeItem *parent = 0);
|
||||
~TreeItem();
|
||||
|
||||
void appendChild(TreeItem *child);
|
||||
|
||||
TreeItem *child(int row);
|
||||
int childCount() const;
|
||||
int columnCount() const;
|
||||
QVariant data(int column) const;
|
||||
QList<QVariant> getData() const;
|
||||
int row() const;
|
||||
TreeItem *parent();
|
||||
TreeItem *parentItem;
|
||||
unsigned long long int id;
|
||||
QList<QString> comicNames;
|
||||
TreeItem * originalItem;
|
||||
private:
|
||||
QList<TreeItem*> childItems;
|
||||
QList<QVariant> itemData;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
||||
417
YACReaderLibrary/db/treemodel.cpp
Normal file
417
YACReaderLibrary/db/treemodel.cpp
Normal file
@ -0,0 +1,417 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
treemodel.cpp
|
||||
|
||||
Provides a simple tree model to show how to create and use hierarchical
|
||||
models.
|
||||
*/
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
|
||||
#include "treeitem.h"
|
||||
#include "treemodel.h"
|
||||
#include "data_base_management.h"
|
||||
|
||||
#define ROOT 1
|
||||
|
||||
TreeModel::TreeModel(QObject *parent)
|
||||
: QAbstractItemModel(parent),rootItem(0),rootBeforeFilter(0),filterEnabled(false),includeComics(false)
|
||||
{
|
||||
connect(this,SIGNAL(beforeReset()),this,SIGNAL(modelAboutToBeReset()));
|
||||
connect(this,SIGNAL(reset()),this,SIGNAL(modelReset()));
|
||||
}
|
||||
|
||||
//! [0]
|
||||
TreeModel::TreeModel( QSqlQuery &sqlquery, QObject *parent)
|
||||
: QAbstractItemModel(parent),rootItem(0),rootBeforeFilter(0),filterEnabled(false),includeComics(false)
|
||||
{
|
||||
//lo m<>s probable es que el nodo ra<72>z no necesite tener informaci<63>n
|
||||
QList<QVariant> rootData;
|
||||
rootData << "root"; //id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
||||
rootItem = new TreeItem(rootData);
|
||||
rootItem->id = ROOT;
|
||||
rootItem->parentItem = 0;
|
||||
setupModelData(sqlquery, rootItem);
|
||||
//sqlquery.finish();
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
TreeModel::~TreeModel()
|
||||
{
|
||||
if(rootItem != 0)
|
||||
delete rootItem;
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
int TreeModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
|
||||
else
|
||||
return rootItem->columnCount();
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QVariant TreeModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DecorationRole)
|
||||
#ifdef Q_OS_MAC
|
||||
return QVariant(QIcon(":/images/folder_macosx.png"));
|
||||
#else
|
||||
return QVariant(QIcon(":/images/folder.png"));
|
||||
#endif
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
|
||||
|
||||
return item->data(index.column());
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
return rootItem->data(section);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
|
||||
const
|
||||
{
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
TreeItem *parentItem;
|
||||
|
||||
if (!parent.isValid())
|
||||
parentItem = rootItem;
|
||||
else
|
||||
parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
||||
|
||||
TreeItem *childItem = parentItem->child(row);
|
||||
if (childItem)
|
||||
return createIndex(row, column, childItem);
|
||||
else
|
||||
return QModelIndex();
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
QModelIndex TreeModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
|
||||
TreeItem *parentItem = childItem->parent();
|
||||
|
||||
if (parentItem == rootItem)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
//! [7]
|
||||
|
||||
QModelIndex TreeModel::indexFromItem(TreeItem * item,int column)
|
||||
{
|
||||
//if(item->parent() != 0)
|
||||
// return index(item->row(),column,parent(indexFromItem(item->parent(),column-1)));
|
||||
//else
|
||||
// return index(item->row(),0,QModelIndex());
|
||||
return createIndex(item->row(), column, item);
|
||||
}
|
||||
|
||||
|
||||
//! [8]
|
||||
int TreeModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
TreeItem *parentItem;
|
||||
if (parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
if (!parent.isValid())
|
||||
parentItem = rootItem;
|
||||
else
|
||||
parentItem = static_cast<TreeItem*>(parent.internalPointer());
|
||||
|
||||
return parentItem->childCount();
|
||||
}
|
||||
//! [8]
|
||||
|
||||
void TreeModel::setupModelData(QString path)
|
||||
{
|
||||
beginResetModel();
|
||||
if(rootItem != 0)
|
||||
delete rootItem; //TODO comprobar que se libera bien la memoria
|
||||
filterEnabled = false;
|
||||
rootItem = 0;
|
||||
rootBeforeFilter = 0;
|
||||
//inicializar el nodo ra<72>z
|
||||
QList<QVariant> rootData;
|
||||
rootData << "root"; //id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
||||
rootItem = new TreeItem(rootData);
|
||||
rootItem->id = ROOT;
|
||||
rootItem->parentItem = 0;
|
||||
|
||||
//cargar la base de datos
|
||||
_databasePath = path;
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(path);
|
||||
//crear la consulta
|
||||
{
|
||||
QSqlQuery selectQuery("select * from folder where id <> 1 order by parentId,name",db);
|
||||
|
||||
setupModelData(selectQuery,rootItem);
|
||||
}
|
||||
//selectQuery.finish();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(path);
|
||||
endResetModel();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void TreeModel::setupModelData(QSqlQuery &sqlquery, TreeItem *parent)
|
||||
{
|
||||
//64 bits para la primary key, es decir la misma precisi<73>n que soporta sqlit 2^64
|
||||
//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);
|
||||
|
||||
while (sqlquery.next()) {
|
||||
QList<QVariant> data;
|
||||
QSqlRecord record = sqlquery.record();
|
||||
|
||||
data << record.value("name").toString();
|
||||
data << record.value("path").toString();
|
||||
TreeItem * item = new TreeItem(data);
|
||||
|
||||
item->id = record.value("id").toULongLong();
|
||||
//la inserci<63>n de hijos se hace de forma ordenada
|
||||
items.value(record.value("parentId").toULongLong())->appendChild(item);
|
||||
//se a<>ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
|
||||
items.insert(item->id,item);
|
||||
}
|
||||
}
|
||||
|
||||
void TreeModel::setupFilteredModelData()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
//TODO hay que liberar memoria de anteriores filtrados
|
||||
|
||||
//inicializar el nodo ra<72>z
|
||||
|
||||
if(rootBeforeFilter == 0)
|
||||
rootBeforeFilter = rootItem;
|
||||
else
|
||||
delete rootItem;//los resultados de la b<>squeda anterior deben ser borrados
|
||||
|
||||
QList<QVariant> rootData;
|
||||
rootData << "root"; //id 1, padre 1, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
|
||||
rootItem = new TreeItem(rootData);
|
||||
rootItem->id = ROOT;
|
||||
rootItem->parentItem = 0;
|
||||
|
||||
//cargar la base de datos
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
|
||||
//crear la consulta
|
||||
{
|
||||
QSqlQuery selectQuery(db); //TODO check
|
||||
if(!includeComics)
|
||||
{
|
||||
selectQuery.prepare("select * from folder where id <> 1 and upper(name) like upper(:filter) order by parentId,name ");
|
||||
selectQuery.bindValue(":filter", "%%"+filter+"%%");
|
||||
}
|
||||
else
|
||||
{
|
||||
selectQuery.prepare("SELECT DISTINCT f.id, f.parentId, f.name, f.path FROM folder f INNER JOIN comic c ON (f.id = c.parentId) WHERE f.id <> 1 AND ((UPPER(c.fileName) like UPPER(:filter)) OR (UPPER(f.name) like UPPER(:filter2))) ORDER BY f.parentId,f.name");
|
||||
selectQuery.bindValue(":filter", "%%"+filter+"%%");
|
||||
selectQuery.bindValue(":filter2", "%%"+filter+"%%");
|
||||
}
|
||||
selectQuery.exec();
|
||||
|
||||
setupFilteredModelData(selectQuery,rootItem);
|
||||
}
|
||||
//selectQuery.finish();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(_databasePath);
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void TreeModel::setupFilteredModelData(QSqlQuery &sqlquery, TreeItem *parent)
|
||||
{
|
||||
//64 bits para la primary key, es decir la misma precisi<73>n que soporta sqlit 2^64
|
||||
filteredItems.clear();
|
||||
|
||||
//se a<>ade el nodo 0 al modelo que representa el arbol de elementos que cumplen con el filtro
|
||||
filteredItems.insert(parent->id,parent);
|
||||
|
||||
while (sqlquery.next()) { //se procesan todos los folders que cumplen con el filtro
|
||||
//datos de la base de datos
|
||||
QList<QVariant> data;
|
||||
QSqlRecord record = sqlquery.record();
|
||||
|
||||
data << record.value("name").toString();
|
||||
data << record.value("path").toString();
|
||||
TreeItem * item = new TreeItem(data);
|
||||
item->id = sqlquery.value(0).toULongLong();
|
||||
|
||||
//id del padre
|
||||
quint64 parentId = record.value("parentId").toULongLong();
|
||||
|
||||
//se a<>ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
|
||||
if(!filteredItems.contains(item->id))
|
||||
filteredItems.insert(item->id,item);
|
||||
|
||||
//es necesario conocer las coordenadas de origen para poder realizar scroll autom<6F>tico en la vista
|
||||
item->originalItem = items.value(item->id);
|
||||
|
||||
//si el padre ya existe en el modelo, el item se a<>ade como hijo
|
||||
if(filteredItems.contains(parentId))
|
||||
filteredItems.value(parentId)->appendChild(item);
|
||||
else//si el padre a<>n no se ha a<>adido, hay que a<>adirlo a <20>l y todos los padres hasta el nodo ra<72>z
|
||||
{
|
||||
//comprobamos con esta variable si el <20>ltimo de los padres (antes del nodo ra<72>z) ya exist<73>a en el modelo
|
||||
bool parentPreviousInserted = false;
|
||||
|
||||
//mientras no se alcance el nodo ra<72>z se procesan todos los padres (de abajo a arriba)
|
||||
while(parentId != ROOT )
|
||||
{
|
||||
//el padre no estaba en el modelo filtrado, as<61> que se rescata del modelo original
|
||||
TreeItem * parentItem = items.value(parentId);
|
||||
//se debe crear un nuevo nodo (para no compartir los hijos con el nodo original)
|
||||
TreeItem * newparentItem = new TreeItem(parentItem->getData()); //padre que se a<>adir<69> a la estructura de directorios filtrados
|
||||
newparentItem->id = parentId;
|
||||
|
||||
newparentItem->originalItem = parentItem;
|
||||
|
||||
//si el modelo contiene al padre, se a<>ade el item actual como hijo
|
||||
if(filteredItems.contains(parentId))
|
||||
{
|
||||
filteredItems.value(parentId)->appendChild(item);
|
||||
parentPreviousInserted = true;
|
||||
}
|
||||
//sino se registra el nodo para poder encontrarlo con posterioridad y se a<>ade el item actual como hijo
|
||||
else
|
||||
{
|
||||
newparentItem->appendChild(item);
|
||||
filteredItems.insert(newparentItem->id,newparentItem);
|
||||
parentPreviousInserted = false;
|
||||
}
|
||||
|
||||
//variables de control del bucle, se avanza hacia el nodo padre
|
||||
item = newparentItem;
|
||||
parentId = parentItem->parentItem->id;
|
||||
}
|
||||
|
||||
//si el nodo es hijo de 1 y no hab<61>a sido previamente insertado como hijo, se a<>ade como tal
|
||||
if(!parentPreviousInserted)
|
||||
filteredItems.value(ROOT)->appendChild(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString TreeModel::getDatabase()
|
||||
{
|
||||
return _databasePath;
|
||||
}
|
||||
|
||||
QString TreeModel::getFolderPath(const QModelIndex &folder)
|
||||
{
|
||||
return static_cast<TreeItem*>(folder.internalPointer())->data(1).toString();
|
||||
}
|
||||
|
||||
void TreeModel::setFilter(QString filter, bool includeComics)
|
||||
{
|
||||
this->filter = filter;
|
||||
this->includeComics = includeComics;
|
||||
filterEnabled = true;
|
||||
setupFilteredModelData();
|
||||
}
|
||||
|
||||
void TreeModel::resetFilter()
|
||||
{
|
||||
beginResetModel();
|
||||
filter = "";
|
||||
includeComics = false;
|
||||
//TODO hay que liberar la memoria reservada para el filtrado
|
||||
//items.clear();
|
||||
filteredItems.clear();
|
||||
TreeItem * root = rootItem;
|
||||
rootItem = rootBeforeFilter; //TODO si no se aplica el filtro previamente, esto invalidar<61>a en modelo
|
||||
if(root !=0)
|
||||
delete root;
|
||||
|
||||
rootBeforeFilter = 0;
|
||||
filterEnabled = false;
|
||||
endResetModel();
|
||||
|
||||
|
||||
}
|
||||
106
YACReaderLibrary/db/treemodel.h
Normal file
106
YACReaderLibrary/db/treemodel.h
Normal file
@ -0,0 +1,106 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TREEMODEL_H
|
||||
#define TREEMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
class TreeItem;
|
||||
|
||||
//! [0]
|
||||
class TreeModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TreeModel(QObject *parent = 0);
|
||||
TreeModel( QSqlQuery &sqlquery, QObject *parent = 0);
|
||||
~TreeModel();
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
QModelIndex indexFromItem(TreeItem * item, int column);
|
||||
/*QModelIndex _indexFromItem(TreeItem * item, int column);
|
||||
int column;*/
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
void setupModelData(QString path);
|
||||
QString getDatabase();
|
||||
|
||||
//M<>todos de conveniencia
|
||||
QString getFolderPath(const QModelIndex &folder);
|
||||
|
||||
void setFilter(QString filter, bool includeComics);
|
||||
void resetFilter();
|
||||
bool isFilterEnabled(){return filterEnabled;};
|
||||
private:
|
||||
void setupModelData( QSqlQuery &sqlquery, TreeItem *parent);
|
||||
void setupFilteredModelData( QSqlQuery &sqlquery, TreeItem *parent);
|
||||
void setupFilteredModelData();
|
||||
|
||||
TreeItem *rootItem; //el <20>rbol
|
||||
QMap<unsigned long long int, TreeItem *> items; //relaci<63>n entre folders
|
||||
|
||||
TreeItem *rootBeforeFilter;
|
||||
QMap<unsigned long long int, TreeItem *> filteredItems; //relaci<63>n entre folders
|
||||
|
||||
QString _databasePath;
|
||||
|
||||
bool includeComics;
|
||||
QString filter;
|
||||
bool filterEnabled;
|
||||
signals:
|
||||
void beforeReset();
|
||||
void reset();
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif
|
||||
564
YACReaderLibrary/db_helper.cpp
Normal file
564
YACReaderLibrary/db_helper.cpp
Normal file
@ -0,0 +1,564 @@
|
||||
#include "db_helper.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QCoreApplication>
|
||||
#include <QTextStream>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlRecord>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "library_item.h"
|
||||
#include "comic_db.h"
|
||||
#include "data_base_management.h"
|
||||
#include "folder.h"
|
||||
|
||||
//server
|
||||
|
||||
//TODO optimizar, evitar que se tenga que leer en cada petición el archivo
|
||||
//conservar un QDateTime stático que compruebe si libraries.yacr ha sido modificado
|
||||
//libraries debe ser una variable estática
|
||||
static QDateTime lastModified;
|
||||
static QMap<QString,QString> libraries;
|
||||
|
||||
QMap<QString,QString> DBHelper::getLibraries()
|
||||
{
|
||||
QFileInfo fi(QCoreApplication::applicationDirPath()+"/libraries.yacr");
|
||||
if(fi.lastModified() == lastModified)
|
||||
return libraries;
|
||||
|
||||
lastModified = fi.lastModified();
|
||||
libraries.clear();
|
||||
QFile f(QCoreApplication::applicationDirPath()+"/libraries.yacr");
|
||||
f.open(QIODevice::ReadOnly);
|
||||
QTextStream txtS(&f);
|
||||
QString content = txtS.readAll();
|
||||
QStringList lines = content.split('\n');
|
||||
QString line,name;
|
||||
int i=0;
|
||||
foreach(line,lines)
|
||||
{
|
||||
if((i%2)==0)
|
||||
{
|
||||
name = line;
|
||||
}
|
||||
else
|
||||
{
|
||||
//sólo se agregan las bibliotecas realmente disponibles
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(line.trimmed()+"/.yacreaderlibrary");
|
||||
if(db.isValid())
|
||||
libraries.insert(name.trimmed(),line.trimmed());
|
||||
db.close();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
f.close();
|
||||
return libraries;
|
||||
}
|
||||
QList<LibraryItem *> DBHelper::getFolderContentFromLibrary(const QString & libraryName, qulonglong folderId)
|
||||
{
|
||||
QString libraryPath = DBHelper::getLibraries().value(libraryName);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
|
||||
|
||||
QList<LibraryItem *> list = DBHelper::getFoldersFromParent(folderId,db,false);
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(libraryPath);
|
||||
return list;
|
||||
}
|
||||
QList<LibraryItem *> DBHelper::getFolderComicsFromLibrary(const QString & libraryName, qulonglong folderId)
|
||||
{
|
||||
QString libraryPath = DBHelper::getLibraries().value(libraryName);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
|
||||
|
||||
QList<LibraryItem *> list = DBHelper::getComicsFromParent(folderId,db,false);
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(libraryPath);
|
||||
return list;
|
||||
}
|
||||
qulonglong DBHelper::getParentFromComicFolderId(const QString & libraryName, qulonglong id)
|
||||
{
|
||||
QString libraryPath = DBHelper::getLibraries().value(libraryName);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
|
||||
|
||||
Folder f = DBHelper::loadFolder(id,db);
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(libraryPath);
|
||||
return f.parentId;
|
||||
}
|
||||
ComicDB DBHelper::getComicInfo(const QString & libraryName, qulonglong id)
|
||||
{
|
||||
QString libraryPath = DBHelper::getLibraries().value(libraryName);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
|
||||
|
||||
ComicDB comic = DBHelper::loadComic(id,db);
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(libraryPath);
|
||||
return comic;
|
||||
}
|
||||
QString DBHelper::getFolderName(const QString & libraryName, qulonglong id)
|
||||
{
|
||||
QString libraryPath = DBHelper::getLibraries().value(libraryName);
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath+"/.yacreaderlibrary");
|
||||
|
||||
QString name="";
|
||||
|
||||
{
|
||||
QSqlQuery selectQuery(db); //TODO check
|
||||
selectQuery.prepare("SELECT name FROM folder WHERE id = :id");
|
||||
selectQuery.bindValue(":id", id);
|
||||
selectQuery.exec();
|
||||
|
||||
if(selectQuery.next())
|
||||
{
|
||||
QSqlRecord record = selectQuery.record();
|
||||
name = record.value(0).toString();
|
||||
}
|
||||
}
|
||||
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(libraryPath);
|
||||
return name;
|
||||
}
|
||||
|
||||
//objects management
|
||||
//deletes
|
||||
void DBHelper::removeFromDB(LibraryItem * item, QSqlDatabase & db)
|
||||
{
|
||||
if(item->isDir())
|
||||
DBHelper::removeFromDB(dynamic_cast<Folder *>(item),db);
|
||||
else
|
||||
DBHelper::removeFromDB(dynamic_cast<ComicDB *>(item),db);
|
||||
}
|
||||
void DBHelper::removeFromDB(Folder * folder, QSqlDatabase & db)
|
||||
{
|
||||
QSqlQuery query(db);
|
||||
query.prepare("DELETE FROM folder WHERE id = :id");
|
||||
query.bindValue(":id", folder->id);
|
||||
query.exec();
|
||||
}
|
||||
void DBHelper::removeFromDB(ComicDB * comic, QSqlDatabase & db)
|
||||
{
|
||||
QSqlQuery query(db);
|
||||
query.prepare("DELETE FROM comic WHERE id = :id");
|
||||
query.bindValue(":id", comic->id);
|
||||
query.exec();
|
||||
}
|
||||
|
||||
//updates
|
||||
void DBHelper::update(ComicDB * comic, QSqlDatabase & db)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
void DBHelper::update(ComicInfo * comicInfo, QSqlDatabase & db)
|
||||
{
|
||||
QSqlQuery updateComicInfo(db);
|
||||
updateComicInfo.prepare("UPDATE comic_info SET "
|
||||
"title = :title,"
|
||||
|
||||
"coverPage = :coverPage,"
|
||||
"numPages = :numPages,"
|
||||
|
||||
"number = :number,"
|
||||
"isBis = :isBis,"
|
||||
"count = :count,"
|
||||
|
||||
"volume = :volume,"
|
||||
"storyArc = :storyArc,"
|
||||
"arcNumber = :arcNumber,"
|
||||
"arcCount = :arcCount,"
|
||||
|
||||
"genere = :genere,"
|
||||
|
||||
"writer = :writer,"
|
||||
"penciller = :penciller,"
|
||||
"inker = :inker,"
|
||||
"colorist = :colorist,"
|
||||
"letterer = :letterer,"
|
||||
"coverArtist = :coverArtist,"
|
||||
|
||||
"date = :date,"
|
||||
"publisher = :publisher,"
|
||||
"format = :format,"
|
||||
"color = :color,"
|
||||
"ageRating = :ageRating,"
|
||||
|
||||
"synopsis = :synopsis,"
|
||||
"characters = :characters,"
|
||||
"notes = :notes,"
|
||||
|
||||
"read = :read,"
|
||||
"edited = :edited"
|
||||
|
||||
" WHERE id = :id ");
|
||||
bindField(":title",comicInfo->title,updateComicInfo);
|
||||
|
||||
bindField(":coverPage",comicInfo->coverPage,updateComicInfo);
|
||||
bindField(":numPages",comicInfo->numPages,updateComicInfo);
|
||||
|
||||
bindField(":number",comicInfo->number,updateComicInfo);
|
||||
bindField(":isBis",comicInfo->isBis,updateComicInfo);
|
||||
bindField(":count",comicInfo->count,updateComicInfo);
|
||||
|
||||
bindField(":volume",comicInfo->volume,updateComicInfo);
|
||||
bindField(":storyArc",comicInfo->storyArc,updateComicInfo);
|
||||
bindField(":arcNumber",comicInfo->arcNumber,updateComicInfo);
|
||||
bindField(":arcCount",comicInfo->arcCount,updateComicInfo);
|
||||
|
||||
bindField(":genere",comicInfo->genere,updateComicInfo);
|
||||
|
||||
bindField(":writer",comicInfo->writer,updateComicInfo);
|
||||
bindField(":penciller",comicInfo->penciller,updateComicInfo);
|
||||
bindField(":inker",comicInfo->inker,updateComicInfo);
|
||||
bindField(":colorist",comicInfo->colorist,updateComicInfo);
|
||||
bindField(":letterer",comicInfo->letterer,updateComicInfo);
|
||||
bindField(":coverArtist",comicInfo->coverArtist,updateComicInfo);
|
||||
|
||||
bindField(":date",comicInfo->date,updateComicInfo);
|
||||
bindField(":publisher",comicInfo->publisher,updateComicInfo);
|
||||
bindField(":format",comicInfo->format,updateComicInfo);
|
||||
bindField(":color",comicInfo->color,updateComicInfo);
|
||||
bindField(":ageRating",comicInfo->ageRating,updateComicInfo);
|
||||
|
||||
bindField(":synopsis",comicInfo->synopsis,updateComicInfo);
|
||||
bindField(":characters",comicInfo->characters,updateComicInfo);
|
||||
bindField(":notes",comicInfo->notes,updateComicInfo);
|
||||
|
||||
updateComicInfo.bindValue(":read", comicInfo->read?1:0);
|
||||
updateComicInfo.bindValue(":id", comicInfo->id);
|
||||
updateComicInfo.bindValue(":edited", comicInfo->edited?1:0);
|
||||
updateComicInfo.exec();
|
||||
}
|
||||
|
||||
void DBHelper::updateRead(ComicInfo * comicInfo, QSqlDatabase & db)
|
||||
{
|
||||
QSqlQuery findComicInfo(db);
|
||||
findComicInfo.prepare("UPDATE comic_info SET "
|
||||
"read = :read"
|
||||
" WHERE id = :id ");
|
||||
|
||||
findComicInfo.bindValue(":read", comicInfo->read?1:0);
|
||||
findComicInfo.bindValue(":id", comicInfo->id);
|
||||
findComicInfo.exec();
|
||||
}
|
||||
//inserts
|
||||
qulonglong DBHelper::insert(Folder * folder, QSqlDatabase & db)
|
||||
{
|
||||
QSqlQuery query(db);
|
||||
query.prepare("INSERT INTO folder (parentId, name, path) "
|
||||
"VALUES (:parentId, :name, :path)");
|
||||
query.bindValue(":parentId", folder->parentId);
|
||||
query.bindValue(":name", folder->name);
|
||||
query.bindValue(":path", folder->path);
|
||||
query.exec();
|
||||
return query.lastInsertId().toULongLong();
|
||||
}
|
||||
|
||||
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.bindValue(":hash", comic->info.hash);
|
||||
comicInfoInsert.bindValue(":numPages", *(comic->info.numPages));
|
||||
comicInfoInsert.exec();
|
||||
comic->info.id =comicInfoInsert.lastInsertId().toULongLong();
|
||||
comic->_hasCover = false;
|
||||
}
|
||||
else
|
||||
comic->_hasCover = true;
|
||||
|
||||
QSqlQuery query(db);
|
||||
query.prepare("INSERT INTO comic (parentId, comicInfoId, fileName, path) "
|
||||
"VALUES (:parentId,:comicInfoId,:name, :path)");
|
||||
query.bindValue(":parentId", comic->parentId);
|
||||
query.bindValue(":comicInfoId", comic->info.id);
|
||||
query.bindValue(":name", comic->name);
|
||||
query.bindValue(":path", comic->path);
|
||||
query.exec();
|
||||
return query.lastInsertId().toULongLong();
|
||||
}
|
||||
//queries
|
||||
QList<LibraryItem *> DBHelper::getFoldersFromParent(qulonglong parentId, QSqlDatabase & db, bool sort)
|
||||
{
|
||||
QList<LibraryItem *> list;
|
||||
|
||||
QSqlQuery selectQuery(db); //TODO check
|
||||
selectQuery.prepare("SELECT * FROM folder WHERE parentId = :parentId and id <> 1");
|
||||
selectQuery.bindValue(":parentId", parentId);
|
||||
selectQuery.exec();
|
||||
|
||||
Folder * currentItem;
|
||||
while (selectQuery.next())
|
||||
{
|
||||
QList<QVariant> data;
|
||||
QSqlRecord record = selectQuery.record();
|
||||
for(int i=0;i<record.count();i++)
|
||||
data << record.value(i);
|
||||
//TODO sort by sort indicator and name
|
||||
currentItem = new Folder(record.value("id").toULongLong(),record.value("parentId").toULongLong(),record.value("name").toString(),record.value("path").toString());
|
||||
int lessThan = 0;
|
||||
|
||||
if(list.isEmpty() || !sort)
|
||||
list.append(currentItem);
|
||||
else
|
||||
{
|
||||
Folder * last = static_cast<Folder *>(list.back());
|
||||
QString nameLast = last->name;
|
||||
QString nameCurrent = currentItem->name;
|
||||
QList<LibraryItem *>::iterator i;
|
||||
i = list.end();
|
||||
i--;
|
||||
while ((0 > (lessThan = nameCurrent.localeAwareCompare(nameLast))) && i != list.begin())
|
||||
{
|
||||
i--;
|
||||
nameLast = (*i)->name;
|
||||
}
|
||||
if(lessThan>0) //si se ha encontrado un elemento menor que current, se inserta justo después
|
||||
list.insert(++i,currentItem);
|
||||
else
|
||||
list.insert(i,currentItem);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
QList<LibraryItem *> DBHelper::getComicsFromParent(qulonglong parentId, QSqlDatabase & db, bool sort)
|
||||
{
|
||||
QList<LibraryItem *> list;
|
||||
|
||||
QSqlQuery selectQuery(db);
|
||||
selectQuery.prepare("select c.id,c.parentId,c.fileName,c.path,ci.hash from comic c inner join comic_info ci on (c.comicInfoId = ci.id) where c.parentId = :parentId");
|
||||
selectQuery.bindValue(":parentId", parentId);
|
||||
selectQuery.exec();
|
||||
|
||||
ComicDB * currentItem;
|
||||
while (selectQuery.next())
|
||||
{
|
||||
QList<QVariant> data;
|
||||
QSqlRecord record = selectQuery.record();
|
||||
for(int i=0;i<record.count();i++)
|
||||
data << record.value(i);
|
||||
|
||||
currentItem = new ComicDB();
|
||||
currentItem->id = record.value("id").toULongLong();
|
||||
currentItem->parentId = record.value(1).toULongLong();
|
||||
currentItem->name = record.value(2).toString();
|
||||
currentItem->path = record.value(3).toString();
|
||||
currentItem->info = DBHelper::loadComicInfo(record.value(4).toString(),db);
|
||||
int lessThan = 0;
|
||||
if(list.isEmpty() || !sort)
|
||||
list.append(currentItem);
|
||||
else
|
||||
{
|
||||
ComicDB * last = static_cast<ComicDB *>(list.back());
|
||||
QString nameLast = last->name;
|
||||
QString nameCurrent = currentItem->name;
|
||||
QList<LibraryItem *>::iterator i;
|
||||
i = list.end();
|
||||
i--;
|
||||
while ((0 > (lessThan = nameCurrent.localeAwareCompare(nameLast))) && i != list.begin()) //se usa la misma ordenación que en QDir
|
||||
{
|
||||
i--;
|
||||
nameLast = (*i)->name;
|
||||
}
|
||||
if(lessThan>0) //si se ha encontrado un elemento menor que current, se inserta justo después
|
||||
list.insert(++i,currentItem);
|
||||
else
|
||||
list.insert(i,currentItem);
|
||||
|
||||
}
|
||||
}
|
||||
//selectQuery.finish();
|
||||
return list;
|
||||
}
|
||||
|
||||
//loads
|
||||
Folder DBHelper::loadFolder(qulonglong id, QSqlDatabase & db)
|
||||
{
|
||||
Folder folder;
|
||||
|
||||
QSqlQuery query(db);
|
||||
query.prepare("SELECT * FROM folder WHERE id = :id");
|
||||
query.bindValue(":id",id);
|
||||
query.exec();
|
||||
folder.id = id;
|
||||
folder.parentId = 0;
|
||||
if(query.next())
|
||||
{
|
||||
QSqlRecord record = query.record();
|
||||
folder.parentId = record.value("parentId").toULongLong();
|
||||
folder.name = record.value("name").toString();
|
||||
folder.path = record.value("path").toString();
|
||||
}
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
ComicDB DBHelper::loadComic(qulonglong id, QSqlDatabase & db)
|
||||
{
|
||||
ComicDB comic;
|
||||
|
||||
QSqlQuery selectQuery(db);
|
||||
selectQuery.prepare("select c.id,c.parentId,c.fileName,c.path,ci.hash from comic c inner join comic_info ci on (c.comicInfoId = ci.id) where c.id = :id");
|
||||
selectQuery.bindValue(":id", id);
|
||||
selectQuery.exec();
|
||||
comic.id = id;
|
||||
if(selectQuery.next())
|
||||
{
|
||||
QSqlRecord record = selectQuery.record();
|
||||
//id = record.value("id").toULongLong();
|
||||
comic.parentId = record.value("parentId").toULongLong();
|
||||
comic.name = record.value("name").toString();
|
||||
comic.path = record.value("path").toString();
|
||||
comic.info = DBHelper::loadComicInfo(record.value("hash").toString(),db);
|
||||
}
|
||||
|
||||
return comic;
|
||||
}
|
||||
|
||||
ComicDB DBHelper::loadComic(qulonglong cparentId, QString cname, QString cpath, QString chash, QSqlDatabase & database)
|
||||
{
|
||||
ComicDB comic;
|
||||
|
||||
comic.parentId = cparentId;
|
||||
comic.name = cname;
|
||||
comic.path = cpath;
|
||||
|
||||
comic.info = DBHelper::loadComicInfo(chash,database);
|
||||
|
||||
if(!comic.info.existOnDb)
|
||||
{
|
||||
comic.info.hash = chash;
|
||||
comic.info.coverPage = new int(1);
|
||||
comic._hasCover = false;
|
||||
}
|
||||
else
|
||||
comic._hasCover = true;
|
||||
|
||||
return comic;
|
||||
}
|
||||
|
||||
ComicInfo DBHelper::loadComicInfo(QString hash, QSqlDatabase & db)
|
||||
{
|
||||
ComicInfo comicInfo;
|
||||
|
||||
QSqlQuery findComicInfo(db);
|
||||
findComicInfo.prepare("SELECT * FROM comic_info WHERE hash = :hash");
|
||||
findComicInfo.bindValue(":hash", hash);
|
||||
findComicInfo.exec();
|
||||
|
||||
|
||||
if(findComicInfo.next())
|
||||
{
|
||||
comicInfo.hash = hash;
|
||||
QSqlRecord record = findComicInfo.record();
|
||||
|
||||
comicInfo.hash = hash;
|
||||
comicInfo.id = record.value("id").toULongLong();
|
||||
comicInfo.read = record.value("read").toBool();
|
||||
comicInfo.edited = record.value("edited").toBool();
|
||||
|
||||
setField("title",comicInfo.title,record);
|
||||
setField("numPages",comicInfo.numPages,record);
|
||||
|
||||
setField("coverPage",comicInfo.coverPage,record);
|
||||
|
||||
setField("number",comicInfo.number,record);
|
||||
setField("isBis",comicInfo.isBis,record);
|
||||
setField("count",comicInfo.count,record);
|
||||
|
||||
setField("volume",comicInfo.volume,record);
|
||||
setField("storyArc",comicInfo.storyArc,record);
|
||||
setField("arcNumber",comicInfo.arcNumber,record);
|
||||
setField("arcCount",comicInfo.arcCount,record);
|
||||
|
||||
setField("genere",comicInfo.genere,record);
|
||||
|
||||
setField("writer",comicInfo.writer,record);
|
||||
setField("penciller",comicInfo.penciller,record);
|
||||
setField("inker",comicInfo.inker,record);
|
||||
setField("colorist",comicInfo.colorist,record);
|
||||
setField("letterer",comicInfo.letterer,record);
|
||||
setField("coverArtist",comicInfo.coverArtist,record);
|
||||
|
||||
setField("date",comicInfo.date,record);
|
||||
setField("publisher",comicInfo.publisher,record);
|
||||
setField("format",comicInfo.format,record);
|
||||
setField("color",comicInfo.color,record);
|
||||
setField("ageRating",comicInfo.ageRating,record);
|
||||
|
||||
setField("synopsis",comicInfo.synopsis,record);
|
||||
setField("characters",comicInfo.characters,record);
|
||||
setField("notes",comicInfo.notes,record);
|
||||
|
||||
comicInfo.existOnDb = true;
|
||||
}
|
||||
else
|
||||
comicInfo.existOnDb = false;
|
||||
|
||||
return comicInfo;
|
||||
}
|
||||
|
||||
void DBHelper::setField(const QString & name, QString * & field, QSqlRecord & record)
|
||||
{
|
||||
if(!record.value(name).isNull())
|
||||
{
|
||||
field = new QString();
|
||||
*field = record.value(name).toString();
|
||||
}
|
||||
}
|
||||
|
||||
void DBHelper::setField(const QString & name, int * & field, QSqlRecord & record)
|
||||
{
|
||||
if(!record.value(name).isNull())
|
||||
{
|
||||
field = new int;
|
||||
*field = record.value(name).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
void DBHelper::setField(const QString & name, bool * & field, QSqlRecord & record)
|
||||
{
|
||||
if(!record.value(name).isNull())
|
||||
{
|
||||
field = new bool;
|
||||
*field = record.value(name).toBool();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DBHelper::bindField(const QString & name, QString * field, QSqlQuery & query)
|
||||
{
|
||||
if(field != NULL)
|
||||
{
|
||||
query.bindValue(name,*field);
|
||||
}
|
||||
}
|
||||
|
||||
void DBHelper::bindField(const QString & name, int * field, QSqlQuery & query)
|
||||
{
|
||||
if(field != NULL)
|
||||
{
|
||||
query.bindValue(name,*field);
|
||||
}
|
||||
}
|
||||
|
||||
void DBHelper::bindField(const QString & name, bool * field, QSqlQuery & query)
|
||||
{
|
||||
if(field != NULL)
|
||||
{
|
||||
query.bindValue(name,*field);
|
||||
}
|
||||
}
|
||||
57
YACReaderLibrary/db_helper.h
Normal file
57
YACReaderLibrary/db_helper.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef DB_HELPER_H
|
||||
#define DB_HELPER_H
|
||||
|
||||
class QString;
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
|
||||
class ComicDB;
|
||||
class Folder;
|
||||
class LibraryItem;
|
||||
class QSqlDatabase;
|
||||
class ComicInfo;
|
||||
class QSqlRecord;
|
||||
class QSqlQuery;
|
||||
|
||||
class DBHelper
|
||||
{
|
||||
public:
|
||||
//server
|
||||
static QMap<QString,QString> getLibraries();
|
||||
static QList<LibraryItem *> getFolderContentFromLibrary(const QString & libraryName, qulonglong folderId);
|
||||
static QList<LibraryItem *> getFolderComicsFromLibrary(const QString & libraryName, qulonglong folderId);
|
||||
static qulonglong getParentFromComicFolderId(const QString & libraryName, qulonglong id);
|
||||
static ComicDB getComicInfo(const QString & libraryName, qulonglong id);
|
||||
static QString getFolderName(const QString & libraryName, qulonglong id);
|
||||
|
||||
//objects management
|
||||
//deletes
|
||||
static void removeFromDB(LibraryItem * item, QSqlDatabase & db);
|
||||
static void removeFromDB(Folder * folder, QSqlDatabase & db);
|
||||
static void removeFromDB(ComicDB * comic, QSqlDatabase & db);
|
||||
//inserts
|
||||
static qulonglong insert(Folder * folder, QSqlDatabase & db);
|
||||
static qulonglong insert(ComicDB * comic, QSqlDatabase & db);
|
||||
//updates
|
||||
static void update(ComicDB * comics, QSqlDatabase & db);
|
||||
static void update(ComicInfo * comicInfo, QSqlDatabase & db);
|
||||
static void updateRead(ComicInfo * comicInfo, QSqlDatabase & db);
|
||||
//queries
|
||||
static QList<LibraryItem *> getFoldersFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
|
||||
static QList<LibraryItem *> getComicsFromParent(qulonglong parentId, QSqlDatabase & db, bool sort = true);
|
||||
//load
|
||||
static Folder loadFolder(qulonglong id, QSqlDatabase & db);
|
||||
static ComicDB loadComic(qulonglong id, QSqlDatabase & db);
|
||||
static ComicDB loadComic(qulonglong cparentId, QString cname, QString cpath, QString chash, QSqlDatabase & database);
|
||||
static ComicInfo loadComicInfo(QString hash, QSqlDatabase & db);
|
||||
private:
|
||||
static void setField(const QString & name, QString * & field, QSqlRecord & record);
|
||||
static void setField(const QString & name, int * & field, QSqlRecord & record);
|
||||
static void setField(const QString & name, bool * & field, QSqlRecord & record);
|
||||
|
||||
static void bindField(const QString & name, QString * field, QSqlQuery & query);
|
||||
static void bindField(const QString & name, int * field, QSqlQuery & query);
|
||||
static void bindField(const QString & name, bool * field, QSqlQuery & query);
|
||||
};
|
||||
|
||||
#endif
|
||||
92
YACReaderLibrary/export_comics_info_dialog.cpp
Normal file
92
YACReaderLibrary/export_comics_info_dialog.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include "export_comics_info_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "data_base_management.h"
|
||||
|
||||
ExportComicsInfoDialog::ExportComicsInfoDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
textLabel = new QLabel(tr("Output file : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
|
||||
accept = new QPushButton(tr("Create"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(exportComicsInfo()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
connect(cancel,SIGNAL(clicked()),this,SIGNAL(rejected()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/db.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
QHBoxLayout *libraryLayout = new QHBoxLayout;
|
||||
|
||||
libraryLayout->addWidget(textLabel);
|
||||
libraryLayout->addWidget(path);
|
||||
libraryLayout->addWidget(find);
|
||||
libraryLayout->setStretchFactor(find,0); //TODO
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(libraryLayout);
|
||||
mainLayout->addWidget(progress=new QLabel());
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/exportComicsInfo.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Export comics info"));
|
||||
}
|
||||
|
||||
ExportComicsInfoDialog::~ExportComicsInfoDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ExportComicsInfoDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getSaveFileName(this,tr("Destination database name"),".","*.ydb");
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ExportComicsInfoDialog::exportComicsInfo()
|
||||
{
|
||||
QFileInfo f(path->text());
|
||||
QFileInfo fPath(f.absoluteDir().path());
|
||||
if(fPath.exists() && fPath.isDir() && fPath.isWritable())
|
||||
{
|
||||
DataBaseManagement::exportComicsInfo(source,path->text());
|
||||
close();
|
||||
}
|
||||
else
|
||||
QMessageBox::critical(NULL,tr("Problem found while writing"),tr("The selected path for the output file does not exist or is not a valid path. Be sure that you have write access to this folder"));
|
||||
}
|
||||
|
||||
void ExportComicsInfoDialog::close()
|
||||
{
|
||||
path->clear();
|
||||
QDialog::close();
|
||||
}
|
||||
35
YACReaderLibrary/export_comics_info_dialog.h
Normal file
35
YACReaderLibrary/export_comics_info_dialog.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef EXPORT_COMICS_INFO_DIALOG_H
|
||||
#define EXPORT_COMICS_INFO_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
class ExportComicsInfoDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportComicsInfoDialog(QWidget *parent = 0);
|
||||
~ExportComicsInfoDialog();
|
||||
QString source;
|
||||
|
||||
public slots:
|
||||
void findPath();
|
||||
void exportComicsInfo();
|
||||
void close();
|
||||
|
||||
private:
|
||||
QLabel * progress;
|
||||
QLabel * textLabel;
|
||||
QLineEdit * path;
|
||||
QPushButton * find;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // EXPORT_COMICS_INFO_DIALOG_H
|
||||
104
YACReaderLibrary/export_library_dialog.cpp
Normal file
104
YACReaderLibrary/export_library_dialog.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "export_library_dialog.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
|
||||
ExportLibraryDialog::ExportLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent),progressCount(0)
|
||||
{
|
||||
textLabel = new QLabel(tr("Output folder : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
|
||||
accept = new QPushButton(tr("Create"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(exportLibrary()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
connect(cancel,SIGNAL(clicked()),this,SIGNAL(rejected()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/comicFolder.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
QHBoxLayout *libraryLayout = new QHBoxLayout;
|
||||
|
||||
libraryLayout->addWidget(textLabel);
|
||||
libraryLayout->addWidget(path);
|
||||
libraryLayout->addWidget(find);
|
||||
libraryLayout->setStretchFactor(find,0); //TODO
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
progressBar = new QProgressBar(this);
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setTextVisible(false);
|
||||
progressBar->hide();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(libraryLayout);
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addWidget(progressBar);
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/exportLibrary.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Create covers package"));
|
||||
t.setInterval(500);
|
||||
connect(&t,SIGNAL(timeout()),this,SLOT(updateProgress()));
|
||||
}
|
||||
|
||||
void ExportLibraryDialog::exportLibrary()
|
||||
{
|
||||
QFileInfo f(path->text());
|
||||
if(f.exists() && f.isDir() && f.isWritable())
|
||||
{
|
||||
progressBar->show();
|
||||
accept->setEnabled(false);
|
||||
emit exportPath(QDir::cleanPath(path->text()));
|
||||
t.start();
|
||||
}
|
||||
else
|
||||
QMessageBox::critical(NULL,tr("Problem found while writing"),tr("The selected path for the output file does not exist or is not a valid path. Be sure that you have write access to this folder"));
|
||||
|
||||
}
|
||||
|
||||
void ExportLibraryDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getExistingDirectory(0,tr("Destination directory"),".");
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ExportLibraryDialog::close()
|
||||
{
|
||||
path->clear();
|
||||
progressBar->hide();
|
||||
accept->setEnabled(false);
|
||||
t.stop();
|
||||
progressCount=0;
|
||||
QDialog::close();
|
||||
}
|
||||
|
||||
void ExportLibraryDialog::run()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
36
YACReaderLibrary/export_library_dialog.h
Normal file
36
YACReaderLibrary/export_library_dialog.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef EXPORT_LIBRARY_DIALOG_H
|
||||
#define EXPORT_LIBRARY_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QProgressBar>
|
||||
|
||||
class ExportLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ExportLibraryDialog(QWidget * parent = 0);
|
||||
public slots:
|
||||
void exportLibrary();
|
||||
void findPath();
|
||||
void close();
|
||||
private:
|
||||
int progressCount;
|
||||
QProgressBar *progressBar;
|
||||
QLabel * textLabel;
|
||||
QLineEdit * path;
|
||||
QPushButton * find;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
void run();
|
||||
QTimer t;
|
||||
signals:
|
||||
void exportPath(QString);
|
||||
};
|
||||
|
||||
#endif
|
||||
12
YACReaderLibrary/files.qrc
Normal file
12
YACReaderLibrary/files.qrc
Normal file
@ -0,0 +1,12 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>../files/about.html</file>
|
||||
<file>../files/helpYACReaderLibrary.html</file>
|
||||
</qresource>
|
||||
|
||||
<qresource lang="es_ES">
|
||||
<file alias="/files/about.html">../files/about_es_ES.html</file>
|
||||
<file alias="/files/helpYACReaderLibrary.html">../files/helpYACReaderLibrary_es_ES.html</file>
|
||||
</qresource>
|
||||
|
||||
</RCC>
|
||||
BIN
YACReaderLibrary/icon.ico
Normal file
BIN
YACReaderLibrary/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
3
YACReaderLibrary/icon.rc
Normal file
3
YACReaderLibrary/icon.rc
Normal file
@ -0,0 +1,3 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "icon.ico"
|
||||
IDI_ICON2 ICON DISCARDABLE "icon2.ico"
|
||||
IDI_ICON3 ICON DISCARDABLE "icon3.ico"
|
||||
BIN
YACReaderLibrary/icon2.ico
Normal file
BIN
YACReaderLibrary/icon2.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
BIN
YACReaderLibrary/icon3.ico
Normal file
BIN
YACReaderLibrary/icon3.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
109
YACReaderLibrary/images.qrc
Normal file
109
YACReaderLibrary/images.qrc
Normal file
@ -0,0 +1,109 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>../images/deleteLibrary.png</file>
|
||||
<file>../images/folder.png</file>
|
||||
<file>../images/help.png</file>
|
||||
<file>../images/icon.png</file>
|
||||
<file>../images/iconLibrary.png</file>
|
||||
<file>../images/new.png</file>
|
||||
<file>../images/openLibrary.png</file>
|
||||
<file>../images/removeLibrary.png</file>
|
||||
<file>../images/updateLibrary.png</file>
|
||||
<file>../images/comicFolder.png</file>
|
||||
<file>../images/notCover.png</file>
|
||||
<file>../images/edit.png</file>
|
||||
<file>../images/fit.png</file>
|
||||
<file>../images/properties.png</file>
|
||||
<file>../images/options.png</file>
|
||||
<file>../images/flow1.png</file>
|
||||
<file>../images/flow2.png</file>
|
||||
<file>../images/flow3.png</file>
|
||||
<file>../images/flow4.png</file>
|
||||
<file>../images/flow5.png</file>
|
||||
<file>../images/importLibrary.png</file>
|
||||
<file>../images/exportLibrary.png</file>
|
||||
<file>../images/open.png</file>
|
||||
<file>../images/coversPackage.png</file>
|
||||
<file>../images/setRead.png</file>
|
||||
<file>../images/setAllRead.png</file>
|
||||
<file>../images/setUnread.png</file>
|
||||
<file>../images/setAllUnread.png</file>
|
||||
<file>../images/showMarks.png</file>
|
||||
<file>../images/importCover.png</file>
|
||||
<file>../images/editComic.png</file>
|
||||
<file>../images/selectAll.png</file>
|
||||
<file>../images/hideComicFlow.png</file>
|
||||
<file>../images/exportComicsInfo.png</file>
|
||||
<file>../images/importComicsInfo.png</file>
|
||||
<file>../images/db.png</file>
|
||||
<file>../images/asignNumber.png</file>
|
||||
<file>../images/defaultCover.png</file>
|
||||
<file>../images/server.png</file>
|
||||
<file>../images/iphoneConfig.png</file>
|
||||
<file>../images/qrMessage.png</file>
|
||||
<file>../images/onStartFlowSelection.png</file>
|
||||
<file>../images/onStartFlowSelection_es.png</file>
|
||||
<file>../images/useNewFlowButton.png</file>
|
||||
<file>../images/useOldFlowButton.png</file>
|
||||
<file>../images/zip.png</file>
|
||||
<file>../images/rar.png</file>
|
||||
<file>../images/tar.png</file>
|
||||
<file>../images/7z.png</file>
|
||||
<file>../images/pdf.png</file>
|
||||
<file>../images/comicZip.png</file>
|
||||
<file>../images/comicRar.png</file>
|
||||
<file>../images/comicTar.png</file>
|
||||
<file>../images/comic7z.png</file>
|
||||
<file>../images/serverConfigBackground.png</file>
|
||||
<file>../images/noLibrariesIcon.png</file>
|
||||
<file>../images/noLibrariesLine.png</file>
|
||||
<file>../images/importingIcon.png</file>
|
||||
<file>../images/updatingIcon.png</file>
|
||||
<file>../images/importTopCoversDecoration.png</file>
|
||||
<file>../images/importBottomCoversDecoration.png</file>
|
||||
<file>../images/glowLine.png</file>
|
||||
<file>../images/clearSearch.png</file>
|
||||
<file>../images/iconSearch.png</file>
|
||||
<file>../images/readRibbon.png</file>
|
||||
<file>../images/shownCovers.png</file>
|
||||
<file>../images/hiddenCovers.png</file>
|
||||
<file>../images/trash.png</file>
|
||||
<file>../images/setReadButton.png</file>
|
||||
<file>../images/openInYACReader.png</file>
|
||||
<file>../images/deleting_progress/imgTopLeft.png</file>
|
||||
<file>../images/deleting_progress/imgTopMiddle.png</file>
|
||||
<file>../images/deleting_progress/imgTopRight.png</file>
|
||||
<file>../images/deleting_progress/imgLeftMiddle.png</file>
|
||||
<file>../images/deleting_progress/imgRightMiddle.png</file>
|
||||
<file>../images/deleting_progress/imgBottomLeft.png</file>
|
||||
<file>../images/deleting_progress/imgBottomMiddle.png</file>
|
||||
<file>../images/deleting_progress/imgBottomRight.png</file>
|
||||
<file>../images/deleting_progress/icon.png</file>
|
||||
<file>../images/social_dialog/close.png</file>
|
||||
<file>../images/social_dialog/facebook.png</file>
|
||||
<file>../images/social_dialog/google+.png</file>
|
||||
<file>../images/social_dialog/icon.png</file>
|
||||
<file>../images/social_dialog/shadow.png</file>
|
||||
<file>../images/social_dialog/twitter.png</file>
|
||||
<file>../images/social_dialog/separator.png</file>
|
||||
<file>../images/main_toolbar/back.png</file>
|
||||
<file>../images/main_toolbar/back_disabled.png</file>
|
||||
<file>../images/main_toolbar/forward.png</file>
|
||||
<file>../images/main_toolbar/forward_disabled.png</file>
|
||||
<file>../images/main_toolbar/divider.png</file>
|
||||
<file>../images/main_toolbar/settings.png</file>
|
||||
<file>../images/main_toolbar/server.png</file>
|
||||
<file>../images/main_toolbar/help.png</file>
|
||||
<file>../images/main_toolbar/fullscreen.png</file>
|
||||
<file>../images/collapsed_branch_osx.png</file>
|
||||
<file>../images/expanded_branch_osx.png</file>
|
||||
<file>../images/folder_macosx.png</file>
|
||||
<file>../images/libraryIcon.png</file>
|
||||
<file>../images/libraryIconSelected.png</file>
|
||||
<file>../images/libraryOptions.png</file>
|
||||
<file>../images/branch-open.png</file>
|
||||
<file>../images/branch-closed.png</file>
|
||||
<file>../images/expanded_branch_selected.png</file>
|
||||
<file>../images/collapsed_branch_selected.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
9
YACReaderLibrary/images_osx.qrc
Normal file
9
YACReaderLibrary/images_osx.qrc
Normal file
@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file alias="images/setRoot.png">../images/setRoot_osx.png</file>
|
||||
<file alias="images/expand.png">../images/expand_osx.png</file>
|
||||
<file alias="images/colapse.png">../images/colapse_osx.png</file>
|
||||
<file alias="images/newLibraryIcon.png">../images/newLibraryIcon_osx.png</file>
|
||||
<file alias="images/openLibraryIcon.png">../images/openLibraryIcon_osx.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
9
YACReaderLibrary/images_win.qrc
Normal file
9
YACReaderLibrary/images_win.qrc
Normal file
@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>../images/setRoot.png</file>
|
||||
<file>../images/expand.png</file>
|
||||
<file>../images/colapse.png</file>
|
||||
<file>../images/newLibraryIcon.png</file>
|
||||
<file>../images/openLibraryIcon.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
111
YACReaderLibrary/import_comics_info_dialog.cpp
Normal file
111
YACReaderLibrary/import_comics_info_dialog.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include "import_comics_info_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QProgressBar>
|
||||
|
||||
#include "data_base_management.h"
|
||||
|
||||
ImportComicsInfoDialog::ImportComicsInfoDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Import comics info"));
|
||||
|
||||
|
||||
textLabel = new QLabel(tr("Info database location : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
|
||||
accept = new QPushButton(tr("Import"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(import()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
//connect(cancel,SIGNAL(clicked()),this,SIGNAL(rejected()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/db.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
QHBoxLayout *libraryLayout = new QHBoxLayout;
|
||||
|
||||
libraryLayout->addWidget(textLabel);
|
||||
libraryLayout->addWidget(path);
|
||||
libraryLayout->addWidget(find);
|
||||
libraryLayout->setStretchFactor(find,0); //TODO
|
||||
|
||||
progressBar = new QProgressBar(this);
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setTextVisible(false);
|
||||
progressBar->hide();
|
||||
connect(accept,SIGNAL(progressBar()),this,SLOT(show()));
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(libraryLayout);
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addWidget(progressBar);
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/importComicsInfo.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
ImportComicsInfoDialog::~ImportComicsInfoDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ImportComicsInfoDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getOpenFileName(0,"Comics Info",".",tr("Comics info file (*.ydb)"));
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportComicsInfoDialog::import()
|
||||
{
|
||||
progressBar->show();
|
||||
|
||||
Importer * importer = new Importer();
|
||||
importer->source = path->text();
|
||||
importer->dest = dest;
|
||||
connect(importer,SIGNAL(finished()),this,SLOT(close()));
|
||||
connect(importer,SIGNAL(finished()),this,SLOT(hide()));
|
||||
importer->start();
|
||||
}
|
||||
|
||||
void ImportComicsInfoDialog::close()
|
||||
{
|
||||
path->clear();
|
||||
progressBar->hide();
|
||||
accept->setDisabled(true);
|
||||
QDialog::close();
|
||||
emit(finished(0));
|
||||
}
|
||||
|
||||
void Importer::run()
|
||||
{
|
||||
DataBaseManagement::importComicsInfo(source,dest);
|
||||
}
|
||||
|
||||
|
||||
52
YACReaderLibrary/import_comics_info_dialog.h
Normal file
52
YACReaderLibrary/import_comics_info_dialog.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef IMPORT_COMICS_INFO_DIALOG_H
|
||||
#define IMPORT_COMICS_INFO_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QProgressBar>
|
||||
#include <QThread>
|
||||
|
||||
class Importer : public QThread
|
||||
{
|
||||
public:
|
||||
QString source;
|
||||
QString dest;
|
||||
private:
|
||||
void run();
|
||||
};
|
||||
|
||||
class ImportComicsInfoDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImportComicsInfoDialog(QWidget *parent = 0);
|
||||
~ImportComicsInfoDialog();
|
||||
QString dest;
|
||||
|
||||
private:
|
||||
QLabel * nameLabel;
|
||||
QLabel * textLabel;
|
||||
QLabel * destLabel;
|
||||
QLineEdit * path;
|
||||
QLineEdit * destPath;
|
||||
QLineEdit * nameEdit;
|
||||
QPushButton * find;
|
||||
QPushButton * findDest;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
QLabel * progress;
|
||||
void setupUI();
|
||||
int progressCount;
|
||||
QProgressBar *progressBar;
|
||||
|
||||
public slots:
|
||||
void findPath();
|
||||
void import();
|
||||
void close();
|
||||
};
|
||||
|
||||
#endif // IMPORT_COMICS_INFO_DIALOG_H
|
||||
144
YACReaderLibrary/import_library_dialog.cpp
Normal file
144
YACReaderLibrary/import_library_dialog.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
#include "import_library_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
|
||||
|
||||
ImportLibraryDialog::ImportLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent),progressCount(0)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::setupUI()
|
||||
{
|
||||
nameLabel = new QLabel(tr("Library Name : "));
|
||||
nameEdit = new QLineEdit;
|
||||
nameLabel->setBuddy(nameEdit);
|
||||
connect(nameEdit,SIGNAL(textChanged(QString)),this,SLOT(nameEntered()));
|
||||
|
||||
textLabel = new QLabel(tr("Package location : "));
|
||||
path = new QLineEdit;
|
||||
textLabel->setBuddy(path);
|
||||
|
||||
destLabel = new QLabel(tr("Destination folder : "));
|
||||
destPath = new QLineEdit;
|
||||
textLabel->setBuddy(destPath);
|
||||
|
||||
accept = new QPushButton(tr("Unpack"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(add()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
//connect(cancel,SIGNAL(clicked()),this,SIGNAL(rejected()));
|
||||
|
||||
find = new QPushButton(QIcon(":/images/coversPackage.png"),"");
|
||||
connect(find,SIGNAL(clicked()),this,SLOT(findPath()));
|
||||
|
||||
findDest = new QPushButton(QIcon(":/images/open.png"),"");
|
||||
connect(findDest,SIGNAL(clicked()),this,SLOT(findDestination()));
|
||||
|
||||
QGridLayout * content = new QGridLayout;
|
||||
|
||||
content->addWidget(nameLabel,0,0);
|
||||
content->addWidget(nameEdit,0,1);
|
||||
|
||||
content->addWidget(textLabel,1,0);
|
||||
content->addWidget(path,1,1);
|
||||
content->addWidget(find,1,2);
|
||||
content->setColumnStretch(2,0); //TODO
|
||||
|
||||
content->addWidget(destLabel,2,0);
|
||||
content->addWidget(destPath,2,1);
|
||||
content->addWidget(findDest,2,2);
|
||||
//destLayout->setStretchFactor(findDest,0); //TODO
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
progressBar = new QProgressBar(this);
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setTextVisible(false);
|
||||
progressBar->hide();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(content);
|
||||
//mainLayout->addWidget(progress = new QLabel());
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addWidget(progressBar);
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/importLibrary.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Extract a catalog"));
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::add()
|
||||
{
|
||||
accept->setEnabled(false);
|
||||
progressBar->show();
|
||||
emit(unpackCLC(QDir::cleanPath(path->text()),QDir::cleanPath(destPath->text()),nameEdit->text()));
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::findPath()
|
||||
{
|
||||
QString s = QFileDialog::getOpenFileName(0,"Covers Package",".",tr("Compresed library covers (*.clc)"));
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
path->setText(s);
|
||||
if(!destPath->text().isEmpty() && !nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ImportLibraryDialog::findDestination()
|
||||
{
|
||||
QString s = QFileDialog::getExistingDirectory(0,"Folder",".",QFileDialog::ShowDirsOnly);
|
||||
if(!s.isEmpty())
|
||||
{
|
||||
destPath->setText(s);
|
||||
if(!path->text().isEmpty() && !nameEdit->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::nameEntered()
|
||||
{
|
||||
if(!nameEdit->text().isEmpty())
|
||||
{
|
||||
if(!path->text().isEmpty() && !destPath->text().isEmpty())
|
||||
accept->setEnabled(true);
|
||||
}
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::close()
|
||||
{
|
||||
path->clear();
|
||||
destPath->clear();
|
||||
nameEdit->clear();
|
||||
accept->setEnabled(false);
|
||||
progressBar->hide();
|
||||
QDialog::hide();
|
||||
}
|
||||
|
||||
void ImportLibraryDialog::closeEvent ( QCloseEvent * e )
|
||||
{
|
||||
close();
|
||||
}
|
||||
43
YACReaderLibrary/import_library_dialog.h
Normal file
43
YACReaderLibrary/import_library_dialog.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef IMPORT_LIBRARY_DIALOG_H
|
||||
#define IMPORT_LIBRARY_DIALOG_H
|
||||
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QThread>
|
||||
#include <QProgressBar>
|
||||
|
||||
class ImportLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImportLibraryDialog(QWidget * parent = 0);
|
||||
private:
|
||||
QLabel * nameLabel;
|
||||
QLabel * textLabel;
|
||||
QLabel * destLabel;
|
||||
QLineEdit * path;
|
||||
QLineEdit * destPath;
|
||||
QLineEdit * nameEdit;
|
||||
QPushButton * find;
|
||||
QPushButton * findDest;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
QProgressBar *progressBar;
|
||||
void setupUI();
|
||||
int progressCount;
|
||||
void closeEvent ( QCloseEvent * e );
|
||||
public slots:
|
||||
void add();
|
||||
void findPath();
|
||||
void findDestination();
|
||||
void close();
|
||||
void nameEntered();
|
||||
|
||||
signals:
|
||||
void unpackCLC(QString clc,QString targetFolder, QString name);
|
||||
};
|
||||
|
||||
#endif
|
||||
385
YACReaderLibrary/import_widget.cpp
Normal file
385
YACReaderLibrary/import_widget.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
#include "import_widget.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QScrollBar>
|
||||
#include <QGraphicsItemAnimation>
|
||||
#include <QTimeLine>
|
||||
#include <QGLWidget>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QToolButton>
|
||||
#include <QResizeEvent>
|
||||
|
||||
#include <QPropertyAnimation>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
class YACReaderActivityIndicatorWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
YACReaderActivityIndicatorWidget(QWidget * parent = 0);
|
||||
public slots:
|
||||
|
||||
private:
|
||||
QLabel * normal;
|
||||
QLabel * glow;
|
||||
};
|
||||
|
||||
YACReaderActivityIndicatorWidget::YACReaderActivityIndicatorWidget(QWidget * parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
QPixmap line(":/images/noLibrariesLine.png");
|
||||
QPixmap glowLine(":/images/glowLine.png");
|
||||
normal = new QLabel(this);
|
||||
glow = new QLabel(this);
|
||||
|
||||
normal->setPixmap(line);
|
||||
glow->setPixmap(glowLine);
|
||||
|
||||
|
||||
|
||||
QHBoxLayout * layout = new QHBoxLayout();
|
||||
|
||||
layout->addWidget(normal,0,Qt::AlignVCenter);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
layout->setMargin(4);
|
||||
layout->setSpacing(0);
|
||||
|
||||
//setFixedHeight(3);
|
||||
//resize(579,3);
|
||||
glow->setGeometry(4,4,glowLine.width(),glowLine.height());
|
||||
//normal->setGeometry(0,1,579,1);
|
||||
|
||||
QGraphicsOpacityEffect * effect = new QGraphicsOpacityEffect();
|
||||
//effect->setOpacity(1.0);
|
||||
|
||||
|
||||
QPropertyAnimation * animation = new QPropertyAnimation(effect,"opacity");
|
||||
|
||||
animation->setDuration(1000);
|
||||
animation->setStartValue(1);
|
||||
animation->setEndValue(0);
|
||||
//animation->setEasingCurve(QEasingCurve::InQuint);
|
||||
|
||||
QPropertyAnimation * animation2 = new QPropertyAnimation(effect,"opacity");
|
||||
|
||||
animation2->setDuration(1000);
|
||||
animation2->setStartValue(0);
|
||||
animation2->setEndValue(1);
|
||||
//animation2->setEasingCurve(QEasingCurve::InQuint);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
glow->setGraphicsEffect(effect);
|
||||
#endif
|
||||
|
||||
connect(animation,SIGNAL(finished()),animation2,SLOT(start()));
|
||||
connect(animation2,SIGNAL(finished()),animation,SLOT(start()));
|
||||
|
||||
animation->start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ImportWidget::ImportWidget(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
||||
|
||||
QPalette p(palette());
|
||||
p.setColor(QPalette::Background, QColor(250,250,250));
|
||||
setAutoFillBackground(true);
|
||||
setPalette(p);
|
||||
|
||||
QPixmap icon(":/images/importingIcon.png");
|
||||
iconLabel = new QLabel();
|
||||
iconLabel->setPixmap(icon);
|
||||
|
||||
/*QPixmap line(":/images/noLibrariesLine.png");
|
||||
QLabel * lineLabel = new QLabel();
|
||||
lineLabel->setPixmap(line);*/
|
||||
|
||||
YACReaderActivityIndicatorWidget * activityIndicator = new YACReaderActivityIndicatorWidget();
|
||||
|
||||
text = new QLabel();//"<font color=\"#495252\">"+tr("Importing comics")+"</font>");
|
||||
text->setStyleSheet("QLabel {font-size:25px;font-weight:bold;}");
|
||||
textDescription = new QLabel();//"<font color=\"#565959\">"+tr("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")+"</font>");
|
||||
textDescription->setWordWrap(true);
|
||||
textDescription->setMaximumWidth(330);
|
||||
currentComicLabel = new QLabel("<font color=\"#565959\">...</font>");
|
||||
|
||||
coversViewContainer = new QWidget(this);
|
||||
QVBoxLayout * coversViewLayout = new QVBoxLayout;
|
||||
coversViewContainer->setLayout(coversViewLayout);
|
||||
coversView = new QGraphicsView();
|
||||
//coversView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
|
||||
coversView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
coversView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
coversView->setMaximumHeight(300);
|
||||
coversView->setStyleSheet("QGraphicsView {background-color: #E6E6E6;border:none;}");
|
||||
|
||||
coversScene = new QGraphicsScene();
|
||||
coversScene->setSceneRect(0,0,coversView->width(),coversView->height());
|
||||
coversView->setAlignment(Qt::AlignLeft);
|
||||
coversView->setScene(coversScene);
|
||||
|
||||
|
||||
QLabel * topDecorator = new QLabel();
|
||||
QLabel * bottomDecorator = new QLabel();
|
||||
QPixmap top(":/images/importTopCoversDecoration.png");
|
||||
QPixmap bottom(":/images/importBottomCoversDecoration.png");
|
||||
topDecorator->setPixmap(top);
|
||||
bottomDecorator->setPixmap(bottom);
|
||||
topDecorator->setScaledContents(true);
|
||||
bottomDecorator->setScaledContents(true);
|
||||
topDecorator->setFixedHeight(top.height());
|
||||
bottomDecorator->setFixedHeight(bottom.height());
|
||||
|
||||
coversViewLayout->addWidget(topDecorator,0);
|
||||
coversViewLayout->addWidget(coversView,1);
|
||||
coversViewLayout->addWidget(bottomDecorator,0);
|
||||
coversViewLayout->setMargin(0);
|
||||
coversViewLayout->setSpacing(0);
|
||||
|
||||
QPushButton * stop = new QPushButton(tr("stop"));
|
||||
stop->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
|
||||
|
||||
QVBoxLayout * layout = new QVBoxLayout(this);
|
||||
QHBoxLayout * buttonLayout = new QHBoxLayout();
|
||||
QHBoxLayout * topLayout = new QHBoxLayout();
|
||||
QVBoxLayout * textLayout = new QVBoxLayout();
|
||||
|
||||
QWidget * topWidget = new QWidget();
|
||||
topWidget->setFixedWidth(650);
|
||||
textLayout->addStretch();
|
||||
textLayout->addWidget(text);
|
||||
textLayout->addSpacing(12);
|
||||
textLayout->addWidget(textDescription);
|
||||
textLayout->addStretch();
|
||||
|
||||
topLayout->addStretch();
|
||||
topLayout->addWidget(iconLabel,0,Qt::AlignVCenter);
|
||||
topLayout->addSpacing(30);
|
||||
topLayout->addLayout(textLayout,1);
|
||||
topLayout->addStretch();
|
||||
topLayout->setMargin(0);
|
||||
|
||||
topWidget->setLayout(topLayout);
|
||||
|
||||
layout->setAlignment(Qt::AlignHCenter);
|
||||
|
||||
buttonLayout->addSpacing(250);
|
||||
buttonLayout->addWidget(stop);
|
||||
buttonLayout->addSpacing(250);
|
||||
|
||||
layout->addSpacing(50);
|
||||
layout->addWidget(topWidget,0,Qt::AlignHCenter);
|
||||
layout->addSpacing(20);
|
||||
layout->addWidget(activityIndicator,0,Qt::AlignHCenter);
|
||||
layout->addSpacing(10);
|
||||
layout->addLayout(buttonLayout,0);
|
||||
layout->addSpacing(10);
|
||||
layout->addStretch();
|
||||
portadasLabel = new QLabel("<font color=\"#565959\">"+tr("Some of the comics being added...")+"</font>");
|
||||
|
||||
hideButton = new QToolButton(this);
|
||||
hideButton->setFixedSize(25,18);
|
||||
hideButton->setStyleSheet("QToolButton {background: url(\":/images/shownCovers.png\"); border:none;}"
|
||||
" QToolButton:checked {background:url(\":/images/hiddenCovers.png\"); border:none;}");
|
||||
hideButton->setCheckable(true);
|
||||
|
||||
connect(hideButton,SIGNAL(toggled(bool)),this,SLOT(showCovers(bool)));
|
||||
|
||||
layout->addWidget(portadasLabel,0,Qt::AlignHCenter);
|
||||
layout->addWidget(coversViewContainer);
|
||||
//layout->addStretch();
|
||||
layout->addWidget(currentComicLabel,0,Qt::AlignHCenter);
|
||||
layout->setContentsMargins(0,layout->contentsMargins().top(),0,layout->contentsMargins().bottom());
|
||||
|
||||
connect(stop,SIGNAL(clicked()),this,SIGNAL(stop()));
|
||||
//connect(stop,SIGNAL(clicked()),this,SLOT(addCoverTest()));
|
||||
|
||||
previousWidth = 10;
|
||||
updatingCovers = false;
|
||||
elapsedTimer = new QElapsedTimer();
|
||||
}
|
||||
|
||||
void ImportWidget::newComic(const QString & path, const QString & coverPath)
|
||||
{
|
||||
currentComicLabel->setText("<font color=\"#565959\">"+path+"</font>");
|
||||
|
||||
if(((elapsedTimer->elapsed()>=1000) || ((previousWidth < coversView->width()) && (elapsedTimer->elapsed()>=500))) && !updatingCovers)//todo elapsed time
|
||||
{
|
||||
|
||||
QPixmap p(coverPath);
|
||||
p = p.scaledToHeight(300,Qt::SmoothTransformation);
|
||||
QGraphicsPixmapItem * item = new QGraphicsPixmapItem(p);
|
||||
item->setPos(previousWidth,0);
|
||||
item->setZValue(i/10000.0);
|
||||
previousWidth += 10 + p.width();
|
||||
coversScene->addItem(item);
|
||||
|
||||
elapsedTimer->start();
|
||||
if(previousWidth >= coversView->width()+200 && !updatingCovers)
|
||||
{
|
||||
updatingCovers = true;
|
||||
|
||||
foreach(QGraphicsItem * itemToRemove, coversScene->items())
|
||||
{
|
||||
QGraphicsPixmapItem * last = dynamic_cast<QGraphicsPixmapItem *>(itemToRemove);
|
||||
|
||||
if((last->pos().x()+last->pixmap().width())<=0)
|
||||
{
|
||||
coversScene->removeItem(last);
|
||||
delete last;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int width = p.width();
|
||||
|
||||
foreach(QGraphicsItem * itemToMove, coversScene->items())
|
||||
{
|
||||
QTimeLine *timer = new QTimeLine(400);
|
||||
timer->setFrameRange(0, 24);
|
||||
timer->setUpdateInterval(17);
|
||||
|
||||
QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
|
||||
animation->setItem(itemToMove);
|
||||
animation->setTimeLine(timer);
|
||||
|
||||
QPointF point = itemToMove->scenePos();
|
||||
float step = (width+10)/24.0;
|
||||
for (int i = 0; i < 24; ++i)
|
||||
animation->setPosAt(i / 24.0, QPointF(point.x()-((i+1)*step), point.y()));
|
||||
|
||||
timer->start();
|
||||
connect(timer,SIGNAL(finished()),timer,SLOT(deleteLater()));
|
||||
connect(timer,SIGNAL(finished()),animation,SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
QTimer::singleShot(400,this,SLOT(finishedUpdatingCover()));
|
||||
|
||||
previousWidth -= 10+width;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ImportWidget::finishedUpdatingCover()
|
||||
{
|
||||
updatingCovers = false;
|
||||
}
|
||||
|
||||
void ImportWidget::newCover(const QPixmap & image)
|
||||
{
|
||||
|
||||
}
|
||||
static int i = 1;
|
||||
static int previousWidth = 10;
|
||||
static int j = 0;
|
||||
void ImportWidget::addCoverTest()
|
||||
{
|
||||
QPixmap p(QString("c:/temp/%1.jpg").arg(i));
|
||||
p = p.scaledToHeight(300,Qt::SmoothTransformation);
|
||||
QGraphicsPixmapItem * item = new QGraphicsPixmapItem(p);
|
||||
item->setPos(previousWidth,0);
|
||||
item->setZValue(i/10000.0);
|
||||
previousWidth += 10 + p.width();
|
||||
coversScene->addItem(item);
|
||||
if(previousWidth >= coversView->width())
|
||||
{
|
||||
QGraphicsItem * last = coversScene->items().last();
|
||||
int width = p.width();
|
||||
if(j>=1)
|
||||
{
|
||||
coversScene->removeItem(last);
|
||||
delete last;
|
||||
}
|
||||
else
|
||||
j++;
|
||||
|
||||
foreach(QGraphicsItem * itemToMove, coversScene->items())
|
||||
{
|
||||
|
||||
QTimeLine *timer = new QTimeLine(/*350*/1000);
|
||||
timer->setFrameRange(0, 60);
|
||||
|
||||
QGraphicsItemAnimation *animation = new QGraphicsItemAnimation;
|
||||
animation->setItem(itemToMove);
|
||||
animation->setTimeLine(timer);
|
||||
|
||||
QPointF point = itemToMove->scenePos();
|
||||
float step = (width+10)/60.0;
|
||||
for (int i = 0; i < 60; ++i)
|
||||
animation->setPosAt(i / 60.0, QPointF(point.x()-((i+1)*step), point.y()));
|
||||
|
||||
timer->start();
|
||||
}
|
||||
previousWidth -= 10+width;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
void ImportWidget::clear()
|
||||
{
|
||||
previousWidth = 10;
|
||||
|
||||
//nos aseguramos de que las animaciones han finalizado antes de borrar
|
||||
QList<QGraphicsItem*> all = coversScene->items();
|
||||
for (int i = 0; i < all.size(); i++)
|
||||
{
|
||||
QGraphicsItem *gi = all[i];
|
||||
if(gi->parentItem()==NULL)
|
||||
delete gi;
|
||||
}
|
||||
coversScene->clear();
|
||||
|
||||
updatingCovers = false;
|
||||
|
||||
currentComicLabel->setText("<font color=\"#565959\">...</font>");
|
||||
|
||||
i = 0;
|
||||
}
|
||||
|
||||
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>");
|
||||
}
|
||||
|
||||
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>");
|
||||
}
|
||||
|
||||
void ImportWidget::clearScene()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ImportWidget::showCovers(bool hide)
|
||||
{
|
||||
portadasLabel->setHidden(hide);
|
||||
coversViewContainer->setHidden(hide);
|
||||
}
|
||||
|
||||
void ImportWidget::resizeEvent(QResizeEvent * event)
|
||||
{
|
||||
hideButton->move(event->size().width()-hideButton->width()- (currentComicLabel->height()/2),event->size().height()-hideButton->height()- (currentComicLabel->height()/2));
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
52
YACReaderLibrary/import_widget.h
Normal file
52
YACReaderLibrary/import_widget.h
Normal file
@ -0,0 +1,52 @@
|
||||
#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 ImportWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImportWidget(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void stop();
|
||||
public slots:
|
||||
void newComic(const QString & path, const QString & coverPath);
|
||||
void newCover(const QPixmap & image);
|
||||
void clear();
|
||||
void addCoverTest();
|
||||
void finishedUpdatingCover();
|
||||
void clearScene();
|
||||
void setImportLook();
|
||||
void setUpdateLook();
|
||||
void showCovers(bool hide);
|
||||
private:
|
||||
QLabel * currentComicLabel;
|
||||
QLabel * portadasLabel;
|
||||
QLabel * iconLabel;
|
||||
QLabel * text;
|
||||
QLabel * textDescription;
|
||||
QWidget * coversViewContainer;
|
||||
QGraphicsView * coversView;
|
||||
QGraphicsScene * coversScene;
|
||||
int previousWidth;
|
||||
bool updatingCovers;
|
||||
QElapsedTimer * elapsedTimer;
|
||||
quint64 i;
|
||||
|
||||
QToolButton * hideButton;
|
||||
|
||||
void resizeEvent(QResizeEvent * event);
|
||||
|
||||
};
|
||||
|
||||
#endif // IMPORT_WIDGET_H
|
||||
548
YACReaderLibrary/library_creator.cpp
Normal file
548
YACReaderLibrary/library_creator.cpp
Normal file
@ -0,0 +1,548 @@
|
||||
#include "library_creator.h"
|
||||
#include "custom_widgets.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QDebug>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlRecord>
|
||||
#include "data_base_management.h"
|
||||
#include "qnaturalsorting.h"
|
||||
#include "db_helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
#include "poppler-qt4.h"
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
LibraryCreator::LibraryCreator()
|
||||
:creation(false)
|
||||
{
|
||||
_nameFilter << "*.cbr" << "*.cbz" << "*.rar" << "*.zip" << "*.tar" << "*.pdf" << "*.7z" << "*.cb7" << "*.arj" << "*.cbt";
|
||||
}
|
||||
|
||||
void LibraryCreator::createLibrary(const QString &source, const QString &target)
|
||||
{
|
||||
creation = true;
|
||||
processLibrary(source,target);
|
||||
}
|
||||
|
||||
void LibraryCreator::updateLibrary(const QString &source, const QString &target)
|
||||
{
|
||||
processLibrary(source,target);
|
||||
}
|
||||
|
||||
void LibraryCreator::processLibrary(const QString & source, const QString & target)
|
||||
{
|
||||
_source = source;
|
||||
_target = target;
|
||||
if(DataBaseManagement::checkValidDB(target+"/library.ydb")=="")
|
||||
{
|
||||
//se limpia el directorio ./yacreaderlibrary
|
||||
delTree(target);
|
||||
_mode = CREATOR;
|
||||
}
|
||||
else //
|
||||
_mode = UPDATER;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
void LibraryCreator::run()
|
||||
{
|
||||
stopRunning = false;
|
||||
|
||||
if(_mode == CREATOR)
|
||||
{
|
||||
_currentPathFolders.clear();
|
||||
_currentPathFolders.append(Folder(1,1,"root","/"));
|
||||
//se crean los directorios .yacreaderlibrary y .yacreaderlibrary/covers
|
||||
QDir dir;
|
||||
dir.mkpath(_target+"/covers");
|
||||
|
||||
//se crea la base de datos .yacreaderlibrary/library.ydb
|
||||
_database = DataBaseManagement::createDatabase("library",_target);//
|
||||
if(!_database.isOpen())
|
||||
{
|
||||
emit failedCreatingDB(_database.lastError().databaseText() + "-" + _database.lastError().driverText());
|
||||
emit finished();
|
||||
creation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/*QSqlQuery pragma("PRAGMA foreign_keys = ON",_database);*/
|
||||
_database.transaction();
|
||||
//se crea la librer<65>a
|
||||
create(QDir(_source));
|
||||
_database.commit();
|
||||
_database.close();
|
||||
QSqlDatabase::removeDatabase(_database.connectionName());
|
||||
emit(created());
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPathFolders.clear();
|
||||
_currentPathFolders.append(Folder(1,1,"root","/"));
|
||||
_database = DataBaseManagement::loadDatabase(_target);
|
||||
//_database.setDatabaseName(_target+"/library.ydb");
|
||||
if(!_database.open())
|
||||
{
|
||||
emit failedOpeningDB(_database.lastError().databaseText() + "-" + _database.lastError().driverText());
|
||||
emit finished();
|
||||
creation = false;
|
||||
return;
|
||||
}
|
||||
//QSqlQuery pragma("PRAGMA foreign_keys = ON",_database);
|
||||
_database.transaction();
|
||||
update(QDir(_source));
|
||||
_database.commit();
|
||||
_database.close();
|
||||
QSqlDatabase::removeDatabase(_target);
|
||||
//si estabamos en modo creaci<63>n, se est<73> a<>adiendo una librer<65>a que ya exist<73>a y se ha actualizado antes de a<>adirse.
|
||||
if(!creation)
|
||||
emit(updated());
|
||||
else
|
||||
emit(created());
|
||||
}
|
||||
msleep(100);//TODO try to solve the problem with the udpate dialog (ya no se usa m<>s...)
|
||||
emit(finished());
|
||||
creation = false;
|
||||
}
|
||||
|
||||
void LibraryCreator::stop()
|
||||
{
|
||||
_database.commit();
|
||||
stopRunning = true;
|
||||
}
|
||||
|
||||
//retorna el id del ultimo de los folders
|
||||
qulonglong LibraryCreator::insertFolders()
|
||||
{
|
||||
QList<Folder>::iterator i;
|
||||
int currentId = 0;
|
||||
for (i = _currentPathFolders.begin(); i != _currentPathFolders.end(); ++i)
|
||||
{
|
||||
if(!(i->knownId))
|
||||
{
|
||||
i->setFather(currentId);
|
||||
currentId = DBHelper::insert(&(*i),_database);//insertFolder(currentId,*i);
|
||||
i->setId(currentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentId = i->id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LibraryCreator::create(QDir dir)
|
||||
{
|
||||
dir.setNameFilters(_nameFilter);
|
||||
dir.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot);
|
||||
QFileInfoList list = dir.entryInfoList();
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
{
|
||||
if(stopRunning)
|
||||
return;
|
||||
QFileInfo fileInfo = list.at(i);
|
||||
QString fileName = fileInfo.fileName();
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfo.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString relativePath = "/" + fp.join("/");
|
||||
#else
|
||||
QString relativePath = QDir::cleanPath(fileInfo.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
if(fileInfo.isDir())
|
||||
{
|
||||
//se a<>ade al path actual el folder, a<>n no se sabe si habr<62> que a<>adirlo a la base de datos
|
||||
_currentPathFolders.append(Folder(fileInfo.fileName(),relativePath));
|
||||
create(QDir(fileInfo.absoluteFilePath()));
|
||||
//una vez importada la informaci<63>n del folder, se retira del path actual ya que no volver<65> a ser visitado
|
||||
_currentPathFolders.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
insertComic(relativePath,fileInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LibraryCreator::checkCover(const QString & hash)
|
||||
{
|
||||
return QFile::exists(_target+"/covers/"+hash+".jpg");
|
||||
}
|
||||
|
||||
void LibraryCreator::insertComic(const QString & relativePath,const QFileInfo & fileInfo)
|
||||
{
|
||||
//en este punto sabemos que todos los folders que hay en _currentPath, deber<65>an estar a<>adidos a la base de datos
|
||||
insertFolders();
|
||||
emit(coverExtracted(relativePath));
|
||||
|
||||
//Se calcula el hash del c<>mic
|
||||
|
||||
QCryptographicHash crypto(QCryptographicHash::Sha1);
|
||||
QFile file(fileInfo.absoluteFilePath());
|
||||
file.open(QFile::ReadOnly);
|
||||
crypto.addData(file.read(524288));
|
||||
file.close();
|
||||
//hash Sha1 del primer 0.5MB + filesize
|
||||
QString hash = QString(crypto.result().toHex().constData()) + QString::number(fileInfo.size());
|
||||
ComicDB comic = DBHelper::loadComic(_currentPathFolders.last().id,fileInfo.fileName(),relativePath,hash,_database);
|
||||
int numPages;
|
||||
|
||||
if(! ( comic.hasCover() && checkCover(hash)))
|
||||
{
|
||||
ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+"/covers/"+hash+".jpg",*comic.info.coverPage);
|
||||
//ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+"/covers/"+fileInfo.fileName()+".jpg");
|
||||
tc.create();
|
||||
numPages = tc.getNumPages();
|
||||
|
||||
emit(comicAdded(relativePath,_target+"/covers/"+hash+".jpg"));
|
||||
}
|
||||
comic.info.setNumPages(numPages);
|
||||
DBHelper::insert(&comic,_database);
|
||||
}
|
||||
|
||||
void LibraryCreator::update(QDir dirS)
|
||||
{
|
||||
dirS.setNameFilters(_nameFilter);
|
||||
dirS.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot);
|
||||
dirS.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware|QDir::DirsFirst);
|
||||
QFileInfoList listS = dirS.entryInfoList();
|
||||
|
||||
QList<LibraryItem *> folders = DBHelper::getFoldersFromParent(_currentPathFolders.last().id,_database);
|
||||
QList<LibraryItem *> comics = DBHelper::getComicsFromParent(_currentPathFolders.last().id,_database);
|
||||
|
||||
QList <LibraryItem *> listD;
|
||||
listD.append(folders);
|
||||
listD.append(comics);
|
||||
|
||||
int lenghtS = listS.size();
|
||||
int lenghtD = listD.size();
|
||||
int maxLenght = qMax(lenghtS,lenghtD);
|
||||
|
||||
bool updated;
|
||||
int i,j;
|
||||
for (i=0,j=0; (i < lenghtS)||(j < lenghtD);)
|
||||
{
|
||||
if(stopRunning)
|
||||
return;
|
||||
updated = false;
|
||||
if(i>=lenghtS) //finished source files/dirs
|
||||
{
|
||||
//delete listD //from j
|
||||
for(;j<lenghtD;j++)
|
||||
{
|
||||
if(stopRunning)
|
||||
return;
|
||||
DBHelper::removeFromDB(listD.at(j),(_database));
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if(j>=lenghtD) //finished library files/dirs
|
||||
{
|
||||
//create listS //from i
|
||||
for(;i<lenghtS;i++)
|
||||
{
|
||||
if(stopRunning)
|
||||
return;
|
||||
QFileInfo fileInfoS = listS.at(i);
|
||||
if(fileInfoS.isDir()) //create folder
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfoS.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString path = "/" + fp.join("/");
|
||||
#else
|
||||
QString path = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
_currentPathFolders.append(Folder(fileInfoS.fileName(),path)); //folder actual no est<73> en la BD
|
||||
create(QDir(fileInfoS.absoluteFilePath()));
|
||||
_currentPathFolders.pop_back();
|
||||
}
|
||||
else //create comic
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfoS.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString path = "/" + fp.join("/");
|
||||
#else
|
||||
|
||||
QString path = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
insertComic(path,fileInfoS);
|
||||
}
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if(!updated)
|
||||
{
|
||||
QFileInfo fileInfoS = listS.at(i);
|
||||
LibraryItem * fileInfoD = listD.at(j);
|
||||
QString nameS = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(QDir::cleanPath(fileInfoS.absolutePath())); //remove source
|
||||
QString nameD = "/"+fileInfoD->name;
|
||||
|
||||
int comparation = QString::localeAwareCompare(nameS,nameD);
|
||||
if(fileInfoS.isDir()&&fileInfoD->isDir())
|
||||
if(comparation == 0)//same folder, update
|
||||
{
|
||||
_currentPathFolders.append(*static_cast<Folder *>(fileInfoD));//fileInfoD conoce su padre y su id
|
||||
update(QDir(fileInfoS.absoluteFilePath()));
|
||||
_currentPathFolders.pop_back();
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
else
|
||||
if(comparation < 0) //nameS doesn't exist on DB
|
||||
{
|
||||
if(nameS!="/.yacreaderlibrary")
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfoS.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString path = "/" + fp.join("/");
|
||||
#else
|
||||
QString path = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
_currentPathFolders.append(Folder(fileInfoS.fileName(),path));
|
||||
create(QDir(fileInfoS.absoluteFilePath()));
|
||||
_currentPathFolders.pop_back();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else //nameD no longer avaliable on Source folder...
|
||||
{
|
||||
if(nameS!="/.yacreaderlibrary")
|
||||
{
|
||||
DBHelper::removeFromDB(fileInfoD,_database);
|
||||
j++;
|
||||
}
|
||||
else
|
||||
i++; //skip library directory
|
||||
}
|
||||
else // one of them(or both) is a file
|
||||
if(fileInfoS.isDir()) //this folder doesn't exist on library
|
||||
{
|
||||
if(nameS!="/.yacreaderlibrary") //skip .yacreaderlibrary folder
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfoS.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString path = "/" + fp.join("/");
|
||||
#else
|
||||
QString path = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
_currentPathFolders.append(Folder(fileInfoS.fileName(),path));
|
||||
create(QDir(fileInfoS.absoluteFilePath()));
|
||||
_currentPathFolders.pop_back();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else
|
||||
if(fileInfoD->isDir()) //delete this folder from library
|
||||
{
|
||||
DBHelper::removeFromDB(fileInfoD,_database);
|
||||
j++;
|
||||
}
|
||||
else //both are files //BUG on windows (no case sensitive)
|
||||
{
|
||||
//nameD.remove(nameD.size()-4,4);
|
||||
int comparation = QString::localeAwareCompare(nameS,nameD);
|
||||
if(comparation < 0) //create new thumbnail
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList src = _source.split("/");
|
||||
QString filePath = fileInfoS.absoluteFilePath();
|
||||
QStringList fp = filePath.split("/");
|
||||
for(int i = 0; i< src.count();i++)
|
||||
{
|
||||
fp.removeFirst();
|
||||
}
|
||||
QString path = "/" + fp.join("/");
|
||||
#else
|
||||
QString path = QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source);
|
||||
#endif
|
||||
insertComic(path,fileInfoS);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(comparation > 0) //delete thumbnail
|
||||
{
|
||||
DBHelper::removeFromDB(fileInfoD,_database);
|
||||
j++;
|
||||
}
|
||||
else //same file
|
||||
{
|
||||
if(fileInfoS.isFile() && !fileInfoD->isDir())
|
||||
{
|
||||
//TODO comprobar fechas + tama<6D>o
|
||||
//if(fileInfoS.lastModified()>fileInfoD.lastModified())
|
||||
//{
|
||||
// dirD.mkpath(_target+(QDir::cleanPath(fileInfoS.absolutePath()).remove(_source)));
|
||||
// emit(coverExtracted(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source)));
|
||||
// ThumbnailCreator tc(QDir::cleanPath(fileInfoS.absoluteFilePath()),_target+(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source))+".jpg");
|
||||
// tc.create();
|
||||
//}
|
||||
}
|
||||
i++;j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ThumbnailCreator::ThumbnailCreator(QString fileSource, QString target="", int coverPage)
|
||||
:_fileSource(fileSource),_target(target),_numPages(0),_coverPage(coverPage)
|
||||
{
|
||||
}
|
||||
|
||||
void ThumbnailCreator::create()
|
||||
{
|
||||
QFileInfo fi(_fileSource);
|
||||
if(fi.suffix().compare("pdf",Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
Poppler::Document * pdfComic = Poppler::Document::load(_fileSource);
|
||||
if (!pdfComic)
|
||||
{
|
||||
delete pdfComic;
|
||||
pdfComic = 0;
|
||||
QImage p;
|
||||
p.load(":/images/notCover.png");
|
||||
p.save(_target);
|
||||
return;
|
||||
}
|
||||
_numPages = pdfComic->numPages();
|
||||
if(_numPages >= _coverPage)
|
||||
{
|
||||
|
||||
QImage p = pdfComic->page(_coverPage-1)->renderToImage(72,72); //TODO check if the the page is valid
|
||||
_cover = QPixmap::fromImage(p);
|
||||
QImage scaled;
|
||||
if(p.width()>p.height()) //landscape??
|
||||
scaled = p.scaledToWidth(640,Qt::SmoothTransformation);
|
||||
else
|
||||
scaled = p.scaledToWidth(480,Qt::SmoothTransformation);
|
||||
scaled.save(_target,0,75);
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage p;
|
||||
p.load(":/images/notCover.png");
|
||||
p.save(_target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_7z = new QProcess();
|
||||
QStringList attributes;
|
||||
attributes << "l" << "-ssc-" << "-r" << _fileSource << "*.jpg" << "*.jpeg" << "*.png" << "*.gif" << "*.tiff" << "*.tif" << "*.bmp";
|
||||
//connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(loadFirstImage(void)));
|
||||
connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError)));
|
||||
_7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes);
|
||||
_7z->waitForFinished(60000);
|
||||
|
||||
QRegExp rx("[0-9]{4}-[0-9]{2}-[0-9]{2}[ ]+[0-9]{2}:[0-9]{2}:[0-9]{2}[ ]+.{5}[ ]+([0-9]+)[ ]+([0-9]+)[ ]+(.+)");
|
||||
|
||||
QString ba = QString::fromUtf8(_7z->readAllStandardOutput());
|
||||
QList<QString> lines = ba.split('\n');
|
||||
QString line;
|
||||
_currentName = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; //TODO
|
||||
QString name;
|
||||
if(_coverPage == 1)
|
||||
{
|
||||
foreach(line,lines)
|
||||
{
|
||||
if(rx.indexIn(line)!=-1)
|
||||
{
|
||||
name = rx.cap(3).trimmed();
|
||||
if(naturalSortLessThanCI(name,_currentName))
|
||||
_currentName = name;
|
||||
_numPages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QList<QString> names;
|
||||
foreach(line,lines)
|
||||
{
|
||||
if(rx.indexIn(line)!=-1)
|
||||
{
|
||||
name = rx. cap(3).trimmed();
|
||||
names.append(name);
|
||||
}
|
||||
}
|
||||
std::sort(names.begin(),names.end(),naturalSortLessThanCI);
|
||||
_currentName = names[_coverPage-1];
|
||||
}
|
||||
delete _7z;
|
||||
attributes.clear();
|
||||
_currentName = QDir::fromNativeSeparators(_currentName).split('/').last(); //separator fixed.
|
||||
#ifdef Q_OS_WIN32
|
||||
attributes << "e" << "-so" << "-r" << _fileSource << QString(_currentName.toLocal8Bit().constData()); //TODO platform dependency?? OEM 437
|
||||
#else
|
||||
attributes << "e" << "-so" << "-r" << _fileSource << _currentName; //TODO platform dependency?? OEM 437
|
||||
#endif
|
||||
_7z = new QProcess();
|
||||
connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError)));
|
||||
//connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(writeThumbnail(void)));
|
||||
_7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes);
|
||||
_7z->waitForFinished(60000);
|
||||
|
||||
QByteArray image = _7z->readAllStandardOutput();
|
||||
QString error = _7z->readAllStandardError();
|
||||
QImage p;
|
||||
if(_target=="")
|
||||
{
|
||||
if(!_cover.loadFromData(image))
|
||||
_cover.load(":/images/notCover.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(p.loadFromData(image))
|
||||
{
|
||||
QImage scaled;
|
||||
if(p.width()>p.height()) //landscape??
|
||||
scaled = p.scaledToWidth(640,Qt::SmoothTransformation);
|
||||
else
|
||||
scaled = p.scaledToWidth(480,Qt::SmoothTransformation);
|
||||
scaled.save(_target,0,75);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.load(":/images/notCover.png");
|
||||
p.save(_target);
|
||||
}
|
||||
}
|
||||
delete _7z;
|
||||
}
|
||||
}
|
||||
86
YACReaderLibrary/library_creator.h
Normal file
86
YACReaderLibrary/library_creator.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef __LIBRARY_CREATOR_H
|
||||
#define __LIBRARY_CREATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
#include <QRegExp>
|
||||
#include <QProcess>
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "folder.h"
|
||||
#include "comic_db.h"
|
||||
|
||||
|
||||
class LibraryCreator : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LibraryCreator();
|
||||
void createLibrary(const QString & source, const QString & target);
|
||||
void updateLibrary(const QString & source, const QString & target);
|
||||
void stop();
|
||||
private:
|
||||
void processLibrary(const QString & source, const QString & target);
|
||||
enum Mode {CREATOR,UPDATER};
|
||||
//atributos "globales" durante el proceso de creaci<63>n y actualizaci<63>n
|
||||
enum Mode _mode;
|
||||
QString _source;
|
||||
QString _target;
|
||||
QStringList _nameFilter;
|
||||
QSqlDatabase _database;
|
||||
QList<Folder> _currentPathFolders; //lista de folders en el orden en el que est<73>n siendo explorados, el <20>ltimo es el folder actual
|
||||
//recursive method
|
||||
void create(QDir currentDirectory);
|
||||
void update(QDir currentDirectory);
|
||||
void run();
|
||||
qulonglong insertFolders();//devuelve el id del <20>ltimo folder a<>adido (<28>ltimo en la ruta)
|
||||
bool checkCover(const QString & hash);
|
||||
void insertComic(const QString & relativePath,const QFileInfo & fileInfo);
|
||||
//qulonglong insertFolder(qulonglong parentId,const Folder & folder);
|
||||
//qulonglong insertComic(const Comic & comic);
|
||||
bool stopRunning;
|
||||
//LibraryCreator est<73> en modo creaci<63>n si creation == true;
|
||||
bool creation;
|
||||
signals:
|
||||
void finished();
|
||||
void coverExtracted(QString);
|
||||
void folderUpdated(QString);
|
||||
void comicAdded(QString,QString);
|
||||
void updated();
|
||||
void created();
|
||||
void failedCreatingDB(QString);
|
||||
void failedOpeningDB(QString);
|
||||
};
|
||||
|
||||
class ThumbnailCreator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ThumbnailCreator(QString fileSource, QString target, int coverPage = 1);
|
||||
private:
|
||||
QProcess * _7z;
|
||||
QString _fileSource;
|
||||
QString _target;
|
||||
QString _currentName;
|
||||
int _numPages;
|
||||
QPixmap _cover;
|
||||
int _coverPage;
|
||||
|
||||
public slots:
|
||||
void create();
|
||||
int getNumPages(){return _numPages;};
|
||||
QPixmap getCover(){return _cover;};
|
||||
signals:
|
||||
void openingError(QProcess::ProcessError error);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
1523
YACReaderLibrary/library_window.cpp
Normal file
1523
YACReaderLibrary/library_window.cpp
Normal file
File diff suppressed because it is too large
Load Diff
256
YACReaderLibrary/library_window.h
Normal file
256
YACReaderLibrary/library_window.h
Normal file
@ -0,0 +1,256 @@
|
||||
#ifndef __LIBRARYWINDOW_H
|
||||
#define __LIBRARYWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <QModelIndex>
|
||||
#include <QFileInfo>
|
||||
|
||||
class QTreeView;
|
||||
class QDirModel;
|
||||
class QAction;
|
||||
class QToolBar;
|
||||
class QComboBox;
|
||||
class QThread;
|
||||
class QStackedWidget;
|
||||
class YACReaderSearchLineEdit;
|
||||
class CreateLibraryDialog;
|
||||
class UpdateLibraryDialog;
|
||||
class ExportLibraryDialog;
|
||||
class ImportLibraryDialog;
|
||||
class ExportComicsInfoDialog;
|
||||
class ImportComicsInfoDialog;
|
||||
class AddLibraryDialog;
|
||||
class LibraryCreator;
|
||||
class HelpAboutDialog;
|
||||
class RenameLibraryDialog;
|
||||
class PropertiesDialog;
|
||||
class PackageManager;
|
||||
class ComicFlowWidget;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class TableModel;
|
||||
class QSplitter;
|
||||
class TreeItem;
|
||||
class TreeModel;
|
||||
class QItemSelectionModel;
|
||||
class QString;
|
||||
class QLabel;
|
||||
class NoLibrariesWidget;
|
||||
class OptionsDialog;
|
||||
class ServerConfigDialog;
|
||||
class QCloseEvent;
|
||||
class ImportWidget;
|
||||
class QSettings;
|
||||
class LibraryItem;
|
||||
class YACReaderTableView;
|
||||
class YACReaderSideBar;
|
||||
class YACReaderLibraryListWidget;
|
||||
class YACReaderTreeView;
|
||||
class YACReaderMainToolBar;
|
||||
#include "comic_db.h"
|
||||
|
||||
class LibraryWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
YACReaderSideBar * sideBar;
|
||||
QSplitter * sVertical;
|
||||
CreateLibraryDialog * createLibraryDialog;
|
||||
UpdateLibraryDialog * updateLibraryDialog;
|
||||
ExportLibraryDialog * exportLibraryDialog;
|
||||
ImportLibraryDialog * importLibraryDialog;
|
||||
ExportComicsInfoDialog * exportComicsInfoDialog;
|
||||
ImportComicsInfoDialog * importComicsInfoDialog;
|
||||
AddLibraryDialog * addLibraryDialog;
|
||||
LibraryCreator * libraryCreator;
|
||||
HelpAboutDialog * had;
|
||||
RenameLibraryDialog * renameLibraryDialog;
|
||||
PropertiesDialog * propertiesDialog;
|
||||
//YACReaderSocialDialog * socialDialog;
|
||||
bool fullscreen;
|
||||
bool importedCovers; //if true, the library is read only (not updates,open comic or properties)
|
||||
bool fromMaximized;
|
||||
//Ya no se usan proxies, el rendimiento de la BD es suficiente
|
||||
//YACReaderTreeSearch * proxyFilter;
|
||||
//YACReaderSortComics * proxySort;
|
||||
PackageManager * packageManager;
|
||||
|
||||
ComicFlowWidget * comicFlow;
|
||||
QSize slideSizeW;
|
||||
QSize slideSizeF;
|
||||
//search filter
|
||||
YACReaderSearchLineEdit * foldersFilter;
|
||||
TreeItem * index; //index al que hay que hacer scroll despu<70>s de pulsar sobre un folder filtrado
|
||||
int column;
|
||||
QString previousFilter;
|
||||
QPushButton * clearFoldersFilter;
|
||||
QCheckBox * includeComicsCheckBox;
|
||||
//-------------
|
||||
QWidget *comics;
|
||||
YACReaderTableView * comicView;
|
||||
YACReaderTreeView * foldersView;
|
||||
YACReaderLibraryListWidget * selectedLibrary;
|
||||
TreeModel * dm;
|
||||
QItemSelectionModel * sm;
|
||||
TableModel * dmCV;
|
||||
//QStringList paths;
|
||||
QMap<QString,QString> libraries;
|
||||
QLabel * fullScreenToolTip;
|
||||
|
||||
QStackedWidget * mainWidget;
|
||||
NoLibrariesWidget * noLibrariesWidget;
|
||||
ImportWidget * importWidget;
|
||||
|
||||
bool fetching;
|
||||
|
||||
int i;
|
||||
|
||||
QAction * backAction;
|
||||
QAction * fordwardAction;
|
||||
|
||||
QAction * openComicAction;
|
||||
QAction * showPropertiesAction;
|
||||
QAction * createLibraryAction;
|
||||
QAction * openLibraryAction;
|
||||
|
||||
QAction * exportComicsInfo;
|
||||
QAction * importComicsInfo;
|
||||
|
||||
QAction * exportLibraryAction;
|
||||
QAction * importLibraryAction;
|
||||
|
||||
QAction * updateLibraryAction;
|
||||
QAction * removeLibraryAction;
|
||||
QAction * helpAboutAction;
|
||||
QAction * renameLibraryAction;
|
||||
QAction * toggleFullScreenAction;
|
||||
QAction * optionsAction;
|
||||
QAction * serverConfigAction;
|
||||
//QAction * socialAction;
|
||||
|
||||
//tree actions
|
||||
QAction * setRootIndexAction;
|
||||
QAction * expandAllNodesAction;
|
||||
QAction * colapseAllNodesAction;
|
||||
|
||||
QAction * openContainingFolderAction;
|
||||
QAction * openContainingFolderComicAction;
|
||||
QAction * setAsReadAction;
|
||||
QAction * setAsNonReadAction;
|
||||
QAction * setAllAsReadAction;
|
||||
QAction * setAllAsNonReadAction;
|
||||
QAction * showHideMarksAction;
|
||||
|
||||
//edit info actions
|
||||
QAction * selectAllComicsAction;
|
||||
QAction * editSelectedComicsAction;
|
||||
QAction * asignOrderActions;
|
||||
QAction * forceConverExtractedAction;
|
||||
QAction * deleteComicsAction;
|
||||
QAction * hideComicViewAction;
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QToolBar * libraryToolBar;
|
||||
#else
|
||||
YACReaderMainToolBar * libraryToolBar;
|
||||
#endif
|
||||
QToolBar * treeActions;
|
||||
QToolBar * comicsToolBar;
|
||||
QToolBar * editInfoToolBar;
|
||||
|
||||
OptionsDialog * optionsDialog;
|
||||
ServerConfigDialog * serverConfigDialog;
|
||||
|
||||
QString libraryPath;
|
||||
QString comicsPath;
|
||||
|
||||
QString _lastAdded;
|
||||
QString _sourceLastAdded;
|
||||
|
||||
QModelIndex _rootIndex;
|
||||
QModelIndex _rootIndexCV;
|
||||
|
||||
quint64 _comicIdEdited;
|
||||
|
||||
void setupUI();
|
||||
void createActions();
|
||||
void createToolBars();
|
||||
void createMenus();
|
||||
void createConnections();
|
||||
void doLayout();
|
||||
void doDialogs();
|
||||
void doModels();
|
||||
|
||||
void disableAllActions();
|
||||
void disableActions();
|
||||
void enableActions();
|
||||
void enableLibraryActions();
|
||||
|
||||
QString currentPath();
|
||||
|
||||
//settings
|
||||
QSettings * settings;
|
||||
protected:
|
||||
virtual void closeEvent ( QCloseEvent * event );
|
||||
public:
|
||||
LibraryWindow();
|
||||
public slots:
|
||||
void loadLibrary(const QString & path);
|
||||
void loadCovers(const QModelIndex & mi);
|
||||
void checkEmptyFolder(QStringList * paths = 0);
|
||||
void reloadCovers();
|
||||
void centerComicFlow(const QModelIndex & mi);
|
||||
void updateComicView(int i);
|
||||
void openComic();
|
||||
void createLibrary();
|
||||
void create(QString source,QString dest, QString name);
|
||||
void showAddLibrary();
|
||||
void openLibrary(QString path, QString name);
|
||||
void loadLibraries();
|
||||
void saveLibraries();
|
||||
void reloadCurrentLibrary();
|
||||
void openLastCreated();
|
||||
void updateLibrary();
|
||||
//void deleteLibrary();
|
||||
void openContainingFolder();
|
||||
void openContainingFolderComic();
|
||||
void deleteCurrentLibrary();
|
||||
void removeLibrary();
|
||||
void renameLibrary();
|
||||
void rename(QString newName);
|
||||
void cancelCreating();
|
||||
void stopLibraryCreator();
|
||||
void setRootIndex();
|
||||
void toggleFullScreen();
|
||||
void toNormal();
|
||||
void toFullScreen();
|
||||
void setFoldersFilter(QString filter);
|
||||
void showProperties();
|
||||
void exportLibrary(QString destPath);
|
||||
void importLibrary(QString clc,QString destPath,QString name);
|
||||
void reloadOptions();
|
||||
void setCurrentComicsStatusReaded(bool readed);
|
||||
void setCurrentComicReaded();
|
||||
void setCurrentComicUnreaded();
|
||||
void setComicsReaded();
|
||||
void setComicsUnreaded();
|
||||
void hideComicFlow(bool hide);
|
||||
void showExportComicsInfo();
|
||||
void showImportComicsInfo();
|
||||
void asignNumbers();
|
||||
void showNoLibrariesWidget();
|
||||
void showRootWidget();
|
||||
void showImportingWidget();
|
||||
void manageCreatingError(const QString & error);
|
||||
void manageUpdatingError(const QString & error);
|
||||
void manageOpeningLibraryError(const QString & error);
|
||||
QModelIndexList getSelectedComics();
|
||||
void deleteComics();
|
||||
//void showSocial();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
59
YACReaderLibrary/main.cpp
Normal file
59
YACReaderLibrary/main.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include "library_window.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
#include <QSettings>
|
||||
#include <QLocale>
|
||||
|
||||
#include "yacreader_global.h"
|
||||
#include "startup.h"
|
||||
#include "yacreader_local_server.h"
|
||||
#define PICTUREFLOW_QT4 1
|
||||
|
||||
//interfaz al servidor
|
||||
Startup * s;
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
QApplication app( argc, argv );
|
||||
|
||||
QTranslator translator;
|
||||
QString sufix = QLocale::system().name();
|
||||
translator.load(QCoreApplication::applicationDirPath()+"/languages/yacreaderlibrary_"+sufix);
|
||||
app.installTranslator(&translator);
|
||||
app.setApplicationName("YACReaderLibrary");
|
||||
|
||||
#ifdef SERVER_RELEASE
|
||||
QSettings * settings = new QSettings(QCoreApplication::applicationDirPath()+"/YACReaderLibrary.ini",QSettings::IniFormat); //TODO unificar la creaci<63>n del fichero de config con el servidor
|
||||
settings->beginGroup("libraryConfig");
|
||||
|
||||
s = new Startup();
|
||||
|
||||
if(settings->value(SERVER_ON,true).toBool())
|
||||
{
|
||||
|
||||
s->start();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(YACReaderLocalServer::isRunning()) //s<>lo se permite una instancia de YACReaderLibrary
|
||||
return 0;
|
||||
|
||||
YACReaderLocalServer * localServer = new YACReaderLocalServer();
|
||||
|
||||
LibraryWindow * mw = new LibraryWindow();
|
||||
|
||||
//connections to localServer
|
||||
|
||||
mw->show();
|
||||
/*mw->resize(800,480);
|
||||
mw->showMaximized();*/
|
||||
|
||||
int ret = app.exec();
|
||||
|
||||
//server shutdown
|
||||
s->stop();
|
||||
delete s;
|
||||
|
||||
return ret;
|
||||
}
|
||||
80
YACReaderLibrary/no_libraries_widget.cpp
Normal file
80
YACReaderLibrary/no_libraries_widget.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include "no_libraries_widget.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
NoLibrariesWidget::NoLibrariesWidget(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
|
||||
|
||||
QPalette p(palette());
|
||||
p.setColor(QPalette::Background, QColor(250,250,250));
|
||||
setAutoFillBackground(true);
|
||||
setPalette(p);
|
||||
|
||||
QPixmap icon(":/images/noLibrariesIcon.png");
|
||||
QLabel * iconLabel = new QLabel();
|
||||
iconLabel->setPixmap(icon);
|
||||
|
||||
QPixmap line(":/images/noLibrariesLine.png");
|
||||
QLabel * lineLabel = new QLabel();
|
||||
lineLabel->setPixmap(line);
|
||||
|
||||
QLabel * text = new QLabel("<font color=\"#495252\">"+tr("You don't have any librarires yet")+"</font>");
|
||||
text->setStyleSheet("QLabel {font-size:25px;font-weight:bold;}");
|
||||
QLabel * textDescription = new QLabel("<font color=\"#565959\">"+tr("<p>You can create a library in any folder, YACReaderLibrary will import all comics and folders from this folder. If you have created any library in the past you can open them.</p><p>Don't forget that you can use YACReader as a stand alone application for reading the comics on your computer.</p>")+"</font>");
|
||||
textDescription->setWordWrap(true);
|
||||
textDescription->setMaximumWidth(330);
|
||||
|
||||
QPushButton * createButton = new QPushButton(tr("create your first library"));
|
||||
createButton->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
|
||||
QPushButton * addButton = new QPushButton(tr("add an existing one"));
|
||||
addButton->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
|
||||
|
||||
QVBoxLayout * layout = new QVBoxLayout(this);
|
||||
QHBoxLayout * buttonLayout = new QHBoxLayout();
|
||||
QHBoxLayout * topLayout = new QHBoxLayout();
|
||||
QVBoxLayout * textLayout = new QVBoxLayout();
|
||||
|
||||
QWidget * topWidget = new QWidget();
|
||||
topWidget->setFixedWidth(650);
|
||||
textLayout->addStretch();
|
||||
textLayout->addWidget(text);
|
||||
textLayout->addSpacing(12);
|
||||
textLayout->addWidget(textDescription);
|
||||
textLayout->addStretch();
|
||||
|
||||
topLayout->addStretch();
|
||||
topLayout->addWidget(iconLabel,0,Qt::AlignVCenter);
|
||||
topLayout->addSpacing(30);
|
||||
topLayout->addLayout(textLayout,1);
|
||||
topLayout->addStretch();
|
||||
topLayout->setMargin(0);
|
||||
|
||||
topWidget->setLayout(topLayout);
|
||||
|
||||
layout->setAlignment(Qt::AlignHCenter);
|
||||
|
||||
buttonLayout->addSpacing(125);
|
||||
buttonLayout->addWidget(createButton);
|
||||
layout->addSpacing(25);
|
||||
buttonLayout->addWidget(addButton);
|
||||
buttonLayout->addSpacing(125);
|
||||
|
||||
layout->addStretch();
|
||||
layout->addWidget(topWidget);
|
||||
layout->addSpacing(20);
|
||||
layout->addWidget(lineLabel,0,Qt::AlignHCenter);
|
||||
layout->addSpacing(10);
|
||||
layout->addLayout(buttonLayout,0);
|
||||
layout->addSpacing(150);
|
||||
layout->addStretch();
|
||||
|
||||
connect(createButton,SIGNAL(clicked()),this,SIGNAL(createNewLibrary()));
|
||||
connect(addButton,SIGNAL(clicked()),this,SIGNAL(addExistingLibrary()));
|
||||
|
||||
|
||||
}
|
||||
19
YACReaderLibrary/no_libraries_widget.h
Normal file
19
YACReaderLibrary/no_libraries_widget.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef NO_LIBRARIES_WIDGET_H
|
||||
#define NO_LIBRARIES_WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class NoLibrariesWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NoLibrariesWidget(QWidget *parent = 0);
|
||||
|
||||
signals:
|
||||
void createNewLibrary();
|
||||
void addExistingLibrary();
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // NO_LIBRARIES_WIDGET_H
|
||||
52
YACReaderLibrary/options_dialog.cpp
Normal file
52
YACReaderLibrary/options_dialog.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "options_dialog.h"
|
||||
|
||||
#include "yacreader_flow_gl.h"
|
||||
#include "yacreader_flow_config_widget.h"
|
||||
#include "yacreader_gl_flow_config_widget.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
#include <QTextStream>
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
FlowType flowType = Strip;
|
||||
|
||||
OptionsDialog::OptionsDialog(QWidget * parent)
|
||||
:YACReaderOptionsDialog(parent)
|
||||
{
|
||||
QVBoxLayout * layout = new QVBoxLayout;
|
||||
|
||||
QHBoxLayout * switchFlowType = new QHBoxLayout;
|
||||
switchFlowType->addStretch();
|
||||
switchFlowType->addWidget(useGL);
|
||||
|
||||
|
||||
|
||||
QHBoxLayout * buttons = new QHBoxLayout();
|
||||
buttons->addStretch();
|
||||
buttons->addWidget(accept);
|
||||
buttons->addWidget(cancel);
|
||||
|
||||
layout->addWidget(sw);
|
||||
layout->addWidget(gl);
|
||||
layout->addLayout(switchFlowType);
|
||||
layout->addLayout(buttons);
|
||||
|
||||
sw->hide();
|
||||
|
||||
setLayout(layout);
|
||||
//restoreOptions(settings); //load options
|
||||
//resize(200,0);
|
||||
setModal (true);
|
||||
setWindowTitle(tr("Options"));
|
||||
|
||||
this->layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
}
|
||||
|
||||
|
||||
18
YACReaderLibrary/options_dialog.h
Normal file
18
YACReaderLibrary/options_dialog.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __OPTIONS_DIALOG_H
|
||||
#define __OPTIONS_DIALOG_H
|
||||
|
||||
#include "yacreader_options_dialog.h"
|
||||
|
||||
#include "yacreader_global.h"
|
||||
|
||||
extern FlowType flowType;
|
||||
|
||||
class OptionsDialog : public YACReaderOptionsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OptionsDialog(QWidget * parent = 0);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
47
YACReaderLibrary/package_manager.cpp
Normal file
47
YACReaderLibrary/package_manager.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "package_manager.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
PackageManager::PackageManager()
|
||||
:_7z(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PackageManager::createPackage(const QString & libraryPath,const QString & dest)
|
||||
{
|
||||
QStringList attributes;
|
||||
attributes << "a" << "-y" << "-ttar" << dest+".clc" << libraryPath ;
|
||||
_7z = new QProcess();
|
||||
connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SLOT(openingError(QProcess::ProcessError)));
|
||||
connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SIGNAL(exported()));
|
||||
_7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes);
|
||||
}
|
||||
|
||||
void PackageManager::extractPackage(const QString & packagePath,const QString & destDir)
|
||||
{
|
||||
QStringList attributes;
|
||||
QString output = "-o";
|
||||
output += destDir;
|
||||
attributes << "x" << "-y" << output << packagePath;
|
||||
_7z = new QProcess();
|
||||
connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SLOT(openingError(QProcess::ProcessError)));
|
||||
connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SIGNAL(imported()));
|
||||
_7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes);
|
||||
}
|
||||
|
||||
void PackageManager::cancel()
|
||||
{
|
||||
if(_7z!=0)
|
||||
{
|
||||
_7z->disconnect();
|
||||
_7z->kill();
|
||||
if(creating)
|
||||
{
|
||||
//TODO remove dest+".clc"
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO fixed: is done by libraryWindow
|
||||
}
|
||||
}
|
||||
}
|
||||
24
YACReaderLibrary/package_manager.h
Normal file
24
YACReaderLibrary/package_manager.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef PACKAGE_MANAGER_H
|
||||
#define PACKAGE_MANAGER_H
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
class PackageManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PackageManager();
|
||||
void createPackage(const QString & libraryPath,const QString & dest);
|
||||
void extractPackage(const QString & packagePath,const QString & destDir);
|
||||
public slots:
|
||||
void cancel();
|
||||
private:
|
||||
bool creating;
|
||||
QProcess * _7z;
|
||||
|
||||
signals:
|
||||
void exported();
|
||||
void imported();
|
||||
};
|
||||
|
||||
#endif
|
||||
697
YACReaderLibrary/properties_dialog.cpp
Normal file
697
YACReaderLibrary/properties_dialog.cpp
Normal file
@ -0,0 +1,697 @@
|
||||
#include "properties_dialog.h"
|
||||
|
||||
#include "data_base_management.h"
|
||||
#include "library_creator.h"
|
||||
#include "yacreader_field_edit.h"
|
||||
#include "yacreader_field_plain_text_edit.h"
|
||||
#include "db_helper.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QSizePolicy>
|
||||
#include <QFormLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QTabWidget>
|
||||
#include <QIntValidator>
|
||||
|
||||
PropertiesDialog::PropertiesDialog(QWidget * parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
|
||||
createCoverBox();
|
||||
createGeneralInfoBox();
|
||||
createAuthorsBox();
|
||||
createPublishingBox();
|
||||
createButtonBox();
|
||||
createPlotBox();
|
||||
|
||||
createTabBar();
|
||||
|
||||
mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(coverBox,0,0);
|
||||
mainLayout->addWidget(tabBar,0,1);
|
||||
mainLayout->setColumnStretch(1,1);
|
||||
/*mainLayout->addWidget(authorsBox,1,1);
|
||||
mainLayout->addWidget(publishingBox,2,1);*/
|
||||
mainLayout->addWidget(buttonBox,1,1,Qt::AlignBottom);
|
||||
|
||||
this->setLayout(mainLayout);
|
||||
mainLayout->setSizeConstraint(QLayout::SetMinimumSize);
|
||||
|
||||
int heightDesktopResolution = QApplication::desktop()->screenGeometry().height();
|
||||
int widthDesktopResolution = QApplication::desktop()->screenGeometry().width();
|
||||
int sHeight,sWidth;
|
||||
sHeight = static_cast<int>(heightDesktopResolution*0.65);
|
||||
sWidth = static_cast<int>(sHeight*1.4);
|
||||
setCover(QPixmap(":/images/notCover.png"));
|
||||
this->resize(sWidth,this->height());
|
||||
this->move(QPoint((widthDesktopResolution-sWidth)/2,((heightDesktopResolution-sHeight)-40)/2));
|
||||
setModal(true);
|
||||
repaint();
|
||||
|
||||
}
|
||||
|
||||
void PropertiesDialog::createTabBar()
|
||||
{
|
||||
tabBar = new QTabWidget;
|
||||
tabBar->addTab(generalInfoBox,tr("General info"));
|
||||
tabBar->addTab(authorsBox,tr("Authors"));
|
||||
tabBar->addTab(publishingBox,tr("Publishing"));
|
||||
tabBar->addTab(plotBox,tr("Plot"));
|
||||
}
|
||||
|
||||
void PropertiesDialog::createCoverBox()
|
||||
{
|
||||
coverBox = new QGroupBox(tr("Cover"));
|
||||
|
||||
sa = new QScrollArea();
|
||||
cover = new QLabel();
|
||||
cover->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
cover->setScaledContents(false);
|
||||
cover->setAlignment(Qt::AlignTop|Qt::AlignHCenter);
|
||||
|
||||
|
||||
/*sa->setWidget(cover);
|
||||
sa->setBackgroundRole(QPalette::Dark);
|
||||
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
sa->setFrameStyle(QFrame::NoFrame);
|
||||
sa->setAlignment(Qt::AlignCenter);*/
|
||||
|
||||
QVBoxLayout * coverLayout = new QVBoxLayout();
|
||||
coverLayout->addWidget(cover);
|
||||
|
||||
QHBoxLayout * coverPageLayout = new QHBoxLayout;
|
||||
coverPageLayout->addWidget(new QLabel(tr("Cover page : ")));
|
||||
coverPageLayout->addWidget(coverPageEdit = new YACReaderFieldEdit());
|
||||
coverPageLayout->setStretch(1,0);
|
||||
|
||||
coverLayout->addLayout(coverPageLayout);
|
||||
|
||||
coverBox->setLayout(coverLayout);
|
||||
}
|
||||
|
||||
QFrame * createLine()
|
||||
{
|
||||
QFrame * line = new QFrame();
|
||||
line->setObjectName(QString::fromUtf8("line"));
|
||||
//line->setGeometry(QRect(320, 150, 118, 3));
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
void PropertiesDialog::createGeneralInfoBox()
|
||||
{
|
||||
generalInfoBox = new QWidget;
|
||||
|
||||
QFormLayout *generalInfoLayout = new QFormLayout;
|
||||
|
||||
//generalInfoLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
|
||||
generalInfoLayout->addRow(tr("Title:"), title = new YACReaderFieldEdit());
|
||||
|
||||
|
||||
QHBoxLayout * number = new QHBoxLayout;
|
||||
number->addWidget(numberEdit = new YACReaderFieldEdit());
|
||||
numberValidator.setBottom(0);
|
||||
numberEdit->setValidator(&numberValidator);
|
||||
number->addWidget(new QLabel("Bis:"));
|
||||
number->addWidget(isBisCheck = new QCheckBox());
|
||||
number->addWidget(new QLabel("of:"));
|
||||
number->addWidget(countEdit = new YACReaderFieldEdit());
|
||||
countValidator.setBottom(0);
|
||||
countEdit->setValidator(&countValidator);
|
||||
number->addStretch(1);
|
||||
/*generalInfoLayout->addRow(tr("&Issue number:"), );
|
||||
generalInfoLayout->addRow(tr("&Bis:"), );*/
|
||||
generalInfoLayout->addRow(tr("Issue number:"), number);
|
||||
|
||||
generalInfoLayout->addRow(tr("Volume:"), volumeEdit = new YACReaderFieldEdit());
|
||||
|
||||
QHBoxLayout * arc = new QHBoxLayout;
|
||||
arc->addWidget(storyArcEdit = new YACReaderFieldEdit());
|
||||
arc->addWidget(new QLabel("Arc number:"));
|
||||
arc->addWidget(arcNumberEdit = new YACReaderFieldEdit());
|
||||
arcNumberValidator.setBottom(0);
|
||||
arcNumberEdit->setValidator(&arcNumberValidator);
|
||||
arc->addWidget(new QLabel("of:"));
|
||||
arc->addWidget(arcCountEdit = new YACReaderFieldEdit());
|
||||
arcCountValidator.setBottom(0);
|
||||
arcCountEdit->setValidator(&arcCountValidator);
|
||||
arc->addStretch(1);
|
||||
generalInfoLayout->addRow(tr("Story arc:"), arc);
|
||||
|
||||
generalInfoLayout->addRow(tr("Genere:"), genereEdit = new YACReaderFieldEdit());
|
||||
|
||||
generalInfoLayout->addRow(tr("Size:"), size = new QLabel("size"));
|
||||
|
||||
generalInfoBox->setLayout(generalInfoLayout);
|
||||
}
|
||||
|
||||
void PropertiesDialog::createAuthorsBox()
|
||||
{
|
||||
authorsBox = new QWidget;
|
||||
|
||||
QVBoxLayout *authorsLayout = new QVBoxLayout;
|
||||
|
||||
//authorsLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
|
||||
QHBoxLayout * h1 = new QHBoxLayout;
|
||||
QVBoxLayout * vl1 = new QVBoxLayout;
|
||||
QVBoxLayout * vr1 = new QVBoxLayout;
|
||||
vl1->addWidget(new QLabel(tr("Writer(s):")));
|
||||
vl1->addWidget(writer = new YACReaderFieldPlainTextEdit());
|
||||
h1->addLayout(vl1);
|
||||
vr1->addWidget(new QLabel(tr("Penciller(s):")));
|
||||
vr1->addWidget(penciller = new YACReaderFieldPlainTextEdit());
|
||||
h1->addLayout(vr1);
|
||||
//authorsLayout->addRow(tr("Writer(s):"), new YACReaderFieldPlainTextEdit());
|
||||
//authorsLayout->addRow(tr("Penciller(s):"), new YACReaderFieldPlainTextEdit());
|
||||
QHBoxLayout * h2 = new QHBoxLayout;
|
||||
QVBoxLayout * vl2 = new QVBoxLayout;
|
||||
QVBoxLayout * vr2 = new QVBoxLayout;
|
||||
vl2->addWidget(new QLabel(tr("Inker(s):")));
|
||||
vl2->addWidget(inker = new YACReaderFieldPlainTextEdit());
|
||||
h2->addLayout(vl2);
|
||||
vr2->addWidget(new QLabel(tr("Colorist(s):")));
|
||||
vr2->addWidget(colorist = new YACReaderFieldPlainTextEdit());
|
||||
h2->addLayout(vr2);
|
||||
|
||||
//authorsLayout->addRow(tr("Inker(s):"), new YACReaderFieldPlainTextEdit());
|
||||
//authorsLayout->addRow(tr("Colorist(s):"), new YACReaderFieldPlainTextEdit());
|
||||
|
||||
QHBoxLayout * h3 = new QHBoxLayout;
|
||||
QVBoxLayout * vl3 = new QVBoxLayout;
|
||||
QVBoxLayout * vr3 = new QVBoxLayout;
|
||||
vl3->addWidget(new QLabel(tr("Letterer(s):")));
|
||||
vl3->addWidget(letterer = new YACReaderFieldPlainTextEdit());
|
||||
h3->addLayout(vl3);
|
||||
vr3->addWidget(new QLabel(tr("Cover Artist(s):")));
|
||||
vr3->addWidget(coverArtist = new YACReaderFieldPlainTextEdit());
|
||||
h3->addLayout(vr3);
|
||||
//authorsLayout->addRow(tr("Letterer(es):"), new YACReaderFieldPlainTextEdit());
|
||||
//authorsLayout->addRow(tr("Cover Artist(s):"), new YACReaderFieldPlainTextEdit());
|
||||
|
||||
authorsLayout->addLayout(h1);
|
||||
authorsLayout->addLayout(h2);
|
||||
authorsLayout->addLayout(h3);
|
||||
authorsLayout->addStretch(1);
|
||||
authorsBox->setLayout(authorsLayout);
|
||||
|
||||
}
|
||||
|
||||
void PropertiesDialog::createPublishingBox()
|
||||
{
|
||||
publishingBox = new QWidget;
|
||||
|
||||
QFormLayout *publishingLayout = new QFormLayout;
|
||||
|
||||
QHBoxLayout * date = new QHBoxLayout;
|
||||
date->addWidget(new QLabel(tr("Day:")));
|
||||
date->addWidget(dayEdit = new YACReaderFieldEdit());
|
||||
dayValidator.setRange(1,31);
|
||||
dayEdit->setValidator(&dayValidator);
|
||||
date->addWidget(new QLabel(tr("Month:")));
|
||||
date->addWidget(monthEdit = new YACReaderFieldEdit());
|
||||
monthValidator.setRange(1,12);
|
||||
monthEdit->setValidator(&monthValidator);
|
||||
date->addWidget(new QLabel(tr("Year:")));
|
||||
date->addWidget(yearEdit = new YACReaderFieldEdit());
|
||||
yearValidator.setRange(1,9999);
|
||||
yearEdit->setValidator(&yearValidator);
|
||||
date->addStretch(1);
|
||||
|
||||
publishingLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
|
||||
publishingLayout->addRow(date);
|
||||
publishingLayout->addRow(tr("Publisher:"), publisherEdit = new YACReaderFieldEdit());
|
||||
publishingLayout->addRow(tr("Format:"), formatEdit = new YACReaderFieldEdit());
|
||||
publishingLayout->addRow(tr("Color/BW:"), colorCheck = new QCheckBox());
|
||||
publishingLayout->addRow(tr("Age rating:"), ageRatingEdit = new YACReaderFieldEdit());
|
||||
|
||||
publishingBox->setLayout(publishingLayout);
|
||||
}
|
||||
|
||||
void PropertiesDialog::createPlotBox()
|
||||
{
|
||||
plotBox = new QWidget;
|
||||
|
||||
QFormLayout *plotLayout = new QFormLayout;
|
||||
|
||||
plotLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
|
||||
plotLayout->addRow(tr("Synopsis:"), synopsis = new YACReaderFieldPlainTextEdit());
|
||||
plotLayout->addRow(tr("Characters:"), characters = new YACReaderFieldPlainTextEdit());
|
||||
plotLayout->addRow(tr("Notes:"), notes = new YACReaderFieldPlainTextEdit());
|
||||
|
||||
plotBox->setLayout(plotLayout);
|
||||
|
||||
}
|
||||
|
||||
void PropertiesDialog::createButtonBox()
|
||||
{
|
||||
buttonBox = new QDialogButtonBox;
|
||||
|
||||
closeButton = buttonBox->addButton(QDialogButtonBox::Close);
|
||||
saveButton = buttonBox->addButton(QDialogButtonBox::Save);
|
||||
//rotateWidgetsButton = buttonBox->addButton(tr("Rotate &Widgets"),QDialogButtonBox::ActionRole);
|
||||
|
||||
//connect(rotateWidgetsButton, SIGNAL(clicked()), this, SLOT(rotateWidgets()));
|
||||
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(saveButton, SIGNAL(clicked()), this, SLOT(save()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PropertiesDialog::setComics(QList<ComicDB> comics)
|
||||
{
|
||||
this->comics = comics;
|
||||
|
||||
ComicDB comic = comics.at(0);
|
||||
|
||||
if(comic.info.title != NULL)
|
||||
title->setText(*comic.info.title);
|
||||
|
||||
if(comic.info.coverPage != NULL)
|
||||
{
|
||||
coverPageEdit->setText(QString::number(*comic.info.coverPage));
|
||||
coverPageValidator.setRange(1,*comic.info.numPages);
|
||||
coverPageEdit->setValidator(&coverPageValidator);
|
||||
}
|
||||
/*if(comic.info.numPages != NULL)
|
||||
numPagesEdit->setText(QString::number(*comic.info.numPages));*/
|
||||
|
||||
|
||||
if(comic.info.number != NULL)
|
||||
numberEdit->setText(QString::number(*comic.info.number));
|
||||
if(comic.info.isBis != NULL)
|
||||
isBisCheck->setChecked(*comic.info.isBis);
|
||||
if(comic.info.count != NULL)
|
||||
countEdit->setText(QString::number(*comic.info.count));
|
||||
|
||||
if(comic.info.volume != NULL)
|
||||
volumeEdit->setText(*comic.info.volume);
|
||||
if(comic.info.storyArc != NULL)
|
||||
storyArcEdit->setText(*comic.info.storyArc);
|
||||
if(comic.info.arcNumber != NULL)
|
||||
arcNumberEdit->setText(QString::number(*comic.info.arcNumber));
|
||||
if(comic.info.arcCount != NULL)
|
||||
arcCountEdit->setText(QString::number(*comic.info.arcCount));
|
||||
|
||||
if(comic.info.genere != NULL)
|
||||
genereEdit->setText(*comic.info.genere);
|
||||
|
||||
if(comic.info.writer != NULL)
|
||||
writer->setPlainText(*comic.info.writer);
|
||||
if(comic.info.penciller != NULL)
|
||||
penciller->setPlainText(*comic.info.penciller);
|
||||
if(comic.info.inker != NULL)
|
||||
inker->setPlainText(*comic.info.inker);
|
||||
if(comic.info.colorist != NULL)
|
||||
colorist->setPlainText(*comic.info.colorist);
|
||||
if(comic.info.letterer != NULL)
|
||||
letterer->setPlainText(*comic.info.letterer);
|
||||
if(comic.info.coverArtist != NULL)
|
||||
coverArtist->setPlainText(*comic.info.coverArtist);
|
||||
|
||||
size->setText(QString::number(comic.info.hash.right(comic.info.hash.length()-40).toInt()/1024.0/1024.0,'f',2)+"Mb");
|
||||
|
||||
if(comic.info.date != NULL)
|
||||
{
|
||||
QStringList date = (*comic.info.date).split("/");
|
||||
dayEdit->setText(date[0]);
|
||||
monthEdit->setText(date[1]);
|
||||
yearEdit->setText(date[2]);
|
||||
}
|
||||
if(comic.info.publisher != NULL)
|
||||
publisherEdit->setText(*comic.info.publisher);
|
||||
if(comic.info.format != NULL)
|
||||
formatEdit->setText(*comic.info.format);
|
||||
if(comic.info.color != NULL)
|
||||
colorCheck->setChecked(*comic.info.color);
|
||||
else
|
||||
colorCheck->setCheckState(Qt::PartiallyChecked);
|
||||
|
||||
if(comic.info.ageRating != NULL)
|
||||
ageRatingEdit->setText(*comic.info.ageRating);
|
||||
|
||||
if(comic.info.synopsis != NULL)
|
||||
synopsis->setPlainText(*comic.info.synopsis);
|
||||
if(comic.info.characters != NULL)
|
||||
characters->setPlainText(*comic.info.characters);
|
||||
if(comic.info.notes != NULL)
|
||||
notes->setPlainText(*comic.info.notes);
|
||||
|
||||
|
||||
if(comics.length() > 1)
|
||||
{
|
||||
setDisableUniqueValues(true);
|
||||
this->setWindowTitle(tr("Edit selected comics information"));
|
||||
setCover(QPixmap(":/images/editComic.png"));
|
||||
|
||||
QList<ComicDB>::iterator itr;
|
||||
for(itr = ++comics.begin();itr!=comics.end();itr++)
|
||||
{
|
||||
if(itr->info.title == NULL || *(itr->info.title) != title->text())
|
||||
title->clear();
|
||||
|
||||
if(itr->info.count == NULL || *(itr->info.count) != countEdit->text().toInt())
|
||||
countEdit->clear();
|
||||
|
||||
if(itr->info.volume == NULL || *(itr->info.volume) != volumeEdit->text())
|
||||
volumeEdit->clear();
|
||||
if(itr->info.storyArc == NULL || *(itr->info.storyArc) != storyArcEdit->text())
|
||||
storyArcEdit->clear();
|
||||
if(itr->info.arcCount == NULL || *(itr->info.arcCount) != storyArcEdit->text().toInt())
|
||||
arcCountEdit->clear();
|
||||
|
||||
if(itr->info.genere == NULL || *(itr->info.genere) != genereEdit->text())
|
||||
genereEdit->clear();
|
||||
|
||||
if(itr->info.writer == NULL || *(itr->info.writer) != writer->toPlainText())
|
||||
writer->clear();
|
||||
if(itr->info.penciller == NULL || *(itr->info.penciller) != penciller->toPlainText())
|
||||
penciller->clear();
|
||||
if(itr->info.inker == NULL || *(itr->info.inker) != inker->toPlainText())
|
||||
inker->clear();
|
||||
if(itr->info.colorist == NULL || *(itr->info.colorist) != colorist->toPlainText())
|
||||
colorist->clear();
|
||||
if(itr->info.letterer == NULL || *(itr->info.letterer) != letterer->toPlainText())
|
||||
letterer->clear();
|
||||
if(itr->info.coverArtist == NULL || *(itr->info.coverArtist) != coverArtist->toPlainText())
|
||||
coverArtist->clear();
|
||||
|
||||
if(itr->info.date == NULL)
|
||||
{
|
||||
dayEdit->clear();
|
||||
monthEdit->clear();
|
||||
yearEdit->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList date = itr->info.date->split("/");
|
||||
if(dayEdit->text() != date[0])
|
||||
dayEdit->clear();
|
||||
if(monthEdit->text() != date[1])
|
||||
monthEdit->clear();
|
||||
if(yearEdit->text() != date[2])
|
||||
yearEdit->clear();
|
||||
}
|
||||
|
||||
if(itr->info.publisher == NULL || *(itr->info.publisher) != publisherEdit->text())
|
||||
publisherEdit->clear();
|
||||
if(itr->info.format == NULL || *(itr->info.format) != formatEdit->text())
|
||||
formatEdit->clear();
|
||||
if(itr->info.color == NULL || *(itr->info.color) != colorCheck->isChecked())
|
||||
colorCheck->setCheckState(Qt::PartiallyChecked);
|
||||
if(itr->info.ageRating == NULL || *(itr->info.ageRating) != ageRatingEdit->text())
|
||||
ageRatingEdit->clear();
|
||||
|
||||
if(itr->info.synopsis == NULL || *(itr->info.synopsis) != synopsis->toPlainText())
|
||||
synopsis->clear();
|
||||
if(itr->info.characters == NULL || *(itr->info.characters) != characters->toPlainText())
|
||||
characters->clear();
|
||||
if(itr->info.notes == NULL || *(itr->info.notes) != notes->toPlainText())
|
||||
notes->clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setWindowTitle(tr("Edit comic information"));
|
||||
setCover(comic.info.getCover(basePath));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PropertiesDialog::updateComics()
|
||||
{
|
||||
QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath);
|
||||
db.open();
|
||||
db.transaction();
|
||||
QList<ComicDB>::iterator itr;
|
||||
for(itr = comics.begin();itr!=comics.end();itr++)
|
||||
{
|
||||
if(itr->info.edited)
|
||||
DBHelper::update(&(itr->info),db);
|
||||
}
|
||||
db.commit();
|
||||
db.close();
|
||||
QSqlDatabase::removeDatabase(databasePath);
|
||||
}
|
||||
//Deprecated
|
||||
void PropertiesDialog::setCover(const QPixmap & coverImage)
|
||||
{
|
||||
cover->setPixmap(coverImage.scaledToWidth(125,Qt::SmoothTransformation));
|
||||
//cover->repaint();
|
||||
|
||||
//float aspectRatio = (float)coverImage.width()/coverImage.height();
|
||||
//int heightDesktopResolution = QApplication::desktop()->screenGeometry().height();
|
||||
//int widthDesktopResolution = QApplication::desktop()->screenGeometry().width();
|
||||
//int sHeight,sWidth;
|
||||
//sHeight = static_cast<int>(heightDesktopResolution*0.65);
|
||||
|
||||
//if(aspectRatio<1)
|
||||
//{
|
||||
// sWidth = static_cast<int>(sHeight*1.4);
|
||||
// //this->resize(sWidth,sHeight);
|
||||
// this->move(QPoint((widthDesktopResolution-sWidth)/2,((heightDesktopResolution-sHeight)-40)/2));
|
||||
// //sa->resize(sa->width(),sa->width()*1.333);
|
||||
// /*cover->resize(static_cast<int>((sa->height())*aspectRatio),
|
||||
// (sa->height()));*/
|
||||
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// sWidth = static_cast<int>(sHeight/1.16);
|
||||
// //this->resize(sWidth,sHeight);
|
||||
// this->move(QPoint((widthDesktopResolution-sWidth)/2,((heightDesktopResolution-sHeight)-40)/2));
|
||||
// cover->resize((width()-25),
|
||||
// static_cast<int>((width()-25)/aspectRatio));
|
||||
//}
|
||||
|
||||
}
|
||||
void PropertiesDialog::setFilename(const QString & nameString)
|
||||
{
|
||||
title->setText(nameString);
|
||||
}
|
||||
void PropertiesDialog::setNumpages(int pagesNum)
|
||||
{
|
||||
numPagesEdit->setText(QString::number(pagesNum));
|
||||
}
|
||||
void PropertiesDialog::setSize(float sizeFloat)
|
||||
{
|
||||
|
||||
size->setText(QString::number(sizeFloat,'f',2) + " MB");
|
||||
}
|
||||
|
||||
void PropertiesDialog::save()
|
||||
{
|
||||
QList<ComicDB>::iterator itr;
|
||||
for(itr = comics.begin();itr!=comics.end();itr++)
|
||||
{
|
||||
//Comic & comic = comics[0];
|
||||
bool edited = false;
|
||||
|
||||
if(title->isModified())
|
||||
{
|
||||
itr->info.setTitle(title->text());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(comics.size()==1)
|
||||
if(coverPageEdit->isModified() && !coverPageEdit->text().isEmpty() && coverPageEdit->text().toInt() != 0)
|
||||
{
|
||||
itr->info.setCoverPage(coverPageEdit->text().toInt());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
/*if(comic.info.numPages != NULL)
|
||||
numPagesEdit->setText(QString::number(*comic.info.numPages));*/
|
||||
if(comics.size()==1)
|
||||
if(numberEdit->isModified() && !numberEdit->text().isEmpty())
|
||||
{
|
||||
itr->info.setNumber(numberEdit->text().toInt());
|
||||
edited = true;
|
||||
}
|
||||
if(comics.size()==1)
|
||||
if(itr->info.isBis != NULL || isBisCheck->isChecked())
|
||||
{
|
||||
itr->info.setIsBis(isBisCheck->isChecked());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(countEdit->isModified())
|
||||
{
|
||||
itr->info.setCount(countEdit->text().toInt());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(volumeEdit->isModified())
|
||||
{
|
||||
itr->info.setVolume(volumeEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
if(storyArcEdit->isModified())
|
||||
{
|
||||
itr->info.setStoryArc(storyArcEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
if(comics.size()==1)
|
||||
if(arcNumberEdit->isModified() && !arcNumberEdit->text().isEmpty())
|
||||
{
|
||||
itr->info.setArcNumber(arcNumberEdit->text().toInt());
|
||||
edited = true;
|
||||
}
|
||||
if(arcCountEdit->isModified())
|
||||
{
|
||||
itr->info.setArcCount(arcCountEdit->text().toInt());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(genereEdit->isModified())
|
||||
{
|
||||
itr->info.setGenere(genereEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(writer->document()->isModified())
|
||||
{
|
||||
itr->info.setWriter(writer->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(penciller->document()->isModified())
|
||||
{
|
||||
itr->info.setPenciller(penciller->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(inker->document()->isModified())
|
||||
{
|
||||
itr->info.setInker(inker->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(colorist->document()->isModified())
|
||||
{
|
||||
itr->info.setColorist(colorist->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(letterer->document()->isModified())
|
||||
{
|
||||
itr->info.setLetterer(letterer->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(coverArtist->document()->isModified())
|
||||
{
|
||||
itr->info.setCoverArtist(coverArtist->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(dayEdit->isModified() || monthEdit->isModified() || yearEdit->isModified() )
|
||||
{
|
||||
itr->info.setDate(dayEdit->text()+"/"+monthEdit->text()+"/"+yearEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
if(publisherEdit->isModified())
|
||||
{
|
||||
itr->info.setPublisher(publisherEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
if(formatEdit->isModified())
|
||||
{
|
||||
itr->info.setFormat(formatEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
if(colorCheck->checkState() != Qt::PartiallyChecked)
|
||||
{
|
||||
itr->info.setColor(colorCheck->isChecked());
|
||||
edited = true;
|
||||
}
|
||||
if(ageRatingEdit->isModified())
|
||||
{
|
||||
itr->info.setAgeRating(ageRatingEdit->text());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
if(synopsis->document()->isModified())
|
||||
{
|
||||
itr->info.setSynopsis(synopsis->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(characters->document()->isModified())
|
||||
{
|
||||
itr->info.setCharacters(characters->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
if(notes->document()->isModified())
|
||||
{
|
||||
itr->info.setNotes(notes->toPlainText());
|
||||
edited = true;
|
||||
}
|
||||
|
||||
itr->info.edited = edited;
|
||||
}
|
||||
updateComics();
|
||||
if(comics.count() == 1)
|
||||
{
|
||||
if(coverPageEdit->isModified())// && 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);
|
||||
tc.create();
|
||||
}
|
||||
}
|
||||
close();
|
||||
emit(accepted());
|
||||
}
|
||||
|
||||
void PropertiesDialog::setDisableUniqueValues(bool disabled)
|
||||
{
|
||||
coverPageEdit->setDisabled(disabled);
|
||||
coverPageEdit->clear();
|
||||
numberEdit->setDisabled(disabled);
|
||||
numberEdit->clear();
|
||||
isBisCheck->setDisabled(disabled);
|
||||
isBisCheck->setChecked(false);
|
||||
arcNumberEdit->setDisabled(disabled);
|
||||
arcNumberEdit->clear();
|
||||
}
|
||||
|
||||
void PropertiesDialog::closeEvent ( QCloseEvent * e )
|
||||
{
|
||||
|
||||
title->clear();
|
||||
title->setModified(false);
|
||||
coverPageEdit->clear();
|
||||
// numPagesEdit->setText(QString::number(*comic.info.numPages));
|
||||
numberEdit->clear();
|
||||
isBisCheck->setChecked(false);
|
||||
countEdit->clear();
|
||||
volumeEdit->clear();
|
||||
storyArcEdit->clear();
|
||||
arcNumberEdit->clear();
|
||||
arcCountEdit->clear();
|
||||
genereEdit->clear();
|
||||
writer->clear();
|
||||
penciller->clear();
|
||||
inker->clear();
|
||||
colorist->clear();
|
||||
letterer->clear();
|
||||
coverArtist->clear();
|
||||
dayEdit->clear();
|
||||
monthEdit->clear();
|
||||
yearEdit->clear();
|
||||
publisherEdit->clear();
|
||||
formatEdit->clear();
|
||||
colorCheck->setCheckState(Qt::PartiallyChecked);
|
||||
ageRatingEdit->clear();
|
||||
synopsis->clear();
|
||||
characters->clear();
|
||||
notes->clear();
|
||||
|
||||
setDisableUniqueValues(false);
|
||||
|
||||
tabBar->setCurrentIndex(0);
|
||||
|
||||
coverPageEdit->setFocus();
|
||||
|
||||
QDialog::closeEvent(e);
|
||||
}
|
||||
118
YACReaderLibrary/properties_dialog.h
Normal file
118
YACReaderLibrary/properties_dialog.h
Normal file
@ -0,0 +1,118 @@
|
||||
#ifndef __PROPERTIES_DIALOG_H
|
||||
#define __PROPERTIES_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <QIntValidator>
|
||||
|
||||
class QGridLayout;
|
||||
class QTabWidget;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QScrollArea;
|
||||
class QWidget;
|
||||
class YACReaderFieldEdit;
|
||||
class YACReaderFieldPlainTextEdit;
|
||||
class QDialogButtonBox;
|
||||
class QCheckBox;
|
||||
#include "comic_db.h"
|
||||
|
||||
class PropertiesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QGridLayout * mainLayout;
|
||||
|
||||
QTabWidget * tabBar;
|
||||
|
||||
QGroupBox * coverBox;
|
||||
QLabel * cover;
|
||||
QScrollArea * sa;
|
||||
|
||||
QWidget * generalInfoBox;
|
||||
YACReaderFieldEdit * title;
|
||||
YACReaderFieldEdit * numPagesEdit;
|
||||
QLabel * size;
|
||||
|
||||
YACReaderFieldEdit * coverPageEdit;
|
||||
QIntValidator coverPageValidator;
|
||||
|
||||
YACReaderFieldEdit * numberEdit;
|
||||
QIntValidator numberValidator;
|
||||
QCheckBox * isBisCheck;
|
||||
YACReaderFieldEdit * countEdit;
|
||||
QIntValidator countValidator;
|
||||
|
||||
YACReaderFieldEdit * volumeEdit;
|
||||
YACReaderFieldEdit * storyArcEdit;
|
||||
YACReaderFieldEdit * arcNumberEdit;
|
||||
QIntValidator arcNumberValidator;
|
||||
YACReaderFieldEdit * arcCountEdit;
|
||||
QIntValidator arcCountValidator;
|
||||
|
||||
YACReaderFieldEdit * genereEdit;
|
||||
|
||||
YACReaderFieldPlainTextEdit * writer;
|
||||
YACReaderFieldPlainTextEdit * penciller;
|
||||
YACReaderFieldPlainTextEdit * inker;
|
||||
YACReaderFieldPlainTextEdit * colorist;
|
||||
YACReaderFieldPlainTextEdit * letterer;
|
||||
YACReaderFieldPlainTextEdit * coverArtist;
|
||||
|
||||
YACReaderFieldEdit * dayEdit;
|
||||
QIntValidator dayValidator;
|
||||
YACReaderFieldEdit * monthEdit;
|
||||
QIntValidator monthValidator;
|
||||
YACReaderFieldEdit * yearEdit;
|
||||
QIntValidator yearValidator;
|
||||
YACReaderFieldEdit * publisherEdit;
|
||||
YACReaderFieldEdit * formatEdit;
|
||||
QCheckBox * colorCheck;
|
||||
YACReaderFieldEdit * ageRatingEdit;
|
||||
|
||||
YACReaderFieldPlainTextEdit * synopsis;
|
||||
YACReaderFieldPlainTextEdit * characters;
|
||||
YACReaderFieldPlainTextEdit * notes;
|
||||
|
||||
QWidget * authorsBox;
|
||||
|
||||
QWidget * publishingBox;
|
||||
|
||||
QWidget * plotBox;
|
||||
|
||||
QDialogButtonBox *buttonBox;
|
||||
QPushButton *closeButton;
|
||||
QPushButton *saveButton;
|
||||
QPushButton *restoreButton; //??
|
||||
|
||||
void createTabBar();
|
||||
void createCoverBox();
|
||||
void createGeneralInfoBox();
|
||||
void createAuthorsBox();
|
||||
void createPublishingBox();
|
||||
void createPlotBox();
|
||||
|
||||
void createButtonBox();
|
||||
|
||||
void setDisableUniqueValues(bool disabled);
|
||||
|
||||
QList<ComicDB> comics;
|
||||
void closeEvent ( QCloseEvent * e );
|
||||
public:
|
||||
PropertiesDialog(QWidget * parent = 0);
|
||||
QString databasePath;
|
||||
QString basePath;
|
||||
|
||||
public slots:
|
||||
void setComics(QList<ComicDB> comics);
|
||||
void updateComics();
|
||||
void save();
|
||||
//Deprecated
|
||||
void setCover(const QPixmap & cover);
|
||||
void setFilename(const QString & name);
|
||||
void setNumpages(int pages);
|
||||
void setSize(float size);
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
77
YACReaderLibrary/rename_library_dialog.cpp
Normal file
77
YACReaderLibrary/rename_library_dialog.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "rename_library_dialog.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
|
||||
|
||||
|
||||
RenameLibraryDialog::RenameLibraryDialog(QWidget * parent)
|
||||
:QDialog(parent)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void RenameLibraryDialog::setupUI()
|
||||
{
|
||||
newNameLabel = new QLabel(tr("New Library Name : "));
|
||||
newNameEdit = new QLineEdit;
|
||||
newNameLabel->setBuddy(newNameEdit);
|
||||
connect(newNameEdit,SIGNAL(textChanged(QString)),this,SLOT(nameSetted(QString)));
|
||||
|
||||
accept = new QPushButton(tr("Rename"));
|
||||
accept->setDisabled(true);
|
||||
connect(accept,SIGNAL(clicked()),this,SLOT(rename()));
|
||||
|
||||
cancel = new QPushButton(tr("Cancel"));
|
||||
connect(cancel,SIGNAL(clicked()),this,SLOT(close()));
|
||||
|
||||
QHBoxLayout *nameLayout = new QHBoxLayout;
|
||||
|
||||
nameLayout->addWidget(newNameLabel);
|
||||
nameLayout->addWidget(newNameEdit);
|
||||
|
||||
QHBoxLayout *bottomLayout = new QHBoxLayout;
|
||||
bottomLayout->addStretch();
|
||||
bottomLayout->addWidget(accept);
|
||||
bottomLayout->addWidget(cancel);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(nameLayout);
|
||||
mainLayout->addStretch();
|
||||
mainLayout->addLayout(bottomLayout);
|
||||
|
||||
QHBoxLayout * imgMainLayout = new QHBoxLayout;
|
||||
QLabel * imgLabel = new QLabel(this);
|
||||
QPixmap p(":/images/edit.png");
|
||||
imgLabel->setPixmap(p);
|
||||
imgMainLayout->addWidget(imgLabel);
|
||||
imgMainLayout->addLayout(mainLayout);
|
||||
|
||||
setLayout(imgMainLayout);
|
||||
|
||||
setModal(true);
|
||||
setWindowTitle(tr("Rename current library"));
|
||||
}
|
||||
|
||||
void RenameLibraryDialog::rename()
|
||||
{
|
||||
//accept->setEnabled(false);
|
||||
emit(renameLibrary(newNameEdit->text()));
|
||||
close();
|
||||
}
|
||||
|
||||
void RenameLibraryDialog::nameSetted(const QString & text)
|
||||
{
|
||||
if(!text.isEmpty())
|
||||
accept->setEnabled(true);
|
||||
else
|
||||
accept->setEnabled(false);
|
||||
}
|
||||
|
||||
void RenameLibraryDialog::close()
|
||||
{
|
||||
newNameEdit->clear();
|
||||
//accept->setEnabled(false);
|
||||
QDialog::close();
|
||||
}
|
||||
31
YACReaderLibrary/rename_library_dialog.h
Normal file
31
YACReaderLibrary/rename_library_dialog.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __RENAME_LIBRARY_DIALOG_H
|
||||
#define __RENAME_LIBRARY_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
class RenameLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RenameLibraryDialog(QWidget * parent = 0);
|
||||
private:
|
||||
QLabel * newNameLabel;
|
||||
QLineEdit * newNameEdit;
|
||||
QPushButton * accept;
|
||||
QPushButton * cancel;
|
||||
void setupUI();
|
||||
public slots:
|
||||
void rename();
|
||||
void close();
|
||||
void nameSetted(const QString & name);
|
||||
signals:
|
||||
void renameLibrary(QString newName);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
84
YACReaderLibrary/server/controllers/comiccontroller.cpp
Normal file
84
YACReaderLibrary/server/controllers/comiccontroller.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "comiccontroller.h"
|
||||
|
||||
#include "db_helper.h"
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
#include "comic_db.h"
|
||||
#include "comic.h"
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
ComicController::ComicController() {}
|
||||
|
||||
void ComicController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||||
|
||||
QString path = QUrl::fromPercentEncoding(request.getPath()).toLatin1();
|
||||
QStringList pathElements = path.split('/');
|
||||
QString libraryName = pathElements.at(2);
|
||||
qulonglong comicId = pathElements.at(4).toULongLong();
|
||||
|
||||
//TODO
|
||||
//if(pathElements.size() == 6)
|
||||
//{
|
||||
// QString action = pathElements.at(5);
|
||||
// if(!action.isEmpty() && (action == "close"))
|
||||
// {
|
||||
// session.dismissCurrentComic();
|
||||
// response.write("",true);
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
|
||||
//Aplicar a todos los controladores
|
||||
//TODO usar LibraryWindow para acceder a informaci<63>n de las bases de datos est<73> mal, hay
|
||||
//que crear una clase que se encargue de estas cosas
|
||||
//<2F>Se est<73> accediendo a la UI desde un hilo?
|
||||
|
||||
QMap<QString,QString> libraries = DBHelper::getLibraries();
|
||||
|
||||
|
||||
ComicDB comic = DBHelper::getComicInfo(libraryName, comicId);
|
||||
|
||||
session.setDownloadedComic(comic.info.hash);
|
||||
|
||||
Comic * comicFile = FactoryComic::newComic(libraries.value(libraryName)+comic.path);
|
||||
|
||||
if(comicFile != NULL)
|
||||
{
|
||||
QThread * thread = NULL;
|
||||
if (typeid(*comicFile) != typeid(FileComic))
|
||||
{
|
||||
thread = new QThread();
|
||||
|
||||
comicFile->moveToThread(thread);
|
||||
|
||||
connect(thread, SIGNAL(started()), comicFile, SLOT(process()));
|
||||
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||
|
||||
}
|
||||
|
||||
comicFile->load(libraries.value(libraryName)+comic.path);
|
||||
|
||||
if(thread != NULL)
|
||||
thread->start();
|
||||
|
||||
session.setCurrentComic(comic.id, comicFile);
|
||||
|
||||
response.setHeader("Content-Type", "plain/text; charset=ISO-8859-1");
|
||||
|
||||
response.writeText(QString("library:%1\r\n").arg(libraryName));
|
||||
response.writeText(comic.toTXT(),true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//delete comicFile;
|
||||
response.setStatus(404,"not found");
|
||||
response.write("404 not found",true);
|
||||
}
|
||||
//response.write(t.toLatin1(),true);
|
||||
|
||||
}
|
||||
23
YACReaderLibrary/server/controllers/comiccontroller.h
Normal file
23
YACReaderLibrary/server/controllers/comiccontroller.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef COMICCONTROLLER_H
|
||||
#define COMICCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
#include <QThread>
|
||||
class Comic;
|
||||
class QString;
|
||||
|
||||
class ComicController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ComicController);
|
||||
public:
|
||||
/** Constructor */
|
||||
ComicController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // COMICCONTROLLER_H
|
||||
63
YACReaderLibrary/server/controllers/covercontroller.cpp
Normal file
63
YACReaderLibrary/server/controllers/covercontroller.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "covercontroller.h"
|
||||
#include "db_helper.h" //get libraries
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
CoverController::CoverController() {}
|
||||
|
||||
void CoverController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
|
||||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||||
|
||||
response.setHeader("Content-Type", "image/jpeg");
|
||||
response.setHeader("Connection","close");
|
||||
//response.setHeader("Content-Type", "plain/text; charset=ISO-8859-1");
|
||||
|
||||
QMap<QString,QString> libraries = DBHelper::getLibraries();
|
||||
|
||||
QString path = QUrl::fromPercentEncoding(request.getPath()).toLatin1();
|
||||
QStringList pathElements = path.split('/');
|
||||
QString libraryName = pathElements.at(2);
|
||||
QString fileName = pathElements.at(4);
|
||||
|
||||
//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.value(libraryName)+"/.yacreaderlibrary/covers/"+fileName);
|
||||
if (!img.isNull()) {
|
||||
|
||||
int width = 80;
|
||||
if(session.getDisplayType()=="retina")
|
||||
width = 160;
|
||||
img = img.scaledToWidth(width,Qt::SmoothTransformation);
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
img.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);
|
||||
}
|
||||
}
|
||||
|
||||
20
YACReaderLibrary/server/controllers/covercontroller.h
Normal file
20
YACReaderLibrary/server/controllers/covercontroller.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef COVERCONTROLLER_H
|
||||
#define COVERCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
class CoverController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(CoverController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
CoverController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // COVERCONTROLLER_H
|
||||
62
YACReaderLibrary/server/controllers/dumpcontroller.cpp
Normal file
62
YACReaderLibrary/server/controllers/dumpcontroller.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
@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);
|
||||
}
|
||||
29
YACReaderLibrary/server/controllers/dumpcontroller.h
Normal file
29
YACReaderLibrary/server/controllers/dumpcontroller.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
@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
|
||||
25
YACReaderLibrary/server/controllers/errorcontroller.cpp
Normal file
25
YACReaderLibrary/server/controllers/errorcontroller.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "errorcontroller.h"
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
|
||||
ErrorController::ErrorController(int errorCode)
|
||||
:error(errorCode)
|
||||
{}
|
||||
|
||||
void ErrorController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
22
YACReaderLibrary/server/controllers/errorcontroller.h
Normal file
22
YACReaderLibrary/server/controllers/errorcontroller.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef ERRORCONTROLLER_H
|
||||
#define ERRORCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
class ErrorController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ErrorController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ErrorController(int errorCode);
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
private:
|
||||
int error;
|
||||
};
|
||||
|
||||
#endif // ERRORCONTROLLER_H
|
||||
38
YACReaderLibrary/server/controllers/fileuploadcontroller.cpp
Normal file
38
YACReaderLibrary/server/controllers/fileuploadcontroller.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
30
YACReaderLibrary/server/controllers/fileuploadcontroller.h
Normal file
30
YACReaderLibrary/server/controllers/fileuploadcontroller.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
@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
|
||||
312
YACReaderLibrary/server/controllers/foldercontroller.cpp
Normal file
312
YACReaderLibrary/server/controllers/foldercontroller.cpp
Normal file
@ -0,0 +1,312 @@
|
||||
#include "foldercontroller.h"
|
||||
#include "db_helper.h" //get libraries
|
||||
#include "comic_db.h"
|
||||
|
||||
#include "folder.h"
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
#include "qnaturalsorting.h"
|
||||
|
||||
struct LibraryItemSorter
|
||||
{
|
||||
bool operator()(const LibraryItem * a,const LibraryItem * b) const
|
||||
{
|
||||
return naturalSortLessThanCI(a->name,b->name);
|
||||
}
|
||||
};
|
||||
|
||||
FolderController::FolderController() {}
|
||||
|
||||
void FolderController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||||
|
||||
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
|
||||
response.setHeader("Connection","close");
|
||||
|
||||
//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"));
|
||||
t.enableWarnings();
|
||||
QString path = QUrl::fromPercentEncoding(request.getPath()).toLatin1();
|
||||
QStringList pathElements = path.split('/');
|
||||
QString libraryName = pathElements.at(2);
|
||||
qulonglong parentId = pathElements.at(4).toULongLong();
|
||||
QString folderName = DBHelper::getFolderName(libraryName,parentId);
|
||||
if(parentId!=1)
|
||||
t.setVariable("folder.name",folderName);
|
||||
else
|
||||
t.setVariable("folder.name",libraryName);
|
||||
QList<LibraryItem *> folderContent = DBHelper::getFolderContentFromLibrary(libraryName,parentId);
|
||||
QList<LibraryItem *> folderComics = DBHelper::getFolderComicsFromLibrary(libraryName,parentId);
|
||||
|
||||
//response.writeText(libraryName);
|
||||
|
||||
folderContent.append(folderComics);
|
||||
|
||||
qSort(folderContent.begin(),folderContent.end(),LibraryItemSorter());
|
||||
folderComics.clear();
|
||||
|
||||
qulonglong backId = DBHelper::getParentFromComicFolderId(libraryName,parentId);
|
||||
|
||||
int page = 0;
|
||||
QByteArray p = request.getParameter("page");
|
||||
if(p.length() != 0)
|
||||
page = p.toInt();
|
||||
|
||||
// /comicIdi/pagei/comicIdj/pagej/....../comicIdn/pagen
|
||||
//QString currentPath = session.get("currentPath").toString();
|
||||
//QStringList pathSize = currentPath.split("/").last().toInt;
|
||||
|
||||
bool fromUp = false;
|
||||
|
||||
QMultiMap<QByteArray,QByteArray> map = request.getParameterMap();
|
||||
if(map.contains("up"))
|
||||
fromUp = true;
|
||||
|
||||
int upPage = 0;
|
||||
|
||||
|
||||
|
||||
if(backId == 1 && parentId == 1)
|
||||
{
|
||||
session.popPage();
|
||||
session.pushPage(page);
|
||||
t.setVariable(QString("upurl"),"/?page=0");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fromUp)
|
||||
{
|
||||
session.popPage();
|
||||
upPage = session.topPage();
|
||||
page = upPage;
|
||||
}
|
||||
else //este nivel puede haberse cargado por primera vez <20> puede que estemos navegando horizontalmente
|
||||
if(p.length() == 0) // acabamos de entrar
|
||||
{
|
||||
upPage = session.topPage();
|
||||
session.pushPage(page);
|
||||
}
|
||||
else //navegaci<63>n horizontal
|
||||
{
|
||||
session.popPage();
|
||||
upPage = session.topPage();
|
||||
session.pushPage(page);
|
||||
}
|
||||
t.setVariable(QString("upurl"),"/library/" + QUrl::toPercentEncoding(libraryName) + "/folder/" +QString("%1?page=%2&up=true").arg(backId).arg(upPage));
|
||||
}
|
||||
|
||||
/*if(currentPath.length()>0)
|
||||
{
|
||||
if(currentPath.contains(QString("%1").arg(parentId))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
session.set("currentPath",currentPath+QString("/%1/%2").arg(parentId).arg(page);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//t.loop("element",folderContent.length());
|
||||
|
||||
int elementsPerPage = 18;
|
||||
|
||||
int numFolders = folderContent.length();
|
||||
int numComics = folderComics.length();
|
||||
int totalLength = folderContent.length() + folderComics.length();
|
||||
|
||||
int numFolderPages = numFolders / elementsPerPage + ((numFolders%elementsPerPage)>0?1:0);
|
||||
int numPages = totalLength / elementsPerPage + ((totalLength%elementsPerPage)>0?1:0);
|
||||
|
||||
//response.writeText(QString("Number of pages : %1 <br/>").arg(numPages));
|
||||
|
||||
if(page < 0)
|
||||
page = 0;
|
||||
else if(page >= numPages)
|
||||
page = numPages-1;
|
||||
|
||||
int indexCurrentPage = page*elementsPerPage;
|
||||
int numFoldersAtCurrentPage = qMax(0,qMin(numFolders - indexCurrentPage, elementsPerPage));
|
||||
|
||||
//response.writeText(QString("indexCurrentPage : %1 <br/>").arg(indexCurrentPage));
|
||||
//response.writeText(QString("numFoldersAtCurrentPage : %1 <br/>").arg(numFoldersAtCurrentPage));
|
||||
//response.writeText(QString("foldersLength : %1 <br/>").arg(folderContent.length()));
|
||||
|
||||
t.loop("element",numFoldersAtCurrentPage);
|
||||
int i = 0;
|
||||
while(i<numFoldersAtCurrentPage)
|
||||
{
|
||||
LibraryItem * item = folderContent.at(i + (page*elementsPerPage));
|
||||
t.setVariable(QString("element%1.name").arg(i),folderContent.at(i + (page*elementsPerPage))->name);
|
||||
if(item->isDir())
|
||||
{
|
||||
t.setVariable(QString("element%1.class").arg(i),"folder");
|
||||
t.setVariable(QString("element%1.image.width").arg(i),"89px");
|
||||
t.setVariable(QString("element%1.image.url").arg(i),"/images/f.png");
|
||||
|
||||
t.setVariable(QString("element%1.browse").arg(i),QString("<a class =\"browseButton\" href=\"%1\">browse</a>").arg(QString("/library/%1/folder/%2").arg(libraryName).arg(item->id)));
|
||||
|
||||
//t.setVariable(QString("element%1.url").arg(i),"/library/"+libraryName+"/folder/"+QString("%1").arg(folderContent.at(i + (page*10))->id));
|
||||
//t.setVariable(QString("element%1.downloadurl").arg(i),"/library/"+libraryName+"/folder/"+QString("%1/info").arg(folderContent.at(i + (page*elementsPerPage))->id));
|
||||
|
||||
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/"+QUrl::toPercentEncoding(libraryName)+"/folder/"+QString("%1/info").arg(folderContent.at(i + (page*elementsPerPage))->id)));
|
||||
}
|
||||
else
|
||||
{
|
||||
t.setVariable(QString("element%1.class").arg(i),"cover");
|
||||
const ComicDB * comic = (ComicDB *)item;
|
||||
t.setVariable(QString("element%1.browse").arg(i),"");
|
||||
t.setVariable(QString("element%1.image.width").arg(i),"80px");
|
||||
//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))
|
||||
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/"+QUrl::toPercentEncoding(libraryName)+"/comic/"+QString("%1").arg(comic->id)));
|
||||
else if (!session.isComicDownloaded(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>"));
|
||||
|
||||
//t.setVariable(QString("element%1.image.url").arg(i),"/images/f.png");
|
||||
|
||||
t.setVariable(QString("element%1.image.url").arg(i),QString("/library/%1/cover/%2.jpg").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(comic->info.hash));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
//int comicsOffset;// = qMax(0,((page - (numFolderPages - 1)) * 10) - (numFolders%10));
|
||||
|
||||
//int comicPage = numFolderPages!=0?page-(numFolderPages - 1):page;
|
||||
|
||||
//if(comicPage > 0)
|
||||
//{
|
||||
// comicsOffset = elementsPerPage - (numFolders%elementsPerPage);
|
||||
// comicsOffset += (comicPage-1) *elementsPerPage;
|
||||
//}
|
||||
//else
|
||||
// comicsOffset = 0;
|
||||
|
||||
//
|
||||
|
||||
//int globalComicsOffset = elementsPerPage - (numFolders%elementsPerPage);
|
||||
//int numComicsAtCurrentPage = 0;
|
||||
|
||||
//if(comicPage == 0) //primera p<>gina de los c<>mics
|
||||
// numComicsAtCurrentPage = qMin(globalComicsOffset,numComics);
|
||||
// else if (page == (numPages-1)) //<2F>ltima p<>gina de los c<>mics
|
||||
// numComicsAtCurrentPage = elementsPerPage-globalComicsOffset + (numComics%elementsPerPage);
|
||||
// else
|
||||
// numComicsAtCurrentPage = elementsPerPage - numFoldersAtCurrentPage;
|
||||
|
||||
//if(numComics == 0)
|
||||
// numComicsAtCurrentPage = 0;
|
||||
////response.writeText(QString("numComicsAtCurrentPage : %1 <br/>").arg(numComicsAtCurrentPage));
|
||||
////response.writeText(QString("comicsOffset : %1 <br/>").arg(comicsOffset));
|
||||
|
||||
//t.loop("elementcomic",numComicsAtCurrentPage);
|
||||
////
|
||||
//int j = 0;
|
||||
|
||||
//while(j<numComicsAtCurrentPage)
|
||||
//{
|
||||
// const ComicDB * comic = (ComicDB *)folderComics.at(j+comicsOffset);
|
||||
// //if(comic->info.title == 0 || comic->info.title->isEmpty())
|
||||
// t.setVariable(QString("elementcomic%1.name").arg(j),comic->name);
|
||||
// //else
|
||||
// // t.setVariable(QString("elementcomic%1.name").arg(i),*comic->info.title);
|
||||
// t.setVariable(QString("elementcomic%1.url").arg(j),"/library/"+QUrl::toPercentEncoding(libraryName)+"/comic/"+QString("%1").arg(comic->id));
|
||||
// t.setVariable(QString("elementcomic%1.coverulr").arg(j),"/library/"+QUrl::toPercentEncoding(libraryName)+"/cover/"+QString("%1").arg(comic->info.hash + ".jpg"));
|
||||
// j++;
|
||||
//}
|
||||
|
||||
if(numPages > 1)
|
||||
{
|
||||
t.setCondition("pageIndex",true);
|
||||
|
||||
QMap<QString,int> indexCount;
|
||||
|
||||
QString firstChar;
|
||||
int xyz = 1;
|
||||
for(QList<LibraryItem *>::const_iterator itr=folderContent.constBegin();itr!=folderContent.constEnd();itr++)
|
||||
{
|
||||
firstChar = QString((*itr)->name[0]).toUpper();
|
||||
firstChar = firstChar.normalized(QString::NormalizationForm_D).at(0);//TODO _D or _KD??
|
||||
bool ok;
|
||||
int dec = firstChar.toInt(&ok, 10);
|
||||
if(ok)
|
||||
firstChar = "#";
|
||||
//response.writeText(QString("%1 - %2 <br />").arg((*itr)->name).arg(xyz));
|
||||
if(indexCount.contains(firstChar))
|
||||
indexCount.insert(firstChar, indexCount.value(firstChar)+1);
|
||||
else
|
||||
indexCount.insert(firstChar, 1);
|
||||
|
||||
xyz++;
|
||||
}
|
||||
|
||||
QList<QString> index = indexCount.keys();
|
||||
if(index.length()>1)
|
||||
{
|
||||
t.setCondition("alphaIndex",true);
|
||||
|
||||
qSort(index.begin(),index.end(),naturalSortLessThanCI);
|
||||
t.loop("index",index.length());
|
||||
int i=0;
|
||||
int count=0;
|
||||
int indexPage=0;
|
||||
for(QList<QString>::const_iterator itr=index.constBegin();itr!=index.constEnd();itr++)
|
||||
{
|
||||
//response.writeText(QString("%1 - %2 <br />").arg(*itr).arg(count));
|
||||
t.setVariable(QString("index%1.indexname").arg(i), *itr);
|
||||
t.setVariable(QString("index%1.url").arg(i),QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg(indexPage));
|
||||
i++;
|
||||
count += indexCount.value(*itr);
|
||||
indexPage = count/elementsPerPage;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t.loop("index",0);
|
||||
t.setCondition("alphaIndex",false);
|
||||
|
||||
}
|
||||
|
||||
t.loop("page",numPages);
|
||||
int z = 0;
|
||||
while(z < numPages)
|
||||
{
|
||||
|
||||
t.setVariable(QString("page%1.url").arg(z),QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg(z));
|
||||
t.setVariable(QString("page%1.number").arg(z),QString("%1").arg(z));
|
||||
if(page == z)
|
||||
t.setVariable(QString("page%1.current").arg(z),"current");
|
||||
else
|
||||
t.setVariable(QString("page%1.current").arg(z),"");
|
||||
z++;
|
||||
}
|
||||
|
||||
t.setVariable("page.first",QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg(0));
|
||||
t.setVariable("page.previous",QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg((page==0)?page:page-1));
|
||||
t.setVariable("page.next",QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg((page==numPages-1)?page:page+1));
|
||||
t.setVariable("page.last",QString("/library/%1/folder/%2?page=%3").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(parentId).arg(numPages-1));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
t.loop("page",0);
|
||||
t.loop("index",0);
|
||||
t.setCondition("pageIndex",false);
|
||||
t.setCondition("alphaIndex",false);
|
||||
}
|
||||
|
||||
t.setVariable("page",QString("%1").arg(page+1));
|
||||
t.setVariable("pages",QString("%1").arg(numPages));
|
||||
|
||||
response.write(t.toLatin1(),true);
|
||||
|
||||
}
|
||||
20
YACReaderLibrary/server/controllers/foldercontroller.h
Normal file
20
YACReaderLibrary/server/controllers/foldercontroller.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef FOLDERCONTROLLER_H
|
||||
#define FOLDERCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
class FolderController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FolderController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FolderController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // FOLDERCONTROLLER_H
|
||||
38
YACReaderLibrary/server/controllers/folderinfocontroller.cpp
Normal file
38
YACReaderLibrary/server/controllers/folderinfocontroller.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "folderinfocontroller.h"
|
||||
#include "db_helper.h" //get libraries
|
||||
|
||||
#include "folder.h"
|
||||
#include "comic_db.h"
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
|
||||
FolderInfoController::FolderInfoController() {}
|
||||
|
||||
void FolderInfoController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
response.setHeader("Content-Type", "plain/text; charset=ISO-8859-1");
|
||||
|
||||
QString path = QUrl::fromPercentEncoding(request.getPath()).toLatin1();
|
||||
QStringList pathElements = path.split('/');
|
||||
QString libraryName = pathElements.at(2);
|
||||
qulonglong parentId = pathElements.at(4).toULongLong();
|
||||
QList<LibraryItem *> folderContent = DBHelper::getFolderContentFromLibrary(libraryName,parentId);
|
||||
QList<LibraryItem *> folderComics = DBHelper::getFolderComicsFromLibrary(libraryName,parentId);
|
||||
|
||||
Folder * currentFolder;
|
||||
for(QList<LibraryItem *>::const_iterator itr = folderContent.constBegin();itr!=folderContent.constEnd();itr++)
|
||||
{
|
||||
currentFolder = (Folder *)(*itr);
|
||||
response.writeText(QString("/library/%1/folder/%2/info\n").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(currentFolder->id));
|
||||
}
|
||||
|
||||
ComicDB * currentComic;
|
||||
for(QList<LibraryItem *>::const_iterator itr = folderComics.constBegin();itr!=folderComics.constEnd();itr++)
|
||||
{
|
||||
currentComic = (ComicDB *)(*itr);
|
||||
response.writeText(QString("/library/%1/comic/%2\n").arg(QString(QUrl::toPercentEncoding(libraryName))).arg(currentComic->id));
|
||||
}
|
||||
|
||||
}
|
||||
20
YACReaderLibrary/server/controllers/folderinfocontroller.h
Normal file
20
YACReaderLibrary/server/controllers/folderinfocontroller.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef FOLDERINFOCONTROLLER_H
|
||||
#define FOLDERINFOCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
class FolderInfoController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FolderInfoController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FolderInfoController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // FOLDERINFOCONTROLLER_H
|
||||
64
YACReaderLibrary/server/controllers/formcontroller.cpp
Normal file
64
YACReaderLibrary/server/controllers/formcontroller.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
@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);
|
||||
}*/
|
||||
}
|
||||
|
||||
30
YACReaderLibrary/server/controllers/formcontroller.h
Normal file
30
YACReaderLibrary/server/controllers/formcontroller.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef FORMCONTROLLER_H
|
||||
#define FORMCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
/**
|
||||
This controller displays a HTML form and dumps the submitted input.
|
||||
*/
|
||||
|
||||
|
||||
class FormController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(FormController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FormController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // FORMCONTROLLER_H
|
||||
54
YACReaderLibrary/server/controllers/librariescontroller.cpp
Normal file
54
YACReaderLibrary/server/controllers/librariescontroller.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "librariescontroller.h"
|
||||
#include "db_helper.h" //get libraries
|
||||
|
||||
#include "template.h"
|
||||
#include "../static.h"
|
||||
|
||||
LibrariesController::LibrariesController() {}
|
||||
|
||||
void LibrariesController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
HttpSession session=Static::sessionStore->getSession(request,response);
|
||||
session.set("ySession","ok");
|
||||
session.clearNavigationPath();
|
||||
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
|
||||
response.setHeader("Connection","close");
|
||||
|
||||
|
||||
QString postData = QString::fromUtf8(request.getBody());
|
||||
//response.writeText(postData);
|
||||
|
||||
QList<QString> data = postData.split("\n");
|
||||
if(data.length() > 2)
|
||||
{
|
||||
session.setDeviceType(data.at(0).split(":").at(1));
|
||||
session.setDisplayType(data.at(1).split(":").at(1));
|
||||
QList<QString> comics = data.at(2).split(":").at(1).split("\t");
|
||||
foreach(QString hash,comics)
|
||||
{
|
||||
session.setComicOnDevice(hash);
|
||||
}
|
||||
}
|
||||
else //valores por defecto, con propositos de depuraci<63>n
|
||||
{
|
||||
session.setDeviceType("ipad");
|
||||
session.setDisplayType("retina");
|
||||
}
|
||||
|
||||
Template t=Static::templateLoader->getTemplate("libraries_"+session.getDeviceType(),request.getHeader("Accept-Language"));
|
||||
t.enableWarnings();
|
||||
|
||||
QMap<QString,QString> libraries = DBHelper::getLibraries();
|
||||
QList<QString> names = libraries.keys();
|
||||
|
||||
t.loop("library",names.length());
|
||||
int i=0;
|
||||
while (i<names.length()) {
|
||||
t.setVariable(QString("library%1.name").arg(i),QUrl::toPercentEncoding(names.at(i)));
|
||||
t.setVariable(QString("library%1.label").arg(i),names.at(i));
|
||||
i++;
|
||||
}
|
||||
|
||||
response.write(t.toLatin1(),true);
|
||||
|
||||
}
|
||||
25
YACReaderLibrary/server/controllers/librariescontroller.h
Normal file
25
YACReaderLibrary/server/controllers/librariescontroller.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef LIBRARIESCONTROLLER_H
|
||||
#define LIBRARIESCONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
/**
|
||||
This controller displays a HTML form and dumps the submitted input.
|
||||
*/
|
||||
|
||||
|
||||
class LibrariesController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(LibrariesController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
LibrariesController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // LIBRARIESCONTROLLER_H
|
||||
74
YACReaderLibrary/server/controllers/pagecontroller.cpp
Normal file
74
YACReaderLibrary/server/controllers/pagecontroller.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "pagecontroller.h"
|
||||
|
||||
#include "../static.h"
|
||||
|
||||
#include "comic.h"
|
||||
#include "comiccontroller.h"
|
||||
#include <QDataStream>
|
||||
#include <QPointer>
|
||||
|
||||
PageController::PageController() {}
|
||||
|
||||
void PageController::service(HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||||
|
||||
QString path = QUrl::fromPercentEncoding(request.getPath()).toLatin1();
|
||||
|
||||
//QByteArray path2=request.getPath();
|
||||
//qDebug("PageController: request to -> %s ",path2.data());
|
||||
|
||||
QStringList pathElements = path.split('/');
|
||||
QString libraryName = pathElements.at(2);
|
||||
qulonglong comicId = pathElements.at(4).toULongLong();
|
||||
unsigned int page = pathElements.at(6).toUInt();
|
||||
|
||||
//qDebug("lib name : %s",pathElements.at(2).data());
|
||||
|
||||
Comic * comicFile = session.getCurrentComic();
|
||||
if(session.getCurrentComicId() != 0 && !QPointer<Comic>(comicFile).isNull())
|
||||
{
|
||||
if(comicId == session.getCurrentComicId() && 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<71> mensaje enviar
|
||||
response.write("404 not found",true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(comicId != session.getCurrentComicId())
|
||||
{
|
||||
//delete comicFile;
|
||||
session.dismissCurrentComic();
|
||||
}
|
||||
response.setStatus(404,"not found"); //TODO qu<71> 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);
|
||||
|
||||
}
|
||||
20
YACReaderLibrary/server/controllers/pagecontroller.h
Normal file
20
YACReaderLibrary/server/controllers/pagecontroller.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef PAGECONTROLLER_H
|
||||
#define PAGECONTROLLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
class PageController : public HttpRequestHandler {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(PageController);
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
PageController();
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
};
|
||||
|
||||
#endif // PAGECONTROLLER_H
|
||||
31
YACReaderLibrary/server/controllers/sessioncontroller.cpp
Normal file
31
YACReaderLibrary/server/controllers/sessioncontroller.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "sessioncontroller.h"
|
||||
#include "../static.h"
|
||||
#include <QVariant>
|
||||
#include <QDateTime>
|
||||
|
||||
SessionController::SessionController(){}
|
||||
|
||||
void SessionController::service(HttpRequest& request, HttpResponse& response) {
|
||||
|
||||
response.setHeader("Content-Type", "text/html; charset=ISO-8859-1");
|
||||
|
||||
// Get current session, or create a new one
|
||||
HttpSession session=Static::sessionStore->getSession(request,response);
|
||||
if (!session.contains("startTime")) {
|
||||
response.write("<html><body>New session started. Reload this page now.</body></html>");
|
||||
session.set("startTime",QDateTime::currentDateTime());
|
||||
}
|
||||
|
||||
else {
|
||||
QDateTime startTime=session.get("startTime").toDateTime();
|
||||
response.write("<html><body>Your session started ");
|
||||
response.write(startTime.toString().toLatin1());
|
||||
response.write("</body></html>");
|
||||
}
|
||||
|
||||
}
|
||||
29
YACReaderLibrary/server/controllers/sessioncontroller.h
Normal file
29
YACReaderLibrary/server/controllers/sessioncontroller.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
@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
|
||||
31
YACReaderLibrary/server/controllers/templatecontroller.cpp
Normal file
31
YACReaderLibrary/server/controllers/templatecontroller.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
@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);
|
||||
}
|
||||
30
YACReaderLibrary/server/controllers/templatecontroller.h
Normal file
30
YACReaderLibrary/server/controllers/templatecontroller.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
@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
|
||||
4
YACReaderLibrary/server/documentcache.h
Normal file
4
YACReaderLibrary/server/documentcache.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef DOCUMENTCACHE_H
|
||||
#define DOCUMENTCACHE_H
|
||||
|
||||
#endif // DOCUMENTCACHE_H
|
||||
12
YACReaderLibrary/server/lib/bfHttpServer/bfHttpServer.pri
Normal file
12
YACReaderLibrary/server/lib/bfHttpServer/bfHttpServer.pri
Normal file
@ -0,0 +1,12 @@
|
||||
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
|
||||
@ -0,0 +1,164 @@
|
||||
/**
|
||||
@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(int 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() {
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef HTTPCONNECTIONHANDLER_H
|
||||
#define HTTPCONNECTIONHANDLER_H
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
#include "httprequest.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
/**
|
||||
The connection handler accepts incoming connections and dispatches incoming requests to to a
|
||||
request mapper. Since HTTP clients can send multiple requests before waiting for the response,
|
||||
the incoming requests are queued and processed one after the other.
|
||||
<p>
|
||||
Example for the required configuration settings:
|
||||
<code><pre>
|
||||
readTimeout=60000
|
||||
maxRequestSize=16000
|
||||
maxMultiPartSize=1000000
|
||||
</pre></code>
|
||||
<p>
|
||||
The readTimeout value defines the maximum time to wait for a complete HTTP request.
|
||||
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize
|
||||
*/
|
||||
|
||||
class HttpConnectionHandler : public QThread {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HttpConnectionHandler)
|
||||
public:
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings of the HTTP webserver
|
||||
@param requestHandler handler that will process each incomin HTTP request
|
||||
*/
|
||||
HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpConnectionHandler();
|
||||
|
||||
/** Returns true, if this handler is in use. */
|
||||
bool isBusy();
|
||||
|
||||
/** Mark this handler as busy */
|
||||
void setBusy();
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration settings */
|
||||
QSettings* settings;
|
||||
|
||||
/** TCP socket of the current connection */
|
||||
QTcpSocket socket;
|
||||
|
||||
/** Time for read timeout detection */
|
||||
QTimer readTimer;
|
||||
|
||||
/** Storage for the current incoming HTTP request */
|
||||
HttpRequest* currentRequest;
|
||||
|
||||
/** Dispatches received requests to services */
|
||||
HttpRequestHandler* requestHandler;
|
||||
|
||||
/** This shows the busy-state from a very early time */
|
||||
bool busy;
|
||||
|
||||
/** Executes the htreads own event loop */
|
||||
void run();
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
Received from from the listener, when the handler shall start processing a new connection.
|
||||
@param socketDescriptor references the accepted connection.
|
||||
*/
|
||||
void handleConnection(int socketDescriptor);
|
||||
|
||||
private slots:
|
||||
|
||||
/** Received from the socket when a read-timeout occured */
|
||||
void readTimeout();
|
||||
|
||||
/** Received from the socket when incoming data can be read */
|
||||
void read();
|
||||
|
||||
/** Received from the socket when a connection has been closed */
|
||||
void disconnected();
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTPCONNECTIONHANDLER_H
|
||||
@ -0,0 +1,64 @@
|
||||
#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();
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
#ifndef HTTPCONNECTIONHANDLERPOOL_H
|
||||
#define HTTPCONNECTIONHANDLERPOOL_H
|
||||
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include "httpconnectionhandler.h"
|
||||
|
||||
/**
|
||||
Pool of http connection handlers. Connection handlers are created on demand and idle handlers are
|
||||
cleaned up in regular time intervals.
|
||||
<p>
|
||||
Example for the required configuration settings:
|
||||
<code><pre>
|
||||
minThreads=1
|
||||
maxThreads=100
|
||||
cleanupInterval=1000
|
||||
maxRequestSize=16000
|
||||
maxMultiPartSize=1000000
|
||||
</pre></code>
|
||||
The pool is empty initially and grows with the number of concurrent
|
||||
connections. A timer removes one idle connection handler at each
|
||||
interval, but it leaves some spare handlers in memory to improve
|
||||
performance.
|
||||
@see HttpConnectionHandler for description of config settings readTimeout
|
||||
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize
|
||||
*/
|
||||
|
||||
class HttpConnectionHandlerPool : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HttpConnectionHandlerPool)
|
||||
public:
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings for the HTTP server. Must not be 0.
|
||||
@param requestHandler The handler that will process each received HTTP request.
|
||||
@warning The requestMapper gets deleted by the destructor of this pool
|
||||
*/
|
||||
HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpConnectionHandlerPool();
|
||||
|
||||
/** Get a free connection handler, or 0 if not available. */
|
||||
HttpConnectionHandler* getConnectionHandler();
|
||||
|
||||
private:
|
||||
|
||||
/** Settings for this pool */
|
||||
QSettings* settings;
|
||||
|
||||
/** Will be assigned to each Connectionhandler during their creation */
|
||||
HttpRequestHandler* requestHandler;
|
||||
|
||||
/** Pool of connection handlers */
|
||||
QList<HttpConnectionHandler*> pool;
|
||||
|
||||
/** Timer to clean-up unused connection handler */
|
||||
QTimer cleanupTimer;
|
||||
|
||||
/** Used to synchronize threads */
|
||||
QMutex mutex;
|
||||
|
||||
private slots:
|
||||
|
||||
/** Received from the clean-up timer. */
|
||||
void cleanup();
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTPCONNECTIONHANDLERPOOL_H
|
||||
199
YACReaderLibrary/server/lib/bfHttpServer/httpcookie.cpp
Normal file
199
YACReaderLibrary/server/lib/bfHttpServer/httpcookie.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "httpcookie.h"
|
||||
|
||||
HttpCookie::HttpCookie() {
|
||||
version=1;
|
||||
maxAge=0;
|
||||
secure=false;
|
||||
}
|
||||
|
||||
HttpCookie::HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path, const QByteArray comment, const QByteArray domain, const bool secure) {
|
||||
this->name=name;
|
||||
this->value=value;
|
||||
this->maxAge=maxAge;
|
||||
this->path=path;
|
||||
this->comment=comment;
|
||||
this->domain=domain;
|
||||
this->secure=secure;
|
||||
this->version=1;
|
||||
}
|
||||
|
||||
HttpCookie::HttpCookie(const QByteArray source) {
|
||||
version=1;
|
||||
maxAge=0;
|
||||
secure=false;
|
||||
QList<QByteArray> list=splitCSV(source);
|
||||
foreach(QByteArray part, list) {
|
||||
|
||||
// Split the part into name and value
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
int posi=part.indexOf('=');
|
||||
if (posi) {
|
||||
name=part.left(posi).trimmed();
|
||||
value=part.mid(posi+1).trimmed();
|
||||
}
|
||||
else {
|
||||
name=part.trimmed();
|
||||
value="";
|
||||
}
|
||||
|
||||
// Set fields
|
||||
if (name=="Comment") {
|
||||
comment=value;
|
||||
}
|
||||
else if (name=="Domain") {
|
||||
domain=value;
|
||||
}
|
||||
else if (name=="Max-Age") {
|
||||
maxAge=value.toInt();
|
||||
}
|
||||
else if (name=="Path") {
|
||||
path=value;
|
||||
}
|
||||
else if (name=="Secure") {
|
||||
secure=true;
|
||||
}
|
||||
else if (name=="Version") {
|
||||
version=value.toInt();
|
||||
}
|
||||
else {
|
||||
if (this->name.isEmpty()) {
|
||||
this->name=name;
|
||||
this->value=value;
|
||||
}
|
||||
else {
|
||||
qWarning("HttpCookie: Ignoring unknown %s=%s",name.data(),value.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::toByteArray() const {
|
||||
QByteArray buffer(name);
|
||||
buffer.append('=');
|
||||
buffer.append(value);
|
||||
if (!comment.isEmpty()) {
|
||||
buffer.append("; Comment=");
|
||||
buffer.append(comment);
|
||||
}
|
||||
if (!domain.isEmpty()) {
|
||||
buffer.append("; Domain=");
|
||||
buffer.append(domain);
|
||||
}
|
||||
if (maxAge!=0) {
|
||||
buffer.append("; Max-Age=");
|
||||
buffer.append(QByteArray::number(maxAge));
|
||||
}
|
||||
if (!path.isEmpty()) {
|
||||
buffer.append("; Path=");
|
||||
buffer.append(path);
|
||||
}
|
||||
if (secure) {
|
||||
buffer.append("; Secure");
|
||||
}
|
||||
buffer.append("; Version=");
|
||||
buffer.append(QByteArray::number(version));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void HttpCookie::setName(const QByteArray name){
|
||||
this->name=name;
|
||||
}
|
||||
|
||||
void HttpCookie::setValue(const QByteArray value){
|
||||
this->value=value;
|
||||
}
|
||||
|
||||
void HttpCookie::setComment(const QByteArray comment){
|
||||
this->comment=comment;
|
||||
}
|
||||
|
||||
void HttpCookie::setDomain(const QByteArray domain){
|
||||
this->domain=domain;
|
||||
}
|
||||
|
||||
void HttpCookie::setMaxAge(const int maxAge){
|
||||
this->maxAge=maxAge;
|
||||
}
|
||||
|
||||
void HttpCookie::setPath(const QByteArray path){
|
||||
this->path=path;
|
||||
}
|
||||
|
||||
void HttpCookie::setSecure(const bool secure){
|
||||
this->secure=secure;
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::getValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::getComment() const {
|
||||
return comment;
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::getDomain() const {
|
||||
return domain;
|
||||
}
|
||||
|
||||
int HttpCookie::getMaxAge() const {
|
||||
return maxAge;
|
||||
}
|
||||
|
||||
QByteArray HttpCookie::getPath() const {
|
||||
return path;
|
||||
}
|
||||
|
||||
bool HttpCookie::getSecure() const {
|
||||
return secure;
|
||||
}
|
||||
|
||||
int HttpCookie::getVersion() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
QList<QByteArray> HttpCookie::splitCSV(const QByteArray source) {
|
||||
bool inString=false;
|
||||
QList<QByteArray> list;
|
||||
QByteArray buffer;
|
||||
for (int i=0; i<source.size(); ++i) {
|
||||
char c=source.at(i);
|
||||
if (inString==false) {
|
||||
if (c=='\"') {
|
||||
inString=true;
|
||||
}
|
||||
else if (c==';') {
|
||||
QByteArray trimmed=buffer.trimmed();
|
||||
if (!trimmed.isEmpty()) {
|
||||
list.append(trimmed);
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
else {
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c=='\"') {
|
||||
inString=false;
|
||||
}
|
||||
else {
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
QByteArray trimmed=buffer.trimmed();
|
||||
if (!trimmed.isEmpty()) {
|
||||
list.append(trimmed);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
110
YACReaderLibrary/server/lib/bfHttpServer/httpcookie.h
Normal file
110
YACReaderLibrary/server/lib/bfHttpServer/httpcookie.h
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef HTTPCOOKIE_H
|
||||
#define HTTPCOOKIE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QByteArray>
|
||||
|
||||
/**
|
||||
HTTP cookie as defined in RFC 2109. This class can also parse
|
||||
RFC 2965 cookies, but skips fields that are not defined in RFC
|
||||
2109.
|
||||
*/
|
||||
|
||||
class HttpCookie
|
||||
{
|
||||
public:
|
||||
|
||||
/** Creates an empty cookie */
|
||||
HttpCookie();
|
||||
|
||||
/**
|
||||
Create a cookie and set name/value pair.
|
||||
@param name name of the cookie
|
||||
@param value value of the cookie
|
||||
@param maxAge maximum age of the cookie in seconds. 0=discard immediately
|
||||
@param path Path for that the cookie will be sent, default="/" which means the whole domain
|
||||
@param comment Optional comment, may be displayed by the web browser somewhere
|
||||
@param domain Optional domain for that the cookie will be sent. Defaults to the current domain
|
||||
@param secure If true, the cookie will only be sent on secure connections
|
||||
*/
|
||||
HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false);
|
||||
|
||||
/**
|
||||
Create a cookie from a string.
|
||||
@param source String as received in a HTTP Cookie2 header.
|
||||
*/
|
||||
HttpCookie(const QByteArray source);
|
||||
|
||||
/** Convert this cookie to a string that may be used in a Set-Cookie2 header. */
|
||||
QByteArray toByteArray() const ;
|
||||
|
||||
/**
|
||||
Split a string list into parts, where each part is delimited by semicolon.
|
||||
Semicolons within double quotes are skipped. Double quotes are removed.
|
||||
*/
|
||||
static QList<QByteArray> splitCSV(const QByteArray source);
|
||||
|
||||
/** Set the name of this cookie */
|
||||
void setName(const QByteArray name);
|
||||
|
||||
/** Set the value of this cookie */
|
||||
void setValue(const QByteArray value);
|
||||
|
||||
/** Set the comment of this cookie */
|
||||
void setComment(const QByteArray comment);
|
||||
|
||||
/** Set the domain of this cookie */
|
||||
void setDomain(const QByteArray domain);
|
||||
|
||||
/** Set the maximum age of this cookie in seconds. 0=discard immediately */
|
||||
void setMaxAge(const int maxAge);
|
||||
|
||||
/** Set the path for that the cookie will be sent, default="/" which means the whole domain */
|
||||
void setPath(const QByteArray path);
|
||||
|
||||
/** Set secure mode, so that the cokkie will only be sent on secure connections */
|
||||
void setSecure(const bool secure);
|
||||
|
||||
/** Get the name of this cookie */
|
||||
QByteArray getName() const;
|
||||
|
||||
/** Get the value of this cookie */
|
||||
QByteArray getValue() const;
|
||||
|
||||
/** Get the comment of this cookie */
|
||||
QByteArray getComment() const;
|
||||
|
||||
/** Get the domain of this cookie */
|
||||
QByteArray getDomain() const;
|
||||
|
||||
/** Set the maximum age of this cookie in seconds. */
|
||||
int getMaxAge() const;
|
||||
|
||||
/** Set the path of this cookie */
|
||||
QByteArray getPath() const;
|
||||
|
||||
/** Get the secure flag of this cookie */
|
||||
bool getSecure() const;
|
||||
|
||||
/** Returns always 1 */
|
||||
int getVersion() const;
|
||||
|
||||
private:
|
||||
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
QByteArray comment;
|
||||
QByteArray domain;
|
||||
int maxAge;
|
||||
QByteArray path;
|
||||
bool secure;
|
||||
int version;
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTPCOOKIE_H
|
||||
66
YACReaderLibrary/server/lib/bfHttpServer/httplistener.cpp
Normal file
66
YACReaderLibrary/server/lib/bfHttpServer/httplistener.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "httplistener.h"
|
||||
#include "httpconnectionhandler.h"
|
||||
#include "httpconnectionhandlerpool.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
HttpListener::HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject *parent)
|
||||
: QTcpServer(parent)
|
||||
{
|
||||
Q_ASSERT(settings!=0);
|
||||
this->settings=settings;
|
||||
pool=new HttpConnectionHandlerPool(settings,requestHandler);
|
||||
// Start listening
|
||||
int port=settings->value("port",8080).toInt();
|
||||
listen(QHostAddress::Any, port);
|
||||
//Cambiado
|
||||
int i = 0;
|
||||
while (!isListening() && i < 1000) {
|
||||
listen(QHostAddress::Any, (rand() % 45535)+20000);
|
||||
i++;
|
||||
}
|
||||
if(!isListening())
|
||||
{
|
||||
qCritical("HttpListener: Cannot bind on port %i: %s",port,qPrintable(errorString()));
|
||||
}
|
||||
else {
|
||||
qDebug("HttpListener: Listening on port %i",port);
|
||||
}
|
||||
}
|
||||
|
||||
HttpListener::~HttpListener() {
|
||||
close();
|
||||
qDebug("HttpListener: closed");
|
||||
delete pool;
|
||||
qDebug("HttpListener: destroyed");
|
||||
}
|
||||
|
||||
|
||||
void HttpListener::incomingConnection(int socketDescriptor) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpListener: New connection");
|
||||
#endif
|
||||
HttpConnectionHandler* freeHandler=pool->getConnectionHandler();
|
||||
|
||||
// Let the handler process the new connection.
|
||||
if (freeHandler) {
|
||||
// The descriptor is passed via signal/slot because the handler lives in another
|
||||
// thread and cannot open the socket when called by another thread.
|
||||
connect(this,SIGNAL(handleConnection(int)),freeHandler,SLOT(handleConnection(int)));
|
||||
emit handleConnection(socketDescriptor);
|
||||
disconnect(this,SIGNAL(handleConnection(int)),freeHandler,SLOT(handleConnection(int)));
|
||||
}
|
||||
else {
|
||||
// Reject the connection
|
||||
qDebug("HttpListener: Too many connections");
|
||||
QTcpSocket* socket=new QTcpSocket(this);
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
|
||||
socket->write("HTTP/1.1 503 too many connections\r\nConnection: close\r\n\r\nToo many connections\r\n");
|
||||
socket->disconnectFromHost();
|
||||
}
|
||||
}
|
||||
76
YACReaderLibrary/server/lib/bfHttpServer/httplistener.h
Normal file
76
YACReaderLibrary/server/lib/bfHttpServer/httplistener.h
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef LISTENER_H
|
||||
#define LISTENER_H
|
||||
|
||||
#include <QTcpServer>
|
||||
#include <QSettings>
|
||||
#include <QBasicTimer>
|
||||
#include "httpconnectionhandler.h"
|
||||
#include "httpconnectionhandlerpool.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
/**
|
||||
Listens for incoming TCP connections and passes control to
|
||||
one of the pooled connection handlers. This class is also
|
||||
responsible for managing the pool.
|
||||
<p>
|
||||
Example for the required settings in the config file:
|
||||
<code><pre>
|
||||
port=8080
|
||||
minThreads=1
|
||||
maxThreads=10
|
||||
cleanupInterval=1000
|
||||
readTimeout=60000
|
||||
maxRequestSize=16000
|
||||
maxMultiPartSize=1000000
|
||||
</pre></code>
|
||||
The port number is the incoming TCP port that this listener listens to.
|
||||
@see HttpConnectionHandlerPool for description of config settings minThreads, maxThreads and cleanupInterval
|
||||
@see HttpConnectionHandler for description of config settings readTimeout
|
||||
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize
|
||||
*/
|
||||
|
||||
class HttpListener : public QTcpServer {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HttpListener)
|
||||
public:
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings for the HTTP server. Must not be 0.
|
||||
@param requestHandler Processes each received HTTP request, usually by dispatching to controller classes.
|
||||
@param parent Parent object
|
||||
*/
|
||||
HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = 0);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpListener();
|
||||
|
||||
protected:
|
||||
|
||||
/** Serves new incoming connection requests */
|
||||
void incomingConnection(int socketDescriptor);
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration settings for the HTTP server */
|
||||
QSettings* settings;
|
||||
|
||||
/** Pool of connection handlers */
|
||||
HttpConnectionHandlerPool* pool;
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
Emitted when the connection handler shall process a new incoming onnection.
|
||||
@param socketDescriptor references the accepted connection.
|
||||
*/
|
||||
void handleConnection(int socketDescriptor);
|
||||
|
||||
};
|
||||
|
||||
#endif // LISTENER_H
|
||||
431
YACReaderLibrary/server/lib/bfHttpServer/httprequest.cpp
Normal file
431
YACReaderLibrary/server/lib/bfHttpServer/httprequest.cpp
Normal file
@ -0,0 +1,431 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "httprequest.h"
|
||||
#include <QList>
|
||||
#include <QDir>
|
||||
#include "httpcookie.h"
|
||||
|
||||
HttpRequest::HttpRequest(QSettings* settings) {
|
||||
status=waitForRequest;
|
||||
currentSize=0;
|
||||
expectedBodySize=0;
|
||||
maxSize=settings->value("maxRequestSize","16000000").toInt();
|
||||
maxMultiPartSize=settings->value("maxMultiPartSize","1000000").toInt();
|
||||
}
|
||||
|
||||
void HttpRequest::readRequest(QTcpSocket& socket) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: read request");
|
||||
#endif
|
||||
int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
|
||||
QByteArray newData=socket.readLine(toRead).trimmed();
|
||||
currentSize+=newData.size();
|
||||
if (!newData.isEmpty()) {
|
||||
QList<QByteArray> list=newData.split(' ');
|
||||
if (list.count()!=3 || !list.at(2).contains("HTTP")) {
|
||||
qWarning("HttpRequest: received broken HTTP request, invalid first line");
|
||||
status=abort;
|
||||
}
|
||||
else {
|
||||
method=list.at(0);
|
||||
path=list.at(1);
|
||||
version=list.at(2);
|
||||
status=waitForHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::readHeader(QTcpSocket& socket) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: read header");
|
||||
#endif
|
||||
int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
|
||||
QByteArray newData=socket.readLine(toRead).trimmed();
|
||||
currentSize+=newData.size();
|
||||
int colon=newData.indexOf(':');
|
||||
if (colon>0) {
|
||||
// Received a line with a colon - a header
|
||||
currentHeader=newData.left(colon);
|
||||
QByteArray value=newData.mid(colon+1).trimmed();
|
||||
headers.insert(currentHeader,value);
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: received header %s: %s",currentHeader.data(),value.data());
|
||||
#endif
|
||||
}
|
||||
else if (!newData.isEmpty()) {
|
||||
// received another line - belongs to the previous header
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: read additional line of header");
|
||||
#endif
|
||||
// Received additional line of previous header
|
||||
if (headers.contains(currentHeader)) {
|
||||
headers.insert(currentHeader,headers.value(currentHeader)+" "+newData);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// received an empty line - end of headers reached
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: headers completed");
|
||||
#endif
|
||||
// Empty line received, that means all headers have been received
|
||||
// Check for multipart/form-data
|
||||
QByteArray contentType=headers.value("Content-Type");
|
||||
if (contentType.startsWith("multipart/form-data")) {
|
||||
int posi=contentType.indexOf("boundary=");
|
||||
if (posi>=0) {
|
||||
boundary=contentType.mid(posi+9);
|
||||
}
|
||||
}
|
||||
QByteArray contentLength=getHeader("Content-Length");
|
||||
if (!contentLength.isEmpty()) {
|
||||
expectedBodySize=contentLength.toInt();
|
||||
}
|
||||
if (expectedBodySize==0) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: expect no body");
|
||||
#endif
|
||||
status=complete;
|
||||
}
|
||||
else if (boundary.isEmpty() && expectedBodySize+currentSize>maxSize) {
|
||||
qWarning("HttpRequest: expected body is too large");
|
||||
status=abort;
|
||||
}
|
||||
else if (!boundary.isEmpty() && expectedBodySize>maxMultiPartSize) {
|
||||
qWarning("HttpRequest: expected multipart body is too large");
|
||||
status=abort;
|
||||
}
|
||||
else {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: expect %i bytes body",expectedBodySize);
|
||||
#endif
|
||||
status=waitForBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::readBody(QTcpSocket& socket) {
|
||||
Q_ASSERT(expectedBodySize!=0);
|
||||
if (boundary.isEmpty()) {
|
||||
// normal body, no multipart
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: receive body");
|
||||
#endif
|
||||
int toRead=expectedBodySize-bodyData.size();
|
||||
QByteArray newData=socket.read(toRead);
|
||||
currentSize+=newData.size();
|
||||
bodyData.append(newData);
|
||||
if (bodyData.size()>=expectedBodySize) {
|
||||
status=complete;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// multipart body, store into temp file
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: receiving multipart body");
|
||||
#endif
|
||||
if (!tempFile.isOpen()) {
|
||||
tempFile.open();
|
||||
}
|
||||
// Transfer data in 64kb blocks
|
||||
int fileSize=tempFile.size();
|
||||
int toRead=expectedBodySize-fileSize;
|
||||
if (toRead>65536) {
|
||||
toRead=65536;
|
||||
}
|
||||
fileSize+=tempFile.write(socket.read(toRead));
|
||||
if (fileSize>=maxMultiPartSize) {
|
||||
qWarning("HttpRequest: received too many multipart bytes");
|
||||
status=abort;
|
||||
}
|
||||
else if (fileSize>=expectedBodySize) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: received whole multipart body");
|
||||
#endif
|
||||
tempFile.flush();
|
||||
if (tempFile.error()) {
|
||||
qCritical("HttpRequest: Error writing temp file for multipart body");
|
||||
}
|
||||
parseMultiPartFile();
|
||||
tempFile.close();
|
||||
status=complete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::decodeRequestParams() {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: extract and decode request parameters");
|
||||
#endif
|
||||
// Get URL parameters
|
||||
QByteArray rawParameters;
|
||||
int questionMark=path.indexOf('?');
|
||||
if (questionMark>=0) {
|
||||
rawParameters=path.mid(questionMark+1);
|
||||
path=path.left(questionMark);
|
||||
}
|
||||
// Get request body parameters
|
||||
QByteArray contentType=headers.value("Content-Type");
|
||||
if (!bodyData.isEmpty() && (contentType.isEmpty() || contentType.startsWith("application/x-www-form-urlencoded"))) {
|
||||
if (rawParameters.isEmpty()) {
|
||||
rawParameters.append('&');
|
||||
rawParameters.append(bodyData);
|
||||
}
|
||||
else {
|
||||
rawParameters=bodyData;
|
||||
}
|
||||
}
|
||||
// Split the parameters into pairs of value and name
|
||||
QList<QByteArray> list=rawParameters.split('&');
|
||||
foreach (QByteArray part, list) {
|
||||
int equalsChar=part.indexOf('=');
|
||||
if (equalsChar>=0) {
|
||||
QByteArray name=part.left(equalsChar).trimmed();
|
||||
QByteArray value=part.mid(equalsChar+1).trimmed();
|
||||
parameters.insert(urlDecode(name),urlDecode(value));
|
||||
}
|
||||
else if (!part.isEmpty()){
|
||||
// Name without value
|
||||
parameters.insert(urlDecode(part),"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::extractCookies() {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: extract cookies");
|
||||
#endif
|
||||
foreach(QByteArray cookieStr, headers.values("Cookie")) {
|
||||
QList<QByteArray> list=HttpCookie::splitCSV(cookieStr);
|
||||
foreach(QByteArray part, list) {
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: found cookie %s",part.data());
|
||||
#endif // Split the part into name and value
|
||||
QByteArray name;
|
||||
QByteArray value;
|
||||
int posi=part.indexOf('=');
|
||||
if (posi) {
|
||||
name=part.left(posi).trimmed();
|
||||
value=part.mid(posi+1).trimmed();
|
||||
}
|
||||
else {
|
||||
name=part.trimmed();
|
||||
value="";
|
||||
}
|
||||
cookies.insert(name,value);
|
||||
}
|
||||
}
|
||||
headers.remove("Cookie");
|
||||
}
|
||||
|
||||
void HttpRequest::readFromSocket(QTcpSocket& socket) {
|
||||
Q_ASSERT(status!=complete);
|
||||
if (status==waitForRequest) {
|
||||
readRequest(socket);
|
||||
}
|
||||
else if (status==waitForHeader) {
|
||||
readHeader(socket);
|
||||
}
|
||||
else if (status==waitForBody) {
|
||||
readBody(socket);
|
||||
}
|
||||
if (currentSize>maxSize) {
|
||||
qWarning("HttpRequest: received too many bytes");
|
||||
status=abort;
|
||||
}
|
||||
if (status==complete) {
|
||||
// Extract and decode request parameters from url and body
|
||||
decodeRequestParams();
|
||||
// Extract cookies from headers
|
||||
extractCookies();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HttpRequest::RequestStatus HttpRequest::getStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
QByteArray HttpRequest::getMethod() const {
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
QByteArray HttpRequest::getPath() const {
|
||||
return urlDecode(path);
|
||||
}
|
||||
|
||||
|
||||
QByteArray HttpRequest::getVersion() const {
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
QByteArray HttpRequest::getHeader(const QByteArray& name) const {
|
||||
return headers.value(name);
|
||||
}
|
||||
|
||||
QList<QByteArray> HttpRequest::getHeaders(const QByteArray& name) const {
|
||||
return headers.values(name);
|
||||
}
|
||||
|
||||
QMultiMap<QByteArray,QByteArray> HttpRequest::getHeaderMap() const {
|
||||
return headers;
|
||||
}
|
||||
|
||||
QByteArray HttpRequest::getParameter(const QByteArray& name) const {
|
||||
return parameters.value(name);
|
||||
}
|
||||
|
||||
QList<QByteArray> HttpRequest::getParameters(const QByteArray& name) const {
|
||||
return parameters.values(name);
|
||||
}
|
||||
|
||||
QMultiMap<QByteArray,QByteArray> HttpRequest::getParameterMap() const {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
QByteArray HttpRequest::getBody() const {
|
||||
return bodyData;
|
||||
}
|
||||
|
||||
QByteArray HttpRequest::urlDecode(const QByteArray source) {
|
||||
QByteArray buffer(source);
|
||||
buffer.replace('+',' ');
|
||||
int percentChar=buffer.indexOf('%');
|
||||
while (percentChar>=0) {
|
||||
bool ok;
|
||||
char byte=buffer.mid(percentChar+1,2).toInt(&ok,16);
|
||||
if (ok) {
|
||||
buffer.replace(percentChar,3,(char*)&byte,1);
|
||||
}
|
||||
percentChar=buffer.indexOf('%',percentChar+1);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void HttpRequest::parseMultiPartFile() {
|
||||
qDebug("HttpRequest: parsing multipart temp file");
|
||||
tempFile.seek(0);
|
||||
bool finished=false;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error()) {
|
||||
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: reading multpart headers");
|
||||
#endif
|
||||
QByteArray fieldName;
|
||||
QByteArray fileName;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error()) {
|
||||
QByteArray line=tempFile.readLine(65536).trimmed();
|
||||
if (line.startsWith("Content-Disposition:")) {
|
||||
if (line.contains("form-data")) {
|
||||
int start=line.indexOf(" name=\"");
|
||||
int end=line.indexOf("\"",start+7);
|
||||
if (start>=0 && end>=start) {
|
||||
fieldName=line.mid(start+7,end-start-7);
|
||||
}
|
||||
start=line.indexOf(" filename=\"");
|
||||
end=line.indexOf("\"",start+11);
|
||||
if (start>=0 && end>=start) {
|
||||
fileName=line.mid(start+11,end-start-11);
|
||||
}
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: multipart field=%s, filename=%s",fieldName.data(),fileName.data());
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
qDebug("HttpRequest: ignoring unsupported content part %s",line.data());
|
||||
}
|
||||
}
|
||||
else if (line.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: reading multpart data");
|
||||
#endif
|
||||
QTemporaryFile* uploadedFile=0;
|
||||
QByteArray fieldValue;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error()) {
|
||||
QByteArray line=tempFile.readLine(65536);
|
||||
if (line.startsWith("--"+boundary)) {
|
||||
// Boundary found. Until now we have collected 2 bytes too much,
|
||||
// so remove them from the last result
|
||||
if (fileName.isEmpty() && !fieldName.isEmpty()) {
|
||||
// last field was a form field
|
||||
fieldValue.remove(fieldValue.size()-2,2);
|
||||
parameters.insert(fieldName,fieldValue);
|
||||
qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fieldValue.data());
|
||||
}
|
||||
else if (!fileName.isEmpty() && !fieldName.isEmpty()) {
|
||||
// last field was a file
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: finishing writing to uploaded file");
|
||||
#endif
|
||||
uploadedFile->resize(uploadedFile->size()-2);
|
||||
uploadedFile->flush();
|
||||
uploadedFile->seek(0);
|
||||
parameters.insert(fieldName,fileName);
|
||||
qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fileName.data());
|
||||
uploadedFiles.insert(fieldName,uploadedFile);
|
||||
qDebug("HttpRequest: uploaded file size is %i",(int) uploadedFile->size());
|
||||
}
|
||||
if (line.contains(boundary+"--")) {
|
||||
finished=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (fileName.isEmpty() && !fieldName.isEmpty()) {
|
||||
// this is a form field.
|
||||
currentSize+=line.size();
|
||||
fieldValue.append(line);
|
||||
}
|
||||
else if (!fileName.isEmpty() && !fieldName.isEmpty()) {
|
||||
// this is a file
|
||||
if (!uploadedFile) {
|
||||
uploadedFile=new QTemporaryFile();
|
||||
uploadedFile->open();
|
||||
}
|
||||
uploadedFile->write(line);
|
||||
if (uploadedFile->error()) {
|
||||
qCritical("HttpRequest: error writing temp file, %s",qPrintable(uploadedFile->errorString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tempFile.error()) {
|
||||
qCritical("HttpRequest: cannot read temp file, %s",qPrintable(tempFile.errorString()));
|
||||
}
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: finished parsing multipart temp file");
|
||||
#endif
|
||||
}
|
||||
|
||||
HttpRequest::~HttpRequest() {
|
||||
foreach(QByteArray key, uploadedFiles.keys()) {
|
||||
QTemporaryFile* file=uploadedFiles.value(key);
|
||||
file->close();
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
||||
QTemporaryFile* HttpRequest::getUploadedFile(const QByteArray fieldName) {
|
||||
return uploadedFiles.value(fieldName);
|
||||
}
|
||||
|
||||
QByteArray HttpRequest::getCookie(const QByteArray& name) const {
|
||||
return cookies.value(name);
|
||||
}
|
||||
|
||||
/** Get the map of cookies */
|
||||
QMap<QByteArray,QByteArray>& HttpRequest::getCookieMap() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
212
YACReaderLibrary/server/lib/bfHttpServer/httprequest.h
Normal file
212
YACReaderLibrary/server/lib/bfHttpServer/httprequest.h
Normal file
@ -0,0 +1,212 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef HTTPREQUEST_H
|
||||
#define HTTPREQUEST_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QTcpSocket>
|
||||
#include <QMap>
|
||||
#include <QMultiMap>
|
||||
#include <QSettings>
|
||||
#include <QTemporaryFile>
|
||||
#include <QUuid>
|
||||
|
||||
/**
|
||||
This object represents a single HTTP request. It reads the request
|
||||
from a TCP socket and provides getters for the individual parts
|
||||
of the request.
|
||||
<p>
|
||||
The follwing config settings are required:
|
||||
<code><pre>
|
||||
maxRequestSize=16000
|
||||
maxMultiPartSize=1000000
|
||||
</pre></code>
|
||||
<p>
|
||||
MaxRequestSize is the maximum size of a HTTP request. In case of
|
||||
multipart/form-data requests (also known as file-upload), the maximum
|
||||
size of the body must not exceed maxMultiPartSize.
|
||||
The body is always a little larger than the file itself.
|
||||
*/
|
||||
|
||||
class HttpRequest {
|
||||
Q_DISABLE_COPY(HttpRequest)
|
||||
friend class HttpSessionStore;
|
||||
public:
|
||||
|
||||
/** Values for getStatus() */
|
||||
enum RequestStatus {waitForRequest, waitForHeader, waitForBody, complete, abort};
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings
|
||||
*/
|
||||
HttpRequest(QSettings* settings);
|
||||
|
||||
/**
|
||||
Destructor.
|
||||
*/
|
||||
virtual ~HttpRequest();
|
||||
|
||||
/**
|
||||
Read the request from a socket. This method must be called repeatedly
|
||||
until the status is RequestStatus::complete or RequestStatus::abort.
|
||||
@param socket Source of the data
|
||||
*/
|
||||
void readFromSocket(QTcpSocket& socket);
|
||||
|
||||
/**
|
||||
Get the status of this reqeust.
|
||||
@see RequestStatus
|
||||
*/
|
||||
RequestStatus getStatus() const;
|
||||
|
||||
/** Get the method of the HTTP request (e.g. "GET") */
|
||||
QByteArray getMethod() const;
|
||||
|
||||
/** Get the decoded path of the HTPP request (e.g. "/index.html") */
|
||||
QByteArray getPath() const;
|
||||
|
||||
/** Get the version of the HTPP request (e.g. "HTTP/1.1") */
|
||||
QByteArray getVersion() const;
|
||||
|
||||
/**
|
||||
Get the value of a HTTP request header.
|
||||
@param name Name of the header
|
||||
@return If the header occurs multiple times, only the last
|
||||
one is returned.
|
||||
*/
|
||||
QByteArray getHeader(const QByteArray& name) const;
|
||||
|
||||
/**
|
||||
Get the values of a HTTP request header.
|
||||
@param name Name of the header
|
||||
*/
|
||||
QList<QByteArray> getHeaders(const QByteArray& name) const;
|
||||
|
||||
/** Get all HTTP request headers */
|
||||
QMultiMap<QByteArray,QByteArray> getHeaderMap() const;
|
||||
|
||||
/**
|
||||
Get the value of a HTTP request parameter.
|
||||
@param name Name of the parameter
|
||||
@return If the parameter occurs multiple times, only the last
|
||||
one is returned.
|
||||
*/
|
||||
QByteArray getParameter(const QByteArray& name) const;
|
||||
|
||||
/**
|
||||
Get the values of a HTTP request parameter.
|
||||
@param name Name of the parameter
|
||||
*/
|
||||
QList<QByteArray> getParameters(const QByteArray& name) const;
|
||||
|
||||
/** Get all HTTP request parameters */
|
||||
QMultiMap<QByteArray,QByteArray> getParameterMap() const;
|
||||
|
||||
/** Get the HTTP request body */
|
||||
QByteArray getBody() const;
|
||||
|
||||
/**
|
||||
Decode an URL parameter.
|
||||
E.g. replace "%23" by '#' and replace '+' by ' '.
|
||||
@param source The url encoded strings
|
||||
@see QUrl::toPercentEncoding for the reverse direction
|
||||
*/
|
||||
static QByteArray urlDecode(const QByteArray source);
|
||||
|
||||
/**
|
||||
Get an uploaded file. The file is already open. It will
|
||||
be closed and deleted by the destructor of this HttpRequest
|
||||
object (after processing the request).
|
||||
<p>
|
||||
For uploaded files, the method getParameters() returns
|
||||
the original fileName as provided by the calling web browser.
|
||||
*/
|
||||
QTemporaryFile* getUploadedFile(const QByteArray fieldName);
|
||||
|
||||
/**
|
||||
Get the value of a cookie
|
||||
@param name Name of the cookie
|
||||
*/
|
||||
QByteArray getCookie(const QByteArray& name) const;
|
||||
|
||||
/** Get the map of cookies */
|
||||
QMap<QByteArray,QByteArray>& getCookieMap();
|
||||
|
||||
private:
|
||||
|
||||
/** Request headers */
|
||||
QMultiMap<QByteArray,QByteArray> headers;
|
||||
|
||||
/** Parameters of the request */
|
||||
QMultiMap<QByteArray,QByteArray> parameters;
|
||||
|
||||
/** Uploaded files of the request, key is the field name. */
|
||||
QMap<QByteArray,QTemporaryFile*> uploadedFiles;
|
||||
|
||||
/** Received cookies */
|
||||
QMap<QByteArray,QByteArray> cookies;
|
||||
|
||||
/** Storage for raw body data */
|
||||
QByteArray bodyData;
|
||||
|
||||
/** Request method */
|
||||
QByteArray method;
|
||||
|
||||
/** Request path (in raw encoded format) */
|
||||
QByteArray path;
|
||||
|
||||
/** Request protocol version */
|
||||
QByteArray version;
|
||||
|
||||
/**
|
||||
Status of this request.
|
||||
@see RequestStatus
|
||||
*/
|
||||
RequestStatus status;
|
||||
|
||||
/** Maximum size of requests in bytes. */
|
||||
int maxSize;
|
||||
|
||||
/** Maximum allowed size of multipart forms in bytes. */
|
||||
int maxMultiPartSize;
|
||||
|
||||
/** Current size */
|
||||
int currentSize;
|
||||
|
||||
/** Expected size of body */
|
||||
int expectedBodySize;
|
||||
|
||||
/** Name of the current header, or empty if no header is being processed */
|
||||
QByteArray currentHeader;
|
||||
|
||||
/** Boundary of multipart/form-data body. Empty if there is no such header */
|
||||
QByteArray boundary;
|
||||
|
||||
/** Temp file, that is used to store the multipart/form-data body */
|
||||
QTemporaryFile tempFile;
|
||||
|
||||
/** Parset he multipart body, that has been stored in the temp file. */
|
||||
void parseMultiPartFile();
|
||||
|
||||
/** Sub-procedure of readFromSocket(), read the first line of a request. */
|
||||
void readRequest(QTcpSocket& socket);
|
||||
|
||||
/** Sub-procedure of readFromSocket(), read header lines. */
|
||||
void readHeader(QTcpSocket& socket);
|
||||
|
||||
/** Sub-procedure of readFromSocket(), read the request body. */
|
||||
void readBody(QTcpSocket& socket);
|
||||
|
||||
/** Sub-procedure of readFromSocket(), extract and decode request parameters. */
|
||||
void decodeRequestParams();
|
||||
|
||||
/** Sub-procedure of readFromSocket(), extract cookies from headers */
|
||||
void extractCookies();
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTPREQUEST_H
|
||||
@ -0,0 +1,19 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
HttpRequestHandler::HttpRequestHandler(QObject* parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
HttpRequestHandler::~HttpRequestHandler() {}
|
||||
|
||||
void HttpRequestHandler::service(HttpRequest& request, HttpResponse& response) {
|
||||
qCritical("HttpRequestHandler: you need to override the dispatch() function");
|
||||
qDebug("HttpRequestHandler: request=%s %s %s",request.getMethod().data(),request.getPath().data(),request.getVersion().data());
|
||||
response.setStatus(501,"not implemented");
|
||||
response.write("501 not implemented",true);
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/**
|
||||
@file
|
||||
@author Stefan Frings
|
||||
*/
|
||||
|
||||
#ifndef HTTPREQUESTHANDLER_H
|
||||
#define HTTPREQUESTHANDLER_H
|
||||
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
|
||||
/**
|
||||
The request handler generates a response for each HTTP request. Web Applications
|
||||
usually have one central request handler that maps incoming requests to several
|
||||
controllers (servlets) based on the requested path.
|
||||
<p>
|
||||
You need to override the service() method or you will always get an HTTP error 501.
|
||||
<p>
|
||||
@warning Be aware that the main request handler instance must be created on the heap and
|
||||
that it is used by multiple threads simultaneously.
|
||||
@see StaticFileController which delivers static local files.
|
||||
*/
|
||||
|
||||
class HttpRequestHandler : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HttpRequestHandler)
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
HttpRequestHandler(QObject* parent=0);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpRequestHandler();
|
||||
|
||||
/**
|
||||
Generate a response for an incoming HTTP request.
|
||||
@param request The received HTTP request
|
||||
@param response Must be used to return the response
|
||||
@warning This method must be thread safe
|
||||
*/
|
||||
virtual void service(HttpRequest& request, HttpResponse& response);
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTPREQUESTHANDLER_H
|
||||
132
YACReaderLibrary/server/lib/bfHttpServer/httpresponse.cpp
Normal file
132
YACReaderLibrary/server/lib/bfHttpServer/httpresponse.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
@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(text.toAscii(),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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user