other thread loads local images

This commit is contained in:
John Preston 2015-09-29 21:44:31 +03:00
parent d90f021e46
commit 58de461c19
9 changed files with 437 additions and 102 deletions

View file

@ -1538,6 +1538,7 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact()));
connect(&_newGroup, SIGNAL(clicked()), this, SLOT(onNewGroup()));
connect(&_cancelSearch, SIGNAL(clicked()), this, SLOT(onCancelSearch()));
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
_chooseByDragTimer.setSingleShot(true);
connect(&_chooseByDragTimer, SIGNAL(timeout()), this, SLOT(onChooseByDrag()));

View file

@ -607,17 +607,12 @@ int32 StorageImage::height() const {
bool StorageImage::check() const {
if (loader->done()) {
switch (loader->fileType()) {
case mtpc_storage_fileGif: format = "GIF"; break;
case mtpc_storage_fileJpeg: format = "JPG"; break;
case mtpc_storage_filePng: format = "PNG"; break;
default: format = QByteArray(); break;
}
if (!data.isNull()) {
globalAquiredSize -= int64(data.width()) * data.height() * 4;
}
format = loader->imageFormat();
data = loader->imagePixmap();
QByteArray bytes = loader->bytes();
data = QPixmap::fromImage(App::readImage(bytes, &format, false), Qt::ColorOnly);
if (!data.isNull()) {
globalAquiredSize += int64(data.width()) * data.height() * 4;
}

View file

@ -158,55 +158,6 @@ inline StorageKey storageKey(const StorageImageLocation &location) {
return storageKey(location.dc, location.volume, location.local);
}
enum StorageFileType {
StorageFileUnknown = 0xaa963b05, // mtpc_storage_fileUnknown
StorageFileJpeg = 0x7efe0e, // mtpc_storage_fileJpeg
StorageFileGif = 0xcae1aadf, // mtpc_storage_fileGif
StorageFilePng = 0xa4f63c0, // mtpc_storage_filePng
StorageFilePdf = 0xae1e508d, // mtpc_storage_filePdf
StorageFileMp3 = 0x528a0677, // mtpc_storage_fileMp3
StorageFileMov = 0x4b09ebbc, // mtpc_storage_fileMov
StorageFilePartial = 0x40bc6f52, // mtpc_storage_filePartial
StorageFileMp4 = 0xb3cea0e4, // mtpc_storage_fileMp4
StorageFileWebp = 0x1081464c, // mtpc_storage_fileWebp
};
inline StorageFileType mtpToStorageType(mtpTypeId type) {
switch (type) {
case mtpc_storage_fileJpeg: return StorageFileJpeg;
case mtpc_storage_fileGif: return StorageFileGif;
case mtpc_storage_filePng: return StorageFilePng;
case mtpc_storage_filePdf: return StorageFilePdf;
case mtpc_storage_fileMp3: return StorageFileMp3;
case mtpc_storage_fileMov: return StorageFileMov;
case mtpc_storage_filePartial: return StorageFilePartial;
case mtpc_storage_fileMp4: return StorageFileMp4;
case mtpc_storage_fileWebp: return StorageFileWebp;
case mtpc_storage_fileUnknown:
default: return StorageFileUnknown;
}
}
inline mtpTypeId mtpFromStorageType(StorageFileType type) {
switch (type) {
case StorageFileGif: return mtpc_storage_fileGif;
case StorageFilePng: return mtpc_storage_filePng;
case StorageFilePdf: return mtpc_storage_filePdf;
case StorageFileMp3: return mtpc_storage_fileMp3;
case StorageFileMov: return mtpc_storage_fileMov;
case StorageFilePartial: return mtpc_storage_filePartial;
case StorageFileMp4: return mtpc_storage_fileMp4;
case StorageFileWebp: return mtpc_storage_fileWebp;
case StorageFileUnknown:
default: return mtpc_storage_fileUnknown;
}
}
struct StorageImageSaved {
StorageImageSaved() : type(StorageFileUnknown) {
}
StorageImageSaved(StorageFileType type, const QByteArray &data) : type(type), data(data) {
}
StorageFileType type;
QByteArray data;
};
class StorageImage : public Image {
public:

View file

@ -21,9 +21,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "audio.h"
#include <libexif/exif-data.h>
LocalImageLoaderPrivate::LocalImageLoaderPrivate(int32 currentUser, LocalImageLoader *loader, QThread *thread) : QObject(0)
LocalImageLoaderPrivate::LocalImageLoaderPrivate(LocalImageLoader *loader, QThread *thread) : QObject(0)
, loader(loader)
, user(currentUser)
{
moveToThread(thread);
connect(loader, SIGNAL(needToPrepare()), this, SLOT(prepareImages()));
@ -295,7 +294,7 @@ void LocalImageLoader::append(const QStringList &files, const PeerId &peer, bool
}
if (!thread) {
thread = new QThread();
priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread);
priv = new LocalImageLoaderPrivate(this, thread);
thread->start();
}
emit needToPrepare();
@ -310,7 +309,7 @@ PhotoId LocalImageLoader::append(const QByteArray &img, const PeerId &peer, bool
}
if (!thread) {
thread = new QThread();
priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread);
priv = new LocalImageLoaderPrivate(this, thread);
thread->start();
}
emit needToPrepare();
@ -326,7 +325,7 @@ AudioId LocalImageLoader::append(const QByteArray &audio, int32 duration, const
}
if (!thread) {
thread = new QThread();
priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread);
priv = new LocalImageLoaderPrivate(this, thread);
thread->start();
}
emit needToPrepare();
@ -342,7 +341,7 @@ PhotoId LocalImageLoader::append(const QImage &img, const PeerId &peer, bool bro
}
if (!thread) {
thread = new QThread();
priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread);
priv = new LocalImageLoaderPrivate(this, thread);
thread->start();
}
emit needToPrepare();
@ -358,7 +357,7 @@ PhotoId LocalImageLoader::append(const QString &file, const PeerId &peer, bool b
}
if (!thread) {
thread = new QThread();
priv = new LocalImageLoaderPrivate(MTP::authedId(), this, thread);
priv = new LocalImageLoaderPrivate(this, thread);
thread->start();
}
emit needToPrepare();
@ -413,3 +412,122 @@ LocalImageLoader::~LocalImageLoader() {
delete priv;
delete thread;
}
TaskQueue::TaskQueue(QObject *parent, int32 stopTimeoutMs) : QObject(parent), _worker(0), _thread(0), _stopTimer(0) {
if (stopTimeoutMs > 0) {
_stopTimer = new QTimer(this);
connect(_stopTimer, SIGNAL(timeout()), this, SLOT(stop()));
_stopTimer->setSingleShot(true);
_stopTimer->setInterval(stopTimeoutMs);
}
}
TaskId TaskQueue::addTask(TaskPtr task) {
{
QMutexLocker lock(&_tasksToProcessMutex);
_tasksToProcess.push_back(task);
}
if (!_thread) {
_thread = new QThread();
_worker = new TaskQueueWorker(this);
_worker->moveToThread(_thread);
connect(this, SIGNAL(taskAdded()), _worker, SLOT(onTaskAdded()));
connect(_worker, SIGNAL(taskProcessed()), this, SLOT(onTaskProcessed()));
_thread->start();
}
if (_stopTimer) _stopTimer->stop();
emit taskAdded();
return task->id();
}
void TaskQueue::cancelTask(TaskId id) {
QMutexLocker lock(&_tasksToProcessMutex);
for (int32 i = 0, l = _tasksToProcess.size(); i < l; ++i) {
if (_tasksToProcess.at(i)->id() == id) {
_tasksToProcess.removeAt(i);
break;
}
}
}
void TaskQueue::onTaskProcessed() {
do {
TaskPtr task;
{
QMutexLocker lock(&_tasksToFinishMutex);
if (_tasksToFinish.isEmpty()) break;
task = _tasksToFinish.front();
_tasksToFinish.pop_front();
}
task->finish();
} while (true);
if (_stopTimer) {
QMutexLocker lock(&_tasksToProcessMutex);
if (_tasksToProcess.isEmpty()) {
_stopTimer->start();
}
}
}
void TaskQueue::stop() {
if (_thread) {
_thread->requestInterruption();
_thread->quit();
_thread->wait();
delete _worker;
delete _thread;
_worker = 0;
_thread = 0;
}
_tasksToProcess.clear();
_tasksToFinish.clear();
}
TaskQueue::~TaskQueue() {
stop();
delete _stopTimer;
}
void TaskQueueWorker::onTaskAdded() {
if (_inTaskAdded) return;
_inTaskAdded = true;
bool someTasksLeft = false;
do {
TaskPtr task;
{
QMutexLocker lock(&_queue->_tasksToProcessMutex);
if (!_queue->_tasksToProcess.isEmpty()) {
task = _queue->_tasksToProcess.front();
}
}
if (task) {
task->process();
bool emitTaskProcessed = false;
{
QMutexLocker lockToProcess(&_queue->_tasksToProcessMutex);
if (!_queue->_tasksToProcess.isEmpty() && _queue->_tasksToProcess.front() == task) {
_queue->_tasksToProcess.pop_front();
someTasksLeft = !_queue->_tasksToProcess.isEmpty();
QMutexLocker lockToFinish(&_queue->_tasksToFinishMutex);
emitTaskProcessed = _queue->_tasksToFinish.isEmpty();
_queue->_tasksToFinish.push_back(task);
}
}
if (emitTaskProcessed) {
emit taskProcessed();
}
}
QCoreApplication::processEvents();
} while (someTasksLeft && !thread()->isInterruptionRequested());
_inTaskAdded = false;
}

View file

@ -87,7 +87,7 @@ class LocalImageLoaderPrivate : public QObject {
public:
LocalImageLoaderPrivate(int32 currentUser, LocalImageLoader *loader, QThread *thread);
LocalImageLoaderPrivate(LocalImageLoader *loader, QThread *thread);
~LocalImageLoaderPrivate();
public slots:
@ -102,7 +102,6 @@ signals:
private:
LocalImageLoader *loader;
int32 user;
};
@ -146,3 +145,76 @@ private:
LocalImageLoaderPrivate *priv;
};
class Task {
public:
virtual void process() = 0; // is executed in a separate thread
virtual void finish() = 0; // is executed in the same as TaskQueue thread
TaskId id() const {
return TaskId(this);
}
};
typedef QSharedPointer<Task> TaskPtr;
class TaskQueue : public QObject {
Q_OBJECT
public:
TaskQueue(QObject *parent, int32 stopTimeoutMs = 0); // <= 0 - never stop worker
TaskId addTask(TaskPtr task);
void cancelTask(TaskId id); // this task finish() won't be called
template <typename DerivedTask>
TaskId addTask(DerivedTask *task) {
return addTask(TaskPtr(task));
}
~TaskQueue();
signals:
void taskAdded();
public slots:
void onTaskProcessed();
void stop();
private:
typedef QList<TaskPtr> Tasks;
friend class TaskQueueWorker;
Tasks _tasksToProcess, _tasksToFinish;
QMutex _tasksToProcessMutex, _tasksToFinishMutex;
QThread *_thread;
TaskQueueWorker *_worker;
QTimer *_stopTimer;
};
class TaskQueueWorker : public QObject {
Q_OBJECT
public:
TaskQueueWorker(TaskQueue *queue) : _queue(queue), _inTaskAdded(false) {
}
signals:
void taskProcessed();
public slots:
void onTaskAdded();
private:
TaskQueue *_queue;
bool _inTaskAdded;
};

View file

@ -70,6 +70,7 @@ namespace {
bool _started = false;
_local_inner::Manager *_manager = 0;
TaskQueue *_localLoader = 0;
bool _working() {
return _manager && !_basePath.isEmpty();
@ -1823,6 +1824,7 @@ namespace Local {
if (!_started) {
_started = true;
_manager = new _local_inner::Manager();
_localLoader = new TaskQueue(0, 5000);
}
}
@ -1832,6 +1834,8 @@ namespace Local {
_manager->finish();
_manager->deleteLater();
_manager = 0;
delete _localLoader;
_localLoader = 0;
}
}
@ -2001,6 +2005,9 @@ namespace Local {
}
void reset() {
if (_localLoader) {
_localLoader->stop();
}
_passKeySalt.clear(); // reset passcode, local key
_draftsMap.clear();
_draftsPositionsMap.clear();
@ -2272,12 +2279,75 @@ namespace Local {
}
}
bool startImageLoad(const StorageKey &location) {
StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend()) {
return false;
class ImageLoadTask : public Task {
public:
ImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) :
_key(key), _location(location), _loader(loader), _result(0) {
}
return true;
void process() {
FileReadDescriptor image;
if (!readEncryptedFile(image, _key, UserPath)) {
return;
}
QByteArray imageData;
quint64 locFirst, locSecond;
quint32 imageType;
image.stream >> locFirst >> locSecond >> imageType >> imageData;
if (locFirst != _location.first || locSecond != _location.second) {
return;
}
_result = new Result(StorageFileType(imageType), imageData);
}
void finish() {
if (_result) {
_loader->localLoaded(_result->image, _result->format, _result->pixmap);
} else {
StorageMap::iterator j = _imagesMap.find(_location);
if (j != _imagesMap.cend() && j->first == _key) {
clearKey(_key, UserPath);
_storageImagesSize -= j->second;
_imagesMap.erase(j);
}
_loader->localLoaded(StorageImageSaved());
}
}
private:
FileKey _key;
StorageKey _location;
struct Result {
Result(StorageFileType type, const QByteArray &data) : image(type, data) {
QByteArray guessFormat;
switch (type) {
case mtpc_storage_fileGif: guessFormat = "GIF"; break;
case mtpc_storage_fileJpeg: guessFormat = "JPG"; break;
case mtpc_storage_filePng: guessFormat = "PNG"; break;
default: guessFormat = QByteArray(); break;
}
pixmap = QPixmap::fromImage(App::readImage(data, &guessFormat, false), Qt::ColorOnly);
if (!pixmap.isNull()) {
format = guessFormat;
}
}
StorageImageSaved image;
QByteArray format;
QPixmap pixmap;
};
mtpFileLoader *_loader;
Result *_result;
};
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend() || !_localLoader) {
return 0;
}
return _localLoader->addTask(new ImageLoadTask(j->first, location, loader));
}
StorageImageSaved readImage(const StorageKey &location) {
@ -2285,8 +2355,8 @@ namespace Local {
if (j == _imagesMap.cend()) {
return StorageImageSaved();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value().first, UserPath)) {
FileReadDescriptor image;
if (!readEncryptedFile(image, j.value().first, UserPath)) {
clearKey(j.value().first, UserPath);
_storageImagesSize -= j.value().second;
_imagesMap.erase(j);
@ -2296,7 +2366,7 @@ namespace Local {
QByteArray imageData;
quint64 locFirst, locSecond;
quint32 imageType;
draft.stream >> locFirst >> locSecond >> imageType >> imageData;
image.stream >> locFirst >> locSecond >> imageType >> imageData;
return (locFirst == location.first && locSecond == location.second) ? StorageImageSaved(StorageFileType(imageType), imageData) : StorageImageSaved();
}
@ -2333,12 +2403,12 @@ namespace Local {
}
}
bool startStickerImageLoad(const StorageKey &location) {
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _stickerImagesMap.find(location);
if (j == _stickerImagesMap.cend()) {
return false;
return 0;
}
return true;
return 0;
}
QByteArray readStickerImage(const StorageKey &location) {
@ -2393,12 +2463,12 @@ namespace Local {
}
}
bool startAudioLoad(const StorageKey &location) {
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) {
return false;
return 0;
}
return true;
return 0;
}
QByteArray readAudio(const StorageKey &location) {
@ -2429,6 +2499,12 @@ namespace Local {
return _storageAudiosSize;
}
void cancelTask(TaskId id) {
if (_localLoader) {
_localLoader->cancelTask(id);
}
}
void _writeStorageImageLocation(QDataStream &stream, const StorageImageLocation &loc) {
stream << qint32(loc.width) << qint32(loc.height);
stream << qint32(loc.dc) << quint64(loc.volume) << qint32(loc.local) << quint64(loc.secret);

View file

@ -120,23 +120,25 @@ namespace Local {
void writeImage(const StorageKey &location, const ImagePtr &img);
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
bool startImageLoad(const StorageKey &location);
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader);
StorageImageSaved readImage(const StorageKey &location);
int32 hasImages();
qint64 storageImagesSize();
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
bool startStickerImageLoad(const StorageKey &location);
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader);
QByteArray readStickerImage(const StorageKey &location);
int32 hasStickers();
qint64 storageStickersSize();
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
bool startAudioLoad(const StorageKey &location);
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader);
QByteArray readAudio(const StorageKey &location);
int32 hasAudios();
qint64 storageAudiosSize();
void cancelTask(TaskId id);
void writeStickers();
void readStickers();

View file

@ -48,7 +48,7 @@ mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const
priority(0), inQueue(false), complete(false),
_localStatus(LocalNotTried), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), _locationType(UnknownFileLocation), volume(volume), local(local), secret(secret),
id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown) {
id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown), _localTaskId(0) {
LoaderQueues::iterator i = queues.find(dc);
if (i == queues.cend()) {
i = queues.insert(dc, mtpFileLoaderQueue());
@ -60,7 +60,7 @@ mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, L
priority(0), inQueue(false), complete(false),
_localStatus(LocalNotTried), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
dc(dc), _locationType(type), volume(0), local(0), secret(0),
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(mtpc_storage_fileUnknown) {
id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(todata), size(size), type(mtpc_storage_fileUnknown), _localTaskId(0) {
LoaderQueues::iterator i = queues.find(MTP::dld[0] + dc);
if (i == queues.cend()) {
i = queues.insert(MTP::dld[0] + dc, mtpFileLoaderQueue());
@ -68,20 +68,32 @@ id(id), access(access), file(to), fname(to), fileIsOpen(false), duplicateInData(
queue = &i.value();
}
QString mtpFileLoader::fileName() const {
return fname;
QByteArray mtpFileLoader::imageFormat() const {
if (_imageFormat.isEmpty() && _locationType == UnknownFileLocation) {
readImage();
}
return _imageFormat;
}
bool mtpFileLoader::done() const {
return complete;
QPixmap mtpFileLoader::imagePixmap() const {
if (_imagePixmap.isNull() && _locationType == UnknownFileLocation) {
readImage();
}
return _imagePixmap;
}
mtpTypeId mtpFileLoader::fileType() const {
return type;
}
const QByteArray &mtpFileLoader::bytes() const {
return data;
void mtpFileLoader::readImage() const {
QByteArray format;
switch (type) {
case mtpc_storage_fileGif: format = "GIF"; break;
case mtpc_storage_fileJpeg: format = "JPG"; break;
case mtpc_storage_filePng: format = "PNG"; break;
default: format = QByteArray(); break;
}
_imagePixmap = QPixmap::fromImage(App::readImage(data, &format, false), Qt::ColorOnly);
if (!_imagePixmap.isNull()) {
_imageFormat = format;
}
}
float64 mtpFileLoader::currentProgress() const {
@ -314,10 +326,10 @@ bool mtpFileLoader::tryLoadLocal() {
}
if (_locationType == UnknownFileLocation) {
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != StorageFileUnknown) {
data = cached.data;
type = mtpFromStorageType(cached.type);
_localTaskId = Local::startImageLoad(storageKey(dc, volume, local), this);
if (_localTaskId) {
_localStatus = LocalLoading;
return true;
}
} else {
if (duplicateInData) {
@ -361,6 +373,42 @@ bool mtpFileLoader::tryLoadLocal() {
return true;
}
void mtpFileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &imageFormat, const QPixmap &imagePixmap) {
_localTaskId = 0;
if (result.type == StorageFileUnknown) {
_localStatus = LocalFailed;
start(true);
return;
}
data = result.data;
type = mtpFromStorageType(result.type);
if (_locationType == UnknownFileLocation) { // photo
_imageFormat = imageFormat;
_imagePixmap = imagePixmap;
}
_localStatus = LocalLoaded;
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
finishFail();
return;
}
if (file.write(data) != qint64(data.size())) {
finishFail();
return;
}
}
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
emit App::wnd()->imageLoaded();
emit progress(this);
loadNext();
}
void mtpFileLoader::start(bool loadFirst, bool prior) {
if (complete || tryLoadLocal()) return;
@ -502,6 +550,9 @@ void mtpFileLoader::started(bool loadFirst, bool prior) {
}
mtpFileLoader::~mtpFileLoader() {
if (_localTaskId) {
Local::cancelTask(_localTaskId);
}
removeFromQueue();
cancelRequests();
}

View file

@ -45,6 +45,56 @@ inline mtpTypeId mtpFromLocationType(LocationType type) {
}
}
enum StorageFileType {
StorageFileUnknown = 0xaa963b05, // mtpc_storage_fileUnknown
StorageFileJpeg = 0x7efe0e, // mtpc_storage_fileJpeg
StorageFileGif = 0xcae1aadf, // mtpc_storage_fileGif
StorageFilePng = 0xa4f63c0, // mtpc_storage_filePng
StorageFilePdf = 0xae1e508d, // mtpc_storage_filePdf
StorageFileMp3 = 0x528a0677, // mtpc_storage_fileMp3
StorageFileMov = 0x4b09ebbc, // mtpc_storage_fileMov
StorageFilePartial = 0x40bc6f52, // mtpc_storage_filePartial
StorageFileMp4 = 0xb3cea0e4, // mtpc_storage_fileMp4
StorageFileWebp = 0x1081464c, // mtpc_storage_fileWebp
};
inline StorageFileType mtpToStorageType(mtpTypeId type) {
switch (type) {
case mtpc_storage_fileJpeg: return StorageFileJpeg;
case mtpc_storage_fileGif: return StorageFileGif;
case mtpc_storage_filePng: return StorageFilePng;
case mtpc_storage_filePdf: return StorageFilePdf;
case mtpc_storage_fileMp3: return StorageFileMp3;
case mtpc_storage_fileMov: return StorageFileMov;
case mtpc_storage_filePartial: return StorageFilePartial;
case mtpc_storage_fileMp4: return StorageFileMp4;
case mtpc_storage_fileWebp: return StorageFileWebp;
case mtpc_storage_fileUnknown:
default: return StorageFileUnknown;
}
}
inline mtpTypeId mtpFromStorageType(StorageFileType type) {
switch (type) {
case StorageFileGif: return mtpc_storage_fileGif;
case StorageFilePng: return mtpc_storage_filePng;
case StorageFilePdf: return mtpc_storage_filePdf;
case StorageFileMp3: return mtpc_storage_fileMp3;
case StorageFileMov: return mtpc_storage_fileMov;
case StorageFilePartial: return mtpc_storage_filePartial;
case StorageFileMp4: return mtpc_storage_fileMp4;
case StorageFileWebp: return mtpc_storage_fileWebp;
case StorageFileUnknown:
default: return mtpc_storage_fileUnknown;
}
}
struct StorageImageSaved {
StorageImageSaved() : type(StorageFileUnknown) {
}
StorageImageSaved(StorageFileType type, const QByteArray &data) : type(type), data(data) {
}
StorageFileType type;
QByteArray data;
};
enum LocalLoadStatus {
LocalNotTried,
LocalNotFound,
@ -53,6 +103,8 @@ enum LocalLoadStatus {
LocalFailed,
};
typedef void *TaskId; // no interface, just id
struct mtpFileLoaderQueue;
class mtpFileLoader : public QObject, public RPCSender {
Q_OBJECT
@ -61,10 +113,20 @@ public:
mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const uint64 &secret, int32 size = 0);
mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, LocationType type, const QString &to, int32 size, bool todata = false);
bool done() const;
mtpTypeId fileType() const;
const QByteArray &bytes() const;
QString fileName() const;
bool done() const {
return complete;
}
mtpTypeId fileType() const {
return type;
}
const QByteArray &bytes() const {
return data;
}
QByteArray imageFormat() const;
QPixmap imagePixmap() const;
QString fileName() const {
return fname;
}
float64 currentProgress() const;
int32 currentOffset(bool includeSkipped = false) const;
int32 fullSize() const;
@ -80,6 +142,8 @@ public:
~mtpFileLoader();
void localLoaded(const StorageImageSaved &result, const QByteArray &imageFormat = QByteArray(), const QPixmap &imagePixmap = QPixmap());
mtpFileLoader *prev, *next;
int32 priority;
@ -131,4 +195,9 @@ private:
int32 size;
mtpTypeId type;
TaskId _localTaskId;
mutable QByteArray _imageFormat;
mutable QPixmap _imagePixmap;
void readImage() const;
};