2014-05-30 08:53:19 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
2018-01-03 10:23:14 +00:00
|
|
|
the official desktop application for the Telegram messaging service.
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2018-01-03 10:23:14 +00:00
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
2014-05-30 08:53:19 +00:00
|
|
|
*/
|
2017-02-28 14:05:30 +00:00
|
|
|
#include "core/file_utilities.h"
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-03-04 10:23:56 +00:00
|
|
|
#include "storage/localstorage.h"
|
2017-02-28 10:51:00 +00:00
|
|
|
#include "platform/platform_file_utilities.h"
|
2019-01-21 13:42:21 +00:00
|
|
|
#include "core/application.h"
|
2019-07-10 17:28:33 +00:00
|
|
|
#include "base/unixtime.h"
|
2019-09-16 11:14:06 +00:00
|
|
|
#include "ui/delayed_activation.h"
|
2018-12-26 09:54:49 +00:00
|
|
|
#include "mainwindow.h"
|
|
|
|
|
2019-09-04 07:19:15 +00:00
|
|
|
#include <QtWidgets/QFileDialog>
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
#include <QtCore/QStandardPaths>
|
|
|
|
#include <QtGui/QDesktopServices>
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
bool filedialogGetSaveFile(
|
2018-04-17 15:19:34 +00:00
|
|
|
QPointer<QWidget> parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
QString &file,
|
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
|
|
|
const QString &initialPath) {
|
2014-05-30 08:53:19 +00:00
|
|
|
QStringList files;
|
|
|
|
QByteArray remoteContent;
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2018-04-17 15:19:34 +00:00
|
|
|
bool result = Platform::FileDialog::Get(
|
|
|
|
parent,
|
|
|
|
files,
|
|
|
|
remoteContent,
|
|
|
|
caption,
|
|
|
|
filter,
|
|
|
|
FileDialog::internal::Type::WriteFile,
|
|
|
|
initialPath);
|
2014-05-30 08:53:19 +00:00
|
|
|
file = files.isEmpty() ? QString() : files.at(0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-04-17 15:19:34 +00:00
|
|
|
bool filedialogGetSaveFile(
|
|
|
|
QString &file,
|
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
|
|
|
const QString &initialPath) {
|
|
|
|
return filedialogGetSaveFile(
|
2019-01-21 13:42:21 +00:00
|
|
|
Core::App().getFileDialogParent(),
|
2018-04-17 15:19:34 +00:00
|
|
|
file,
|
|
|
|
caption,
|
|
|
|
filter,
|
|
|
|
initialPath);
|
|
|
|
}
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
QString filedialogDefaultName(
|
|
|
|
const QString &prefix,
|
|
|
|
const QString &extension,
|
|
|
|
const QString &path,
|
|
|
|
bool skipExistance,
|
2018-02-03 19:52:35 +00:00
|
|
|
TimeId fileTime) {
|
2017-02-28 14:05:30 +00:00
|
|
|
auto directoryPath = path;
|
|
|
|
if (directoryPath.isEmpty()) {
|
|
|
|
if (cDialogLastPath().isEmpty()) {
|
|
|
|
Platform::FileDialog::InitLastPath();
|
|
|
|
}
|
|
|
|
directoryPath = cDialogLastPath();
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-04-04 09:14:32 +00:00
|
|
|
QString base;
|
|
|
|
if (fileTime) {
|
2019-07-10 17:28:33 +00:00
|
|
|
const auto date = base::unixtime::parse(fileTime);
|
2018-02-03 19:52:35 +00:00
|
|
|
base = prefix + date.toString("_yyyy-MM-dd_HH-mm-ss");
|
2017-04-04 09:14:32 +00:00
|
|
|
} else {
|
|
|
|
struct tm tm;
|
|
|
|
time_t t = time(NULL);
|
|
|
|
mylocaltime(&tm, &t);
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2017-04-04 09:14:32 +00:00
|
|
|
QChar zero('0');
|
|
|
|
base = prefix + qsl("_%1-%2-%3_%4-%5-%6").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);
|
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
|
2014-08-11 09:03:45 +00:00
|
|
|
QString name;
|
|
|
|
if (skipExistance) {
|
|
|
|
name = base + extension;
|
|
|
|
} else {
|
2018-06-20 18:12:47 +00:00
|
|
|
QDir directory(directoryPath);
|
|
|
|
const auto dir = directory.absolutePath();
|
|
|
|
const auto nameBase = (dir.endsWith('/') ? dir : (dir + '/'))
|
|
|
|
+ base;
|
2014-08-11 09:03:45 +00:00
|
|
|
name = nameBase + extension;
|
|
|
|
for (int i = 0; QFileInfo(name).exists(); ++i) {
|
2014-10-17 12:57:14 +00:00
|
|
|
name = nameBase + qsl(" (%1)").arg(i + 2) + extension;
|
2014-08-11 09:03:45 +00:00
|
|
|
}
|
2014-05-30 08:53:19 +00:00
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
2014-10-17 12:57:14 +00:00
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
QString filedialogNextFilename(
|
|
|
|
const QString &name,
|
|
|
|
const QString &cur,
|
|
|
|
const QString &path) {
|
2018-06-20 18:12:47 +00:00
|
|
|
QDir directory(path.isEmpty() ? cDialogLastPath() : path);
|
2014-10-17 12:57:14 +00:00
|
|
|
int32 extIndex = name.lastIndexOf('.');
|
|
|
|
QString prefix = name, extension;
|
|
|
|
if (extIndex >= 0) {
|
|
|
|
extension = name.mid(extIndex);
|
|
|
|
prefix = name.mid(0, extIndex);
|
|
|
|
}
|
2018-06-20 18:12:47 +00:00
|
|
|
const auto dir = directory.absolutePath();
|
|
|
|
const auto nameBase = (dir.endsWith('/') ? dir : (dir + '/')) + prefix;
|
|
|
|
auto result = nameBase + extension;
|
2014-10-17 12:57:14 +00:00
|
|
|
for (int i = 0; result.toLower() != cur.toLower() && QFileInfo(result).exists(); ++i) {
|
|
|
|
result = nameBase + qsl(" (%1)").arg(i + 2) + extension;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2016-05-25 17:59:21 +00:00
|
|
|
|
2017-02-28 14:05:30 +00:00
|
|
|
namespace File {
|
|
|
|
|
|
|
|
void OpenEmailLink(const QString &email) {
|
2017-12-30 21:28:38 +00:00
|
|
|
crl::on_main([=] {
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-02-28 14:05:30 +00:00
|
|
|
Platform::File::UnsafeOpenEmailLink(email);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenWith(const QString &filepath, QPoint menuPosition) {
|
2019-09-04 07:19:15 +00:00
|
|
|
InvokeQueued(QCoreApplication::instance(), [=] {
|
2017-02-28 14:05:30 +00:00
|
|
|
if (!Platform::File::UnsafeShowOpenWithDropdown(filepath, menuPosition)) {
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-02-28 14:05:30 +00:00
|
|
|
if (!Platform::File::UnsafeShowOpenWith(filepath)) {
|
|
|
|
Platform::File::UnsafeLaunch(filepath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Launch(const QString &filepath) {
|
2017-12-30 21:28:38 +00:00
|
|
|
crl::on_main([=] {
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-02-28 14:05:30 +00:00
|
|
|
Platform::File::UnsafeLaunch(filepath);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowInFolder(const QString &filepath) {
|
2017-12-30 21:28:38 +00:00
|
|
|
crl::on_main([=] {
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-02-28 14:05:30 +00:00
|
|
|
Platform::File::UnsafeShowInFolder(filepath);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-22 13:15:52 +00:00
|
|
|
QString DefaultDownloadPath() {
|
|
|
|
return QStandardPaths::writableLocation(
|
|
|
|
QStandardPaths::DownloadLocation)
|
|
|
|
+ '/'
|
2019-07-24 11:45:24 +00:00
|
|
|
+ (Main::Session::Exists() && Auth().supportMode()
|
2018-11-22 13:15:52 +00:00
|
|
|
? "Tsupport Desktop"
|
|
|
|
: str_const_toString(AppName))
|
|
|
|
+ '/';
|
|
|
|
}
|
|
|
|
|
2017-02-28 14:05:30 +00:00
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
void UnsafeOpenEmailLinkDefault(const QString &email) {
|
|
|
|
auto url = QUrl(qstr("mailto:") + email);
|
|
|
|
QDesktopServices::openUrl(url);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnsafeLaunchDefault(const QString &filepath) {
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(filepath));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace File
|
|
|
|
|
2016-05-25 17:59:21 +00:00
|
|
|
namespace FileDialog {
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
void GetOpenPath(
|
2018-04-17 15:19:34 +00:00
|
|
|
QPointer<QWidget> parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<void(OpenResult &&result)> callback,
|
|
|
|
Fn<void()> failed) {
|
2019-09-04 07:19:15 +00:00
|
|
|
InvokeQueued(QCoreApplication::instance(), [=] {
|
2017-02-28 15:43:03 +00:00
|
|
|
auto files = QStringList();
|
2017-02-03 20:07:26 +00:00
|
|
|
auto remoteContent = QByteArray();
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-12-21 16:15:37 +00:00
|
|
|
const auto success = Platform::FileDialog::Get(
|
2018-04-17 15:19:34 +00:00
|
|
|
parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
files,
|
|
|
|
remoteContent,
|
|
|
|
caption,
|
|
|
|
filter,
|
|
|
|
FileDialog::internal::Type::ReadFile);
|
|
|
|
if (success
|
|
|
|
&& ((!files.isEmpty() && !files[0].isEmpty())
|
|
|
|
|| !remoteContent.isEmpty())) {
|
2017-02-03 20:07:26 +00:00
|
|
|
if (callback) {
|
|
|
|
auto result = OpenResult();
|
2017-02-28 15:43:03 +00:00
|
|
|
if (!files.isEmpty() && !files[0].isEmpty()) {
|
|
|
|
result.paths.push_back(files[0]);
|
2017-02-03 20:07:26 +00:00
|
|
|
}
|
|
|
|
result.remoteContent = remoteContent;
|
2017-12-21 16:15:37 +00:00
|
|
|
callback(std::move(result));
|
2017-02-03 20:07:26 +00:00
|
|
|
}
|
|
|
|
} else if (failed) {
|
|
|
|
failed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
void GetOpenPaths(
|
2018-04-17 15:19:34 +00:00
|
|
|
QPointer<QWidget> parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<void(OpenResult &&result)> callback,
|
|
|
|
Fn<void()> failed) {
|
2019-09-04 07:19:15 +00:00
|
|
|
InvokeQueued(QCoreApplication::instance(), [=] {
|
2017-02-03 20:07:26 +00:00
|
|
|
auto files = QStringList();
|
|
|
|
auto remoteContent = QByteArray();
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-12-21 16:15:37 +00:00
|
|
|
const auto success = Platform::FileDialog::Get(
|
2018-04-17 15:19:34 +00:00
|
|
|
parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
files,
|
|
|
|
remoteContent,
|
|
|
|
caption,
|
|
|
|
filter,
|
|
|
|
FileDialog::internal::Type::ReadFiles);
|
|
|
|
if (success && (!files.isEmpty() || !remoteContent.isEmpty())) {
|
2017-02-03 20:07:26 +00:00
|
|
|
if (callback) {
|
|
|
|
auto result = OpenResult();
|
|
|
|
result.paths = files;
|
|
|
|
result.remoteContent = remoteContent;
|
2017-12-21 16:15:37 +00:00
|
|
|
callback(std::move(result));
|
2017-02-03 20:07:26 +00:00
|
|
|
}
|
|
|
|
} else if (failed) {
|
|
|
|
failed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
void GetWritePath(
|
2018-04-17 15:19:34 +00:00
|
|
|
QPointer<QWidget> parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
|
|
|
const QString &initialPath,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<void(QString &&result)> callback,
|
|
|
|
Fn<void()> failed) {
|
2019-09-04 07:19:15 +00:00
|
|
|
InvokeQueued(QCoreApplication::instance(), [=] {
|
2017-02-03 20:07:26 +00:00
|
|
|
auto file = QString();
|
2018-04-17 15:19:34 +00:00
|
|
|
if (filedialogGetSaveFile(parent, file, caption, filter, initialPath)) {
|
2017-02-03 20:07:26 +00:00
|
|
|
if (callback) {
|
2017-12-21 16:15:37 +00:00
|
|
|
callback(std::move(file));
|
2017-02-03 20:07:26 +00:00
|
|
|
}
|
|
|
|
} else if (failed) {
|
|
|
|
failed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-21 16:15:37 +00:00
|
|
|
void GetFolder(
|
2018-04-17 15:19:34 +00:00
|
|
|
QPointer<QWidget> parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
const QString &caption,
|
|
|
|
const QString &initialPath,
|
2018-06-04 15:35:11 +00:00
|
|
|
Fn<void(QString &&result)> callback,
|
|
|
|
Fn<void()> failed) {
|
2019-09-04 07:19:15 +00:00
|
|
|
InvokeQueued(QCoreApplication::instance(), [=] {
|
2017-02-28 15:43:03 +00:00
|
|
|
auto files = QStringList();
|
|
|
|
auto remoteContent = QByteArray();
|
2019-09-16 11:14:06 +00:00
|
|
|
Ui::PreventDelayedActivation();
|
2017-12-21 16:15:37 +00:00
|
|
|
const auto success = Platform::FileDialog::Get(
|
2018-04-17 15:19:34 +00:00
|
|
|
parent,
|
2017-12-21 16:15:37 +00:00
|
|
|
files,
|
|
|
|
remoteContent,
|
|
|
|
caption,
|
|
|
|
QString(),
|
|
|
|
FileDialog::internal::Type::ReadFolder,
|
|
|
|
initialPath);
|
|
|
|
if (success && !files.isEmpty() && !files[0].isEmpty()) {
|
2017-02-03 20:07:26 +00:00
|
|
|
if (callback) {
|
2017-12-21 16:15:37 +00:00
|
|
|
callback(std::move(files[0]));
|
2017-02-03 20:07:26 +00:00
|
|
|
}
|
|
|
|
} else if (failed) {
|
|
|
|
failed();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-02-28 15:43:03 +00:00
|
|
|
QString AllFilesFilter() {
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
return qsl("All files (*.*)");
|
|
|
|
#else // Q_OS_WIN
|
|
|
|
return qsl("All files (*)");
|
|
|
|
#endif // Q_OS_WIN
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
void InitLastPathDefault() {
|
|
|
|
cSetDialogLastPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
|
|
|
}
|
|
|
|
|
2018-04-17 15:19:34 +00:00
|
|
|
bool GetDefault(
|
|
|
|
QPointer<QWidget> parent,
|
|
|
|
QStringList &files,
|
|
|
|
QByteArray &remoteContent,
|
|
|
|
const QString &caption,
|
|
|
|
const QString &filter,
|
|
|
|
FileDialog::internal::Type type,
|
|
|
|
QString startFile = QString()) {
|
2017-02-28 15:43:03 +00:00
|
|
|
if (cDialogLastPath().isEmpty()) {
|
|
|
|
Platform::FileDialog::InitLastPath();
|
|
|
|
}
|
|
|
|
|
2019-10-07 11:34:40 +00:00
|
|
|
remoteContent = QByteArray();
|
2017-02-28 15:43:03 +00:00
|
|
|
if (startFile.isEmpty() || startFile.at(0) != '/') {
|
|
|
|
startFile = cDialogLastPath() + '/' + startFile;
|
|
|
|
}
|
|
|
|
QString file;
|
2019-10-07 11:34:40 +00:00
|
|
|
|
|
|
|
Core::App().notifyFileDialogShown(true);
|
2017-02-28 15:43:03 +00:00
|
|
|
if (type == Type::ReadFiles) {
|
2019-01-21 13:42:21 +00:00
|
|
|
files = QFileDialog::getOpenFileNames(Core::App().getFileDialogParent(), caption, startFile, filter);
|
2017-02-28 15:43:03 +00:00
|
|
|
QString path = files.isEmpty() ? QString() : QFileInfo(files.back()).absoluteDir().absolutePath();
|
|
|
|
if (!path.isEmpty() && path != cDialogLastPath()) {
|
|
|
|
cSetDialogLastPath(path);
|
|
|
|
Local::writeUserSettings();
|
|
|
|
}
|
|
|
|
return !files.isEmpty();
|
2019-10-07 11:34:40 +00:00
|
|
|
} else if (type == Type::ReadFolder) {
|
2019-01-21 13:42:21 +00:00
|
|
|
file = QFileDialog::getExistingDirectory(Core::App().getFileDialogParent(), caption, startFile);
|
2019-10-07 11:34:40 +00:00
|
|
|
} else if (type == Type::WriteFile) {
|
2019-01-21 13:42:21 +00:00
|
|
|
file = QFileDialog::getSaveFileName(Core::App().getFileDialogParent(), caption, startFile, filter);
|
2019-10-07 11:34:40 +00:00
|
|
|
} else {
|
2019-01-21 13:42:21 +00:00
|
|
|
file = QFileDialog::getOpenFileName(Core::App().getFileDialogParent(), caption, startFile, filter);
|
2019-10-07 11:34:40 +00:00
|
|
|
}
|
|
|
|
Core::App().notifyFileDialogShown(false);
|
|
|
|
|
|
|
|
if (file.isEmpty()) {
|
|
|
|
files = QStringList();
|
|
|
|
return false;
|
|
|
|
}
|
2017-02-28 15:43:03 +00:00
|
|
|
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::writeUserSettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
files = QStringList(file);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace internal
|
2016-05-25 17:59:21 +00:00
|
|
|
} // namespace FileDialog
|