Move source files to src directory
This commit is contained in:
@@ -0,0 +1,607 @@
|
||||
#include "imageringlist.h"
|
||||
#include <functional>
|
||||
#include <QThreadPool>
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
#include <QRegularExpression>
|
||||
#include "loadrunable.h"
|
||||
#include "rawimage.h"
|
||||
#include "database.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int DEFAULT_WIDTH = 2;
|
||||
|
||||
Image::Image(const QString name, int number, ImageRingList *ringList) :
|
||||
m_loading(false),
|
||||
m_released(true),
|
||||
m_current(false),
|
||||
m_number(number),
|
||||
m_name(name),
|
||||
m_ringList(ringList)
|
||||
{
|
||||
}
|
||||
|
||||
void Image::load(int index, QThreadPool *pool)
|
||||
{
|
||||
if(index != m_info.index && !m_loading)
|
||||
m_rawImage.reset();
|
||||
|
||||
if(!m_rawImage && !m_loading)
|
||||
{
|
||||
m_loading = true;
|
||||
m_released = false;
|
||||
pool->start(new LoadRunable(m_name, this, m_ringList->analyzeLevel(), index));
|
||||
}
|
||||
if(!m_loading && m_rawImage)
|
||||
emit pixmapLoaded(this);
|
||||
}
|
||||
|
||||
void Image::loadThumbnail(QThreadPool *pool)
|
||||
{
|
||||
if(!m_thumbnail)
|
||||
pool->start(new LoadRunable(m_name, this, AnalyzeLevel::None, 0, true));
|
||||
else
|
||||
emit thumbnailLoaded(this);
|
||||
}
|
||||
|
||||
void Image::release()
|
||||
{
|
||||
m_rawImage.reset();
|
||||
m_released = true;
|
||||
m_loading = false;
|
||||
}
|
||||
|
||||
QString Image::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::shared_ptr<RawImage> Image::rawImage()
|
||||
{
|
||||
return m_rawImage;
|
||||
}
|
||||
|
||||
const RawImage *Image::thumbnail() const
|
||||
{
|
||||
return m_thumbnail.get();
|
||||
}
|
||||
|
||||
ImageInfoData Image::info() const
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
bool Image::isCurrent() const
|
||||
{
|
||||
return !m_released;
|
||||
}
|
||||
|
||||
int Image::number() const
|
||||
{
|
||||
return m_number;
|
||||
}
|
||||
|
||||
void Image::clearThumbnail()
|
||||
{
|
||||
m_thumbnail.reset();
|
||||
}
|
||||
|
||||
bool Image::isLoading() const
|
||||
{
|
||||
return m_loading;
|
||||
}
|
||||
|
||||
void Image::imageLoaded(std::shared_ptr<RawImage> rawImage, ImageInfoData info)
|
||||
{
|
||||
m_loading = false;
|
||||
if(!m_released)
|
||||
{
|
||||
m_rawImage = rawImage;
|
||||
m_info = info;
|
||||
emit pixmapLoaded(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Image::thumbnailLoadFinish(std::shared_ptr<RawImage> rawImage)
|
||||
{
|
||||
m_thumbnail = rawImage;
|
||||
if(m_thumbnail)
|
||||
emit thumbnailLoaded(this);
|
||||
}
|
||||
|
||||
ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractItemModel(parent)
|
||||
, m_liveMode(false)
|
||||
, m_analyzeLevel(None)
|
||||
, m_database(database)
|
||||
, m_nameFilter(nameFilter)
|
||||
, m_fileSuffix(nameFilter)
|
||||
{
|
||||
connect(&m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &ImageRingList::dirChanged);
|
||||
m_nameFilter.replaceInStrings(QRegularExpression("^"), "*.");
|
||||
m_loadPool = new QThreadPool(this);
|
||||
m_loadPool->setThreadPriority(QThread::LowPriority);
|
||||
m_thumbPool = new QThreadPool(this);
|
||||
m_thumbPool->setThreadPriority(QThread::LowPriority);
|
||||
|
||||
m_slideShowTimer = new QTimer(this);
|
||||
connect(m_slideShowTimer, &QTimer::timeout, this, static_cast<void (ImageRingList::*)()>(&ImageRingList::increment));
|
||||
|
||||
m_dirChangeDelay = new QTimer(this);
|
||||
m_dirChangeDelay->setInterval(3000);
|
||||
m_dirChangeDelay->setSingleShot(true);
|
||||
connect(m_dirChangeDelay, &QTimer::timeout, this, &ImageRingList::reloadDir);
|
||||
}
|
||||
|
||||
ImageRingList::~ImageRingList()
|
||||
{
|
||||
m_loadPool->clear();
|
||||
m_thumbPool->clear();
|
||||
|
||||
m_loadPool->waitForDone();
|
||||
m_thumbPool->waitForDone();
|
||||
}
|
||||
|
||||
bool ImageRingList::setDir(const QString path, const QString ¤tFile, bool recursive)
|
||||
{
|
||||
QDir dir(path);
|
||||
|
||||
if(dir.exists())
|
||||
{
|
||||
m_currentDir = path;
|
||||
QStringList scannedDirs;
|
||||
QStringList absolutePaths;
|
||||
std::function<void(const QString&)> scanDir = [&](const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
if(scannedDirs.contains(dir.canonicalPath()))return;
|
||||
scannedDirs.append(dir.canonicalPath());
|
||||
QDir::SortFlags sortFlags = m_liveMode ? QDir::Time : m_sort | QDir::IgnoreCase;
|
||||
if(m_reversed)sortFlags |= QDir::Reversed;
|
||||
|
||||
if(recursive)
|
||||
{
|
||||
QStringList dirs = dir.entryList(QDir::Readable | QDir::Dirs | QDir::NoDotAndDotDot, sortFlags);
|
||||
for(const QString &subdir : dirs)
|
||||
scanDir(dir.absoluteFilePath(subdir));
|
||||
}
|
||||
|
||||
QStringList list = dir.entryList(m_nameFilter, QDir::Files | QDir::Readable, sortFlags);
|
||||
for(const QString &file : list)
|
||||
{
|
||||
absolutePaths.append(dir.absoluteFilePath(file));
|
||||
}
|
||||
};
|
||||
|
||||
scanDir(path);
|
||||
//qDebug() << absolutePaths.size();
|
||||
setFilesPrivate(absolutePaths, m_liveMode ? absolutePaths.first() : currentFile);
|
||||
|
||||
if(m_fileSystemWatcher.directories().size())
|
||||
m_fileSystemWatcher.removePaths(m_fileSystemWatcher.directories());
|
||||
m_fileSystemWatcher.addPath(path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImageRingList::setFile(const QString &file)
|
||||
{
|
||||
if(!file.isEmpty())
|
||||
{
|
||||
QFileInfo info(file);
|
||||
if(info.isDir())
|
||||
setDir(file, QString(), true);
|
||||
else
|
||||
setDir(info.absolutePath(), file);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::setFiles(QStringList files)
|
||||
{
|
||||
QRegularExpression reg("(" + m_fileSuffix.join("|") + ")");
|
||||
files.removeIf([®](const QString &file){
|
||||
QFileInfo info(file);
|
||||
auto match = reg.match(info.suffix());
|
||||
return !match.hasMatch() || !info.exists() || !info.isReadable() || !info.isFile();
|
||||
});
|
||||
setFilesPrivate(files);
|
||||
}
|
||||
|
||||
ImagePtr ImageRingList::currentImage()
|
||||
{
|
||||
if(m_images.size())
|
||||
return *m_currImage;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString ImageRingList::currentDir() const
|
||||
{
|
||||
return m_currentDir;
|
||||
}
|
||||
|
||||
void ImageRingList::increment()
|
||||
{
|
||||
if(m_images.size())
|
||||
{
|
||||
//don't increment if current image was not loaded yet
|
||||
if((*m_currImage)->isLoading())
|
||||
return;
|
||||
|
||||
(*m_firstImage)->release();
|
||||
m_firstImage = increment(m_firstImage);
|
||||
m_currImage = increment(m_currImage);
|
||||
(*m_currImage)->load(0, m_loadPool);
|
||||
m_lastImage = increment(m_lastImage);
|
||||
(*m_lastImage)->load(0, m_loadPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::decrement()
|
||||
{
|
||||
if(m_images.size())
|
||||
{
|
||||
//don't decrement if current image was not loaded yet
|
||||
if((*m_currImage)->isLoading())
|
||||
return;
|
||||
|
||||
(*m_lastImage)->release();
|
||||
m_firstImage = decrement(m_firstImage);
|
||||
m_currImage = decrement(m_currImage);
|
||||
(*m_currImage)->load(0, m_loadPool);
|
||||
m_lastImage = decrement(m_lastImage);
|
||||
(*m_firstImage)->load(0, m_loadPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::prevSubImage()
|
||||
{
|
||||
if(m_images.size())
|
||||
{
|
||||
if((*m_currImage)->isLoading())
|
||||
return;
|
||||
|
||||
int index = (*m_currImage)->info().index;
|
||||
int num = (*m_currImage)->info().num;
|
||||
if(num > 1)
|
||||
(*m_currImage)->load(index == 0 ? num - 1 : index - 1, m_loadPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::nextSubImage()
|
||||
{
|
||||
if(m_images.size())
|
||||
{
|
||||
if((*m_currImage)->isLoading())
|
||||
return;
|
||||
|
||||
int index = (*m_currImage)->info().index;
|
||||
int num = (*m_currImage)->info().num;
|
||||
if(num > 1)
|
||||
(*m_currImage)->load((index + 1) % num, m_loadPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::setMarked()
|
||||
{
|
||||
QStringList files = m_database->getMarkedFiles();
|
||||
files.removeIf([](const QString &file){
|
||||
QFileInfo info(file);
|
||||
return !info.exists() || !info.isReadable();
|
||||
});
|
||||
setFilesPrivate(files);
|
||||
}
|
||||
|
||||
void ImageRingList::reloadImage()
|
||||
{
|
||||
if(*m_currImage)
|
||||
{
|
||||
int index = (*m_currImage)->info().index;
|
||||
(*m_currImage)->release();
|
||||
(*m_currImage)->load(index, m_loadPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::setLiveMode(bool live)
|
||||
{
|
||||
m_liveMode = live;
|
||||
}
|
||||
|
||||
void ImageRingList::setCalculateStats(bool stats)
|
||||
{
|
||||
m_analyzeLevel = stats ? Statistics : None;
|
||||
}
|
||||
|
||||
void ImageRingList::setFindPeaks(bool findPeaks)
|
||||
{
|
||||
m_analyzeLevel = findPeaks ? Peaks : None;
|
||||
}
|
||||
|
||||
void ImageRingList::setFindStars(bool findStars)
|
||||
{
|
||||
m_analyzeLevel = findStars ? Stars : None;
|
||||
}
|
||||
|
||||
AnalyzeLevel ImageRingList::analyzeLevel() const
|
||||
{
|
||||
return m_analyzeLevel;
|
||||
}
|
||||
|
||||
void ImageRingList::loadFile(int row)
|
||||
{
|
||||
if(row < m_images.size())
|
||||
{
|
||||
int diff = m_currImage != m_images.end() ? row - (m_currImage - m_images.begin()) : -100;
|
||||
if(diff == 1)
|
||||
increment();
|
||||
else if(diff == -1)
|
||||
decrement();
|
||||
else
|
||||
{
|
||||
m_firstImage = m_currImage = m_lastImage = m_images.begin()+row;
|
||||
if(m_images.empty())
|
||||
return;
|
||||
|
||||
(*m_currImage)->load(0, m_loadPool);
|
||||
|
||||
m_width = DEFAULT_WIDTH<m_images.size()/2 ? DEFAULT_WIDTH : m_images.size()/2;
|
||||
if(m_liveMode)
|
||||
m_width = 0;
|
||||
|
||||
for(int i=0; i<m_width; i++)
|
||||
{
|
||||
m_firstImage = decrement(m_firstImage);
|
||||
(*m_firstImage)->load(0, m_loadPool);
|
||||
m_lastImage = increment(m_lastImage);
|
||||
(*m_lastImage)->load(0, m_loadPool);
|
||||
}
|
||||
if(m_lastImage != m_firstImage)
|
||||
{
|
||||
QList<ImagePtr>::iterator iter = increment(m_lastImage);
|
||||
while(m_firstImage != iter)
|
||||
{
|
||||
(*iter)->release();
|
||||
iter = increment(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::loadThumbnails()
|
||||
{
|
||||
for(auto &img : m_images)
|
||||
{
|
||||
img->loadThumbnail(m_thumbPool);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::stopLoading()
|
||||
{
|
||||
m_thumbPool->clear();
|
||||
m_thumbPool->waitForDone();
|
||||
}
|
||||
|
||||
int ImageRingList::imageCount() const
|
||||
{
|
||||
return m_images.size();
|
||||
}
|
||||
|
||||
QStringList ImageRingList::imageNames() const
|
||||
{
|
||||
QStringList ret;
|
||||
for(auto &img : m_images)
|
||||
ret.push_back(img->name());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ImageRingList::updateMark()
|
||||
{
|
||||
if(m_images.size())
|
||||
{
|
||||
QModelIndex idx = index(m_currImage - m_images.begin(), 0);
|
||||
emit dataChanged(idx, idx, {Qt::FontRole});
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::clearThumbnails()
|
||||
{
|
||||
for(auto &img : m_images)
|
||||
img->clearThumbnail();
|
||||
}
|
||||
|
||||
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return createIndex(row, column, m_images.at(row).get());
|
||||
}
|
||||
|
||||
QModelIndex ImageRingList::parent(const QModelIndex &child) const
|
||||
{
|
||||
Q_UNUSED(child);
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int ImageRingList::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(parent == QModelIndex())
|
||||
return m_images.size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImageRingList::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant ImageRingList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
QFileInfo info(m_images.at(index.row())->name());
|
||||
return info.fileName();
|
||||
}
|
||||
case Qt::FontRole:
|
||||
{
|
||||
bool marked = m_database->isMarked(m_images.at(index.row())->name());
|
||||
QFont font;
|
||||
font.setBold(marked);
|
||||
return font;
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ImageRingList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(section==0 && orientation==Qt::Horizontal && role==Qt::DisplayRole)
|
||||
{
|
||||
return tr("Name");
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ImageRingList::setPreload(int width)
|
||||
{
|
||||
DEFAULT_WIDTH = width;
|
||||
if(m_images.size() == 0)return;
|
||||
|
||||
int newWidth = DEFAULT_WIDTH<m_images.size()/2 ? DEFAULT_WIDTH : m_images.size()/2;
|
||||
if(newWidth > m_width)
|
||||
{
|
||||
for(int i = newWidth - m_width; i>0; i--)
|
||||
{
|
||||
m_firstImage = decrement(m_firstImage);
|
||||
(*m_firstImage)->load(0, m_loadPool);
|
||||
m_lastImage = increment(m_lastImage);
|
||||
(*m_lastImage)->load(0, m_loadPool);
|
||||
}
|
||||
}
|
||||
if(newWidth < m_width)
|
||||
{
|
||||
for(int i = m_width - newWidth; i>0; i--)
|
||||
{
|
||||
(*m_firstImage)->release();
|
||||
m_firstImage = increment(m_firstImage);
|
||||
(*m_lastImage)->release();
|
||||
m_lastImage = decrement(m_lastImage);
|
||||
}
|
||||
}
|
||||
m_width = newWidth;
|
||||
}
|
||||
|
||||
void ImageRingList::setSort(QDir::SortFlag sort)
|
||||
{
|
||||
if(m_sort != sort)
|
||||
{
|
||||
m_sort = sort;
|
||||
if(m_images.size())
|
||||
{
|
||||
QString path = (*m_currImage)->name();
|
||||
setFile(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::reverseSort()
|
||||
{
|
||||
m_reversed = !m_reversed;
|
||||
if(m_images.size())
|
||||
{
|
||||
QString path = (*m_currImage)->name();
|
||||
setFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::toggleSlideshow(bool start)
|
||||
{
|
||||
if(start)
|
||||
{
|
||||
QSettings settings;
|
||||
int time = settings.value("settings/slideshowtime", 1.0).toDouble() * 1000;
|
||||
m_slideShowTimer->start(time);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_slideShowTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::setFilesPrivate(const QStringList files, const QString ¤tFile)
|
||||
{
|
||||
m_loadPool->clear();
|
||||
m_thumbPool->clear();
|
||||
m_loadPool->waitForDone();
|
||||
m_thumbPool->waitForDone();
|
||||
beginResetModel();
|
||||
m_images.clear();
|
||||
int i = 0;
|
||||
for(const QString &file : files)
|
||||
{
|
||||
ImagePtr ptr = make_shared<Image>(file, i++, this);
|
||||
connect(ptr.get(), &Image::pixmapLoaded, this, &ImageRingList::imageLoaded);
|
||||
connect(ptr.get(), &Image::thumbnailLoaded, this, &ImageRingList::thumbnailLoaded);
|
||||
m_images.append(ptr);
|
||||
}
|
||||
|
||||
int index = files.indexOf(currentFile);
|
||||
if(index < 0)
|
||||
index = 0;
|
||||
|
||||
endResetModel();
|
||||
m_currImage = m_images.end();
|
||||
loadFile(index);
|
||||
}
|
||||
|
||||
QList<ImagePtr>::iterator ImageRingList::increment(QList<ImagePtr>::iterator iter)
|
||||
{
|
||||
iter++;
|
||||
if(iter == m_images.end())
|
||||
iter = m_images.begin();
|
||||
return iter;
|
||||
}
|
||||
|
||||
QList<ImagePtr>::iterator ImageRingList::decrement(QList<ImagePtr>::iterator iter)
|
||||
{
|
||||
if(iter == m_images.begin())
|
||||
iter = m_images.end();
|
||||
iter--;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void ImageRingList::imageLoaded(Image *image)
|
||||
{
|
||||
if(image->name() == (*m_currImage)->name())
|
||||
{
|
||||
emit pixmapLoaded(image);
|
||||
emit infoLoaded(image->info());
|
||||
emit currentImageChanged(m_currImage-m_images.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void ImageRingList::dirChanged(QString)
|
||||
{
|
||||
if(m_liveMode)
|
||||
reloadDir();
|
||||
else
|
||||
m_dirChangeDelay->start();
|
||||
}
|
||||
|
||||
void ImageRingList::reloadDir()
|
||||
{
|
||||
QString currentFile;
|
||||
|
||||
if(m_images.size())
|
||||
currentFile = (*m_currImage)->name();
|
||||
|
||||
setDir(m_currentDir, currentFile);
|
||||
if(m_images.size())
|
||||
emit currentImageChanged(m_currImage-m_images.begin());
|
||||
}
|
||||
Reference in New Issue
Block a user