yacreader/YACReader/goto_flow.cpp
Luis Ángel San Martín 9dfa9c5f62 Modificaciones en pictureflow/goto_flow y comic_flow que aumentan la fuidez
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
2012-05-27 22:32:46 +02:00

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();
}
}