tdesktop/Telegram/SourceFiles/core/file_utilities.cpp

401 lines
9.9 KiB
C++
Raw Normal View History

/*
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"
2017-03-04 10:23:56 +00:00
#include "storage/localstorage.h"
#include "platform/platform_file_utilities.h"
#include "core/application.h"
#include "base/unixtime.h"
2019-09-16 11:14:06 +00:00
#include "ui/delayed_activation.h"
#include "mainwindow.h"
2019-09-04 07:19:15 +00:00
#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;
2019-09-16 11:14:06 +00:00
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);
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);
}
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;
name = nameBase + extension;
for (int i = 0; QFileInfo(name).exists(); ++i) {
name = nameBase + qsl(" (%1)").arg(i + 2) + extension;
}
}
return name;
}
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);
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;
for (int i = 0; result.toLower() != cur.toLower() && QFileInfo(result).exists(); ++i) {
result = nameBase + qsl(" (%1)").arg(i + 2) + extension;
}
return result;
}
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();
Platform::File::UnsafeOpenEmailLink(email);
});
}
void OpenWith(const QString &filepath, QPoint menuPosition) {
2019-09-04 07:19:15 +00:00
InvokeQueued(QCoreApplication::instance(), [=] {
if (!Platform::File::UnsafeShowOpenWithDropdown(filepath, menuPosition)) {
2019-09-16 11:14:06 +00:00
Ui::PreventDelayedActivation();
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();
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();
Platform::File::UnsafeShowInFolder(filepath);
});
}
QString DefaultDownloadPath() {
return QStandardPaths::writableLocation(
QStandardPaths::DownloadLocation)
+ '/'
2019-07-24 11:45:24 +00:00
+ (Main::Session::Exists() && Auth().supportMode()
? "Tsupport Desktop"
: str_const_toString(AppName))
+ '/';
}
2019-09-03 08:43:29 +00:00
QString NameFromUserString(QString name) {
static const auto Bad = { '/', '\\', '<', '>', ':', '"', '|', '?', '*' };
for (auto &ch : name) {
if (ch < 32 || ranges::find(Bad, ch.unicode()) != end(Bad)) {
ch = '_';
}
}
if (name.isEmpty() || name.endsWith(' ') || name.endsWith('.')) {
name.append('_');
}
#ifdef Q_OS_WIN
static const auto BadNames = {
qstr("CON"),
qstr("PRN"),
qstr("AUX"),
qstr("NUL"),
qstr("COM1"),
qstr("COM2"),
qstr("COM3"),
qstr("COM4"),
qstr("COM5"),
qstr("COM6"),
qstr("COM7"),
qstr("COM8"),
qstr("COM9"),
qstr("LPT1"),
qstr("LPT2"),
qstr("LPT3"),
qstr("LPT4"),
qstr("LPT5"),
qstr("LPT6"),
qstr("LPT7"),
qstr("LPT8"),
qstr("LPT9")
};
for (const auto bad : BadNames) {
if (name.startsWith(bad, Qt::CaseInsensitive)) {
if (name.size() == bad.size() || name[bad.size()] == '.') {
name = '_' + name;
break;
}
}
}
#endif // Q_OS_WIN
return name;
}
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
namespace FileDialog {
void GetOpenPath(
QPointer<QWidget> parent,
const QString &caption,
const QString &filter,
Fn<void(OpenResult &&result)> callback,
Fn<void()> failed) {
2019-09-04 07:19:15 +00:00
InvokeQueued(QCoreApplication::instance(), [=] {
auto files = QStringList();
auto remoteContent = QByteArray();
2019-09-16 11:14:06 +00:00
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) {
2019-09-04 07:19:15 +00:00
InvokeQueued(QCoreApplication::instance(), [=] {
auto files = QStringList();
auto remoteContent = QByteArray();
2019-09-16 11:14:06 +00:00
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) {
2019-09-04 07:19:15 +00:00
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) {
2019-09-04 07:19:15 +00:00
InvokeQueued(QCoreApplication::instance(), [=] {
auto files = QStringList();
auto remoteContent = QByteArray();
2019-09-16 11:14:06 +00:00
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 qsl("All files (*.*)");
#else // Q_OS_WIN
return qsl("All files (*)");
#endif // Q_OS_WIN
}
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;
if (type == Type::ReadFiles) {
files = QFileDialog::getOpenFileNames(Core::App().getFileDialogParent(), caption, startFile, filter);
QString path = files.isEmpty() ? QString() : QFileInfo(files.back()).absoluteDir().absolutePath();
if (!path.isEmpty() && path != cDialogLastPath()) {
cSetDialogLastPath(path);
Local::writeUserSettings();
}
return !files.isEmpty();
} else if (type == Type::ReadFolder) {
file = QFileDialog::getExistingDirectory(Core::App().getFileDialogParent(), caption, startFile);
} else if (type == Type::WriteFile) {
file = QFileDialog::getSaveFileName(Core::App().getFileDialogParent(), caption, startFile, filter);
} else {
file = QFileDialog::getOpenFileName(Core::App().getFileDialogParent(), 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::writeUserSettings();
}
}
files = QStringList(file);
return true;
}
} // namespace internal
} // namespace FileDialog