Corregido picture flow, ahora centerIndexChanged funciona igual que en la versi?n OpenGL.

Implementada la versi?n RC del borrado de c?mics.
This commit is contained in:
Luis Ángel San Martín 2013-06-14 17:04:13 +02:00
parent 7bacad6884
commit 04e56f1d03
13 changed files with 427 additions and 266 deletions

View File

@ -108,6 +108,7 @@ void GoToFlow::setNumSlides(unsigned int slides)
numImagesLoaded = 0;
connect(flow, SIGNAL(centerIndexChanged(int)), this, SLOT(preload()));
connect(flow, SIGNAL(centerIndexChangedSilent(int)), this, SLOT(preload()));
ready = true;
worker->reset();

View File

@ -75,7 +75,8 @@ HEADERS += comic_flow.h \
no_libraries_widget.h \
import_widget.h \
yacreader_local_server.h \
yacreader_main_toolbar.h
yacreader_main_toolbar.h \
comics_remover.h
SOURCES += comic_flow.cpp \
create_library_dialog.cpp \
@ -113,7 +114,8 @@ SOURCES += comic_flow.cpp \
no_libraries_widget.cpp \
import_widget.cpp \
yacreader_local_server.cpp \
yacreader_main_toolbar.cpp
yacreader_main_toolbar.cpp \
comics_remover.cpp
include(./server/server.pri)

View File

@ -1,220 +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()));
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)
#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;
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;
}

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

View 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

View File

@ -435,6 +435,33 @@ QModelIndex TableModel::getIndexFromId(quint64 id)
return index(i,0);
}
void TableModel::startTransaction(int first, int last)
{
beginRemoveRows(QModelIndex(),first,last);
dbTransaction = DataBaseManagement::loadDatabase(_databasePath);
dbTransaction.transaction();
}
void TableModel::finishTransaction()
{
dbTransaction.commit();
dbTransaction.close();
QSqlDatabase::removeDatabase(_databasePath);
endRemoveRows();
}
void TableModel::removeInTransaction(int row)
{
ComicDB c = DBHelper::loadComic(_data.at(row)->data(ID).toULongLong(),dbTransaction);
DBHelper::removeFromDB(&c,dbTransaction);
removeRow(row);
delete _data.at(row);
_data.removeAt(row);
}
void TableModel::remove(ComicDB * comic, int row)
{
beginRemoveRows(QModelIndex(),row,row);
@ -449,4 +476,14 @@ void TableModel::remove(ComicDB * comic, int row)
db.close();
QSqlDatabase::removeDatabase(_databasePath);
endRemoveRows();
}
ComicDB TableModel::getComic(int row)
{
return getComic(index(row,0));
}
void TableModel::remove(int row)
{
removeInTransaction(row);
}

View File

@ -21,6 +21,7 @@ public:
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,
@ -31,11 +32,12 @@ public:
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ón
ComicDB getComic(int row);
QVector<bool> getReadList();
QVector<bool> setAllComicsRead(bool read);
QList<ComicDB> getComics(QList<QModelIndex> list); //--> recupera la información común a los comics seleccionados
@ -46,6 +48,13 @@ public:
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(int first, int last);
void finishTransaction();
private:
void setupModelData( QSqlQuery &sqlquery);
ComicDB _getComic(const QModelIndex & mi);
@ -53,6 +62,8 @@ private:
QString _databasePath;
QSqlDatabase dbTransaction;
signals:
void beforeReset();
void reset();

View File

@ -50,11 +50,13 @@
#include "yacreader_titled_toolbar.h"
#include "yacreader_main_toolbar.h"
#include "comics_remover.h"
//#include "yacreader_social_dialog.h"
//
LibraryWindow::LibraryWindow()
:QMainWindow(),skip(0),fullscreen(false),fetching(false)
:QMainWindow(),fullscreen(false),fetching(false)
{
setupUI();
loadLibraries();
@ -882,7 +884,18 @@ void LibraryWindow::loadCovers(const QModelIndex & mi)
comicFlow->setMarks(dmCV->getReadList());
comicFlow->setFocus(Qt::OtherFocusReason);
if(paths.size()>0 && !importedCovers)
checkEmptyFolder(&paths);
if(paths.size()>0)
comicView->setCurrentIndex(dmCV->index(0,0));
}
void LibraryWindow::checkEmptyFolder(QStringList * paths)
{
if(paths == 0)
paths = &dmCV->getPaths(currentPath());
if(paths->size()>0 && !importedCovers)
{
openComicAction->setEnabled(true);
showPropertiesAction->setEnabled(true);
@ -896,6 +909,8 @@ void LibraryWindow::loadCovers(const QModelIndex & mi)
showHideMarksAction->setEnabled(true);
toggleFullScreenAction->setEnabled(true);
deleteComicsAction->setEnabled(true);
}
else
{
@ -911,9 +926,9 @@ void LibraryWindow::loadCovers(const QModelIndex & mi)
showHideMarksAction->setEnabled(false);
toggleFullScreenAction->setEnabled(false);
deleteComicsAction->setEnabled(false);
}
if(paths.size()>0)
comicView->setCurrentIndex(dmCV->index(0,0));
}
void LibraryWindow::reloadCovers()
@ -929,35 +944,15 @@ void LibraryWindow::reloadCovers()
void LibraryWindow::centerComicFlow(const QModelIndex & mi)
{
//TODO corregir el comportamiento de ComicFlowWidgetSW para evitar skip
if(typeid(comicFlow) == typeid(ComicFlowWidgetSW))
{
int distance = comicFlow->centerIndex()-mi.row();
if(abs(distance)>10)
{
if(distance<0)
comicFlow->setCenterIndex(comicFlow->centerIndex()+(-distance)-10);
else
comicFlow->setCenterIndex(comicFlow->centerIndex()-distance+10);
skip = 10;
}
else
skip = abs(comicFlow->centerIndex()-mi.row());
}
comicFlow->showSlide(mi.row());
comicFlow->setFocus(Qt::OtherFocusReason);
}
void LibraryWindow::updateComicView(int i)
{
if(skip==0)
{
QModelIndex mi = dmCV->index(i,2);
comicView->setCurrentIndex(mi);
comicView->scrollTo(mi,QAbstractItemView::EnsureVisible);
}
skip?(--skip):0;
}
void LibraryWindow::openComic()
@ -1450,22 +1445,36 @@ QModelIndexList LibraryWindow::getSelectedComics()
void LibraryWindow::deleteComics()
{
//TODO move this to another thread
QModelIndexList indexList = getSelectedComics();
int ret = QMessageBox::question(this,tr("Delete comics"),tr("All the selected comics will be deleted from your disk. Are you sure?"),QMessageBox::Yes,QMessageBox::No);
QString currentComicPath;
QListIterator<QModelIndex> i(indexList);
i.toBack();
while (i.hasPrevious())
if(ret == QMessageBox::Yes)
{
QModelIndex mi = i.previous();
ComicDB comic = dmCV->getComic(mi);
currentComicPath = currentPath() + comic.path;
if(QFile::remove(currentComicPath))
QModelIndexList indexList = getSelectedComics();
QList<ComicDB> comics = dmCV->getComics(indexList);
QList<QString> paths;
QString libraryPath = currentPath();
foreach(ComicDB comic, comics)
{
dmCV->remove(&comic,mi.row());
comicFlow->remove(mi.row());
paths.append(libraryPath + comic.path);
}
ComicsRemover * remover = new ComicsRemover(indexList,paths);
//comicView->showDeleteProgress();
dmCV->startTransaction(indexList.first().row(),indexList.last().row());
connect(remover, SIGNAL(remove(int)), dmCV, SLOT(remove(int)));
connect(remover, SIGNAL(remove(int)), comicFlow, SLOT(remove(int)));
connect(remover, SIGNAL(finished()), dmCV, SLOT(finishTransaction()));
//connect(remover, SIGNAL(finished()), comicView, SLOT(hideDeleteProgress()));
connect(remover, SIGNAL(finished()),this,SLOT(checkEmptyFolder()));
connect(remover, SIGNAL(finished()), remover, SLOT(deleteLater()));
//connect(remover, SIGNAL(finished()), thread, SLOT(deleteLater()));
remover->start();
}
}

View File

@ -102,7 +102,6 @@ private:
bool fetching;
int i;
unsigned int skip;
QAction * openComicAction;
QAction * showPropertiesAction;
@ -190,6 +189,7 @@ public:
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);

View File

@ -1092,8 +1092,7 @@ void PictureFlow::removeSlide(int index)
{
d->state->slideImages.remove(index);
d->state->marks.remove(index);
//TODO remove loaded flags
triggerRender();
setCenterIndex(index);
}
}
@ -1164,14 +1163,24 @@ void PictureFlow::showPrevious()
int center = d->state->centerIndex;
if(step > 0)
{
d->animator->start(center);
emit centerIndexChanged(center);
}
if(step == 0)
if(center > 0)
{
d->animator->start(center - 1);
emit centerIndexChanged(center - 1);
}
if(step < 0)
{
d->animator->target = qMax(0, center - 2);
emit centerIndexChanged(qMax(0, center - 2));
}
}
void PictureFlow::showNext()
@ -1179,15 +1188,27 @@ void PictureFlow::showNext()
int step = d->animator->step;
int center = d->state->centerIndex;
if(step < 0)
{
d->animator->start(center);
emit centerIndexChanged(center);
}
if(step == 0)
if(center < slideCount()-1)
{
d->animator->start(center + 1);
emit centerIndexChanged(center + 1);
}
if(step > 0)
{
d->animator->target = qMin(center + 2, slideCount()-1);
emit centerIndexChanged(qMin(center + 2, slideCount()-1));
}
}
void PictureFlow::showSlide(unsigned int index)
@ -1214,20 +1235,20 @@ void PictureFlow::keyPressEvent(QKeyEvent* event)
{
if(event->key() == Qt::Key_Left)
{
if(event->modifiers() == Qt::ControlModifier)
/*if(event->modifiers() == Qt::ControlModifier)
showSlide(centerIndex()-10);
else
showPrevious();
else*/
showPrevious();
event->accept();
return;
}
if(event->key() == Qt::Key_Right)
{
if(event->modifiers() == Qt::ControlModifier)
/*if(event->modifiers() == Qt::ControlModifier)
showSlide(centerIndex()+10);
else
showNext();
else*/
showNext();
event->accept();
return;
}
@ -1278,8 +1299,9 @@ void PictureFlow::updateAnimation() //bucle principal
frameSkiped = true;
}
if(d->state->centerIndex != old_center)
emit centerIndexChanged(d->state->centerIndex);
emit centerIndexChangedSilent(d->state->centerIndex);
if(d->animator->animating == true)
{
int difference = 10-now.elapsed();

View File

@ -204,6 +204,7 @@ public slots:
signals:
void centerIndexChanged(int index);
void centerIndexChangedSilent(int index);
public:
void paintEvent(QPaintEvent *event);

View File

@ -2,11 +2,12 @@
#include <QHeaderView>
#include <QResizeEvent>
#include <QPropertyAnimation>
#include "yacreader_deleting_progress.h"
YACReaderTableView::YACReaderTableView(QWidget *parent) :
QTableView(parent)
QTableView(parent),showDelete(false)
{
setAlternatingRowColors(true);
verticalHeader()->setAlternatingRowColors(true);
@ -36,24 +37,41 @@ YACReaderTableView::YACReaderTableView(QWidget *parent) :
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::ExtendedSelection);
deletingProgress = new YACReaderDeletingProgress(/*this*/);
/*deletingProgress = new YACReaderDeletingProgress(this);
showDeletingProgressAnimation = new QPropertyAnimation(deletingProgress,"pos");
showDeletingProgressAnimation->setDuration(150);*/
}
void YACReaderTableView::showDeleteProgress()
{
/*showDelete = true;
showDeletingProgressAnimation->setStartValue(deletingProgress->pos());
showDeletingProgressAnimation->setEndValue(QPoint((width()-deletingProgress->width())/2 ,1));
showDeletingProgressAnimation->start();*/
}
void YACReaderTableView::hideDeleteProgress()
{
/*showDelete = false;
if(showDeletingProgressAnimation->state()==QPropertyAnimation::Running)
showDeletingProgressAnimation->stop();
showDeletingProgressAnimation->setStartValue(deletingProgress->pos());
showDeletingProgressAnimation->setEndValue(QPoint((width()-deletingProgress->width())/2 ,-deletingProgress->height()));
showDeletingProgressAnimation->start();*/
}
void YACReaderTableView::resizeEvent(QResizeEvent * event)
{
event->size();
/*event->size();
deletingProgress->move((event->size().width()-deletingProgress->width())/2 ,1);
if(showDelete)
deletingProgress->move((event->size().width()-deletingProgress->width())/2 ,1);
else
deletingProgress->move((event->size().width()-deletingProgress->width())/2 ,-deletingProgress->height());*/
QTableView::resizeEvent(event);
}

View File

@ -5,6 +5,7 @@
class YACReaderDeletingProgress;
class QResizeEvent;
class QPropertyAnimation;
class YACReaderTableView : public QTableView
{
@ -20,6 +21,8 @@ public slots:
private:
YACReaderDeletingProgress * deletingProgress;
bool showDelete;
QPropertyAnimation * showDeletingProgressAnimation;
void resizeEvent(QResizeEvent * event);
};