mirror of
https://github.com/YACReader/yacreader
synced 2025-05-28 03:10:27 -04:00
Ordenaci?n naturalSorting a?adida a los modelos ?rbol y tabla Primera versi?n de la actualizaci?n de librer?as basadas en BD (falta realizar bateria de pruebas) Los di?logos deben ser mostrados antes de lanzar los hilos que los cerrar?n para evitar estados inconsistentes en la GUI
374 lines
8.5 KiB
C++
374 lines
8.5 KiB
C++
#include "goto_flow.h"
|
|
#include "configuration.h"
|
|
#include "comic.h"
|
|
#include "custom_widgets.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QSize>
|
|
#include <QImage>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QMutex>
|
|
#include <QCoreApplication>
|
|
|
|
/*#define WIDTH 126
|
|
#define HEIGHT 200*/
|
|
|
|
QMutex mutexGoToFlow;
|
|
|
|
|
|
|
|
GoToFlow::GoToFlow(QWidget *parent,PictureFlow::FlowType flowType)
|
|
:QWidget(parent),ready(false)
|
|
{
|
|
updateTimer = new QTimer;
|
|
connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateImageData()));
|
|
|
|
worker = new PageLoader;
|
|
|
|
QVBoxLayout * layout = new QVBoxLayout(this);
|
|
flow = new YACReaderFlow(this,flowType);
|
|
flow->setReflectionEffect(PictureFlow::PlainReflection);
|
|
imageSize = Configuration::getConfiguration().getGotoSlideSize();
|
|
|
|
flow->setSlideSize(imageSize);
|
|
connect(flow,SIGNAL(centerIndexChanged(int)),this,SLOT(setPageNumber(int)));
|
|
connect(flow,SIGNAL(selected(unsigned int)),this,SLOT(goTo()));
|
|
|
|
QHBoxLayout * bottom = new QHBoxLayout(this);
|
|
bottom->addStretch();
|
|
bottom->addWidget(new QLabel(tr("Page : "),this));
|
|
bottom->addWidget(edit = new QLineEdit(this));
|
|
v = new QIntValidator(this);
|
|
v->setBottom(1);
|
|
edit->setValidator(v);
|
|
edit->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
|
edit->setFixedWidth(40);
|
|
edit->setSizePolicy(QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Minimum));
|
|
|
|
centerButton = new QPushButton(this);
|
|
centerButton->setIcon(QIcon(":/images/center.png"));
|
|
connect(centerButton,SIGNAL(clicked()),this,SLOT(centerSlide()));
|
|
bottom->addWidget(centerButton);
|
|
|
|
goToButton = new QPushButton(this);
|
|
goToButton->setIcon(QIcon(":/images/goto.png"));
|
|
connect(goToButton,SIGNAL(clicked()),this,SLOT(goTo()));
|
|
bottom->addWidget(goToButton);
|
|
|
|
bottom->addStretch();
|
|
|
|
layout->addWidget(flow);
|
|
layout->addLayout(bottom);
|
|
layout->setStretchFactor(flow,1);
|
|
layout->setStretchFactor(bottom,0);
|
|
layout->setMargin(0);
|
|
layout->setSpacing(0);
|
|
setLayout(layout);
|
|
this->setAutoFillBackground(true);
|
|
resize(static_cast<int>(5*imageSize.width()),static_cast<int>(imageSize.height()*1.7));
|
|
|
|
//install eventFilter
|
|
//flow->installEventFilter(this);
|
|
edit->installEventFilter(this);
|
|
centerButton->installEventFilter(this);
|
|
goToButton->installEventFilter(this);
|
|
|
|
connect(edit,SIGNAL(returnPressed()),goToButton,SIGNAL(clicked()));
|
|
|
|
this->setCursor(QCursor(Qt::ArrowCursor));
|
|
}
|
|
|
|
void GoToFlow::goTo()
|
|
{
|
|
//emit(goToPage(flow->centerIndex()+1));
|
|
emit(goToPage(edit->text().toInt()));
|
|
}
|
|
|
|
void GoToFlow::setPageNumber(int page)
|
|
{
|
|
edit->setText(QString::number(page+1));
|
|
}
|
|
|
|
void GoToFlow::centerSlide()
|
|
{
|
|
int page = edit->text().toInt()-1;
|
|
int distance = flow->centerIndex()-page;
|
|
|
|
if(abs(distance)>10)
|
|
{
|
|
if(distance<0)
|
|
flow->setCenterIndex(flow->centerIndex()+(-distance)-10);
|
|
else
|
|
flow->setCenterIndex(flow->centerIndex()-distance+10);
|
|
}
|
|
|
|
flow->showSlide(page);
|
|
}
|
|
|
|
void GoToFlow::centerSlide(int slide)
|
|
{
|
|
if(flow->centerIndex()!=slide)
|
|
{
|
|
flow->setCenterIndex(slide);
|
|
if(ready)// load images if pages are loaded.
|
|
{
|
|
//worker->reset(); //BUG FIXED : image didn't load if worker was working
|
|
preload();
|
|
}
|
|
}
|
|
}
|
|
|
|
void GoToFlow::setNumSlides(unsigned int slides)
|
|
{
|
|
// numPagesLabel->setText(tr("Total pages : ")+QString::number(slides));
|
|
// numPagesLabel->adjustSize();
|
|
imagesReady.clear();
|
|
imagesReady.fill(false,slides);
|
|
|
|
rawImages.clear();
|
|
rawImages.resize(slides);
|
|
|
|
v->setTop(slides);
|
|
|
|
SlideInitializer * si = new SlideInitializer(flow,slides);
|
|
|
|
imagesLoaded.clear();
|
|
imagesLoaded.fill(false,slides);
|
|
|
|
imagesSetted.clear();
|
|
imagesSetted.fill(false,slides);
|
|
|
|
numImagesLoaded = 0;
|
|
|
|
connect(flow, SIGNAL(centerIndexChanged(int)), this, SLOT(preload()));
|
|
|
|
ready = true;
|
|
worker->reset();
|
|
|
|
si->start();
|
|
}
|
|
|
|
void GoToFlow::reset()
|
|
{
|
|
updateTimer->stop();
|
|
/*imagesLoaded.clear();
|
|
numImagesLoaded = 0;
|
|
imagesReady.clear();
|
|
rawImages.clear();*/
|
|
ready = false;
|
|
}
|
|
|
|
void GoToFlow::setImageReady(int index,const QByteArray & image)
|
|
{
|
|
rawImages[index]=image;
|
|
imagesReady[index]=true;
|
|
preload();
|
|
}
|
|
|
|
void GoToFlow::preload()
|
|
{
|
|
if(numImagesLoaded < imagesLoaded.size())
|
|
updateTimer->start(30); //TODO comprobar rendimiento, antes era 70
|
|
}
|
|
|
|
void GoToFlow::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])
|
|
{
|
|
flow->setSlide(idx, worker->result());
|
|
imagesSetted[idx] = true;
|
|
numImagesLoaded++;
|
|
rawImages[idx].clear();; //release memory
|
|
}
|
|
|
|
}
|
|
|
|
// 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 = flow->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 < flow->slideCount()))
|
|
if(!imagesLoaded[i]&&imagesReady[i])//slide(i).isNull())
|
|
{
|
|
// schedule thumbnail generation
|
|
imagesLoaded[i]=true;
|
|
worker->generate(i, flow->slideSize(),rawImages[i]);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// no need to generate anything? stop polling...
|
|
updateTimer->stop();
|
|
}
|
|
|
|
bool GoToFlow::eventFilter(QObject *target, QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::KeyPress)
|
|
{
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
|
int key = keyEvent->key();
|
|
if((key==Qt::Key_Return)||
|
|
(key==Qt::Key_Enter)||
|
|
(key==Qt::Key_Space)||
|
|
(key==Qt::Key_Left)||
|
|
(key==Qt::Key_Right)||
|
|
(key==Qt::Key_S))
|
|
this->keyPressEvent(keyEvent);
|
|
}
|
|
return QWidget::eventFilter(target, event);
|
|
}
|
|
|
|
|
|
void GoToFlow::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
switch (event->key())
|
|
{
|
|
case Qt::Key_Return: case Qt::Key_Enter:
|
|
goTo();
|
|
centerSlide();
|
|
break;
|
|
case Qt::Key_Space:
|
|
centerSlide();
|
|
break;
|
|
case Qt::Key_S:
|
|
QCoreApplication::sendEvent(this->parent(),event);
|
|
break;
|
|
case Qt::Key_Left: case Qt::Key_Right:
|
|
QCoreApplication::sendEvent(flow,event);
|
|
}
|
|
|
|
event->accept();
|
|
}
|
|
|
|
void GoToFlow::wheelEvent(QWheelEvent * event)
|
|
{
|
|
if(event->delta()<0)
|
|
flow->showNext();
|
|
else
|
|
flow->showPrevious();
|
|
event->accept();
|
|
}
|
|
|
|
void GoToFlow::setFlowType(PictureFlow::FlowType flowType)
|
|
{
|
|
flow->setFlowType(flowType);
|
|
}
|
|
|
|
void GoToFlow::updateSize() //TODO : fix. it doesn't work.
|
|
{
|
|
imageSize = Configuration::getConfiguration().getGotoSlideSize();
|
|
flow->setSlideSize(imageSize);
|
|
resize(static_cast<int>(5*imageSize.width()),static_cast<int>(imageSize.height()*1.7));
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
//SlideInitializer
|
|
//-----------------------------------------------------------------------------
|
|
SlideInitializer::SlideInitializer(PictureFlow * flow,int slides)
|
|
:QThread(),_flow(flow),_slides(slides)
|
|
{
|
|
|
|
}
|
|
void SlideInitializer::run()
|
|
{
|
|
mutexGoToFlow.lock();
|
|
|
|
_flow->clear();
|
|
for(int i=0;i<_slides;i++)
|
|
_flow->addSlide(QImage());
|
|
_flow->setCenterIndex(0);
|
|
|
|
mutexGoToFlow.unlock();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
//PageLoader
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
PageLoader::PageLoader():
|
|
QThread(), restart(false), working(false), idx(-1)
|
|
{
|
|
}
|
|
|
|
PageLoader::~PageLoader()
|
|
{
|
|
mutexGoToFlow.lock();
|
|
condition.wakeOne();
|
|
mutexGoToFlow.unlock();
|
|
wait();
|
|
}
|
|
|
|
bool PageLoader::busy() const
|
|
{
|
|
return isRunning() ? working : false;
|
|
}
|
|
|
|
void PageLoader::generate(int index, QSize size,const QByteArray & rImage)
|
|
{
|
|
mutexGoToFlow.lock();
|
|
this->idx = index;
|
|
//this->img = QImage();
|
|
this->size = size;
|
|
this->rawImage = rImage;
|
|
mutexGoToFlow.unlock();
|
|
|
|
if (!isRunning())
|
|
start();
|
|
else
|
|
{
|
|
// already running, wake up whenever ready
|
|
restart = true;
|
|
condition.wakeOne();
|
|
}
|
|
}
|
|
|
|
void PageLoader::run()
|
|
{
|
|
for(;;)
|
|
{
|
|
// copy necessary data
|
|
mutexGoToFlow.lock();
|
|
this->working = true;
|
|
//int idx = this->idx;
|
|
|
|
|
|
QImage image;
|
|
image.loadFromData(this->rawImage);
|
|
// let everyone knows it is ready
|
|
image = image.scaled(this->size,Qt::KeepAspectRatio,Qt::SmoothTransformation);
|
|
|
|
mutexGoToFlow.unlock();
|
|
|
|
mutexGoToFlow.lock();
|
|
this->working = false;
|
|
this->img = image;
|
|
mutexGoToFlow.unlock();
|
|
|
|
// put to sleep
|
|
mutexGoToFlow.lock();
|
|
if (!this->restart)
|
|
condition.wait(&mutexGoToFlow);
|
|
restart = false;
|
|
mutexGoToFlow.unlock();
|
|
}
|
|
}
|