init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
This commit is contained in:
408
Telegram/SourceFiles/core/file_utilities.cpp
Normal file
408
Telegram/SourceFiles/core/file_utilities.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "core/file_utilities.h"
|
||||
|
||||
#include "storage/localstorage.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "base/platform/base_platform_file_utilities.h"
|
||||
#include "platform/platform_file_utilities.h"
|
||||
#include "core/application.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "ui/delayed_activation.h"
|
||||
#include "ui/chat/attach/attach_extensions.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtGui/QDesktopServices>
|
||||
|
||||
bool filedialogGetSaveFile(
|
||||
QPointer<QWidget> parent,
|
||||
QString &file,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
const QString &initialPath) {
|
||||
QStringList files;
|
||||
QByteArray remoteContent;
|
||||
Ui::PreventDelayedActivation();
|
||||
bool result = Platform::FileDialog::Get(
|
||||
parent,
|
||||
files,
|
||||
remoteContent,
|
||||
caption,
|
||||
filter,
|
||||
FileDialog::internal::Type::WriteFile,
|
||||
initialPath);
|
||||
file = files.isEmpty() ? QString() : files.at(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool filedialogGetSaveFile(
|
||||
QString &file,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
const QString &initialPath) {
|
||||
return filedialogGetSaveFile(
|
||||
Core::App().getFileDialogParent(),
|
||||
file,
|
||||
caption,
|
||||
filter,
|
||||
initialPath);
|
||||
}
|
||||
|
||||
QString filedialogDefaultName(
|
||||
const QString &prefix,
|
||||
const QString &extension,
|
||||
const QString &path,
|
||||
bool skipExistance,
|
||||
TimeId fileTime) {
|
||||
auto directoryPath = path;
|
||||
if (directoryPath.isEmpty()) {
|
||||
if (cDialogLastPath().isEmpty()) {
|
||||
Platform::FileDialog::InitLastPath();
|
||||
}
|
||||
directoryPath = cDialogLastPath();
|
||||
}
|
||||
|
||||
QString base;
|
||||
if (fileTime) {
|
||||
const auto date = base::unixtime::parse(fileTime);
|
||||
base = prefix + date.toString("_yyyy-MM-dd_HH-mm-ss");
|
||||
} else {
|
||||
struct tm tm;
|
||||
time_t t = time(NULL);
|
||||
mylocaltime(&tm, &t);
|
||||
|
||||
const auto zero = QChar('0');
|
||||
base = prefix + u"_%1-%2-%3_%4-%5-%6"_q.arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero);
|
||||
}
|
||||
|
||||
QString name;
|
||||
if (skipExistance) {
|
||||
name = base + extension;
|
||||
} else {
|
||||
QDir directory(directoryPath);
|
||||
const auto dir = directory.absolutePath();
|
||||
const auto nameBase = (dir.endsWith('/') ? dir : (dir + '/'))
|
||||
+ base;
|
||||
name = nameBase + extension;
|
||||
for (int i = 0; QFileInfo::exists(name); ++i) {
|
||||
name = nameBase + u" (%1)"_q.arg(i + 2) + extension;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
QString filedialogNextFilename(
|
||||
const QString &name,
|
||||
const QString &cur,
|
||||
const QString &path) {
|
||||
QDir directory(path.isEmpty() ? cDialogLastPath() : path);
|
||||
int32 extIndex = name.lastIndexOf('.');
|
||||
QString prefix = name, extension;
|
||||
if (extIndex >= 0) {
|
||||
extension = name.mid(extIndex);
|
||||
prefix = name.mid(0, extIndex);
|
||||
}
|
||||
const auto dir = directory.absolutePath();
|
||||
const auto nameBase = (dir.endsWith('/') ? dir : (dir + '/')) + prefix;
|
||||
auto result = nameBase + extension;
|
||||
for (int i = 0; result.toLower() != cur.toLower() && QFileInfo::exists(result); ++i) {
|
||||
result = nameBase + u" (%1)"_q.arg(i + 2) + extension;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace File {
|
||||
|
||||
void OpenUrl(const QString &url) {
|
||||
crl::on_main([=] {
|
||||
Ui::PreventDelayedActivation();
|
||||
Platform::File::UnsafeOpenUrl(url);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenEmailLink(const QString &email) {
|
||||
crl::on_main([=] {
|
||||
Ui::PreventDelayedActivation();
|
||||
Platform::File::UnsafeOpenEmailLink(email);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenWith(const QString &filepath) {
|
||||
InvokeQueued(QCoreApplication::instance(), [=] {
|
||||
if (!Platform::File::UnsafeShowOpenWithDropdown(filepath)) {
|
||||
Ui::PreventDelayedActivation();
|
||||
if (!Platform::File::UnsafeShowOpenWith(filepath)) {
|
||||
Platform::File::UnsafeLaunch(filepath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Launch(const QString &filepath) {
|
||||
crl::on_main([=] {
|
||||
Ui::PreventDelayedActivation();
|
||||
Platform::File::UnsafeLaunch(filepath);
|
||||
});
|
||||
}
|
||||
|
||||
void ShowInFolder(const QString &filepath) {
|
||||
crl::on_main([=] {
|
||||
Ui::PreventDelayedActivation();
|
||||
base::Platform::ShowInFolder(filepath);
|
||||
});
|
||||
}
|
||||
|
||||
QString DefaultDownloadPathFolder(not_null<Main::Session*> session) {
|
||||
#if OS_MAC_STORE
|
||||
return u"Telegram Lite"_q;
|
||||
#else // OS_MAC_STORE
|
||||
return session->supportMode() ? u"Tsupport Desktop"_q : AppName.utf16();
|
||||
#endif // OS_MAC_STORE
|
||||
}
|
||||
|
||||
QString DefaultDownloadPath(not_null<Main::Session*> session) {
|
||||
if (!Core::App().canReadDefaultDownloadPath()) {
|
||||
return session->local().tempDirectory();
|
||||
}
|
||||
return QStandardPaths::writableLocation(
|
||||
QStandardPaths::DownloadLocation)
|
||||
+ '/'
|
||||
+ DefaultDownloadPathFolder(session)
|
||||
+ '/';
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
void UnsafeOpenUrlDefault(const QString &url) {
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void UnsafeOpenEmailLinkDefault(const QString &email) {
|
||||
auto url = QUrl(u"mailto:"_q + email);
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void UnsafeLaunchDefault(const QString &filepath) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(filepath));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace File
|
||||
|
||||
namespace FileDialog {
|
||||
|
||||
void GetOpenPath(
|
||||
QPointer<QWidget> parent,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
Fn<void(OpenResult &&result)> callback,
|
||||
Fn<void()> failed) {
|
||||
InvokeQueued(QCoreApplication::instance(), [=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
Ui::PreventDelayedActivation();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
parent,
|
||||
files,
|
||||
remoteContent,
|
||||
caption,
|
||||
filter,
|
||||
FileDialog::internal::Type::ReadFile);
|
||||
if (success
|
||||
&& ((!files.isEmpty() && !files[0].isEmpty())
|
||||
|| !remoteContent.isEmpty())) {
|
||||
if (callback) {
|
||||
auto result = OpenResult();
|
||||
if (!files.isEmpty() && !files[0].isEmpty()) {
|
||||
result.paths.push_back(files[0]);
|
||||
}
|
||||
result.remoteContent = remoteContent;
|
||||
callback(std::move(result));
|
||||
}
|
||||
} else if (failed) {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GetOpenPaths(
|
||||
QPointer<QWidget> parent,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
Fn<void(OpenResult &&result)> callback,
|
||||
Fn<void()> failed) {
|
||||
InvokeQueued(QCoreApplication::instance(), [=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
Ui::PreventDelayedActivation();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
parent,
|
||||
files,
|
||||
remoteContent,
|
||||
caption,
|
||||
filter,
|
||||
FileDialog::internal::Type::ReadFiles);
|
||||
if (success && (!files.isEmpty() || !remoteContent.isEmpty())) {
|
||||
if (callback) {
|
||||
auto result = OpenResult();
|
||||
result.paths = files;
|
||||
result.remoteContent = remoteContent;
|
||||
callback(std::move(result));
|
||||
}
|
||||
} else if (failed) {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GetWritePath(
|
||||
QPointer<QWidget> parent,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
const QString &initialPath,
|
||||
Fn<void(QString &&result)> callback,
|
||||
Fn<void()> failed) {
|
||||
InvokeQueued(QCoreApplication::instance(), [=] {
|
||||
auto file = QString();
|
||||
if (filedialogGetSaveFile(parent, file, caption, filter, initialPath)) {
|
||||
if (callback) {
|
||||
callback(std::move(file));
|
||||
}
|
||||
} else if (failed) {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GetFolder(
|
||||
QPointer<QWidget> parent,
|
||||
const QString &caption,
|
||||
const QString &initialPath,
|
||||
Fn<void(QString &&result)> callback,
|
||||
Fn<void()> failed) {
|
||||
InvokeQueued(QCoreApplication::instance(), [=] {
|
||||
auto files = QStringList();
|
||||
auto remoteContent = QByteArray();
|
||||
Ui::PreventDelayedActivation();
|
||||
const auto success = Platform::FileDialog::Get(
|
||||
parent,
|
||||
files,
|
||||
remoteContent,
|
||||
caption,
|
||||
QString(),
|
||||
FileDialog::internal::Type::ReadFolder,
|
||||
initialPath);
|
||||
if (success && !files.isEmpty() && !files[0].isEmpty()) {
|
||||
if (callback) {
|
||||
callback(std::move(files[0]));
|
||||
}
|
||||
} else if (failed) {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString AllFilesFilter() {
|
||||
#ifdef Q_OS_WIN
|
||||
return u"All files (*.*)"_q;
|
||||
#else // Q_OS_WIN
|
||||
return u"All files (*)"_q;
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
QString ImagesFilter() {
|
||||
return u"Image files (*"_q + Ui::ImageExtensions().join(u" *"_q) + u")"_q;
|
||||
}
|
||||
|
||||
QString AllOrImagesFilter() {
|
||||
return AllFilesFilter() + u";;"_q + ImagesFilter();
|
||||
}
|
||||
|
||||
QString ImagesOrAllFilter() {
|
||||
return ImagesFilter() + u";;"_q + AllFilesFilter();
|
||||
}
|
||||
|
||||
QString PhotoVideoFilesFilter() {
|
||||
return u"Image and Video Files (*"_q + Ui::ImageExtensions().join(u" *"_q) + u" *.mp4 *.mov *.m4v);;"_q
|
||||
+ AllFilesFilter();
|
||||
}
|
||||
|
||||
const QString &Tmp() {
|
||||
static const auto tmp = u"tmp"_q;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
void InitLastPathDefault() {
|
||||
cSetDialogLastPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||
}
|
||||
|
||||
bool GetDefault(
|
||||
QPointer<QWidget> parent,
|
||||
QStringList &files,
|
||||
QByteArray &remoteContent,
|
||||
const QString &caption,
|
||||
const QString &filter,
|
||||
FileDialog::internal::Type type,
|
||||
QString startFile = QString()) {
|
||||
if (cDialogLastPath().isEmpty()) {
|
||||
Platform::FileDialog::InitLastPath();
|
||||
}
|
||||
|
||||
remoteContent = QByteArray();
|
||||
if (startFile.isEmpty() || startFile.at(0) != '/') {
|
||||
startFile = cDialogLastPath() + '/' + startFile;
|
||||
}
|
||||
QString file;
|
||||
|
||||
const auto resolvedParent = (parent && parent->window()->isVisible())
|
||||
? parent->window()
|
||||
: Core::App().getFileDialogParent();
|
||||
Core::App().notifyFileDialogShown(true);
|
||||
const auto guard = gsl::finally([] {
|
||||
Core::App().notifyFileDialogShown(false);
|
||||
});
|
||||
if (type == Type::ReadFiles) {
|
||||
files = QFileDialog::getOpenFileNames(resolvedParent, caption, startFile, filter);
|
||||
QString path = files.isEmpty() ? QString() : QFileInfo(files.back()).absoluteDir().absolutePath();
|
||||
if (!path.isEmpty() && path != cDialogLastPath()) {
|
||||
cSetDialogLastPath(path);
|
||||
Local::writeSettings();
|
||||
}
|
||||
return !files.isEmpty();
|
||||
} else if (type == Type::ReadFolder) {
|
||||
file = QFileDialog::getExistingDirectory(resolvedParent, caption, startFile);
|
||||
} else if (type == Type::WriteFile) {
|
||||
file = QFileDialog::getSaveFileName(resolvedParent, caption, startFile, filter);
|
||||
} else {
|
||||
file = QFileDialog::getOpenFileName(resolvedParent, caption, startFile, filter);
|
||||
}
|
||||
|
||||
if (file.isEmpty()) {
|
||||
files = QStringList();
|
||||
return false;
|
||||
}
|
||||
if (type != Type::ReadFolder) {
|
||||
// Save last used directory for all queries except directory choosing.
|
||||
auto path = QFileInfo(file).absoluteDir().absolutePath();
|
||||
if (!path.isEmpty() && path != cDialogLastPath()) {
|
||||
cSetDialogLastPath(path);
|
||||
Local::writeSettings();
|
||||
}
|
||||
}
|
||||
files = QStringList(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace FileDialog
|
||||
Reference in New Issue
Block a user