mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-29 19:03:03 +00:00
other thread loads local images
This commit is contained in:
parent
d90f021e46
commit
58de461c19
@ -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()));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user