saving QByteArray bookmark along with file paths and download path for OS X sandbox, will be actually implemented only in macstore branch

This commit is contained in:
John Preston 2015-11-26 20:34:52 +03:00
parent 50222ad87e
commit 4487ad9e15
32 changed files with 591 additions and 206 deletions

View File

@ -1632,8 +1632,9 @@ namespace App {
convert->sticker()->loc = thumbLocation;
}
if (convert->location.check()) {
Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), convert->location);
const FileLocation &loc(convert->location(true));
if (!loc.isEmpty()) {
Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), loc);
}
}
DocumentsData::const_iterator i = documentsData.constFind(document);

View File

@ -709,6 +709,9 @@ void Application::checkMapVersion() {
}
}
}
if (cNeedConfigResave()) {
Local::writeUserSettings();
}
}
void Application::startApp() {

View File

@ -270,7 +270,7 @@ void audioFinish() {
}
void AudioPlayer::Msg::clearData() {
fname = QString();
file = FileLocation();
data = QByteArray();
position = duration = 0;
frequency = AudioVoiceMsgFrequency;
@ -463,9 +463,9 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
current = &_audioData[_audioCurrent];
}
current->audio = audio;
current->fname = audio.audio->already(true);
current->file = audio.audio->location(true);
current->data = audio.audio->data;
if (current->fname.isEmpty() && current->data.isEmpty()) {
if (current->file.isEmpty() && current->data.isEmpty()) {
setStoppedState(current, AudioPlayerStoppedAtError);
onError(audio);
} else {
@ -507,9 +507,9 @@ void AudioPlayer::play(const SongMsgId &song, int64 position) {
current = &_songData[_songCurrent];
}
current->song = song;
current->fname = song.song->already(true);
current->file = song.song->location(true);
current->data = song.song->data;
if (current->fname.isEmpty() && current->data.isEmpty()) {
if (current->file.isEmpty() && current->data.isEmpty()) {
setStoppedState(current);
if (!song.song->loader) {
DocumentOpenLink::doOpen(song.song);
@ -1076,13 +1076,17 @@ void AudioPlayerFader::resumeDevice() {
class AudioPlayerLoader {
public:
AudioPlayerLoader(const QString &fname, const QByteArray &data) : fname(fname), data(data), dataPos(0) {
AudioPlayerLoader(const FileLocation &file, const QByteArray &data) : file(file), access(false), data(data), dataPos(0) {
}
virtual ~AudioPlayerLoader() {
if (access) {
file.accessDisable();
access = false;
}
}
bool check(const QString &fname, const QByteArray &data) {
return this->fname == fname && this->data.size() == data.size();
bool check(const FileLocation &file, const QByteArray &data) {
return this->file == file && this->data.size() == data.size();
}
virtual bool open(qint64 position = 0) = 0;
@ -1093,7 +1097,8 @@ public:
protected:
QString fname;
FileLocation file;
bool access;
QByteArray data;
QFile f;
@ -1102,9 +1107,16 @@ protected:
bool openFile() {
if (data.isEmpty()) {
if (f.isOpen()) f.close();
f.setFileName(fname);
if (!access) {
if (!file.accessEnable()) {
LOG(("Audio Error: could not open file access '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(f.error()).arg(f.errorString()));
return false;
}
access = true;
}
f.setFileName(file.name());
if (!f.open(QIODevice::ReadOnly)) {
LOG(("Audio Error: could not open file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(f.error()).arg(f.errorString()));
LOG(("Audio Error: could not open file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(f.error()).arg(f.errorString()));
return false;
}
}
@ -1121,7 +1133,7 @@ static const int32 _toChannels = 2;
class FFMpegLoader : public AudioPlayerLoader {
public:
FFMpegLoader(const QString &fname, const QByteArray &data) : AudioPlayerLoader(fname, data),
FFMpegLoader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data),
freq(AudioVoiceMsgFrequency), fmt(AL_FORMAT_STEREO16),
sampleSize(2 * sizeof(short)), srcRate(AudioVoiceMsgFrequency), dstRate(AudioVoiceMsgFrequency),
maxResampleSamples(1024), dstSamplesData(0), len(0),
@ -1143,7 +1155,7 @@ public:
}
fmtContext = avformat_alloc_context();
if (!fmtContext) {
LOG(("Audio Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(fname).arg(data.size()));
LOG(("Audio Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(file.name()).arg(data.size()));
return false;
}
fmtContext->pb = ioContext;
@ -1153,19 +1165,19 @@ public:
if ((res = avformat_open_input(&fmtContext, 0, 0, 0)) < 0) {
ioBuffer = 0;
LOG(("Audio Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
return false;
}
_opened = true;
if ((res = avformat_find_stream_info(fmtContext, 0)) < 0) {
LOG(("Audio Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
return false;
}
streamId = av_find_best_stream(fmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (streamId < 0) {
LOG(("Audio Error: Unable to av_find_best_stream for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId)));
LOG(("Audio Error: Unable to av_find_best_stream for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId)));
return false;
}
@ -1173,7 +1185,7 @@ public:
codecContext = fmtContext->streams[streamId]->codec;
av_opt_set_int(codecContext, "refcounted_frames", 1, 0);
if ((res = avcodec_open2(codecContext, codec, 0)) < 0) {
LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
return false;
}
@ -1217,7 +1229,7 @@ public:
if (sampleSize < 0) {
swrContext = swr_alloc();
if (!swrContext) {
LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(fname).arg(data.size()));
LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(file.name()).arg(data.size()));
return false;
}
int64_t src_ch_layout = layout, dst_ch_layout = _toChannelLayout;
@ -1233,7 +1245,7 @@ public:
av_opt_set_sample_fmt(swrContext, "out_sample_fmt", dst_sample_fmt, 0);
if ((res = swr_init(swrContext)) < 0) {
LOG(("Audio Error: Unable to swr_init for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to swr_init for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
return false;
}
@ -1244,7 +1256,7 @@ public:
maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP);
if ((res = av_samples_alloc_array_and_samples(&dstSamplesData, 0, _toChannels, maxResampleSamples, _toFormat, 0)) < 0) {
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
return false;
}
}
@ -1279,7 +1291,7 @@ public:
if ((res = av_read_frame(fmtContext, &avpkt)) < 0) {
if (res != AVERROR_EOF) {
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
}
return -1;
}
@ -1288,7 +1300,7 @@ public:
int got_frame = 0;
if ((res = avcodec_decode_audio4(codecContext, frame, &got_frame, &avpkt)) < 0) {
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
av_free_packet(&avpkt);
if (res == AVERROR_INVALIDDATA) return 0; // try to skip bad packet
@ -1305,7 +1317,7 @@ public:
if ((res = av_samples_alloc(dstSamplesData, 0, _toChannels, maxResampleSamples, _toFormat, 1)) < 0) {
dstSamplesData[0] = 0;
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
av_free_packet(&avpkt);
return -1;
@ -1313,7 +1325,7 @@ public:
}
if ((res = swr_convert(swrContext, dstSamplesData, dstSamples, (const uint8_t**)frame->extended_data, frame->nb_samples)) < 0) {
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
av_free_packet(&avpkt);
return -1;
@ -1678,7 +1690,7 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
return 0;
}
if (*l && (!isGoodId || !(*l)->check(m->fname, m->data))) {
if (*l && (!isGoodId || !(*l)->check(m->file, m->data))) {
delete *l;
*l = 0;
switch (type) {
@ -1693,23 +1705,23 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
case OverviewDocuments: _song = *static_cast<const SongMsgId*>(objId); break;
}
QByteArray header = m->data.mid(0, 8);
if (header.isEmpty()) {
QFile f(m->fname);
if (!f.open(QIODevice::ReadOnly)) {
LOG(("Audio Error: could not open file '%1'").arg(m->fname));
m->state = AudioPlayerStoppedAtStart;
return 0;
}
header = f.read(8);
}
if (header.size() < 8) {
LOG(("Audio Error: could not read header from file '%1', data size %2").arg(m->fname).arg(m->data.isEmpty() ? QFileInfo(m->fname).size() : m->data.size()));
m->state = AudioPlayerStoppedAtStart;
return 0;
}
// QByteArray header = m->data.mid(0, 8);
// if (header.isEmpty()) {
// QFile f(m->fname);
// if (!f.open(QIODevice::ReadOnly)) {
// LOG(("Audio Error: could not open file '%1'").arg(m->fname));
// m->state = AudioPlayerStoppedAtStart;
// return 0;
// }
// header = f.read(8);
// }
// if (header.size() < 8) {
// LOG(("Audio Error: could not read header from file '%1', data size %2").arg(m->fname).arg(m->data.isEmpty() ? QFileInfo(m->fname).size() : m->data.size()));
// m->state = AudioPlayerStoppedAtStart;
// return 0;
// }
*l = new FFMpegLoader(m->fname, m->data);
*l = new FFMpegLoader(m->file, m->data);
int ret;
if (!(*l)->open(position)) {
@ -1758,7 +1770,7 @@ AudioPlayer::Msg *AudioPlayerLoaders::checkLoader(MediaOverviewType type) {
}
if (!l || !m) return 0;
if (!isGoodId || !m->loading || !(*l)->check(m->fname, m->data)) {
if (!isGoodId || !m->loading || !(*l)->check(m->file, m->data)) {
LOG(("Audio Error: playing changed while loading"));
return 0;
}
@ -2278,7 +2290,7 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
class FFMpegAttributesReader : public AudioPlayerLoader {
public:
FFMpegAttributesReader(const QString &fname, const QByteArray &data) : AudioPlayerLoader(fname, data),
FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data),
ioBuffer(0), ioContext(0), fmtContext(0), codec(0), streamId(0),
_opened(false) {
}
@ -2488,7 +2500,7 @@ private:
};
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat) {
FFMpegAttributesReader reader(fname, data);
FFMpegAttributesReader reader(FileLocation(StorageFilePartial, fname), data);
if (reader.open()) {
int32 duration = reader.duration() / reader.frequency();
if (reader.duration() > 0) {

View File

@ -127,7 +127,7 @@ private:
void clearData();
QString fname;
FileLocation file;
QByteArray data;
int64 position, duration;
int32 frequency;

View File

@ -25,15 +25,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "downloadpathbox.h"
#include "gui/filedialog.h"
#include "pspecific.h"
DownloadPathBox::DownloadPathBox() :
_path(cDownloadPath()),
_default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty()),
_temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp")),
_dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp")),
_pathLink(this, QString(), st::defaultBoxLinkButton),
_save(this, lang(lng_connection_save), st::defaultBoxButton),
_cancel(this, lang(lng_cancel), st::cancelBoxButton) {
DownloadPathBox::DownloadPathBox() : AbstractBox()
, _path(cDownloadPath())
, _pathBookmark(cDownloadPathBookmark())
, _default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty())
, _temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp"))
, _dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp"))
, _pathLink(this, QString(), st::defaultBoxLinkButton)
, _save(this, lang(lng_connection_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
@ -124,12 +126,13 @@ void DownloadPathBox::onChange() {
void DownloadPathBox::onEditPath() {
filedialogInit();
QString path, lastPath = cDialogLastPath();
if (!cDownloadPath().isEmpty()) {
cSetDialogLastPath(cDownloadPath());
if (!cDownloadPath().isEmpty() && cDownloadPath() != qstr("tmp")) {
cSetDialogLastPath(cDownloadPath().left(cDownloadPath().size() - (cDownloadPath().endsWith('/') ? 1 : 0)));
}
if (filedialogGetDir(path, lang(lng_download_path_choose))) {
if (!path.isEmpty()) {
_path = path + '/';
_pathBookmark = psDownloadPathBookmark(_path);
setPathText(QDir::toNativeSeparators(_path));
}
}
@ -138,6 +141,7 @@ void DownloadPathBox::onEditPath() {
void DownloadPathBox::onSave() {
cSetDownloadPath(_default.checked() ? QString() : (_temp.checked() ? qsl("tmp") : _path));
cSetDownloadPathBookmark((_default.checked() || _temp.checked()) ? QByteArray() : _pathBookmark);
Local::writeUserSettings();
emit closed();
}

View File

@ -47,6 +47,7 @@ private:
void setPathText(const QString &text);
QString _path;
QByteArray _pathBookmark;
Radiobutton _default, _temp, _dir;
LinkButton _pathLink;

View File

@ -20,9 +20,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 9013;
static const wchar_t *AppVersionStr = L"0.9.13";
static const bool DevVersion = false;
static const int32 AppVersion = 9014;
static const wchar_t *AppVersionStr = L"0.9.14";
static const bool DevVersion = true;
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -41,7 +41,7 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
}
document->status = FileUploading;
if (!media.file.isEmpty()) {
document->location = FileLocation(StorageFilePartial, media.file);
document->setLocation(FileLocation(StorageFilePartial, media.file));
}
} else if (media.type == PrepareAudio) {
AudioData *audio = App::feedAudio(media.audio);
@ -64,7 +64,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
}
document->status = FileUploading;
if (!file->filepath.isEmpty()) {
document->location = FileLocation(StorageFilePartial, file->filepath);
document->setLocation(FileLocation(StorageFilePartial, file->filepath));
}
} else if (file->type == PrepareAudio) {
AudioData *audio = App::feedAudio(file->audio);

View File

@ -161,10 +161,17 @@ bool AnimatedGif::animStep(float64 ms) {
return true;
}
void AnimatedGif::start(HistoryItem *row, const QString &file) {
void AnimatedGif::start(HistoryItem *row, const FileLocation &f) {
stop();
reader = new QImageReader(file);
file = new FileLocation(f);
if (!file->accessEnable()) {
stop();
return;
}
access = true;
reader = new QImageReader(file->name());
if (!reader->canRead() || !reader->supportsAnimation()) {
stop();
return;
@ -206,6 +213,15 @@ void AnimatedGif::start(HistoryItem *row, const QString &file) {
}
void AnimatedGif::stop(bool onItemRemoved) {
if (file) {
if (access) {
file->accessDisable();
}
delete file;
file = 0;
}
access = false;
if (isNull()) return;
delete reader;

View File

@ -387,17 +387,18 @@ private:
};
class HistoryItem;
class FileLocation;
class AnimatedGif : public QObject, public Animated {
Q_OBJECT
public:
AnimatedGif() : msg(0), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
AnimatedGif() : msg(0), file(0), access(false), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
}
bool animStep(float64 ms);
void start(HistoryItem *row, const QString &file);
void start(HistoryItem *row, const FileLocation &file);
void stop(bool onItemRemoved = false);
bool isNull() const {
@ -418,6 +419,8 @@ public:
HistoryItem *msg;
QImage img;
FileLocation *file;
bool access;
QImageReader *reader;
int32 w, h, frame;

View File

@ -89,7 +89,7 @@ bool _filedialogGetFiles(QStringList &files, QByteArray &remoteContent, const QS
}
return !files.isEmpty();
} else if (multipleFiles < -1) {
file = QFileDialog::getExistingDirectory(App::wnd() ? App::wnd()->filedialogParent() : 0, caption);
file = QFileDialog::getExistingDirectory(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, startFile);
} else if (multipleFiles < 0) {
file = QFileDialog::getSaveFileName(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, startFile, filter);
} else {

View File

@ -24,6 +24,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "localstorage.h"
#include "pspecific.h"
namespace {
typedef QMap<QString, LocalImage*> LocalImages;
LocalImages localImages;
@ -712,3 +714,82 @@ StorageImage *getImage(const StorageImageLocation &location, const QByteArray &b
}
return i.value();
}
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark) : _bookmark(bookmark), _failed(_bookmark ? !_bookmark->enable() : false) {
}
ReadAccessEnabler::ReadAccessEnabler(const QSharedPointer<PsFileBookmark> &bookmark) : _bookmark(bookmark.data()), _failed(_bookmark ? !_bookmark->enable() : false) {
}
ReadAccessEnabler::~ReadAccessEnabler() {
if (_bookmark && !_failed) _bookmark->disable();
}
FileLocation::FileLocation(StorageFileType type, const QString &name) : type(type), fname(name) {
if (fname.isEmpty()) {
size = 0;
type = StorageFileUnknown;
} else {
setBookmark(psPathBookmark(name));
QFileInfo f(name);
if (f.exists()) {
qint64 s = f.size();
if (s > INT_MAX) {
fname = QString();
_bookmark.reset(0);
size = 0;
type = StorageFileUnknown;
} else {
modified = f.lastModified();
size = qint32(s);
}
} else {
fname = QString();
_bookmark.reset(0);
size = 0;
type = StorageFileUnknown;
}
}
}
bool FileLocation::check() const {
if (fname.isEmpty()) return false;
ReadAccessEnabler enabler(_bookmark);
if (enabler.failed()) {
const_cast<FileLocation*>(this)->_bookmark.reset(0);
}
QFileInfo f(name());
if (!f.exists() || !f.isReadable()) return false;
quint64 s = f.size();
if (s > INT_MAX) return false;
return (f.lastModified() == modified) && (qint32(s) == size);
}
const QString &FileLocation::name() const {
return _bookmark ? _bookmark->name(fname) : fname;
}
QByteArray FileLocation::bookmark() const {
return _bookmark ? _bookmark->bookmark() : QByteArray();
}
void FileLocation::setBookmark(const QByteArray &bm) {
if (bm.isEmpty()) {
_bookmark.reset(0);
} else {
_bookmark.reset(new PsFileBookmark(bm));
}
}
bool FileLocation::accessEnable() const {
return isEmpty() ? false : (_bookmark ? _bookmark->enable() : true);
}
void FileLocation::accessDisable() const {
return _bookmark ? _bookmark->disable() : (void)0;
}

View File

@ -240,46 +240,50 @@ void clearStorageImages();
void clearAllImages();
int64 imageCacheSize();
struct FileLocation {
FileLocation(StorageFileType type, const QString &name, const QDateTime &modified, qint32 size) : type(type), name(name), modified(modified), size(size) {
}
FileLocation(StorageFileType type, const QString &name) : type(type), name(name) {
QFileInfo f(name);
if (f.exists()) {
qint64 s = f.size();
if (s > INT_MAX) {
this->name = QString();
size = 0;
type = StorageFileUnknown;
} else {
modified = f.lastModified();
size = qint32(s);
}
} else {
this->name = QString();
size = 0;
type = StorageFileUnknown;
}
class PsFileBookmark;
class ReadAccessEnabler {
public:
ReadAccessEnabler(const PsFileBookmark *bookmark);
ReadAccessEnabler(const QSharedPointer<PsFileBookmark> &bookmark);
bool failed() const {
return _failed;
}
~ReadAccessEnabler();
private:
const PsFileBookmark *_bookmark;
bool _failed;
};
class FileLocation {
public:
FileLocation(StorageFileType type, const QString &name);
FileLocation() : size(0) {
}
bool check() const {
if (name.isEmpty()) return false;
QFileInfo f(name);
if (!f.exists()) return false;
quint64 s = f.size();
if (s > INT_MAX) return false;
return (f.lastModified() == modified) && (qint32(s) == size);
bool check() const;
const QString &name() const;
void setBookmark(const QByteArray &bookmark);
QByteArray bookmark() const;
bool isEmpty() const {
return name().isEmpty();
}
bool accessEnable() const;
void accessDisable() const;
StorageFileType type;
QString name;
QString fname;
QDateTime modified;
qint32 size;
private:
QSharedPointer<PsFileBookmark> _bookmark;
};
inline bool operator==(const FileLocation &a, const FileLocation &b) {
return a.type == b.type && a.name == b.name && a.modified == b.modified && a.size == b.size;
return a.type == b.type && a.name() == b.name() && a.modified == b.modified && a.size == b.size;
}
inline bool operator!=(const FileLocation &a, const FileLocation &b) {
return !(a == b);

View File

@ -150,7 +150,7 @@ void historyInit() {
_initTextOptions();
}
void startGif(HistoryItem *row, const QString &file) {
void startGif(HistoryItem *row, const FileLocation &file) {
if (row == animated.msg) {
stopGif();
} else {

View File

@ -24,7 +24,7 @@ void historyInit();
class HistoryItem;
void startGif(HistoryItem *row, const QString &file);
void startGif(HistoryItem *row, const FileLocation &file);
void itemRemovedGif(HistoryItem *item);
void itemReplacedGif(HistoryItem *oldItem, HistoryItem *newItem);
void stopGif();

View File

@ -579,11 +579,23 @@ namespace {
}
quint32 size = 0;
for (FileLocations::const_iterator i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
// location + type + namelen + name + date + size
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name) + _dateTimeSize() + sizeof(quint32);
// location + type + namelen + name
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name());
if (AppVersion > 9013) {
// bookmark
size += _bytearraySize(i.value().bookmark());
}
// date + size
size += _dateTimeSize() + sizeof(quint32);
}
//end mark
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString()) + _dateTimeSize() + sizeof(quint32);
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString());
if (AppVersion > 9013) {
size += _bytearraySize(QByteArray());
}
size += _dateTimeSize() + sizeof(quint32);
size += sizeof(quint32); // aliases count
for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
// alias + location
@ -592,9 +604,19 @@ namespace {
EncryptedDescriptor data(size);
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name << i.value().modified << quint32(i.value().size);
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name();
if (AppVersion > 9013) {
data.stream << i.value().bookmark();
}
data.stream << i.value().modified << quint32(i.value().size);
}
data.stream << quint64(0) << quint64(0) << quint32(0) << QString() << QDateTime::currentDateTime() << quint32(0);
data.stream << quint64(0) << quint64(0) << quint32(0) << QString();
if (AppVersion > 9013) {
data.stream << QByteArray();
}
data.stream << QDateTime::currentDateTime() << quint32(0);
data.stream << quint32(_fileLocationAliases.size());
for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
data.stream << quint64(i.key().first) << quint64(i.key().second) << quint64(i.value().first) << quint64(i.value().second);
@ -617,11 +639,17 @@ namespace {
bool endMarkFound = false;
while (!locations.stream.atEnd()) {
quint64 first, second;
QByteArray bookmark;
FileLocation loc;
quint32 type;
locations.stream >> first >> second >> type >> loc.name >> loc.modified >> loc.size;
locations.stream >> first >> second >> type >> loc.fname;
if (locations.version > 9013) {
locations.stream >> bookmark;
}
locations.stream >> loc.modified >> loc.size;
loc.setBookmark(bookmark);
if (!first && !second && !type && loc.name.isEmpty() && !loc.size) { // end mark
if (!first && !second && !type && loc.fname.isEmpty() && !loc.size) { // end mark
endMarkFound = true;
break;
}
@ -629,12 +657,8 @@ namespace {
MediaKey key(first, second);
loc.type = StorageFileType(type);
if (loc.check()) {
_fileLocations.insert(key, loc);
_fileLocationPairs.insert(loc.name, FileLocationPair(key, loc));
} else {
_writeLocations();
}
_fileLocations.insert(key, loc);
_fileLocationPairs.insert(loc.fname, FileLocationPair(key, loc));
}
if (endMarkFound) {
@ -1038,12 +1062,26 @@ namespace {
cSetAskDownloadPath(v == 1);
} break;
case dbiDownloadPath: {
case dbiDownloadPathOld: {
QString v;
stream >> v;
if (!_checkStreamStatus(stream)) return false;
if (!v.isEmpty() && v != qstr("tmp") && !v.endsWith('/')) v += '/';
cSetDownloadPath(v);
cSetDownloadPathBookmark(QByteArray());
} break;
case dbiDownloadPath: {
QString v;
QByteArray bookmark;
stream >> v >> bookmark;
if (!_checkStreamStatus(stream)) return false;
if (!v.isEmpty() && v != qstr("tmp") && !v.endsWith('/')) v += '/';
cSetDownloadPath(v);
cSetDownloadPathBookmark(bookmark);
psDownloadPathEnableAccess();
} break;
case dbiCompressPastedImage: {
@ -1362,7 +1400,7 @@ namespace {
}
uint32 size = 14 * (sizeof(quint32) + sizeof(qint32));
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath()) + _bytearraySize(cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
@ -1380,7 +1418,7 @@ namespace {
data.stream << quint32(dbiNotifyView) << qint32(cNotifyView());
data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications());
data.stream << quint32(dbiAskDownloadPath) << qint32(cAskDownloadPath());
data.stream << quint32(dbiDownloadPath) << (cAskDownloadPath() ? QString() : cDownloadPath());
data.stream << quint32(dbiDownloadPath) << (cAskDownloadPath() ? QString() : cDownloadPath()) << (cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
@ -2178,14 +2216,14 @@ namespace Local {
}
void writeFileLocation(MediaKey location, const FileLocation &local) {
if (local.name.isEmpty()) return;
if (local.fname.isEmpty()) return;
FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
if (aliasIt != _fileLocationAliases.cend()) {
location = aliasIt.value();
}
FileLocationPairs::iterator i = _fileLocationPairs.find(local.name);
FileLocationPairs::iterator i = _fileLocationPairs.find(local.fname);
if (i != _fileLocationPairs.cend()) {
if (i.value().second == local) {
if (i.value().first != location) {
@ -2205,7 +2243,7 @@ namespace Local {
}
}
_fileLocations.insert(location, local);
_fileLocationPairs.insert(local.name, FileLocationPair(location, local));
_fileLocationPairs.insert(local.fname, FileLocationPair(location, local));
_writeLocations(WriteMapFast);
}
@ -2218,9 +2256,8 @@ namespace Local {
FileLocations::iterator i = _fileLocations.find(location);
for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
if (check) {
QFileInfo info(i.value().name);
if (!info.exists() || info.lastModified() != i.value().modified || info.size() != i.value().size) {
_fileLocationPairs.remove(i.value().name);
if (!i.value().check()) {
_fileLocationPairs.remove(i.value().fname);
i = _fileLocations.erase(i);
_writeLocations();
continue;

View File

@ -30,6 +30,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
#include "boxes/confirmbox.h"
#include "boxes/stickersetbox.h"
#include "boxes/contactsbox.h"
#include "boxes/downloadpathbox.h"
#include "localstorage.h"
@ -1585,6 +1586,7 @@ void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMess
void MainWidget::videoLoadProgress(mtpFileLoader *loader) {
VideoData *video = App::video(loader->objId());
if (video->loader) {
video->status = FileReady;
if (video->loader->done()) {
video->finish();
QString already = video->already();
@ -1614,7 +1616,17 @@ void MainWidget::loadFailed(mtpFileLoader *loader, bool started, const char *ret
if (started) {
connect(box, SIGNAL(confirmed()), this, retrySlot);
} else {
connect(box, SIGNAL(confirmed()), App::wnd(), SLOT(showSettings()));
connect(box, SIGNAL(confirmed()), this, SLOT(onDownloadPathSettings()));
}
App::wnd()->showLayer(box);
}
void MainWidget::onDownloadPathSettings() {
cSetDownloadPath(QString());
cSetDownloadPathBookmark(QByteArray());
DownloadPathBox *box = new DownloadPathBox();
if (App::wnd() && App::wnd()->settingsWidget()) {
connect(box, SIGNAL(closed()), App::wnd()->settingsWidget(), SLOT(onDownloadPathEdited()));
}
App::wnd()->showLayer(box);
}
@ -1634,6 +1646,7 @@ void MainWidget::videoLoadRetry() {
void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
AudioData *audio = App::audio(loader->objId());
if (audio->loader) {
audio->status = FileReady;
if (audio->loader->done()) {
audio->finish();
QString already = audio->already();
@ -1688,7 +1701,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
if (f.write(audio->data) == audio->data.size()) {
f.close();
already = filename;
audio->location = FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename);
audio->setLocation(FileLocation(StorageFilePartial, filename));
Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputAudioFileLocation), audio->dc, audio->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
}
}
@ -1736,7 +1749,7 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
if (f.write(document->data) == document->data.size()) {
f.close();
already = filename;
document->location = FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename);
document->setLocation(FileLocation(StorageFilePartial, filename));
Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputDocumentFileLocation), document->dc, document->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
}
}
@ -1793,6 +1806,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
bool songPlayActivated = false;
DocumentData *document = App::document(loader->objId());
if (document->loader) {
document->status = FileReady;
if (document->loader->done()) {
document->finish();
QString already = document->already();
@ -1813,16 +1827,22 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
}
songPlayActivated = true;
} else if(document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
QImageReader reader(already);
if (reader.canRead()) {
if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
startGif(item, already);
} else if (item) {
App::wnd()->showDocument(document, item);
} else if (document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
const FileLocation &location(document->location(true));
if (location.accessEnable()) {
QImageReader reader(location.name());
if (reader.canRead()) {
if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
startGif(item, location);
} else if (item) {
App::wnd()->showDocument(document, item);
} else {
psOpenFile(already);
}
} else {
psOpenFile(already);
}
location.accessDisable();
} else {
psOpenFile(already);
}

View File

@ -482,6 +482,8 @@ public slots:
void onViewsIncrement();
void onActiveChannelUpdateFull();
void onDownloadPathSettings();
private:
void sendReadRequest(PeerData *peer, MsgId upTo);

View File

@ -453,10 +453,13 @@ bool MediaView::animStep(float64 msp) {
_docRadialFirst = _docRadialLast = _docRadialStart = 0;
a_docRadial = anim::fvalue(0, 0);
if (!_doc->already().isEmpty() && _doc->size < MediaViewImageSizeLimit) {
QString fname(_doc->already(true));
QImageReader reader(fname);
if (reader.canRead()) {
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
const FileLocation &location(_doc->location(true));
if (location.accessEnable()) {
QImageReader reader(location.name());
if (reader.canRead()) {
displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
}
location.accessDisable();
}
}
} else {
@ -529,8 +532,33 @@ void MediaView::onToMessage() {
void MediaView::onSaveAs() {
QString file;
if (_doc) {
QString cur = _doc->already(true);
if (cur.isEmpty()) {
const FileLocation &location(_doc->location(true));
if (location.accessEnable()) {
QFileInfo alreadyInfo(location.name());
QDir alreadyDir(alreadyInfo.dir());
QString name = alreadyInfo.fileName(), filter;
MimeType mimeType = mimeTypeForName(_doc->mime);
QStringList p = mimeType.globPatterns();
QString pattern = p.isEmpty() ? QString() : p.front();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
if (pattern.isEmpty()) {
filter = QString();
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
}
psBringToBack(this);
file = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, true, alreadyDir);
psShowOverAll(this);
if (!file.isEmpty() && file != location.name()) {
QFile(location.name()).copy(file);
}
location.accessDisable();
} else {
if (_current.isNull() && _currentGif.isNull()) {
DocumentSaveLink::doSave(_doc, true);
updateControls();
@ -539,30 +567,6 @@ void MediaView::onSaveAs() {
update(_saveNav);
}
updateOver(_lastMouseMovePos);
return;
}
QFileInfo alreadyInfo(cur);
QDir alreadyDir(alreadyInfo.dir());
QString name = alreadyInfo.fileName(), filter;
MimeType mimeType = mimeTypeForName(_doc->mime);
QStringList p = mimeType.globPatterns();
QString pattern = p.isEmpty() ? QString() : p.front();
if (name.isEmpty()) {
name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
}
if (pattern.isEmpty()) {
filter = QString();
} else {
filter = mimeType.filterString() + qsl(";;All files (*.*)");
}
psBringToBack(this);
file = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, true, alreadyDir);
psShowOverAll(this);
if (!file.isEmpty() && file != cur) {
QFile(cur).copy(file);
}
} else {
if (!_photo || !_photo->full->loaded()) return;
@ -609,8 +613,15 @@ void MediaView::onDownload() {
}
QString toName;
if (_doc) {
QString cur = _doc->already(true);
if (cur.isEmpty()) {
const FileLocation &location(_doc->location(true));
if (location.accessEnable()) {
if (!QDir().exists(path)) QDir().mkpath(path);
toName = filedialogNextFilename(_doc->name, location.name(), path);
if (toName != location.name() && !QFile(location.name()).copy(toName)) {
toName = QString();
}
location.accessDisable();
} else {
if (_current.isNull() && _currentGif.isNull()) {
DocumentSaveLink::doSave(_doc);
updateControls();
@ -619,12 +630,6 @@ void MediaView::onDownload() {
update(_saveNav);
}
updateOver(_lastMouseMovePos);
} else {
if (!QDir().exists(path)) QDir().mkpath(path);
toName = filedialogNextFilename(_doc->name, cur, path);
if (toName != cur && !QFile(cur).copy(toName)) {
toName = QString();
}
}
} else {
if (!_photo || !_photo->full->loaded()) {
@ -902,25 +907,26 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
_caption = Text();
if (_doc) {
QString already = _doc->already(true);
const FileLocation &location(_doc->location(true));
if (_doc->sticker() && !_doc->sticker()->img->isNull() && _doc->sticker()->img->loaded()) {
_currentGif.stop();
_current = _doc->sticker()->img->pix();
} else if (!already.isEmpty()) {
QImageReader reader(already);
} else if (location.accessEnable()) {
QImageReader reader(location.name());
if (reader.canRead()) {
if (reader.supportsAnimation() && reader.imageCount() > 1) {
_currentGif.start(0, already);
_currentGif.start(0, location);
_current = QPixmap();
} else {
_currentGif.stop();
QPixmap pix = QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly);
QPixmap pix = QPixmap::fromImage(App::readImage(location.name(), 0, false), Qt::ColorOnly);
_current = pix;
}
} else {
_currentGif.stop();
_current = QPixmap();
}
location.accessDisable();
} else {
_currentGif.stop();
_current = QPixmap();

View File

@ -78,7 +78,6 @@ void PasscodeWidget::onSubmit() {
} else {
if (Local::readMap(_passcode.text().toUtf8()) != Local::ReadMapPassNeeded) {
cSetPasscodeBadTries(0);
App::app()->checkMapVersion();
MTP::start();
if (MTP::authedId()) {
@ -86,6 +85,8 @@ void PasscodeWidget::onSubmit() {
} else {
App::wnd()->setupIntro(true);
}
App::app()->checkMapVersion();
} else {
cSetPasscodeBadTries(cPasscodeBadTries() + 1);
cSetPasscodeLastTry(getms(true));

View File

@ -323,7 +323,7 @@ void PlayerWidget::preloadNext() {
}
if (next) {
if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
if (document->document()->already(true).isEmpty() && document->document()->data.isEmpty()) {
if (document->document()->location(true).isEmpty() && document->document()->data.isEmpty()) {
if (!document->document()->loader) {
DocumentOpenLink::doOpen(document->document());
document->document()->openOnSave = 0;

View File

@ -175,5 +175,34 @@ void psUpdateOverlayed(QWidget *widget);
inline QString psConvertFileUrl(const QString &url) {
return url;
}
inline QByteArray psDownloadPathBookmark(const QString &path) {
return QByteArray();
}
inline QByteArray psPathBookmark(const QString &path) {
return QByteArray();
}
inline void psDownloadPathEnableAccess() {
}
class PsFileBookmark {
public:
PsFileBookmark(const QByteArray &bookmark) {
}
bool check() const {
return true;
}
bool enable() const {
return true;
}
void disable() const {
}
const QString &name(const QString &original) const {
return original;
}
QByteArray bookmark() const {
return QByteArray();
}
};
bool linuxMoveFile(const char *from, const char *to);

View File

@ -684,6 +684,18 @@ QString psConvertFileUrl(const QString &url) {
return objc_convertFileUrl(url);
}
void psDownloadPathEnableAccess() {
objc_downloadPathEnableAccess(cDownloadPathBookmark());
}
QByteArray psDownloadPathBookmark(const QString &path) {
return objc_downloadPathBookmark(path);
}
QByteArray psPathBookmark(const QString &path) {
return objc_pathBookmark(path);
}
QString strNotificationAboutThemeChange() {
const uint32 letters[] = { 0xE9005541, 0x5600DC70, 0x88001570, 0xF500D86C, 0x8100E165, 0xEE005949, 0x2900526E, 0xAE00FB74, 0x96000865, 0x7000CD72, 0x3B001566, 0x5F007361, 0xAE00B663, 0x74009A65, 0x29003054, 0xC6002668, 0x98003865, 0xFA00336D, 0xA3007A65, 0x93001443, 0xBB007868, 0xE100E561, 0x3500366E, 0xC0007A67, 0x200CA65, 0xBE00DF64, 0xE300BB4E, 0x2900D26F, 0xD500D374, 0xE900E269, 0x86008F66, 0xC4006669, 0x1C00A863, 0xE600A761, 0x8E00EE74, 0xB300B169, 0xCF00B36F, 0xE600D36E };
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));

View File

@ -198,6 +198,35 @@ void psNewVersion();
void psUpdateOverlayed(QWidget *widget);
QString psConvertFileUrl(const QString &url);
void psDownloadPathEnableAccess();
QByteArray psDownloadPathBookmark(const QString &path);
QByteArray psPathBookmark(const QString &path);
class PsFileBookmark {
public:
PsFileBookmark(const QByteArray &bookmark) : _inner(bookmark) {
}
bool check() const {
return _inner.valid();
}
bool enable() const {
return _inner.enable();
}
void disable() const {
return _inner.disable();
}
const QString &name(const QString &original) const {
return _inner.name(original);
}
QByteArray bookmark() const {
return _inner.bookmark();
}
private:
objc_FileBookmark _inner;
};
QString strNotificationAboutThemeChange();
QString strStyleOfInterface();
QString strNeedToReload();

View File

@ -82,3 +82,20 @@ QString objc_downloadPath();
QString objc_currentCountry();
QString objc_currentLang();
QString objc_convertFileUrl(const QString &url);
QByteArray objc_downloadPathBookmark(const QString &path);
QByteArray objc_pathBookmark(const QString &path);
void objc_downloadPathEnableAccess(const QByteArray &bookmark);
class objc_FileBookmark {
public:
objc_FileBookmark(const QByteArray &bookmark);
bool valid() const;
bool enable() const;
void disable() const;
const QString &name(const QString &original) const;
QByteArray bookmark() const;
~objc_FileBookmark();
};

View File

@ -931,8 +931,16 @@ void objc_start() {
name: NSWorkspaceDidWakeNotification object: NULL];
}
namespace {
NSURL *_downloadPathUrl = nil;
}
void objc_finish() {
[_sharedDelegate release];
if (_downloadPathUrl) {
[_downloadPathUrl stopAccessingSecurityScopedResource];
_downloadPathUrl = nil;
}
}
void objc_registerCustomScheme() {
@ -1054,3 +1062,38 @@ QString objc_convertFileUrl(const QString &url) {
return objcString(nsurl);
}
QByteArray objc_downloadPathBookmark(const QString &path) {
return QByteArray();
}
QByteArray objc_pathBookmark(const QString &path) {
return QByteArray();
}
void objc_downloadPathEnableAccess(const QByteArray &bookmark) {
}
objc_FileBookmark::objc_FileBookmark(const QByteArray &bookmark) {
}
bool objc_FileBookmark::valid() const {
return true;
}
bool objc_FileBookmark::enable() const {
return true;
}
void objc_FileBookmark::disable() const {
}
const QString &objc_FileBookmark::name(const QString &original) const {
return original;
}
QByteArray objc_FileBookmark::bookmark() const {
return QByteArray();
}
objc_FileBookmark::~objc_FileBookmark() {
}

View File

@ -177,3 +177,32 @@ void psUpdateOverlayed(TWidget *widget);
inline QString psConvertFileUrl(const QString &url) {
return url;
}
inline QByteArray psDownloadPathBookmark(const QString &path) {
return QByteArray();
}
inline QByteArray psPathBookmark(const QString &path) {
return QByteArray();
}
inline void psDownloadPathEnableAccess() {
}
class PsFileBookmark {
public:
PsFileBookmark(const QByteArray &bookmark) {
}
bool check() const {
return true;
}
bool enable() const {
return true;
}
void disable() const {
}
const QString &name(const QString &original) const {
return original;
}
QByteArray bookmark() const {
return QByteArray();
}
};

View File

@ -74,6 +74,7 @@ DBIDefaultAttach gDefaultAttach = dbidaDocument;
bool gReplaceEmojis = true;
bool gAskDownloadPath = false;
QString gDownloadPath;
QByteArray gDownloadPathBookmark;
bool gNeedConfigResave = false;

View File

@ -134,6 +134,7 @@ DeclareSetting(bool, ReplaceEmojis);
DeclareReadSetting(bool, ManyInstance);
DeclareSetting(bool, AskDownloadPath);
DeclareSetting(QString, DownloadPath);
DeclareSetting(QByteArray, DownloadPathBookmark);
DeclareSetting(QByteArray, LocalSalt);
DeclareSetting(DBIScale, RealScale);
DeclareSetting(DBIScale, ScreenScale);

View File

@ -710,7 +710,7 @@ void VideoCancelLink::onClick(Qt::MouseButton button) const {
VideoData::VideoData(const VideoId &id, const uint64 &access, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) :
id(id), access(access), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), fileType(0), openOnSave(0), loader(0) {
location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
_location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
}
void VideoData::save(const QString &toFile) {
@ -722,9 +722,12 @@ void VideoData::save(const QString &toFile) {
}
QString VideoData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
return location.name;
return location(check).name();
}
const FileLocation &VideoData::location(bool check) {
if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
return _location;
}
void AudioOpenLink::onClick(Qt::MouseButton button) const {
@ -818,7 +821,7 @@ bool StickerData::setInstalled() const {
AudioData::AudioData(const AudioId &id, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size) :
id(id), access(access), date(date), mime(mime), duration(duration), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), loader(0) {
location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
_location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
}
void AudioData::save(const QString &toFile) {
@ -830,17 +833,20 @@ void AudioData::save(const QString &toFile) {
}
QString AudioData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
return location.name;
return location(check).name();
}
const FileLocation &AudioData::location(bool check) {
if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
return _location;
}
void DocumentOpenLink::doOpen(DocumentData *data) {
if (!data->date) return;
bool play = data->song() && App::hoveredLinkItem() && audioPlayer();
QString already = data->already(true);
if (!already.isEmpty() || (!data->data.isEmpty() && play)) {
const FileLocation &location(data->location(true));
if (!location.isEmpty() || (!data->data.isEmpty() && play)) {
if (play) {
SongMsgId playing;
AudioPlayerState playingState = AudioPlayerStopped;
@ -852,21 +858,22 @@ void DocumentOpenLink::doOpen(DocumentData *data) {
audioPlayer()->play(song);
if (App::main()) App::main()->documentPlayProgress(song);
}
} else if (data->size < MediaViewImageSizeLimit) {
QImageReader reader(already);
} else if (data->size < MediaViewImageSizeLimit && location.accessEnable()) {
QImageReader reader(location.name());
if (reader.canRead()) {
if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) {
startGif(App::hoveredLinkItem(), already);
startGif(App::hoveredLinkItem(), location);
} else if (App::hoveredLinkItem() || App::contextItem()) {
App::wnd()->showDocument(data, App::hoveredLinkItem() ? App::hoveredLinkItem() : App::contextItem());
} else {
psOpenFile(already);
psOpenFile(location.name());
}
} else {
psOpenFile(already);
psOpenFile(location.name());
}
location.accessDisable();
} else {
psOpenFile(already);
psOpenFile(location.name());
}
return;
}
@ -954,7 +961,7 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
id(id), type(FileDocument), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), loader(0), _additional(0) {
setattributes(attributes);
location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
_location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
}
void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
@ -1016,9 +1023,12 @@ void DocumentData::save(const QString &toFile) {
}
QString DocumentData::already(bool check) {
if (!check) return location.name;
if (!location.check()) location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
return location.name;
return location(check).name();
}
const FileLocation &DocumentData::location(bool check) {
if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
return _location;
}
WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill) :

View File

@ -807,7 +807,7 @@ struct VideoData {
l->deleteLater();
l->rpcInvalidate();
}
location = FileLocation();
_location = FileLocation();
if (!beforeDownload) {
openOnSave = 0;
openOnSaveMsgId = FullMsgId();
@ -816,7 +816,7 @@ struct VideoData {
void finish() {
if (loader->done()) {
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
}
loader->deleteLater();
loader->rpcInvalidate();
@ -824,6 +824,7 @@ struct VideoData {
}
QString already(bool check = false);
const FileLocation &location(bool check = false);
VideoId id;
uint64 access;
@ -841,7 +842,10 @@ struct VideoData {
int32 openOnSave;
FullMsgId openOnSaveMsgId;
mtpFileLoader *loader;
FileLocation location;
private:
FileLocation _location;
};
class VideoLink : public ITextLink {
@ -902,7 +906,7 @@ struct AudioData {
l->deleteLater();
l->rpcInvalidate();
}
location = FileLocation();
_location = FileLocation();
if (!beforeDownload) {
openOnSave = 0;
openOnSaveMsgId = FullMsgId();
@ -911,7 +915,7 @@ struct AudioData {
void finish() {
if (loader->done()) {
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
data = loader->bytes();
}
loader->deleteLater();
@ -920,6 +924,12 @@ struct AudioData {
}
QString already(bool check = false);
const FileLocation &location(bool check = false);
void setLocation(const FileLocation &loc) {
if (loc.check()) {
_location = loc;
}
}
AudioId id;
uint64 access;
@ -935,9 +945,12 @@ struct AudioData {
int32 openOnSave;
FullMsgId openOnSaveMsgId;
mtpFileLoader *loader;
FileLocation location;
QByteArray data;
int32 md5[8];
private:
FileLocation _location;
};
struct AudioMsgId {
@ -1068,7 +1081,7 @@ struct DocumentData {
l->deleteLater();
l->rpcInvalidate();
}
location = FileLocation();
_location = FileLocation();
if (!beforeDownload) {
openOnSave = 0;
openOnSaveMsgId = FullMsgId();
@ -1077,7 +1090,7 @@ struct DocumentData {
void finish() {
if (loader->done()) {
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
data = loader->bytes();
if (sticker() && !loader->imagePixmap().isNull()) {
sticker()->img = ImagePtr(data, loader->imageFormat(), loader->imagePixmap());
@ -1092,6 +1105,12 @@ struct DocumentData {
}
QString already(bool check = false);
const FileLocation &location(bool check = false);
void setLocation(const FileLocation &loc) {
if (loc.check()) {
_location = loc;
}
}
StickerData *sticker() {
return (type == StickerDocument) ? static_cast<StickerData*>(_additional) : 0;
}
@ -1115,12 +1134,15 @@ struct DocumentData {
int32 openOnSave;
FullMsgId openOnSaveMsgId;
mtpFileLoader *loader;
FileLocation location;
QByteArray data;
DocumentAdditionalData *_additional;
int32 md5[8];
private:
FileLocation _location;
};
struct SongMsgId {

View File

@ -258,7 +258,7 @@ enum DataBlockId {
dbiCatsAndDogs = 0x12,
dbiReplaceEmojis = 0x13,
dbiAskDownloadPath = 0x14,
dbiDownloadPath = 0x15,
dbiDownloadPathOld = 0x15,
dbiScale = 0x16,
dbiEmojiTab = 0x17,
dbiRecentEmojisOld = 0x18,
@ -282,6 +282,7 @@ enum DataBlockId {
dbiWindowsNotifications = 0x30,
dbiIncludeMuted = 0x31,
dbiMaxMegaGroupCount = 0x32,
dbiDownloadPath = 0x33,
dbiEncryptedWithSalt = 333,
dbiEncrypted = 444,