mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Platform-dependent file methods called async.
Some major platform-dependent file operations refactoring. All methods like "open file", "open file with", "show in folder" were moved to core/file_utilities module with platform-dependent backends. All methods interacting with DesktopServices made async.
This commit is contained in:
parent
6f0cf30b12
commit
f8318177b9
56 changed files with 1254 additions and 1088 deletions
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "langloaderplain.h"
|
#include "langloaderplain.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/contactsbox.h"
|
#include "boxes/contactsbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/photocropbox.h"
|
#include "boxes/photocropbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "boxes/abstractbox.h"
|
#include "boxes/abstractbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
class ConfirmBox;
|
class ConfirmBox;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/multi_select.h"
|
#include "ui/widgets/multi_select.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/effects/widget_slide_wrap.h"
|
#include "ui/effects/widget_slide_wrap.h"
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
|
@ -100,19 +100,19 @@ void DownloadPathBox::onChange() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadPathBox::onEditPath() {
|
void DownloadPathBox::onEditPath() {
|
||||||
filedialogInit();
|
auto initialPath = [] {
|
||||||
QString path, lastPath = cDialogLastPath();
|
if (!Global::DownloadPath().isEmpty() && Global::DownloadPath() != qstr("tmp")) {
|
||||||
if (!Global::DownloadPath().isEmpty() && Global::DownloadPath() != qstr("tmp")) {
|
return Global::DownloadPath().left(Global::DownloadPath().size() - (Global::DownloadPath().endsWith('/') ? 1 : 0));
|
||||||
cSetDialogLastPath(Global::DownloadPath().left(Global::DownloadPath().size() - (Global::DownloadPath().endsWith('/') ? 1 : 0)));
|
}
|
||||||
}
|
return QString();
|
||||||
if (filedialogGetDir(path, lang(lng_download_path_choose))) {
|
};
|
||||||
if (!path.isEmpty()) {
|
FileDialog::GetFolder(lang(lng_download_path_choose), initialPath(), base::lambda_guarded(this, [this](const QString &result) {
|
||||||
_path = path + '/';
|
if (!result.isEmpty()) {
|
||||||
|
_path = result + '/';
|
||||||
_pathBookmark = psDownloadPathBookmark(_path);
|
_pathBookmark = psDownloadPathBookmark(_path);
|
||||||
setPathText(QDir::toNativeSeparators(_path));
|
setPathText(QDir::toNativeSeparators(_path));
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
cSetDialogLastPath(lastPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadPathBox::save() {
|
void DownloadPathBox::save() {
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
|
|
@ -28,6 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "core/qthelp_url.h"
|
#include "core/qthelp_url.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
||||||
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
||||||
|
@ -68,10 +69,7 @@ void UrlClickHandler::doOpen(QString url) {
|
||||||
Ui::Tooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
|
|
||||||
if (isEmail(url)) {
|
if (isEmail(url)) {
|
||||||
QUrl u(qstr("mailto:") + url);
|
File::OpenEmailLink(url);
|
||||||
if (!QDesktopServices::openUrl(u)) {
|
|
||||||
psOpenFile(u.toString(QUrl::FullyEncoded), true);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,70 +19,25 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "platform/platform_file_utilities.h"
|
#include "platform/platform_file_utilities.h"
|
||||||
|
|
||||||
#include "core/task_queue.h"
|
#include "core/task_queue.h"
|
||||||
|
|
||||||
void filedialogInit() {
|
|
||||||
if (cDialogLastPath().isEmpty()) {
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
// hack to restore previous dir without hurting performance
|
|
||||||
QSettings settings(QSettings::UserScope, qstr("QtProject"));
|
|
||||||
settings.beginGroup(qstr("Qt"));
|
|
||||||
QByteArray sd = settings.value(qstr("filedialog")).toByteArray();
|
|
||||||
QDataStream stream(&sd, QIODevice::ReadOnly);
|
|
||||||
if (!stream.atEnd()) {
|
|
||||||
int version = 3, _QFileDialogMagic = 190;
|
|
||||||
QByteArray splitterState;
|
|
||||||
QByteArray headerData;
|
|
||||||
QList<QUrl> bookmarks;
|
|
||||||
QStringList history;
|
|
||||||
QString currentDirectory;
|
|
||||||
qint32 marker;
|
|
||||||
qint32 v;
|
|
||||||
qint32 viewMode;
|
|
||||||
stream >> marker;
|
|
||||||
stream >> v;
|
|
||||||
if (marker == _QFileDialogMagic && v == version) {
|
|
||||||
stream >> splitterState
|
|
||||||
>> bookmarks
|
|
||||||
>> history
|
|
||||||
>> currentDirectory
|
|
||||||
>> headerData
|
|
||||||
>> viewMode;
|
|
||||||
cSetDialogLastPath(currentDirectory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cDialogHelperPath().isEmpty()) {
|
|
||||||
QDir temppath(cWorkingDir() + "tdata/tdummy/");
|
|
||||||
if (!temppath.exists()) {
|
|
||||||
temppath.mkpath(temppath.absolutePath());
|
|
||||||
}
|
|
||||||
if (temppath.exists()) {
|
|
||||||
cSetDialogHelperPath(temppath.absolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else // Q_OS_WIN
|
|
||||||
cSetDialogLastPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
bool getFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, FileDialog::internal::Type type, QString startFile = QString()) {
|
void InitLastPathDefault() {
|
||||||
filedialogInit();
|
cSetDialogLastPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||||
|
}
|
||||||
|
|
||||||
if (Platform::FileDialog::Supported()) {
|
bool GetDefault(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, FileDialog::internal::Type type, QString startFile = QString()) {
|
||||||
return Platform::FileDialog::Get(files, remoteContent, caption, filter, type, startFile);
|
if (cDialogLastPath().isEmpty()) {
|
||||||
|
Platform::FileDialog::InitLastPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined Q_OS_LINUX || defined Q_OS_MAC // use native
|
|
||||||
remoteContent = QByteArray();
|
remoteContent = QByteArray();
|
||||||
if (startFile.isEmpty() || startFile.at(0) != '/') {
|
if (startFile.isEmpty() || startFile.at(0) != '/') {
|
||||||
startFile = cDialogLastPath() + '/' + startFile;
|
startFile = cDialogLastPath() + '/' + startFile;
|
||||||
|
@ -107,122 +62,56 @@ bool getFiles(QStringList &files, QByteArray &remoteContent, const QString &capt
|
||||||
files = QStringList();
|
files = QStringList();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QString path = QFileInfo(file).absoluteDir().absolutePath();
|
if (type != Type::ReadFolder) {
|
||||||
if (!path.isEmpty() && path != cDialogLastPath()) {
|
// Save last used directory for all queries except directory choosing.
|
||||||
cSetDialogLastPath(path);
|
auto path = QFileInfo(file).absoluteDir().absolutePath();
|
||||||
Local::writeUserSettings();
|
if (!path.isEmpty() && path != cDialogLastPath()) {
|
||||||
|
cSetDialogLastPath(path);
|
||||||
|
Local::writeUserSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
files = QStringList(file);
|
files = QStringList(file);
|
||||||
return true;
|
return true;
|
||||||
#else // Q_OS_LINUX || Q_OS_MAC
|
|
||||||
|
|
||||||
// A hack for fast dialog create. There was some huge performance problem
|
|
||||||
// if we open a file dialog in some folder with a large amount of files.
|
|
||||||
// Some internal Qt watcher iterated over all of them, querying some information
|
|
||||||
// that forced file icon and maybe other properties being resolved and this was
|
|
||||||
// a blocking operation.
|
|
||||||
auto helperPath = cDialogHelperPathFinal();
|
|
||||||
QFileDialog dialog(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, helperPath, filter);
|
|
||||||
|
|
||||||
dialog.setModal(true);
|
|
||||||
if (type == Type::ReadFile || type == Type::ReadFiles) {
|
|
||||||
dialog.setFileMode((type == Type::ReadFiles) ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile);
|
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
|
||||||
} else if (type == Type::ReadFolder) { // save dir
|
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
|
||||||
|
|
||||||
// We use "obsolete" value ::DirectoryOnly instead of ::Directory + ::ShowDirsOnly
|
|
||||||
// because in Windows XP native dialog this one works, while the "preferred" one
|
|
||||||
// shows a native file choose dialog where you can't choose a directory, only open one.
|
|
||||||
dialog.setFileMode(QFileDialog::DirectoryOnly);
|
|
||||||
dialog.setOption(QFileDialog::ShowDirsOnly);
|
|
||||||
} else { // save file
|
|
||||||
dialog.setFileMode(QFileDialog::AnyFile);
|
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
||||||
}
|
|
||||||
dialog.show();
|
|
||||||
|
|
||||||
auto realLastPath = cDialogLastPath();
|
|
||||||
if (realLastPath.isEmpty() || realLastPath.endsWith(qstr("/tdummy"))) {
|
|
||||||
realLastPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
|
||||||
}
|
|
||||||
dialog.setDirectory(realLastPath);
|
|
||||||
|
|
||||||
if (type == Type::WriteFile) {
|
|
||||||
QString toSelect(startFile);
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
int32 lastSlash = toSelect.lastIndexOf('/');
|
|
||||||
if (lastSlash >= 0) {
|
|
||||||
toSelect = toSelect.mid(lastSlash + 1);
|
|
||||||
}
|
|
||||||
int32 lastBackSlash = toSelect.lastIndexOf('\\');
|
|
||||||
if (lastBackSlash >= 0) {
|
|
||||||
toSelect = toSelect.mid(lastBackSlash + 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
dialog.selectFile(toSelect);
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = dialog.exec();
|
|
||||||
|
|
||||||
QString path = dialog.directory().absolutePath();
|
|
||||||
if (path != cDialogLastPath()) {
|
|
||||||
cSetDialogLastPath(path);
|
|
||||||
Local::writeUserSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == QDialog::Accepted) {
|
|
||||||
if (type == Type::ReadFiles) {
|
|
||||||
files = dialog.selectedFiles();
|
|
||||||
} else {
|
|
||||||
files = dialog.selectedFiles().mid(0, 1);
|
|
||||||
}
|
|
||||||
if (type == Type::ReadFile || type == Type::ReadFiles) {
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
remoteContent = dialog.selectedRemoteContent();
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
files = QStringList();
|
|
||||||
remoteContent = QByteArray();
|
|
||||||
return false;
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace FileDialog
|
} // namespace FileDialog
|
||||||
|
|
||||||
bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter) {
|
bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter) {
|
||||||
return FileDialog::internal::getFiles(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFiles);
|
return Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter) {
|
bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter) {
|
||||||
QStringList files;
|
QStringList files;
|
||||||
bool result = FileDialog::internal::getFiles(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFile);
|
bool result = Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::ReadFile);
|
||||||
file = files.isEmpty() ? QString() : files.at(0);
|
file = files.isEmpty() ? QString() : files.at(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &startName) {
|
bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &initialPath) {
|
||||||
QStringList files;
|
QStringList files;
|
||||||
QByteArray remoteContent;
|
QByteArray remoteContent;
|
||||||
bool result = FileDialog::internal::getFiles(files, remoteContent, caption, filter, FileDialog::internal::Type::WriteFile, startName);
|
bool result = Platform::FileDialog::Get(files, remoteContent, caption, filter, FileDialog::internal::Type::WriteFile, initialPath);
|
||||||
file = files.isEmpty() ? QString() : files.at(0);
|
file = files.isEmpty() ? QString() : files.at(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool filedialogGetDir(QString &dir, const QString &caption) {
|
bool filedialogGetDir(QString &dir, const QString &caption, const QString &initialPath) {
|
||||||
QStringList files;
|
QStringList files;
|
||||||
QByteArray remoteContent;
|
QByteArray remoteContent;
|
||||||
bool result = FileDialog::internal::getFiles(files, remoteContent, caption, QString(), FileDialog::internal::Type::ReadFolder);
|
bool result = Platform::FileDialog::Get(files, remoteContent, caption, QString(), FileDialog::internal::Type::ReadFolder, initialPath);
|
||||||
dir = files.isEmpty() ? QString() : files.at(0);
|
dir = files.isEmpty() ? QString() : files.at(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path, bool skipExistance) {
|
QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path, bool skipExistance) {
|
||||||
filedialogInit();
|
auto directoryPath = path;
|
||||||
|
if (directoryPath.isEmpty()) {
|
||||||
|
if (cDialogLastPath().isEmpty()) {
|
||||||
|
Platform::FileDialog::InitLastPath();
|
||||||
|
}
|
||||||
|
directoryPath = cDialogLastPath();
|
||||||
|
}
|
||||||
|
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
@ -235,7 +124,7 @@ QString filedialogDefaultName(const QString &prefix, const QString &extension, c
|
||||||
if (skipExistance) {
|
if (skipExistance) {
|
||||||
name = base + extension;
|
name = base + extension;
|
||||||
} else {
|
} else {
|
||||||
QDir dir(path.isEmpty() ? cDialogLastPath() : path);
|
QDir dir(directoryPath);
|
||||||
QString nameBase = dir.absolutePath() + '/' + base;
|
QString nameBase = dir.absolutePath() + '/' + base;
|
||||||
name = nameBase + extension;
|
name = nameBase + extension;
|
||||||
for (int i = 0; QFileInfo(name).exists(); ++i) {
|
for (int i = 0; QFileInfo(name).exists(); ++i) {
|
||||||
|
@ -268,6 +157,50 @@ QString filedialogAllFilesFilter() {
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace File {
|
||||||
|
|
||||||
|
void OpenEmailLink(const QString &email) {
|
||||||
|
base::TaskQueue::Main().Put([email] {
|
||||||
|
Platform::File::UnsafeOpenEmailLink(email);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenWith(const QString &filepath, QPoint menuPosition) {
|
||||||
|
base::TaskQueue::Main().Put([filepath, menuPosition] {
|
||||||
|
if (!Platform::File::UnsafeShowOpenWithDropdown(filepath, menuPosition)) {
|
||||||
|
if (!Platform::File::UnsafeShowOpenWith(filepath)) {
|
||||||
|
Platform::File::UnsafeLaunch(filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Launch(const QString &filepath) {
|
||||||
|
base::TaskQueue::Main().Put([filepath] {
|
||||||
|
Platform::File::UnsafeLaunch(filepath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowInFolder(const QString &filepath) {
|
||||||
|
base::TaskQueue::Main().Put([filepath] {
|
||||||
|
Platform::File::UnsafeShowInFolder(filepath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
namespace FileDialog {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -375,7 +308,7 @@ bool processQuery() {
|
||||||
|
|
||||||
case Query::Type::ReadFolder: {
|
case Query::Type::ReadFolder: {
|
||||||
QString folder;
|
QString folder;
|
||||||
if (filedialogGetDir(folder, query.caption)) {
|
if (filedialogGetDir(folder, query.caption, query.filePath)) {
|
||||||
if (!folder.isEmpty()) {
|
if (!folder.isEmpty()) {
|
||||||
update.filePaths.push_back(folder);
|
update.filePaths.push_back(folder);
|
||||||
}
|
}
|
||||||
|
@ -394,7 +327,7 @@ base::Observable<QueryUpdate> &QueryDone() {
|
||||||
return QueryDoneObservable;
|
return QueryDoneObservable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void askOpenPath(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed) {
|
void GetOpenPath(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed) {
|
||||||
base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] {
|
base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] {
|
||||||
auto file = QString();
|
auto file = QString();
|
||||||
auto remoteContent = QByteArray();
|
auto remoteContent = QByteArray();
|
||||||
|
@ -413,7 +346,7 @@ void askOpenPath(const QString &caption, const QString &filter, base::lambda<voi
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void askOpenPaths(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed) {
|
void GetOpenPaths(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed) {
|
||||||
base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] {
|
base::TaskQueue::Main().Put([caption, filter, callback = std::move(callback), failed = std::move(failed)] {
|
||||||
auto files = QStringList();
|
auto files = QStringList();
|
||||||
auto remoteContent = QByteArray();
|
auto remoteContent = QByteArray();
|
||||||
|
@ -431,7 +364,7 @@ void askOpenPaths(const QString &caption, const QString &filter, base::lambda<vo
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void askWritePath(const QString &caption, const QString &filter, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed) {
|
void GetWritePath(const QString &caption, const QString &filter, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed) {
|
||||||
base::TaskQueue::Main().Put([caption, filter, initialPath, callback = std::move(callback), failed = std::move(failed)] {
|
base::TaskQueue::Main().Put([caption, filter, initialPath, callback = std::move(callback), failed = std::move(failed)] {
|
||||||
auto file = QString();
|
auto file = QString();
|
||||||
if (filedialogGetSaveFile(file, caption, filter, initialPath)) {
|
if (filedialogGetSaveFile(file, caption, filter, initialPath)) {
|
||||||
|
@ -444,10 +377,10 @@ void askWritePath(const QString &caption, const QString &filter, const QString &
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void askFolder(const QString &caption, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed) {
|
void GetFolder(const QString &caption, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed) {
|
||||||
base::TaskQueue::Main().Put([caption, callback = std::move(callback), failed = std::move(failed)] {
|
base::TaskQueue::Main().Put([caption, initialPath, callback = std::move(callback), failed = std::move(failed)] {
|
||||||
auto folder = QString();
|
auto folder = QString();
|
||||||
if (filedialogGetDir(folder, caption) && !folder.isEmpty()) {
|
if (filedialogGetDir(folder, caption, initialPath) && !folder.isEmpty()) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(folder);
|
callback(folder);
|
||||||
}
|
}
|
|
@ -22,17 +22,37 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "core/observer.h"
|
#include "core/observer.h"
|
||||||
|
|
||||||
void filedialogInit();
|
// legacy
|
||||||
bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter);
|
bool filedialogGetOpenFiles(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter);
|
||||||
bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter);
|
bool filedialogGetOpenFile(QString &file, QByteArray &remoteContent, const QString &caption, const QString &filter);
|
||||||
bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &startName);
|
bool filedialogGetSaveFile(QString &file, const QString &caption, const QString &filter, const QString &initialPath);
|
||||||
bool filedialogGetDir(QString &dir, const QString &caption);
|
bool filedialogGetDir(QString &dir, const QString &caption, const QString &initialPath);
|
||||||
|
|
||||||
QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path = QString(), bool skipExistance = false);
|
QString filedialogDefaultName(const QString &prefix, const QString &extension, const QString &path = QString(), bool skipExistance = false);
|
||||||
QString filedialogNextFilename(const QString &name, const QString &cur, const QString &path = QString());
|
QString filedialogNextFilename(const QString &name, const QString &cur, const QString &path = QString());
|
||||||
|
|
||||||
QString filedialogAllFilesFilter();
|
QString filedialogAllFilesFilter();
|
||||||
|
|
||||||
|
namespace File {
|
||||||
|
|
||||||
|
// Those functions are async wrappers to Platform::File::Unsafe* calls.
|
||||||
|
void OpenEmailLink(const QString &email);
|
||||||
|
void OpenWith(const QString &filepath, QPoint menuPosition);
|
||||||
|
void Launch(const QString &filepath);
|
||||||
|
void ShowInFolder(const QString &filepath);
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline QString UrlToLocalDefault(const QUrl &url) {
|
||||||
|
return url.toLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsafeOpenEmailLinkDefault(const QString &email);
|
||||||
|
void UnsafeLaunchDefault(const QString &filepath);
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -43,6 +63,10 @@ enum class Type {
|
||||||
WriteFile,
|
WriteFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void InitLastPathDefault();
|
||||||
|
|
||||||
|
bool GetDefault(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
using QueryId = uint64;
|
using QueryId = uint64;
|
||||||
|
@ -69,9 +93,9 @@ struct OpenResult {
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
QByteArray remoteContent;
|
QByteArray remoteContent;
|
||||||
};
|
};
|
||||||
void askOpenPath(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
void GetOpenPath(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
||||||
void askOpenPaths(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
void GetOpenPaths(const QString &caption, const QString &filter, base::lambda<void(const OpenResult &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
||||||
void askWritePath(const QString &caption, const QString &filter, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
void GetWritePath(const QString &caption, const QString &filter, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
||||||
void askFolder(const QString &caption, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
void GetFolder(const QString &caption, const QString &initialPath, base::lambda<void(const QString &result)> callback, base::lambda<void()> failed = base::lambda<void()>());
|
||||||
|
|
||||||
} // namespace FileDialog
|
} // namespace FileDialog
|
|
@ -489,10 +489,11 @@ enum DBIPeerReportSpamStatus {
|
||||||
dbiprsRequesting = 5, // requesting the cloud setting right now
|
dbiprsRequesting = 5, // requesting the cloud setting right now
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString strMakeFromLetters(const uint32 *letters, int32 len) {
|
template <int Size>
|
||||||
|
inline QString strMakeFromLetters(const uint32 (&letters)[Size]) {
|
||||||
QString result;
|
QString result;
|
||||||
result.reserve(len);
|
result.reserve(Size);
|
||||||
for (int32 i = 0; i < len; ++i) {
|
for (int32 i = 0; i < Size; ++i) {
|
||||||
result.push_back(QChar((((letters[i] >> 16) & 0xFF) << 8) | (letters[i] & 0xFF)));
|
result.push_back(QChar((((letters[i] >> 16) & 0xFF) << 8) | (letters[i] & 0xFF)));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -29,7 +29,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/send_files_box.h"
|
#include "boxes/send_files_box.h"
|
||||||
#include "boxes/sharebox.h"
|
#include "boxes/sharebox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/buttons/history_down_button.h"
|
#include "ui/buttons/history_down_button.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -1532,7 +1532,7 @@ void HistoryInner::showContextInFolder() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!filepath.isEmpty()) {
|
if (!filepath.isEmpty()) {
|
||||||
psShowInFolder(filepath);
|
File::ShowInFolder(filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "localimageloader.h"
|
#include "localimageloader.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
|
|
@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "inline_bots/inline_bot_send_data.h"
|
#include "inline_bots/inline_bot_send_data.h"
|
||||||
#include "mtproto/file_download.h"
|
#include "mtproto/file_download.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
|
||||||
namespace InlineBots {
|
namespace InlineBots {
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "styles/style_intro.h"
|
#include "styles/style_intro.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "styles/style_intro.h"
|
#include "styles/style_intro.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "boxes/photocropbox.h"
|
#include "boxes/photocropbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "intro/introwidget.h"
|
#include "intro/introwidget.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/style_stickers.h"
|
#include "styles/style_stickers.h"
|
||||||
|
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
|
|
@ -20,9 +20,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "localimageloader.h"
|
#include "localimageloader.h"
|
||||||
#include "ui/filedialog.h"
|
|
||||||
#include "media/media_audio.h"
|
|
||||||
|
|
||||||
|
#include "core/file_utilities.h"
|
||||||
|
#include "media/media_audio.h"
|
||||||
#include "boxes/send_files_box.h"
|
#include "boxes/send_files_box.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
|
|
@ -1578,7 +1578,7 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) {
|
||||||
auto filepath = document->filepath(DocumentData::FilePathResolveSaveFromData);
|
auto filepath = document->filepath(DocumentData::FilePathResolveSaveFromData);
|
||||||
if (!filepath.isEmpty()) {
|
if (!filepath.isEmpty()) {
|
||||||
if (documentIsValidMediaFile(filepath)) {
|
if (documentIsValidMediaFile(filepath)) {
|
||||||
psOpenFile(filepath);
|
File::Launch(filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
|
@ -631,7 +631,7 @@ void MediaView::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool presse
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::showSaveMsgFile() {
|
void MediaView::showSaveMsgFile() {
|
||||||
psShowInFolder(_saveMsgFilename);
|
File::ShowInFolder(_saveMsgFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::close() {
|
void MediaView::close() {
|
||||||
|
@ -908,9 +908,9 @@ void MediaView::onSaveCancel() {
|
||||||
void MediaView::onShowInFolder() {
|
void MediaView::onShowInFolder() {
|
||||||
if (!_doc) return;
|
if (!_doc) return;
|
||||||
|
|
||||||
QString filepath = _doc->filepath(DocumentData::FilePathResolveChecked);
|
auto filepath = _doc->filepath(DocumentData::FilePathResolveChecked);
|
||||||
if (!filepath.isEmpty()) {
|
if (!filepath.isEmpty()) {
|
||||||
psShowInFolder(filepath);
|
File::ShowInFolder(filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "serialize/serialize_common.h"
|
#include "serialize/serialize_common.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
#include "platform/platform_file_utilities.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -203,7 +204,7 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
|
||||||
if (_fileIsOpen) {
|
if (_fileIsOpen) {
|
||||||
_file.close();
|
_file.close();
|
||||||
_fileIsOpen = false;
|
_fileIsOpen = false;
|
||||||
psPostprocessFile(QFileInfo(_file).absoluteFilePath());
|
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
|
||||||
}
|
}
|
||||||
FileDownload::ImageLoaded().notify();
|
FileDownload::ImageLoaded().notify();
|
||||||
|
|
||||||
|
@ -531,7 +532,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
|
||||||
if (_fileIsOpen) {
|
if (_fileIsOpen) {
|
||||||
_file.close();
|
_file.close();
|
||||||
_fileIsOpen = false;
|
_fileIsOpen = false;
|
||||||
psPostprocessFile(QFileInfo(_file).absoluteFilePath());
|
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
|
||||||
}
|
}
|
||||||
removeFromQueue();
|
removeFromQueue();
|
||||||
|
|
||||||
|
@ -693,7 +694,7 @@ void webFileLoader::onFinished(const QByteArray &data) {
|
||||||
if (_fileIsOpen) {
|
if (_fileIsOpen) {
|
||||||
_file.close();
|
_file.close();
|
||||||
_fileIsOpen = false;
|
_fileIsOpen = false;
|
||||||
psPostprocessFile(QFileInfo(_file).absoluteFilePath());
|
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
|
||||||
}
|
}
|
||||||
removeFromQueue();
|
removeFromQueue();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/photocropbox.h"
|
#include "boxes/photocropbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/widgets/tooltip.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -1440,7 +1440,7 @@ void OverviewInner::showContextInFolder() {
|
||||||
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLnk.data())) {
|
if (auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLnk.data())) {
|
||||||
auto filepath = lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked);
|
auto filepath = lnkDocument->document()->filepath(DocumentData::FilePathResolveChecked);
|
||||||
if (!filepath.isEmpty()) {
|
if (!filepath.isEmpty()) {
|
||||||
psShowInFolder(filepath);
|
File::ShowInFolder(filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,44 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
QStringList qt_make_filter_list(const QString &filter);
|
QStringList qt_make_filter_list(const QString &filter);
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
namespace File {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
QByteArray EscapeShell(const QByteArray &content) {
|
||||||
|
auto result = QByteArray();
|
||||||
|
|
||||||
|
auto b = content.constData(), e = content.constEnd();
|
||||||
|
for (auto ch = b; ch != e; ++ch) {
|
||||||
|
if (*ch == ' ' || *ch == '"' || *ch == '\'' || *ch == '\\') {
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
result.reserve(content.size() * 2);
|
||||||
|
}
|
||||||
|
if (ch > b) {
|
||||||
|
result.append(b, ch - b);
|
||||||
|
}
|
||||||
|
result.append('\\');
|
||||||
|
b = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e > b) {
|
||||||
|
result.append(b, e - b);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
void UnsafeShowInFolder(const QString &filepath) {
|
||||||
|
Ui::hideLayer(true);
|
||||||
|
system(("xdg-open " + internal::EscapeShell(QFile::encodeName(QFileInfo(filepath).absoluteDir().absolutePath()))).constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -43,11 +81,9 @@ namespace {
|
||||||
constexpr auto kPreviewWidth = 256;
|
constexpr auto kPreviewWidth = 256;
|
||||||
constexpr auto kPreviewHeight = 512;
|
constexpr auto kPreviewHeight = 512;
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
using Type = ::FileDialog::internal::Type;
|
using Type = ::FileDialog::internal::Type;
|
||||||
|
|
||||||
bool Supported() {
|
bool NativeSupported() {
|
||||||
return Platform::internal::GdkHelperLoaded()
|
return Platform::internal::GdkHelperLoaded()
|
||||||
&& (Libs::gtk_widget_hide_on_delete != nullptr)
|
&& (Libs::gtk_widget_hide_on_delete != nullptr)
|
||||||
&& (Libs::gtk_clipboard_store != nullptr)
|
&& (Libs::gtk_clipboard_store != nullptr)
|
||||||
|
@ -84,11 +120,11 @@ bool Supported() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PreviewSupported() {
|
bool PreviewSupported() {
|
||||||
return Supported()
|
return NativeSupported()
|
||||||
&& (Libs::gdk_pixbuf_new_from_file_at_size != nullptr);
|
&& (Libs::gdk_pixbuf_new_from_file_at_size != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, Type type, QString startFile) {
|
bool GetNative(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, Type type, QString startFile) {
|
||||||
auto parent = App::wnd() ? App::wnd()->filedialogParent() : nullptr;
|
auto parent = App::wnd() ? App::wnd()->filedialogParent() : nullptr;
|
||||||
internal::GtkFileDialog dialog(parent, caption, QString(), filter);
|
internal::GtkFileDialog dialog(parent, caption, QString(), filter);
|
||||||
|
|
||||||
|
@ -131,6 +167,15 @@ bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, Type type, QString startFile) {
|
||||||
|
if (NativeSupported()) {
|
||||||
|
return GetNative(files, remoteContent, caption, filter, type, startFile);
|
||||||
|
}
|
||||||
|
return ::FileDialog::internal::GetDefault(files, remoteContent, caption, filter, type, startFile);
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
QGtkDialog::QGtkDialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) {
|
QGtkDialog::QGtkDialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) {
|
||||||
|
|
|
@ -31,18 +31,42 @@ extern "C" {
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace File {
|
namespace File {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
QByteArray EscapeShell(const QByteArray &content);
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
inline QString UrlToLocal(const QUrl &url) {
|
inline QString UrlToLocal(const QUrl &url) {
|
||||||
return url.toLocalFile();
|
return ::File::internal::UrlToLocalDefault(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void UnsafeOpenEmailLink(const QString &email) {
|
||||||
|
return ::File::internal::UnsafeOpenEmailLinkDefault(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool UnsafeShowOpenWithDropdown(const QString &filepath, QPoint menuPosition) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool UnsafeShowOpenWith(const QString &filepath) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void UnsafeLaunch(const QString &filepath) {
|
||||||
|
return ::File::internal::UnsafeLaunchDefault(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PostprocessDownloaded(const QString &filepath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace File
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
|
|
||||||
bool Supported();
|
inline void InitLastPath() {
|
||||||
|
::FileDialog::internal::InitLastPathDefault();
|
||||||
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile);
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,7 @@ void MainWindow::updateIconCounters() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::psHasNativeNotifications() {
|
bool MainWindow::psHasNativeNotifications() {
|
||||||
return Notifications::supported();
|
return Notifications::Supported();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::LibsLoaded() {
|
void MainWindow::LibsLoaded() {
|
||||||
|
|
|
@ -23,14 +23,25 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "platform/platform_file_utilities.h"
|
#include "platform/platform_file_utilities.h"
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
namespace File {
|
||||||
|
|
||||||
|
inline void UnsafeOpenEmailLink(const QString &email) {
|
||||||
|
return ::File::internal::UnsafeOpenEmailLinkDefault(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PostprocessDownloaded(const QString &filepath) {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
|
|
||||||
inline bool Supported() {
|
inline void InitLastPath() {
|
||||||
return false;
|
::FileDialog::internal::InitLastPathDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
||||||
return false;
|
return ::FileDialog::internal::GetDefault(files, remoteContent, caption, filter, type, startFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileDialog
|
} // namespace FileDialog
|
||||||
|
|
|
@ -22,10 +22,366 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "platform/mac/file_utilities_mac.h"
|
#include "platform/mac/file_utilities_mac.h"
|
||||||
|
|
||||||
#include "platform/mac/mac_utilities.h"
|
#include "platform/mac/mac_utilities.h"
|
||||||
|
#include "styles/style_window.h"
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <CoreFoundation/CFURL.h>
|
#include <CoreFoundation/CFURL.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace Platform;
|
||||||
|
|
||||||
|
QString strNeedToReload() {
|
||||||
|
const uint32 letters[] = { 0x82007746, 0xBB00C649, 0x7E00235F, 0x9A00FE54, 0x4C004542, 0x91001772, 0x8A00D76F, 0xC700B977, 0x7F005F73, 0x34003665, 0x2300D572, 0x72002E54, 0x18001461, 0x14004A62, 0x5100CC6C, 0x83002365, 0x5A002C56, 0xA5004369, 0x26004265, 0x0D006577 };
|
||||||
|
return strMakeFromLetters(letters);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString strNeedToRefresh1() {
|
||||||
|
const uint32 letters[] = { 0xEF006746, 0xF500CE49, 0x1500715F, 0x95001254, 0x3A00CB4C, 0x17009469, 0xB400DA73, 0xDE00C574, 0x9200EC56, 0x3C00A669, 0xFD00D865, 0x59000977 };
|
||||||
|
return strMakeFromLetters(letters);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString strNeedToRefresh2() {
|
||||||
|
const uint32 letters[] = { 0x8F001546, 0xAF007A49, 0xB8002B5F, 0x1A000B54, 0x0D003E49, 0xE0003663, 0x4900796F, 0x0500836E, 0x9A00D156, 0x5E00FF69, 0x5900C765, 0x3D00D177 };
|
||||||
|
return strMakeFromLetters(letters);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
@interface OpenWithApp : NSObject {
|
||||||
|
NSString *fullname;
|
||||||
|
NSURL *app;
|
||||||
|
NSImage *icon;
|
||||||
|
}
|
||||||
|
@property (nonatomic, retain) NSString *fullname;
|
||||||
|
@property (nonatomic, retain) NSURL *app;
|
||||||
|
@property (nonatomic, retain) NSImage *icon;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation OpenWithApp
|
||||||
|
@synthesize fullname, app, icon;
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[fullname release];
|
||||||
|
[app release];
|
||||||
|
[icon release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface OpenFileWithInterface : NSObject {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init:(NSString *)file;
|
||||||
|
- (BOOL) popupAtX:(int)x andY:(int)y;
|
||||||
|
- (void) itemChosen:(id)sender;
|
||||||
|
- (void) dealloc;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation OpenFileWithInterface {
|
||||||
|
NSString *toOpen;
|
||||||
|
|
||||||
|
NSURL *defUrl;
|
||||||
|
NSString *defBundle, *defName, *defVersion;
|
||||||
|
NSImage *defIcon;
|
||||||
|
|
||||||
|
NSMutableArray *apps;
|
||||||
|
|
||||||
|
NSMenu *menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) fillAppByUrl:(NSURL*)url bundle:(NSString**)bundle name:(NSString**)name version:(NSString**)version icon:(NSImage**)icon {
|
||||||
|
NSBundle *b = [NSBundle bundleWithURL:url];
|
||||||
|
if (b) {
|
||||||
|
NSString *path = [url path];
|
||||||
|
*name = [[NSFileManager defaultManager] displayNameAtPath: path];
|
||||||
|
if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||||
|
if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleName"];
|
||||||
|
if (*name) {
|
||||||
|
*bundle = [b bundleIdentifier];
|
||||||
|
if (bundle) {
|
||||||
|
*version = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||||
|
*icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
|
||||||
|
if (*icon && [*icon isValid]) [*icon setSize: CGSizeMake(16., 16.)];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bundle = *name = *version = nil;
|
||||||
|
*icon = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init:(NSString*)file {
|
||||||
|
toOpen = [file retain];
|
||||||
|
if (self = [super init]) {
|
||||||
|
NSURL *url = [NSURL fileURLWithPath:file];
|
||||||
|
defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url];
|
||||||
|
if (defUrl) {
|
||||||
|
[self fillAppByUrl:defUrl bundle:&defBundle name:&defName version:&defVersion icon:&defIcon];
|
||||||
|
if (!defBundle || !defName) {
|
||||||
|
defUrl = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSArray *appsList = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
|
||||||
|
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:16];
|
||||||
|
int fullcount = 0;
|
||||||
|
for (id app in appsList) {
|
||||||
|
if (fullcount > 15) break;
|
||||||
|
|
||||||
|
NSString *bundle = nil, *name = nil, *version = nil;
|
||||||
|
NSImage *icon = nil;
|
||||||
|
[self fillAppByUrl:(NSURL*)app bundle:&bundle name:&name version:&version icon:&icon];
|
||||||
|
if (bundle && name) {
|
||||||
|
if ([bundle isEqualToString:defBundle] && [version isEqualToString:defVersion]) continue;
|
||||||
|
NSString *key = [[NSArray arrayWithObjects:bundle, name, nil] componentsJoinedByString:@"|"];
|
||||||
|
if (!version) version = @"";
|
||||||
|
|
||||||
|
NSMutableDictionary *versions = (NSMutableDictionary*)[data objectForKey:key];
|
||||||
|
if (!versions) {
|
||||||
|
versions = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||||
|
[data setValue:versions forKey:key];
|
||||||
|
}
|
||||||
|
if (![versions objectForKey:version]) {
|
||||||
|
[versions setValue:[NSArray arrayWithObjects:name, icon, app, nil] forKey:version];
|
||||||
|
++fullcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fullcount || defUrl) {
|
||||||
|
apps = [NSMutableArray arrayWithCapacity:fullcount];
|
||||||
|
for (id key in data) {
|
||||||
|
NSMutableDictionary *val = (NSMutableDictionary*)[data objectForKey:key];
|
||||||
|
for (id ver in val) {
|
||||||
|
NSArray *app = (NSArray*)[val objectForKey:ver];
|
||||||
|
OpenWithApp *a = [[OpenWithApp alloc] init];
|
||||||
|
NSString *fullname = (NSString*)[app objectAtIndex:0], *version = (NSString*)ver;
|
||||||
|
BOOL showVersion = ([val count] > 1);
|
||||||
|
if (!showVersion) {
|
||||||
|
NSError *error = NULL;
|
||||||
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" options:NSRegularExpressionCaseInsensitive error:&error];
|
||||||
|
showVersion = ![regex numberOfMatchesInString:version options:NSMatchingWithoutAnchoringBounds range:{0,[version length]}];
|
||||||
|
}
|
||||||
|
if (showVersion) fullname = [[NSArray arrayWithObjects:fullname, @" (", version, @")", nil] componentsJoinedByString:@""];
|
||||||
|
[a setFullname:fullname];
|
||||||
|
[a setIcon:(NSImage*)[app objectAtIndex:1]];
|
||||||
|
[a setApp:(NSURL*)[app objectAtIndex:2]];
|
||||||
|
[apps addObject:a];
|
||||||
|
[a release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[apps sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"fullname" ascending:YES]]];
|
||||||
|
[appsList release];
|
||||||
|
menu = nil;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) popupAtX:(int)x andY:(int)y {
|
||||||
|
if (![apps count] && !defName) return NO;
|
||||||
|
menu = [[NSMenu alloc] initWithTitle:@"Open With"];
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
if (defName) {
|
||||||
|
NSMenuItem *item = [menu insertItemWithTitle:[[NSArray arrayWithObjects:defName, @" (default)", nil] componentsJoinedByString:@""] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
||||||
|
if (defIcon) [item setImage:defIcon];
|
||||||
|
[item setTarget:self];
|
||||||
|
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
|
||||||
|
}
|
||||||
|
if ([apps count]) {
|
||||||
|
for (id a in apps) {
|
||||||
|
OpenWithApp *app = (OpenWithApp*)a;
|
||||||
|
NSMenuItem *item = [menu insertItemWithTitle:[a fullname] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
||||||
|
if ([app icon]) [item setImage:[app icon]];
|
||||||
|
[item setTarget:self];
|
||||||
|
}
|
||||||
|
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
|
||||||
|
}
|
||||||
|
NSMenuItem *item = [menu insertItemWithTitle:NSlang(lng_mac_choose_program_menu) action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
||||||
|
[item setTarget:self];
|
||||||
|
|
||||||
|
[menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) itemChosen:(id)sender {
|
||||||
|
NSArray *items = [menu itemArray];
|
||||||
|
NSURL *url = nil;
|
||||||
|
for (int i = 0, l = [items count]; i < l; ++i) {
|
||||||
|
if ([items objectAtIndex:i] == sender) {
|
||||||
|
if (defName) i -= 2;
|
||||||
|
if (i < 0) {
|
||||||
|
url = defUrl;
|
||||||
|
} else if (i < int([apps count])) {
|
||||||
|
url = [(OpenWithApp*)[apps objectAtIndex:i] app];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
[[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]];
|
||||||
|
} else if (!Platform::File::UnsafeShowOpenWith(NS2QString(toOpen))) {
|
||||||
|
Platform::File::UnsafeLaunch(NS2QString(toOpen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
[toOpen release];
|
||||||
|
if (menu) [menu release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSURL(CompareUrls)
|
||||||
|
|
||||||
|
- (BOOL) isEquivalent:(NSURL *)aURL;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSURL(CompareUrls)
|
||||||
|
|
||||||
|
- (BOOL) isEquivalent:(NSURL *)aURL {
|
||||||
|
if ([self isEqual:aURL]) return YES;
|
||||||
|
if ([[self scheme] caseInsensitiveCompare:[aURL scheme]] != NSOrderedSame) return NO;
|
||||||
|
if ([[self host] caseInsensitiveCompare:[aURL host]] != NSOrderedSame) return NO;
|
||||||
|
if ([[self path] compare:[aURL path]] != NSOrderedSame) return NO;
|
||||||
|
if ([[self port] compare:[aURL port]] != NSOrderedSame) return NO;
|
||||||
|
if ([[self query] compare:[aURL query]] != NSOrderedSame) return NO;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ChooseApplicationDelegate : NSObject<NSOpenSavePanelDelegate> {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc;
|
||||||
|
- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url;
|
||||||
|
- (void) panelSelectionDidChange:(id)sender;
|
||||||
|
- (void) menuDidClose;
|
||||||
|
- (void) dealloc;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ChooseApplicationDelegate {
|
||||||
|
BOOL onlyRecommended;
|
||||||
|
NSArray *apps;
|
||||||
|
NSOpenPanel *panel;
|
||||||
|
NSPopUpButton *selector;
|
||||||
|
NSTextField *good, *bad;
|
||||||
|
NSImageView *icon;
|
||||||
|
NSString *recom;
|
||||||
|
NSView *accessory;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc {
|
||||||
|
if (self = [super init]) {
|
||||||
|
onlyRecommended = YES;
|
||||||
|
recom = [NSlang(lng_mac_recommended_apps) copy];
|
||||||
|
apps = recommendedApps;
|
||||||
|
panel = creator;
|
||||||
|
selector = menu;
|
||||||
|
good = goodLabel;
|
||||||
|
bad = badLabel;
|
||||||
|
icon = badIcon;
|
||||||
|
accessory = acc;
|
||||||
|
[selector setAction:@selector(menuDidClose)];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isRecommended:(NSURL *)url {
|
||||||
|
if (apps) {
|
||||||
|
for (id app in apps) {
|
||||||
|
if ([(NSURL*)app isEquivalent:url]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url {
|
||||||
|
NSNumber *isDirectory;
|
||||||
|
if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && isDirectory != nil && [isDirectory boolValue]) {
|
||||||
|
if (onlyRecommended) {
|
||||||
|
CFStringRef ext = CFURLCopyPathExtension((CFURLRef)url);
|
||||||
|
NSNumber *isPackage;
|
||||||
|
if ([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && isPackage != nil && [isPackage boolValue]) {
|
||||||
|
return [self isRecommended:url];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) panelSelectionDidChange:(id)sender {
|
||||||
|
NSArray *urls = [panel URLs];
|
||||||
|
if ([urls count]) {
|
||||||
|
if ([self isRecommended:[urls firstObject]]) {
|
||||||
|
[bad removeFromSuperview];
|
||||||
|
[icon removeFromSuperview];
|
||||||
|
[accessory addSubview:good];
|
||||||
|
} else {
|
||||||
|
[good removeFromSuperview];
|
||||||
|
[accessory addSubview:bad];
|
||||||
|
[accessory addSubview:icon];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[good removeFromSuperview];
|
||||||
|
[bad removeFromSuperview];
|
||||||
|
[icon removeFromSuperview];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) menuDidClose {
|
||||||
|
onlyRecommended = [[[selector selectedItem] title] isEqualToString:recom];
|
||||||
|
[self refreshPanelTable];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) refreshDataInViews: (NSArray*)subviews {
|
||||||
|
for (id view in subviews) {
|
||||||
|
NSString *cls = [view className];
|
||||||
|
if ([cls isEqualToString:Q2NSString(strNeedToReload())]) {
|
||||||
|
[view reloadData];
|
||||||
|
} else if ([cls isEqualToString:Q2NSString(strNeedToRefresh1())] || [cls isEqualToString:Q2NSString(strNeedToRefresh2())]) {
|
||||||
|
[view reloadData];
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
NSArray *next = [view subviews];
|
||||||
|
if ([next count] && [self refreshDataInViews:next]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void) refreshPanelTable {
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
[self refreshDataInViews:[[panel contentView] subviews]];
|
||||||
|
[panel validateVisibleColumns];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc {
|
||||||
|
if (apps) {
|
||||||
|
[apps release];
|
||||||
|
[recom release];
|
||||||
|
}
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace File {
|
namespace File {
|
||||||
|
|
||||||
|
@ -40,5 +396,195 @@ QString UrlToLocal(const QUrl &url) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UnsafeShowOpenWithDropdown(const QString &filepath, QPoint menuPosition) {
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
NSString *file = Q2NSString(filepath);
|
||||||
|
@try {
|
||||||
|
OpenFileWithInterface *menu = [[[OpenFileWithInterface alloc] init:file] autorelease];
|
||||||
|
auto r = QApplication::desktop()->screenGeometry(menuPosition);
|
||||||
|
auto x = menuPosition.x();
|
||||||
|
auto y = r.y() + r.height() - menuPosition.y();
|
||||||
|
return !![menu popupAtX:x andY:y];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
}
|
||||||
|
@finally {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsafeShowOpenWith(const QString &filepath) {
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
NSString *file = Q2NSString(filepath);
|
||||||
|
@try {
|
||||||
|
NSURL *url = [NSURL fileURLWithPath:file];
|
||||||
|
NSString *ext = [url pathExtension];
|
||||||
|
NSArray *names = [url pathComponents];
|
||||||
|
NSString *name = [names count] ? [names lastObject] : @"";
|
||||||
|
NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
|
||||||
|
|
||||||
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
||||||
|
|
||||||
|
NSRect fullRect = { { 0., 0. }, { st::macAccessoryWidth, st::macAccessoryHeight } };
|
||||||
|
NSView *accessory = [[NSView alloc] initWithFrame:fullRect];
|
||||||
|
|
||||||
|
[accessory setAutoresizesSubviews:YES];
|
||||||
|
|
||||||
|
NSPopUpButton *selector = [[NSPopUpButton alloc] init];
|
||||||
|
[accessory addSubview:selector];
|
||||||
|
[selector addItemWithTitle:NSlang(lng_mac_recommended_apps)];
|
||||||
|
[selector addItemWithTitle:NSlang(lng_mac_all_apps)];
|
||||||
|
[selector sizeToFit];
|
||||||
|
|
||||||
|
NSTextField *enableLabel = [[NSTextField alloc] init];
|
||||||
|
[accessory addSubview:enableLabel];
|
||||||
|
[enableLabel setStringValue:NSlang(lng_mac_enable_filter)];
|
||||||
|
[enableLabel setFont:[selector font]];
|
||||||
|
[enableLabel setBezeled:NO];
|
||||||
|
[enableLabel setDrawsBackground:NO];
|
||||||
|
[enableLabel setEditable:NO];
|
||||||
|
[enableLabel setSelectable:NO];
|
||||||
|
[enableLabel sizeToFit];
|
||||||
|
|
||||||
|
NSRect selectorFrame = [selector frame], enableFrame = [enableLabel frame];
|
||||||
|
enableFrame.size.width += st::macEnableFilterAdd;
|
||||||
|
enableFrame.origin.x = (fullRect.size.width - selectorFrame.size.width - enableFrame.size.width) / 2.;
|
||||||
|
selectorFrame.origin.x = (fullRect.size.width - selectorFrame.size.width + enableFrame.size.width) / 2.;
|
||||||
|
enableFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macEnableFilterTop + (selectorFrame.size.height - enableFrame.size.height) / 2.;
|
||||||
|
selectorFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macSelectorTop;
|
||||||
|
[enableLabel setFrame:enableFrame];
|
||||||
|
[enableLabel setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
||||||
|
[selector setFrame:selectorFrame];
|
||||||
|
[selector setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
||||||
|
|
||||||
|
NSButton *button = [[NSButton alloc] init];
|
||||||
|
[accessory addSubview:button];
|
||||||
|
[button setButtonType:NSSwitchButton];
|
||||||
|
[button setFont:[selector font]];
|
||||||
|
[button setTitle:NSlang(lng_mac_always_open_with)];
|
||||||
|
[button sizeToFit];
|
||||||
|
NSRect alwaysRect = [button frame];
|
||||||
|
alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2;
|
||||||
|
alwaysRect.origin.y = selectorFrame.origin.y - alwaysRect.size.height - st::macAlwaysThisAppTop;
|
||||||
|
[button setFrame:alwaysRect];
|
||||||
|
[button setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
||||||
|
#ifdef OS_MAC_STORE
|
||||||
|
[button setHidden:YES];
|
||||||
|
#endif // OS_MAC_STORE
|
||||||
|
NSTextField *goodLabel = [[NSTextField alloc] init];
|
||||||
|
[goodLabel setStringValue:Q2NSString(lng_mac_this_app_can_open(lt_file, NS2QString(name)))];
|
||||||
|
[goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
||||||
|
[goodLabel setBezeled:NO];
|
||||||
|
[goodLabel setDrawsBackground:NO];
|
||||||
|
[goodLabel setEditable:NO];
|
||||||
|
[goodLabel setSelectable:NO];
|
||||||
|
[goodLabel sizeToFit];
|
||||||
|
NSRect goodFrame = [goodLabel frame];
|
||||||
|
goodFrame.origin.x = (fullRect.size.width - goodFrame.size.width) / 2.;
|
||||||
|
goodFrame.origin.y = alwaysRect.origin.y - goodFrame.size.height - st::macAppHintTop;
|
||||||
|
[goodLabel setFrame:goodFrame];
|
||||||
|
|
||||||
|
NSTextField *badLabel = [[NSTextField alloc] init];
|
||||||
|
[badLabel setStringValue:Q2NSString(lng_mac_not_known_app(lt_file, NS2QString(name)))];
|
||||||
|
[badLabel setFont:[goodLabel font]];
|
||||||
|
[badLabel setBezeled:NO];
|
||||||
|
[badLabel setDrawsBackground:NO];
|
||||||
|
[badLabel setEditable:NO];
|
||||||
|
[badLabel setSelectable:NO];
|
||||||
|
[badLabel sizeToFit];
|
||||||
|
NSImageView *badIcon = [[NSImageView alloc] init];
|
||||||
|
NSImage *badImage = [NSImage imageNamed:NSImageNameCaution];
|
||||||
|
[badIcon setImage:badImage];
|
||||||
|
[badIcon setFrame:NSMakeRect(0, 0, st::macCautionIconSize, st::macCautionIconSize)];
|
||||||
|
|
||||||
|
NSRect badFrame = [badLabel frame], badIconFrame = [badIcon frame];
|
||||||
|
badFrame.origin.x = (fullRect.size.width - badFrame.size.width + badIconFrame.size.width) / 2.;
|
||||||
|
badIconFrame.origin.x = (fullRect.size.width - badFrame.size.width - badIconFrame.size.width) / 2.;
|
||||||
|
badFrame.origin.y = alwaysRect.origin.y - badFrame.size.height - st::macAppHintTop;
|
||||||
|
badIconFrame.origin.y = badFrame.origin.y;
|
||||||
|
[badLabel setFrame:badFrame];
|
||||||
|
[badIcon setFrame:badIconFrame];
|
||||||
|
|
||||||
|
[openPanel setAccessoryView:accessory];
|
||||||
|
|
||||||
|
ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps withPanel:openPanel withSelector:selector withGood:goodLabel withBad:badLabel withIcon:badIcon withAccessory:accessory];
|
||||||
|
[openPanel setDelegate:delegate];
|
||||||
|
|
||||||
|
[openPanel setCanChooseDirectories:NO];
|
||||||
|
[openPanel setCanChooseFiles:YES];
|
||||||
|
[openPanel setAllowsMultipleSelection:NO];
|
||||||
|
[openPanel setResolvesAliases:YES];
|
||||||
|
[openPanel setTitle:NSlang(lng_mac_choose_app)];
|
||||||
|
[openPanel setMessage:Q2NSString(lng_mac_choose_text(lt_file, NS2QString(name)))];
|
||||||
|
|
||||||
|
NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask];
|
||||||
|
if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]];
|
||||||
|
[openPanel beginWithCompletionHandler:^(NSInteger result){
|
||||||
|
if (result == NSFileHandlingPanelOKButton) {
|
||||||
|
if ([[openPanel URLs] count] > 0) {
|
||||||
|
NSURL *app = [[openPanel URLs] objectAtIndex:0];
|
||||||
|
NSString *path = [app path];
|
||||||
|
if ([button state] == NSOnState) {
|
||||||
|
NSArray *UTIs = (NSArray *)UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension,
|
||||||
|
(CFStringRef)ext,
|
||||||
|
nil);
|
||||||
|
for (NSString *UTI in UTIs) {
|
||||||
|
OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI,
|
||||||
|
kLSRolesAll,
|
||||||
|
(CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]);
|
||||||
|
DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(NS2QString(UTI)).arg(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
[UTIs release];
|
||||||
|
}
|
||||||
|
[[NSWorkspace sharedWorkspace] openFile:file withApplication:[app path]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[selector release];
|
||||||
|
[button release];
|
||||||
|
[enableLabel release];
|
||||||
|
[goodLabel release];
|
||||||
|
[badLabel release];
|
||||||
|
[badIcon release];
|
||||||
|
[accessory release];
|
||||||
|
[delegate release];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
[[NSWorkspace sharedWorkspace] openFile:file];
|
||||||
|
}
|
||||||
|
@finally {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsafeLaunch(const QString &filepath) {
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
NSString *file = Q2NSString(filepath);
|
||||||
|
if ([[NSWorkspace sharedWorkspace] openFile:file] == NO) {
|
||||||
|
UnsafeShowOpenWith(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsafeShowInFolder(const QString &filepath) {
|
||||||
|
auto folder = QFileInfo(filepath).absolutePath();
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
|
[[NSWorkspace sharedWorkspace] selectFile:Q2NSString(filepath) inFileViewerRootedAtPath:Q2NSString(folder)];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace File
|
} // namespace File
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -293,7 +293,7 @@ void MainWindow::psUpdateWorkmode() {
|
||||||
trayIcon = nullptr;
|
trayIcon = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto manager = Platform::Notifications::ManagerNative()) {
|
if (auto manager = Platform::Notifications::GetNativeManager()) {
|
||||||
manager->updateDelegate();
|
manager->updateDelegate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,6 @@ inline bool SkipToast() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Window::Notifications::Manager *GetManager() {
|
|
||||||
return GetNativeManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Manager : public Window::Notifications::NativeManager {
|
class Manager : public Window::Notifications::NativeManager {
|
||||||
public:
|
public:
|
||||||
Manager();
|
Manager();
|
||||||
|
@ -59,5 +55,9 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline Window::Notifications::Manager *GetManager() {
|
||||||
|
return GetNativeManager();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Notifications
|
} // namespace Notifications
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -20,20 +20,29 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace File {
|
namespace File {
|
||||||
|
|
||||||
QString UrlToLocal(const QUrl &url);
|
QString UrlToLocal(const QUrl &url);
|
||||||
|
|
||||||
|
// All these functions may enter a nested event loop. Use with caution.
|
||||||
|
void UnsafeOpenEmailLink(const QString &email);
|
||||||
|
bool UnsafeShowOpenWithDropdown(const QString &filepath, QPoint menuPosition);
|
||||||
|
bool UnsafeShowOpenWith(const QString &filepath);
|
||||||
|
void UnsafeLaunch(const QString &filepath);
|
||||||
|
void UnsafeShowInFolder(const QString &filepath);
|
||||||
|
|
||||||
|
void PostprocessDownloaded(const QString &filepath);
|
||||||
|
|
||||||
} // namespace File
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
namespace FileDialog {
|
||||||
|
|
||||||
bool Supported();
|
void InitLastPath();
|
||||||
|
|
||||||
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile);
|
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile = QString());
|
||||||
|
|
||||||
} // namespace FileDialog
|
} // namespace FileDialog
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -180,7 +180,6 @@ void DeInit() {
|
||||||
if (WasCoInitialized) {
|
if (WasCoInitialized) {
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
AUDCLNT_E_NOT_INITIALIZED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Audio
|
} // namespace Audio
|
||||||
|
|
|
@ -21,3 +21,401 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "platform/win/file_utilities_win.h"
|
#include "platform/win/file_utilities_win.h"
|
||||||
|
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "localstorage.h"
|
||||||
|
#include "platform/win/windows_dlls.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
|
#include <Shlwapi.h>
|
||||||
|
#include <Windowsx.h>
|
||||||
|
|
||||||
|
HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &, int hbitmapFormat);
|
||||||
|
|
||||||
|
namespace Platform {
|
||||||
|
namespace File {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class OpenWithApp {
|
||||||
|
public:
|
||||||
|
OpenWithApp(const QString &name, IAssocHandler *handler, HBITMAP icon = nullptr)
|
||||||
|
: _name(name)
|
||||||
|
, _handler(handler)
|
||||||
|
, _icon(icon) {
|
||||||
|
}
|
||||||
|
OpenWithApp(OpenWithApp &&other)
|
||||||
|
: _name(base::take(other._name))
|
||||||
|
, _handler(base::take(other._handler))
|
||||||
|
, _icon(base::take(other._icon)) {
|
||||||
|
}
|
||||||
|
OpenWithApp &operator=(OpenWithApp &&other) {
|
||||||
|
_name = base::take(other._name);
|
||||||
|
_icon = base::take(other._icon);
|
||||||
|
_handler = base::take(other._handler);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenWithApp(const OpenWithApp &other) = delete;
|
||||||
|
OpenWithApp &operator=(const OpenWithApp &other) = delete;
|
||||||
|
|
||||||
|
~OpenWithApp() {
|
||||||
|
if (_icon) {
|
||||||
|
DeleteBitmap(_icon);
|
||||||
|
}
|
||||||
|
if (_handler) {
|
||||||
|
_handler->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &name() const {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
HBITMAP icon() const {
|
||||||
|
return _icon;
|
||||||
|
}
|
||||||
|
IAssocHandler *handler() const {
|
||||||
|
return _handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _name;
|
||||||
|
IAssocHandler *_handler = nullptr;
|
||||||
|
HBITMAP _icon = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
HBITMAP IconToBitmap(LPWSTR icon, int iconindex) {
|
||||||
|
if (!icon) return 0;
|
||||||
|
WCHAR tmpIcon[4096];
|
||||||
|
if (icon[0] == L'@' && SUCCEEDED(SHLoadIndirectString(icon, tmpIcon, 4096, 0))) {
|
||||||
|
icon = tmpIcon;
|
||||||
|
}
|
||||||
|
int32 w = GetSystemMetrics(SM_CXSMICON), h = GetSystemMetrics(SM_CYSMICON);
|
||||||
|
|
||||||
|
HICON ico = ExtractIcon(0, icon, iconindex);
|
||||||
|
if (!ico) {
|
||||||
|
if (!iconindex) { // try to read image
|
||||||
|
QImage img(QString::fromWCharArray(icon));
|
||||||
|
if (!img.isNull()) {
|
||||||
|
return qt_pixmapToWinHBITMAP(App::pixmapFromImageInPlace(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), /* HBitmapAlpha */ 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HDC screenDC = GetDC(0), hdc = CreateCompatibleDC(screenDC);
|
||||||
|
HBITMAP result = CreateCompatibleBitmap(screenDC, w, h);
|
||||||
|
HGDIOBJ was = SelectObject(hdc, result);
|
||||||
|
DrawIconEx(hdc, 0, 0, ico, w, h, 0, NULL, DI_NORMAL);
|
||||||
|
SelectObject(hdc, was);
|
||||||
|
DeleteDC(hdc);
|
||||||
|
ReleaseDC(0, screenDC);
|
||||||
|
|
||||||
|
DestroyIcon(ico);
|
||||||
|
|
||||||
|
return (HBITMAP)CopyImage(result, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void UnsafeOpenEmailLink(const QString &email) {
|
||||||
|
auto url = QUrl(qstr("mailto:") + email);
|
||||||
|
if (!QDesktopServices::openUrl(url)) {
|
||||||
|
auto wstringUrl = url.toString(QUrl::FullyEncoded).toStdWString();
|
||||||
|
if (Dlls::SHOpenWithDialog) {
|
||||||
|
OPENASINFO info;
|
||||||
|
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC | OAIF_FILE_IS_URI | OAIF_URL_PROTOCOL;
|
||||||
|
info.pcszClass = NULL;
|
||||||
|
info.pcszFile = wstringUrl.c_str();
|
||||||
|
Dlls::SHOpenWithDialog(0, &info);
|
||||||
|
} else if (Dlls::OpenAs_RunDLL) {
|
||||||
|
Dlls::OpenAs_RunDLL(0, 0, wstringUrl.c_str(), SW_SHOWNORMAL);
|
||||||
|
} else {
|
||||||
|
ShellExecute(0, L"open", wstringUrl.c_str(), 0, 0, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsafeShowOpenWithDropdown(const QString &filepath, QPoint menuPosition) {
|
||||||
|
auto window = App::wnd();
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
auto parentHWND = window->psHwnd();
|
||||||
|
auto wstringPath = QDir::toNativeSeparators(filepath).toStdWString();
|
||||||
|
|
||||||
|
auto result = false;
|
||||||
|
std::vector<OpenWithApp> handlers;
|
||||||
|
IShellItem* pItem = nullptr;
|
||||||
|
if (SUCCEEDED(Dlls::SHCreateItemFromParsingName(wstringPath.c_str(), nullptr, IID_PPV_ARGS(&pItem)))) {
|
||||||
|
IEnumAssocHandlers *assocHandlers = nullptr;
|
||||||
|
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_EnumAssocHandlers, IID_PPV_ARGS(&assocHandlers)))) {
|
||||||
|
HRESULT hr = S_FALSE;
|
||||||
|
do {
|
||||||
|
IAssocHandler *handler = nullptr;
|
||||||
|
ULONG ulFetched = 0;
|
||||||
|
hr = assocHandlers->Next(1, &handler, &ulFetched);
|
||||||
|
if (FAILED(hr) || hr == S_FALSE || !ulFetched) break;
|
||||||
|
|
||||||
|
LPWSTR name = 0;
|
||||||
|
if (SUCCEEDED(handler->GetUIName(&name))) {
|
||||||
|
LPWSTR icon = 0;
|
||||||
|
int iconindex = 0;
|
||||||
|
if (SUCCEEDED(handler->GetIconLocation(&icon, &iconindex)) && icon) {
|
||||||
|
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), handler, IconToBitmap(icon, iconindex)));
|
||||||
|
CoTaskMemFree(icon);
|
||||||
|
} else {
|
||||||
|
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), handler));
|
||||||
|
}
|
||||||
|
CoTaskMemFree(name);
|
||||||
|
} else {
|
||||||
|
handler->Release();
|
||||||
|
}
|
||||||
|
} while (hr != S_FALSE);
|
||||||
|
assocHandlers->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handlers.empty()) {
|
||||||
|
HMENU menu = CreatePopupMenu();
|
||||||
|
std::sort(handlers.begin(), handlers.end(), [](const OpenWithApp &a, const OpenWithApp &b) {
|
||||||
|
return a.name() < b.name();
|
||||||
|
});
|
||||||
|
for (int32 i = 0, l = handlers.size(); i < l; ++i) {
|
||||||
|
MENUITEMINFO menuInfo = { 0 };
|
||||||
|
menuInfo.cbSize = sizeof(menuInfo);
|
||||||
|
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
|
||||||
|
menuInfo.fType = MFT_STRING;
|
||||||
|
menuInfo.wID = i + 1;
|
||||||
|
if (auto icon = handlers[i].icon()) {
|
||||||
|
menuInfo.fMask |= MIIM_BITMAP;
|
||||||
|
menuInfo.hbmpItem = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto name = handlers[i].name();
|
||||||
|
if (name.size() > 512) name = name.mid(0, 512);
|
||||||
|
WCHAR nameArr[1024];
|
||||||
|
name.toWCharArray(nameArr);
|
||||||
|
nameArr[name.size()] = 0;
|
||||||
|
menuInfo.dwTypeData = nameArr;
|
||||||
|
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
|
||||||
|
}
|
||||||
|
MENUITEMINFO sepInfo = { 0 };
|
||||||
|
sepInfo.cbSize = sizeof(sepInfo);
|
||||||
|
sepInfo.fMask = MIIM_STRING | MIIM_DATA;
|
||||||
|
sepInfo.fType = MFT_SEPARATOR;
|
||||||
|
InsertMenuItem(menu, GetMenuItemCount(menu), true, &sepInfo);
|
||||||
|
|
||||||
|
MENUITEMINFO menuInfo = { 0 };
|
||||||
|
menuInfo.cbSize = sizeof(menuInfo);
|
||||||
|
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
|
||||||
|
menuInfo.fType = MFT_STRING;
|
||||||
|
menuInfo.wID = handlers.size() + 1;
|
||||||
|
|
||||||
|
QString name = lang(lng_wnd_choose_program_menu);
|
||||||
|
if (name.size() > 512) name = name.mid(0, 512);
|
||||||
|
WCHAR nameArr[1024];
|
||||||
|
name.toWCharArray(nameArr);
|
||||||
|
nameArr[name.size()] = 0;
|
||||||
|
menuInfo.dwTypeData = nameArr;
|
||||||
|
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
|
||||||
|
|
||||||
|
int sel = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, menuPosition.x(), menuPosition.y(), 0, parentHWND, 0);
|
||||||
|
DestroyMenu(menu);
|
||||||
|
|
||||||
|
if (sel > 0) {
|
||||||
|
if (sel <= handlers.size()) {
|
||||||
|
IDataObject *dataObj = 0;
|
||||||
|
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_DataObject, IID_PPV_ARGS(&dataObj))) && dataObj) {
|
||||||
|
handlers[sel - 1].handler()->Invoke(dataObj);
|
||||||
|
dataObj->Release();
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pItem->Release();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnsafeShowOpenWith(const QString &filepath) {
|
||||||
|
auto wstringPath = QDir::toNativeSeparators(filepath).toStdWString();
|
||||||
|
if (Dlls::SHOpenWithDialog) {
|
||||||
|
OPENASINFO info;
|
||||||
|
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
|
||||||
|
info.pcszClass = NULL;
|
||||||
|
info.pcszFile = wstringPath.c_str();
|
||||||
|
Dlls::SHOpenWithDialog(0, &info);
|
||||||
|
return true;
|
||||||
|
} else if (Dlls::OpenAs_RunDLL) {
|
||||||
|
Dlls::OpenAs_RunDLL(0, 0, wstringPath.c_str(), SW_SHOWNORMAL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsafeLaunch(const QString &filepath) {
|
||||||
|
auto wstringPath = QDir::toNativeSeparators(filepath).toStdWString();
|
||||||
|
ShellExecute(0, L"open", wstringPath.c_str(), 0, 0, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnsafeShowInFolder(const QString &filepath) {
|
||||||
|
auto pathEscaped = QDir::toNativeSeparators(filepath).replace('"', qsl("\"\""));
|
||||||
|
auto wstringParam = (qstr("/select,") + pathEscaped).toStdWString();
|
||||||
|
ShellExecute(0, 0, L"explorer", wstringParam.c_str(), 0, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostprocessDownloaded(const QString &filepath) {
|
||||||
|
auto wstringZoneFile = QDir::toNativeSeparators(filepath).toStdWString() + L":Zone.Identifier";
|
||||||
|
auto f = CreateFile(wstringZoneFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (f == INVALID_HANDLE_VALUE) { // :(
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char data[] = "[ZoneTransfer]\r\nZoneId=3\r\n";
|
||||||
|
|
||||||
|
DWORD written = 0;
|
||||||
|
BOOL result = WriteFile(f, data, sizeof(data), &written, NULL);
|
||||||
|
CloseHandle(f);
|
||||||
|
|
||||||
|
if (!result || written != sizeof(data)) { // :(
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace File
|
||||||
|
|
||||||
|
namespace FileDialog {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Type = ::FileDialog::internal::Type;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void InitLastPath() {
|
||||||
|
// hack to restore previous dir without hurting performance
|
||||||
|
QSettings settings(QSettings::UserScope, qstr("QtProject"));
|
||||||
|
settings.beginGroup(qstr("Qt"));
|
||||||
|
QByteArray sd = settings.value(qstr("filedialog")).toByteArray();
|
||||||
|
QDataStream stream(&sd, QIODevice::ReadOnly);
|
||||||
|
if (!stream.atEnd()) {
|
||||||
|
int version = 3, _QFileDialogMagic = 190;
|
||||||
|
QByteArray splitterState;
|
||||||
|
QByteArray headerData;
|
||||||
|
QList<QUrl> bookmarks;
|
||||||
|
QStringList history;
|
||||||
|
QString currentDirectory;
|
||||||
|
qint32 marker;
|
||||||
|
qint32 v;
|
||||||
|
qint32 viewMode;
|
||||||
|
stream >> marker;
|
||||||
|
stream >> v;
|
||||||
|
if (marker == _QFileDialogMagic && v == version) {
|
||||||
|
stream >> splitterState
|
||||||
|
>> bookmarks
|
||||||
|
>> history
|
||||||
|
>> currentDirectory
|
||||||
|
>> headerData
|
||||||
|
>> viewMode;
|
||||||
|
cSetDialogLastPath(currentDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cDialogHelperPath().isEmpty()) {
|
||||||
|
QDir temppath(cWorkingDir() + "tdata/tdummy/");
|
||||||
|
if (!temppath.exists()) {
|
||||||
|
temppath.mkpath(temppath.absolutePath());
|
||||||
|
}
|
||||||
|
if (temppath.exists()) {
|
||||||
|
cSetDialogHelperPath(temppath.absolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
||||||
|
if (cDialogLastPath().isEmpty()) {
|
||||||
|
Platform::FileDialog::InitLastPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A hack for fast dialog create. There was some huge performance problem
|
||||||
|
// if we open a file dialog in some folder with a large amount of files.
|
||||||
|
// Some internal Qt watcher iterated over all of them, querying some information
|
||||||
|
// that forced file icon and maybe other properties being resolved and this was
|
||||||
|
// a blocking operation.
|
||||||
|
auto helperPath = cDialogHelperPathFinal();
|
||||||
|
QFileDialog dialog(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, helperPath, filter);
|
||||||
|
|
||||||
|
dialog.setModal(true);
|
||||||
|
if (type == Type::ReadFile || type == Type::ReadFiles) {
|
||||||
|
dialog.setFileMode((type == Type::ReadFiles) ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile);
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
} else if (type == Type::ReadFolder) { // save dir
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
||||||
|
|
||||||
|
// We use "obsolete" value ::DirectoryOnly instead of ::Directory + ::ShowDirsOnly
|
||||||
|
// because in Windows XP native dialog this one works, while the "preferred" one
|
||||||
|
// shows a native file choose dialog where you can't choose a directory, only open one.
|
||||||
|
dialog.setFileMode(QFileDialog::DirectoryOnly);
|
||||||
|
dialog.setOption(QFileDialog::ShowDirsOnly);
|
||||||
|
} else { // save file
|
||||||
|
dialog.setFileMode(QFileDialog::AnyFile);
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
}
|
||||||
|
dialog.show();
|
||||||
|
|
||||||
|
auto realLastPath = ([startFile] {
|
||||||
|
// If we're given some non empty path containing a folder - use it.
|
||||||
|
if (!startFile.isEmpty() && (startFile.indexOf('/') >= 0 || startFile.indexOf('\\') >= 0)) {
|
||||||
|
return QFileInfo(startFile).dir().absolutePath();
|
||||||
|
}
|
||||||
|
return cDialogLastPath();
|
||||||
|
})();
|
||||||
|
if (realLastPath.isEmpty() || realLastPath.endsWith(qstr("/tdummy"))) {
|
||||||
|
realLastPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||||
|
}
|
||||||
|
dialog.setDirectory(realLastPath);
|
||||||
|
|
||||||
|
if (type == Type::WriteFile) {
|
||||||
|
auto toSelect = startFile;
|
||||||
|
auto lastSlash = toSelect.lastIndexOf('/');
|
||||||
|
if (lastSlash >= 0) {
|
||||||
|
toSelect = toSelect.mid(lastSlash + 1);
|
||||||
|
}
|
||||||
|
auto lastBackSlash = toSelect.lastIndexOf('\\');
|
||||||
|
if (lastBackSlash >= 0) {
|
||||||
|
toSelect = toSelect.mid(lastBackSlash + 1);
|
||||||
|
}
|
||||||
|
dialog.selectFile(toSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = dialog.exec();
|
||||||
|
|
||||||
|
if (type != Type::ReadFolder) {
|
||||||
|
// Save last used directory for all queries except directory choosing.
|
||||||
|
auto path = dialog.directory().absolutePath();
|
||||||
|
if (path != cDialogLastPath()) {
|
||||||
|
cSetDialogLastPath(path);
|
||||||
|
Local::writeUserSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == QDialog::Accepted) {
|
||||||
|
if (type == Type::ReadFiles) {
|
||||||
|
files = dialog.selectedFiles();
|
||||||
|
} else {
|
||||||
|
files = dialog.selectedFiles().mid(0, 1);
|
||||||
|
}
|
||||||
|
if (type == Type::ReadFile || type == Type::ReadFiles) {
|
||||||
|
remoteContent = dialog.selectedRemoteContent();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
files = QStringList();
|
||||||
|
remoteContent = QByteArray();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace FileDialog
|
||||||
|
} // namespace Platform
|
|
@ -30,16 +30,4 @@ inline QString UrlToLocal(const QUrl &url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace File
|
} // namespace File
|
||||||
|
|
||||||
namespace FileDialog {
|
|
||||||
|
|
||||||
inline bool Supported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Get(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, ::FileDialog::internal::Type type, QString startFile) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace FileDialog
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "profile/profile_cover_drop_area.h"
|
#include "profile/profile_cover_drop_area.h"
|
||||||
#include "profile/profile_userpic_button.h"
|
#include "profile/profile_userpic_button.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/observer.h"
|
#include "core/observer.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct RoundButton;
|
struct RoundButton;
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "platform/linux/file_utilities_linux.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -38,32 +38,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include <qpa/qplatformnativeinterface.h>
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
|
||||||
using namespace Platform;
|
using namespace Platform;
|
||||||
|
using Platform::File::internal::EscapeShell;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QByteArray escapeShell(const QByteArray &str) {
|
|
||||||
QByteArray result;
|
|
||||||
const char *b = str.constData(), *e = str.constEnd();
|
|
||||||
for (const char *ch = b; ch != e; ++ch) {
|
|
||||||
if (*ch == ' ' || *ch == '"' || *ch == '\'' || *ch == '\\') {
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
result.reserve(str.size() * 2);
|
|
||||||
}
|
|
||||||
if (ch > b) {
|
|
||||||
result.append(b, ch - b);
|
|
||||||
}
|
|
||||||
result.append('\\');
|
|
||||||
b = ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.isEmpty()) return str;
|
|
||||||
|
|
||||||
if (e > b) {
|
|
||||||
result.append(b, e - b);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PsEventFilter : public QAbstractNativeEventFilter {
|
class _PsEventFilter : public QAbstractNativeEventFilter {
|
||||||
public:
|
public:
|
||||||
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
|
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) {
|
||||||
|
@ -129,7 +107,7 @@ QStringList addr2linestr(uint64 *addresses, int count) {
|
||||||
if (!count) return result;
|
if (!count) return result;
|
||||||
|
|
||||||
result.reserve(count);
|
result.reserve(count);
|
||||||
QByteArray cmd = "addr2line -e " + escapeShell(QFile::encodeName(cExeDir() + cExeName()));
|
QByteArray cmd = "addr2line -e " + EscapeShell(QFile::encodeName(cExeDir() + cExeName()));
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (addresses[i]) {
|
if (addresses[i]) {
|
||||||
cmd += qsl(" 0x%1").arg(addresses[i], 0, 16).toUtf8();
|
cmd += qsl(" 0x%1").arg(addresses[i], 0, 16).toUtf8();
|
||||||
|
@ -387,18 +365,6 @@ int psFixPrevious() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void psOpenFile(const QString &name, bool openWith) {
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void psShowInFolder(const QString &name) {
|
|
||||||
Ui::hideLayer(true);
|
|
||||||
system(("xdg-open " + escapeShell(QFile::encodeName(QFileInfo(name).absoluteDir().absolutePath()))).constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
@ -503,7 +469,7 @@ void psRegisterCustomScheme() {
|
||||||
s << "Version=1.0\n";
|
s << "Version=1.0\n";
|
||||||
s << "Name=Telegram Desktop\n";
|
s << "Name=Telegram Desktop\n";
|
||||||
s << "Comment=Official desktop version of Telegram messaging app\n";
|
s << "Comment=Official desktop version of Telegram messaging app\n";
|
||||||
s << "Exec=" << escapeShell(QFile::encodeName(cExeDir() + cExeName())) << " -- %u\n";
|
s << "Exec=" << EscapeShell(QFile::encodeName(cExeDir() + cExeName())) << " -- %u\n";
|
||||||
s << "Icon=telegram\n";
|
s << "Icon=telegram\n";
|
||||||
s << "Terminal=false\n";
|
s << "Terminal=false\n";
|
||||||
s << "StartupWMClass=Telegram\n";
|
s << "StartupWMClass=Telegram\n";
|
||||||
|
@ -512,11 +478,11 @@ void psRegisterCustomScheme() {
|
||||||
s << "MimeType=x-scheme-handler/tg;\n";
|
s << "MimeType=x-scheme-handler/tg;\n";
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
if (_psRunCommand("desktop-file-install --dir=" + escapeShell(QFile::encodeName(home + qsl(".local/share/applications"))) + " --delete-original " + escapeShell(QFile::encodeName(file)))) {
|
if (_psRunCommand("desktop-file-install --dir=" + EscapeShell(QFile::encodeName(home + qsl(".local/share/applications"))) + " --delete-original " + EscapeShell(QFile::encodeName(file)))) {
|
||||||
DEBUG_LOG(("App Info: removing old .desktop file"));
|
DEBUG_LOG(("App Info: removing old .desktop file"));
|
||||||
QFile(qsl("%1.local/share/applications/telegram.desktop").arg(home)).remove();
|
QFile(qsl("%1.local/share/applications/telegram.desktop").arg(home)).remove();
|
||||||
|
|
||||||
_psRunCommand("update-desktop-database " + escapeShell(QFile::encodeName(home + qsl(".local/share/applications"))));
|
_psRunCommand("update-desktop-database " + EscapeShell(QFile::encodeName(home + qsl(".local/share/applications"))));
|
||||||
_psRunCommand("xdg-mime default telegramdesktop.desktop x-scheme-handler/tg");
|
_psRunCommand("xdg-mime default telegramdesktop.desktop x-scheme-handler/tg");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -526,7 +492,7 @@ void psRegisterCustomScheme() {
|
||||||
#endif // !TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
|
#endif // !TDESKTOP_DISABLE_DESKTOP_FILE_GENERATION
|
||||||
|
|
||||||
DEBUG_LOG(("App Info: registerting for Gnome"));
|
DEBUG_LOG(("App Info: registerting for Gnome"));
|
||||||
if (_psRunCommand("gconftool-2 -t string -s /desktop/gnome/url-handlers/tg/command " + escapeShell(escapeShell(QFile::encodeName(cExeDir() + cExeName())) + " -- %s"))) {
|
if (_psRunCommand("gconftool-2 -t string -s /desktop/gnome/url-handlers/tg/command " + EscapeShell(EscapeShell(QFile::encodeName(cExeDir() + cExeName())) + " -- %s"))) {
|
||||||
_psRunCommand("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/needs_terminal false");
|
_psRunCommand("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/needs_terminal false");
|
||||||
_psRunCommand("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/enabled true");
|
_psRunCommand("gconftool-2 -t bool -s /desktop/gnome/url-handlers/tg/enabled true");
|
||||||
}
|
}
|
||||||
|
@ -547,7 +513,7 @@ void psRegisterCustomScheme() {
|
||||||
QTextStream s(&f);
|
QTextStream s(&f);
|
||||||
s.setCodec("UTF-8");
|
s.setCodec("UTF-8");
|
||||||
s << "[Protocol]\n";
|
s << "[Protocol]\n";
|
||||||
s << "exec=" << QFile::decodeName(escapeShell(QFile::encodeName(cExeDir() + cExeName()))) << " -- %u\n";
|
s << "exec=" << QFile::decodeName(EscapeShell(QFile::encodeName(cExeDir() + cExeName()))) << " -- %u\n";
|
||||||
s << "protocol=tg\n";
|
s << "protocol=tg\n";
|
||||||
s << "input=none\n";
|
s << "input=none\n";
|
||||||
s << "output=none\n";
|
s << "output=none\n";
|
||||||
|
|
|
@ -63,12 +63,6 @@ int psFixPrevious();
|
||||||
void psExecUpdater();
|
void psExecUpdater();
|
||||||
void psExecTelegram(const QString &arg = QString());
|
void psExecTelegram(const QString &arg = QString());
|
||||||
|
|
||||||
bool psShowOpenWithMenu(int x, int y, const QString &file);
|
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name);
|
|
||||||
void psOpenFile(const QString &name, bool openWith = false);
|
|
||||||
void psShowInFolder(const QString &name);
|
|
||||||
|
|
||||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
|
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
|
|
@ -384,21 +384,6 @@ int psFixPrevious() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool psShowOpenWithMenu(int x, int y, const QString &file) {
|
|
||||||
return objc_showOpenWithMenu(x, y, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void psOpenFile(const QString &name, bool openWith) {
|
|
||||||
objc_openFile(name, openWith);
|
|
||||||
}
|
|
||||||
|
|
||||||
void psShowInFolder(const QString &name) {
|
|
||||||
objc_showInFinder(name, QFileInfo(name).absolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
@ -413,7 +398,7 @@ void finish() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransparentWindowsSupported(QPoint globalPosition) {
|
bool TransparentWindowsSupported(QPoint globalPosition) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ThirdParty {
|
namespace ThirdParty {
|
||||||
|
@ -468,35 +453,20 @@ bool psLaunchMaps(const LocationCoords &coords) {
|
||||||
|
|
||||||
QString strNotificationAboutThemeChange() {
|
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, 0x0200CA65, 0xBE00DF64, 0xE300BB4E, 0x2900D26F, 0xD500D374, 0xE900E269, 0x86008F66, 0xC4006669, 0x1C00A863, 0xE600A761, 0x8E00EE74, 0xB300B169, 0xCF00B36F, 0xE600D36E };
|
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, 0x0200CA65, 0xBE00DF64, 0xE300BB4E, 0x2900D26F, 0xD500D374, 0xE900E269, 0x86008F66, 0xC4006669, 0x1C00A863, 0xE600A761, 0x8E00EE74, 0xB300B169, 0xCF00B36F, 0xE600D36E };
|
||||||
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
|
return strMakeFromLetters(letters);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString strNotificationAboutScreenLocked() {
|
QString strNotificationAboutScreenLocked() {
|
||||||
const uint32 letters[] = { 0x22008263, 0x0800DB6F, 0x45004F6D, 0xCC00972E, 0x0E00A861, 0x9700D970, 0xA100D570, 0x8900686C, 0xB300B365, 0xFE00DE2E, 0x76009B73, 0xFA00BF63, 0xE000A772, 0x9C009F65, 0x4E006065, 0xD900426E, 0xB7007849, 0x64006473, 0x6700824C, 0xE300706F, 0x7C00A063, 0x8F00D76B, 0x04001C65, 0x1C00A664 };
|
const uint32 letters[] = { 0x22008263, 0x0800DB6F, 0x45004F6D, 0xCC00972E, 0x0E00A861, 0x9700D970, 0xA100D570, 0x8900686C, 0xB300B365, 0xFE00DE2E, 0x76009B73, 0xFA00BF63, 0xE000A772, 0x9C009F65, 0x4E006065, 0xD900426E, 0xB7007849, 0x64006473, 0x6700824C, 0xE300706F, 0x7C00A063, 0x8F00D76B, 0x04001C65, 0x1C00A664 };
|
||||||
return strMakeFromLetters(letters, base::array_size(letters));
|
return strMakeFromLetters(letters);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString strNotificationAboutScreenUnlocked() {
|
QString strNotificationAboutScreenUnlocked() {
|
||||||
const uint32 letters[] = { 0x9200D763, 0xC8003C6F, 0xD2003F6D, 0x6000012E, 0x36004061, 0x4400E570, 0xA500BF70, 0x2E00796C, 0x4A009E65, 0x2E00612E, 0xC8001D73, 0x57002263, 0xF0005872, 0x49000765, 0xE5008D65, 0xE600D76E, 0xE8007049, 0x19005C73, 0x34009455, 0xB800B36E, 0xF300CA6C, 0x4C00806F, 0x5300A763, 0xD1003B6B, 0x63003565, 0xF800F264 };
|
const uint32 letters[] = { 0x9200D763, 0xC8003C6F, 0xD2003F6D, 0x6000012E, 0x36004061, 0x4400E570, 0xA500BF70, 0x2E00796C, 0x4A009E65, 0x2E00612E, 0xC8001D73, 0x57002263, 0xF0005872, 0x49000765, 0xE5008D65, 0xE600D76E, 0xE8007049, 0x19005C73, 0x34009455, 0xB800B36E, 0xF300CA6C, 0x4C00806F, 0x5300A763, 0xD1003B6B, 0x63003565, 0xF800F264 };
|
||||||
return strMakeFromLetters(letters, base::array_size(letters));
|
return strMakeFromLetters(letters);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString strStyleOfInterface() {
|
QString strStyleOfInterface() {
|
||||||
const uint32 letters[] = { 0xEF004041, 0x4C007F70, 0x1F007A70, 0x9E00A76C, 0x8500D165, 0x2E003749, 0x7B00526E, 0x3400E774, 0x3C00FA65, 0x6200B172, 0xF7001D66, 0x0B002961, 0x71008C63, 0x86005465, 0xA3006F53, 0x11006174, 0xCD001779, 0x8200556C, 0x6C009B65 };
|
const uint32 letters[] = { 0xEF004041, 0x4C007F70, 0x1F007A70, 0x9E00A76C, 0x8500D165, 0x2E003749, 0x7B00526E, 0x3400E774, 0x3C00FA65, 0x6200B172, 0xF7001D66, 0x0B002961, 0x71008C63, 0x86005465, 0xA3006F53, 0x11006174, 0xCD001779, 0x8200556C, 0x6C009B65 };
|
||||||
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
|
return strMakeFromLetters(letters);
|
||||||
}
|
|
||||||
|
|
||||||
QString strNeedToReload() {
|
|
||||||
const uint32 letters[] = { 0x82007746, 0xBB00C649, 0x7E00235F, 0x9A00FE54, 0x4C004542, 0x91001772, 0x8A00D76F, 0xC700B977, 0x7F005F73, 0x34003665, 0x2300D572, 0x72002E54, 0x18001461, 0x14004A62, 0x5100CC6C, 0x83002365, 0x5A002C56, 0xA5004369, 0x26004265, 0x0D006577 };
|
|
||||||
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString strNeedToRefresh1() {
|
|
||||||
const uint32 letters[] = { 0xEF006746, 0xF500CE49, 0x1500715F, 0x95001254, 0x3A00CB4C, 0x17009469, 0xB400DA73, 0xDE00C574, 0x9200EC56, 0x3C00A669, 0xFD00D865, 0x59000977 };
|
|
||||||
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString strNeedToRefresh2() {
|
|
||||||
const uint32 letters[] = { 0x8F001546, 0xAF007A49, 0xB8002B5F, 0x1A000B54, 0x0D003E49, 0xE0003663, 0x4900796F, 0x0500836E, 0x9A00D156, 0x5E00FF69, 0x5900C765, 0x3D00D177 };
|
|
||||||
return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,10 +68,6 @@ void psExecTelegram(const QString &crashreport = QString());
|
||||||
|
|
||||||
bool psShowOpenWithMenu(int x, int y, const QString &file);
|
bool psShowOpenWithMenu(int x, int y, const QString &file);
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name);
|
|
||||||
void psOpenFile(const QString &name, bool openWith = false);
|
|
||||||
void psShowInFolder(const QString &name);
|
|
||||||
|
|
||||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
|
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
@ -111,8 +107,5 @@ QString strNotificationAboutThemeChange();
|
||||||
QString strNotificationAboutScreenLocked();
|
QString strNotificationAboutScreenLocked();
|
||||||
QString strNotificationAboutScreenUnlocked();
|
QString strNotificationAboutScreenUnlocked();
|
||||||
QString strStyleOfInterface();
|
QString strStyleOfInterface();
|
||||||
QString strNeedToReload();
|
|
||||||
QString strNeedToRefresh1();
|
|
||||||
QString strNeedToRefresh2();
|
|
||||||
|
|
||||||
bool psLaunchMaps(const LocationCoords &coords);
|
bool psLaunchMaps(const LocationCoords &coords);
|
||||||
|
|
|
@ -31,10 +31,6 @@ void objc_outputDebugString(const QString &str);
|
||||||
bool objc_idleSupported();
|
bool objc_idleSupported();
|
||||||
bool objc_idleTime(TimeMs &idleTime);
|
bool objc_idleTime(TimeMs &idleTime);
|
||||||
|
|
||||||
bool objc_showOpenWithMenu(int x, int y, const QString &file);
|
|
||||||
|
|
||||||
void objc_showInFinder(const QString &file, const QString &path);
|
|
||||||
void objc_openFile(const QString &file, bool openwith);
|
|
||||||
void objc_start();
|
void objc_start();
|
||||||
void objc_finish();
|
void objc_finish();
|
||||||
bool objc_execUpdater();
|
bool objc_execUpdater();
|
||||||
|
|
|
@ -325,516 +325,6 @@ bool objc_idleTime(TimeMs &idleTime) { // taken from https://github.com/trueinte
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface OpenWithApp : NSObject {
|
|
||||||
NSString *fullname;
|
|
||||||
NSURL *app;
|
|
||||||
NSImage *icon;
|
|
||||||
}
|
|
||||||
@property (nonatomic, retain) NSString *fullname;
|
|
||||||
@property (nonatomic, retain) NSURL *app;
|
|
||||||
@property (nonatomic, retain) NSImage *icon;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation OpenWithApp
|
|
||||||
@synthesize fullname, app, icon;
|
|
||||||
|
|
||||||
- (void) dealloc {
|
|
||||||
[fullname release];
|
|
||||||
[app release];
|
|
||||||
[icon release];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface OpenFileWithInterface : NSObject {
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) init:(NSString *)file;
|
|
||||||
- (BOOL) popupAtX:(int)x andY:(int)y;
|
|
||||||
- (void) itemChosen:(id)sender;
|
|
||||||
- (void) dealloc;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation OpenFileWithInterface {
|
|
||||||
NSString *toOpen;
|
|
||||||
|
|
||||||
NSURL *defUrl;
|
|
||||||
NSString *defBundle, *defName, *defVersion;
|
|
||||||
NSImage *defIcon;
|
|
||||||
|
|
||||||
NSMutableArray *apps;
|
|
||||||
|
|
||||||
NSMenu *menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) fillAppByUrl:(NSURL*)url bundle:(NSString**)bundle name:(NSString**)name version:(NSString**)version icon:(NSImage**)icon {
|
|
||||||
NSBundle *b = [NSBundle bundleWithURL:url];
|
|
||||||
if (b) {
|
|
||||||
NSString *path = [url path];
|
|
||||||
*name = [[NSFileManager defaultManager] displayNameAtPath: path];
|
|
||||||
if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
|
||||||
if (!*name) *name = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleName"];
|
|
||||||
if (*name) {
|
|
||||||
*bundle = [b bundleIdentifier];
|
|
||||||
if (bundle) {
|
|
||||||
*version = (NSString*)[b objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
|
||||||
*icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
|
|
||||||
if (*icon && [*icon isValid]) [*icon setSize: CGSizeMake(16., 16.)];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*bundle = *name = *version = nil;
|
|
||||||
*icon = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) init:(NSString*)file {
|
|
||||||
toOpen = [file retain];
|
|
||||||
if (self = [super init]) {
|
|
||||||
NSURL *url = [NSURL fileURLWithPath:file];
|
|
||||||
defUrl = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:url];
|
|
||||||
if (defUrl) {
|
|
||||||
[self fillAppByUrl:defUrl bundle:&defBundle name:&defName version:&defVersion icon:&defIcon];
|
|
||||||
if (!defBundle || !defName) {
|
|
||||||
defUrl = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NSArray *appsList = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
|
|
||||||
NSMutableDictionary *data = [NSMutableDictionary dictionaryWithCapacity:16];
|
|
||||||
int fullcount = 0;
|
|
||||||
for (id app in appsList) {
|
|
||||||
if (fullcount > 15) break;
|
|
||||||
|
|
||||||
NSString *bundle = nil, *name = nil, *version = nil;
|
|
||||||
NSImage *icon = nil;
|
|
||||||
[self fillAppByUrl:(NSURL*)app bundle:&bundle name:&name version:&version icon:&icon];
|
|
||||||
if (bundle && name) {
|
|
||||||
if ([bundle isEqualToString:defBundle] && [version isEqualToString:defVersion]) continue;
|
|
||||||
NSString *key = [[NSArray arrayWithObjects:bundle, name, nil] componentsJoinedByString:@"|"];
|
|
||||||
if (!version) version = @"";
|
|
||||||
|
|
||||||
NSMutableDictionary *versions = (NSMutableDictionary*)[data objectForKey:key];
|
|
||||||
if (!versions) {
|
|
||||||
versions = [NSMutableDictionary dictionaryWithCapacity:2];
|
|
||||||
[data setValue:versions forKey:key];
|
|
||||||
}
|
|
||||||
if (![versions objectForKey:version]) {
|
|
||||||
[versions setValue:[NSArray arrayWithObjects:name, icon, app, nil] forKey:version];
|
|
||||||
++fullcount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fullcount || defUrl) {
|
|
||||||
apps = [NSMutableArray arrayWithCapacity:fullcount];
|
|
||||||
for (id key in data) {
|
|
||||||
NSMutableDictionary *val = (NSMutableDictionary*)[data objectForKey:key];
|
|
||||||
for (id ver in val) {
|
|
||||||
NSArray *app = (NSArray*)[val objectForKey:ver];
|
|
||||||
OpenWithApp *a = [[OpenWithApp alloc] init];
|
|
||||||
NSString *fullname = (NSString*)[app objectAtIndex:0], *version = (NSString*)ver;
|
|
||||||
BOOL showVersion = ([val count] > 1);
|
|
||||||
if (!showVersion) {
|
|
||||||
NSError *error = NULL;
|
|
||||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^\\d+\\.\\d+\\.\\d+(\\.\\d+)?$" options:NSRegularExpressionCaseInsensitive error:&error];
|
|
||||||
showVersion = ![regex numberOfMatchesInString:version options:NSMatchingWithoutAnchoringBounds range:{0,[version length]}];
|
|
||||||
}
|
|
||||||
if (showVersion) fullname = [[NSArray arrayWithObjects:fullname, @" (", version, @")", nil] componentsJoinedByString:@""];
|
|
||||||
[a setFullname:fullname];
|
|
||||||
[a setIcon:(NSImage*)[app objectAtIndex:1]];
|
|
||||||
[a setApp:(NSURL*)[app objectAtIndex:2]];
|
|
||||||
[apps addObject:a];
|
|
||||||
[a release];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[apps sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"fullname" ascending:YES]]];
|
|
||||||
[appsList release];
|
|
||||||
menu = nil;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) popupAtX:(int)x andY:(int)y {
|
|
||||||
if (![apps count] && !defName) return NO;
|
|
||||||
menu = [[NSMenu alloc] initWithTitle:@"Open With"];
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
if (defName) {
|
|
||||||
NSMenuItem *item = [menu insertItemWithTitle:[[NSArray arrayWithObjects:defName, @" (default)", nil] componentsJoinedByString:@""] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
|
||||||
if (defIcon) [item setImage:defIcon];
|
|
||||||
[item setTarget:self];
|
|
||||||
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
|
|
||||||
}
|
|
||||||
if ([apps count]) {
|
|
||||||
for (id a in apps) {
|
|
||||||
OpenWithApp *app = (OpenWithApp*)a;
|
|
||||||
NSMenuItem *item = [menu insertItemWithTitle:[a fullname] action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
|
||||||
if ([app icon]) [item setImage:[app icon]];
|
|
||||||
[item setTarget:self];
|
|
||||||
}
|
|
||||||
[menu insertItem:[NSMenuItem separatorItem] atIndex:index++];
|
|
||||||
}
|
|
||||||
NSMenuItem *item = [menu insertItemWithTitle:NSlang(lng_mac_choose_program_menu) action:@selector(itemChosen:) keyEquivalent:@"" atIndex:index++];
|
|
||||||
[item setTarget:self];
|
|
||||||
|
|
||||||
[menu popUpMenuPositioningItem:nil atLocation:CGPointMake(x, y) inView:nil];
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) itemChosen:(id)sender {
|
|
||||||
NSArray *items = [menu itemArray];
|
|
||||||
NSURL *url = nil;
|
|
||||||
for (int i = 0, l = [items count]; i < l; ++i) {
|
|
||||||
if ([items objectAtIndex:i] == sender) {
|
|
||||||
if (defName) i -= 2;
|
|
||||||
if (i < 0) {
|
|
||||||
url = defUrl;
|
|
||||||
} else if (i < int([apps count])) {
|
|
||||||
url = [(OpenWithApp*)[apps objectAtIndex:i] app];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (url) {
|
|
||||||
[[NSWorkspace sharedWorkspace] openFile:toOpen withApplication:[url path]];
|
|
||||||
} else {
|
|
||||||
objc_openFile(NS2QString(toOpen), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dealloc {
|
|
||||||
[toOpen release];
|
|
||||||
if (menu) [menu release];
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
bool objc_showOpenWithMenu(int x, int y, const QString &f) {
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
NSString *file = Q2NSString(f);
|
|
||||||
@try {
|
|
||||||
OpenFileWithInterface *menu = [[[OpenFileWithInterface alloc] init:file] autorelease];
|
|
||||||
QRect r = QApplication::desktop()->screenGeometry(QPoint(x, y));
|
|
||||||
y = r.y() + r.height() - y;
|
|
||||||
return !![menu popupAtX:x andY:y];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
}
|
|
||||||
@finally {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void objc_showInFinder(const QString &file, const QString &path) {
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
[[NSWorkspace sharedWorkspace] selectFile:Q2NSString(file) inFileViewerRootedAtPath:Q2NSString(path)];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface NSURL(CompareUrls)
|
|
||||||
|
|
||||||
- (BOOL) isEquivalent:(NSURL *)aURL;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation NSURL(CompareUrls)
|
|
||||||
|
|
||||||
- (BOOL) isEquivalent:(NSURL *)aURL {
|
|
||||||
if ([self isEqual:aURL]) return YES;
|
|
||||||
if ([[self scheme] caseInsensitiveCompare:[aURL scheme]] != NSOrderedSame) return NO;
|
|
||||||
if ([[self host] caseInsensitiveCompare:[aURL host]] != NSOrderedSame) return NO;
|
|
||||||
if ([[self path] compare:[aURL path]] != NSOrderedSame) return NO;
|
|
||||||
if ([[self port] compare:[aURL port]] != NSOrderedSame) return NO;
|
|
||||||
if ([[self query] compare:[aURL query]] != NSOrderedSame) return NO;
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface ChooseApplicationDelegate : NSObject<NSOpenSavePanelDelegate> {
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc;
|
|
||||||
- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url;
|
|
||||||
- (void) panelSelectionDidChange:(id)sender;
|
|
||||||
- (void) menuDidClose;
|
|
||||||
- (void) dealloc;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation ChooseApplicationDelegate {
|
|
||||||
BOOL onlyRecommended;
|
|
||||||
NSArray *apps;
|
|
||||||
NSOpenPanel *panel;
|
|
||||||
NSPopUpButton *selector;
|
|
||||||
NSTextField *good, *bad;
|
|
||||||
NSImageView *icon;
|
|
||||||
NSString *recom;
|
|
||||||
NSView *accessory;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) init:(NSArray *)recommendedApps withPanel:(NSOpenPanel *)creator withSelector:(NSPopUpButton *)menu withGood:(NSTextField *)goodLabel withBad:(NSTextField *)badLabel withIcon:(NSImageView *)badIcon withAccessory:(NSView *)acc {
|
|
||||||
if (self = [super init]) {
|
|
||||||
onlyRecommended = YES;
|
|
||||||
recom = [NSlang(lng_mac_recommended_apps) copy];
|
|
||||||
apps = recommendedApps;
|
|
||||||
panel = creator;
|
|
||||||
selector = menu;
|
|
||||||
good = goodLabel;
|
|
||||||
bad = badLabel;
|
|
||||||
icon = badIcon;
|
|
||||||
accessory = acc;
|
|
||||||
[selector setAction:@selector(menuDidClose)];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) isRecommended:(NSURL *)url {
|
|
||||||
if (apps) {
|
|
||||||
for (id app in apps) {
|
|
||||||
if ([(NSURL*)app isEquivalent:url]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) panel:(id)sender shouldEnableURL:(NSURL *)url {
|
|
||||||
NSNumber *isDirectory;
|
|
||||||
if ([url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil] && isDirectory != nil && [isDirectory boolValue]) {
|
|
||||||
if (onlyRecommended) {
|
|
||||||
CFStringRef ext = CFURLCopyPathExtension((CFURLRef)url);
|
|
||||||
NSNumber *isPackage;
|
|
||||||
if ([url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:nil] && isPackage != nil && [isPackage boolValue]) {
|
|
||||||
return [self isRecommended:url];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) panelSelectionDidChange:(id)sender {
|
|
||||||
NSArray *urls = [panel URLs];
|
|
||||||
if ([urls count]) {
|
|
||||||
if ([self isRecommended:[urls firstObject]]) {
|
|
||||||
[bad removeFromSuperview];
|
|
||||||
[icon removeFromSuperview];
|
|
||||||
[accessory addSubview:good];
|
|
||||||
} else {
|
|
||||||
[good removeFromSuperview];
|
|
||||||
[accessory addSubview:bad];
|
|
||||||
[accessory addSubview:icon];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
[good removeFromSuperview];
|
|
||||||
[bad removeFromSuperview];
|
|
||||||
[icon removeFromSuperview];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) menuDidClose {
|
|
||||||
onlyRecommended = [[[selector selectedItem] title] isEqualToString:recom];
|
|
||||||
[self refreshPanelTable];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) refreshDataInViews: (NSArray*)subviews {
|
|
||||||
for (id view in subviews) {
|
|
||||||
NSString *cls = [view className];
|
|
||||||
if ([cls isEqualToString:Q2NSString(strNeedToReload())]) {
|
|
||||||
[view reloadData];
|
|
||||||
} else if ([cls isEqualToString:Q2NSString(strNeedToRefresh1())] || [cls isEqualToString:Q2NSString(strNeedToRefresh2())]) {
|
|
||||||
[view reloadData];
|
|
||||||
return YES;
|
|
||||||
} else {
|
|
||||||
NSArray *next = [view subviews];
|
|
||||||
if ([next count] && [self refreshDataInViews:next]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void) refreshPanelTable {
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
[self refreshDataInViews:[[panel contentView] subviews]];
|
|
||||||
[panel validateVisibleColumns];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) dealloc {
|
|
||||||
if (apps) {
|
|
||||||
[apps release];
|
|
||||||
[recom release];
|
|
||||||
}
|
|
||||||
[super dealloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
void objc_openFile(const QString &f, bool openwith) {
|
|
||||||
@autoreleasepool {
|
|
||||||
|
|
||||||
NSString *file = Q2NSString(f);
|
|
||||||
if (openwith || [[NSWorkspace sharedWorkspace] openFile:file] == NO) {
|
|
||||||
@try {
|
|
||||||
NSURL *url = [NSURL fileURLWithPath:file];
|
|
||||||
NSString *ext = [url pathExtension];
|
|
||||||
NSArray *names = [url pathComponents];
|
|
||||||
NSString *name = [names count] ? [names lastObject] : @"";
|
|
||||||
NSArray *apps = (NSArray*)LSCopyApplicationURLsForURL(CFURLRef(url), kLSRolesAll);
|
|
||||||
|
|
||||||
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
|
||||||
|
|
||||||
NSRect fullRect = { { 0., 0. }, { st::macAccessoryWidth, st::macAccessoryHeight } };
|
|
||||||
NSView *accessory = [[NSView alloc] initWithFrame:fullRect];
|
|
||||||
|
|
||||||
[accessory setAutoresizesSubviews:YES];
|
|
||||||
|
|
||||||
NSPopUpButton *selector = [[NSPopUpButton alloc] init];
|
|
||||||
[accessory addSubview:selector];
|
|
||||||
[selector addItemWithTitle:NSlang(lng_mac_recommended_apps)];
|
|
||||||
[selector addItemWithTitle:NSlang(lng_mac_all_apps)];
|
|
||||||
[selector sizeToFit];
|
|
||||||
|
|
||||||
NSTextField *enableLabel = [[NSTextField alloc] init];
|
|
||||||
[accessory addSubview:enableLabel];
|
|
||||||
[enableLabel setStringValue:NSlang(lng_mac_enable_filter)];
|
|
||||||
[enableLabel setFont:[selector font]];
|
|
||||||
[enableLabel setBezeled:NO];
|
|
||||||
[enableLabel setDrawsBackground:NO];
|
|
||||||
[enableLabel setEditable:NO];
|
|
||||||
[enableLabel setSelectable:NO];
|
|
||||||
[enableLabel sizeToFit];
|
|
||||||
|
|
||||||
NSRect selectorFrame = [selector frame], enableFrame = [enableLabel frame];
|
|
||||||
enableFrame.size.width += st::macEnableFilterAdd;
|
|
||||||
enableFrame.origin.x = (fullRect.size.width - selectorFrame.size.width - enableFrame.size.width) / 2.;
|
|
||||||
selectorFrame.origin.x = (fullRect.size.width - selectorFrame.size.width + enableFrame.size.width) / 2.;
|
|
||||||
enableFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macEnableFilterTop + (selectorFrame.size.height - enableFrame.size.height) / 2.;
|
|
||||||
selectorFrame.origin.y = fullRect.size.height - selectorFrame.size.height - st::macSelectorTop;
|
|
||||||
[enableLabel setFrame:enableFrame];
|
|
||||||
[enableLabel setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
|
||||||
[selector setFrame:selectorFrame];
|
|
||||||
[selector setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
|
||||||
|
|
||||||
NSButton *button = [[NSButton alloc] init];
|
|
||||||
[accessory addSubview:button];
|
|
||||||
[button setButtonType:NSSwitchButton];
|
|
||||||
[button setFont:[selector font]];
|
|
||||||
[button setTitle:NSlang(lng_mac_always_open_with)];
|
|
||||||
[button sizeToFit];
|
|
||||||
NSRect alwaysRect = [button frame];
|
|
||||||
alwaysRect.origin.x = (fullRect.size.width - alwaysRect.size.width) / 2;
|
|
||||||
alwaysRect.origin.y = selectorFrame.origin.y - alwaysRect.size.height - st::macAlwaysThisAppTop;
|
|
||||||
[button setFrame:alwaysRect];
|
|
||||||
[button setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
|
|
||||||
#ifdef OS_MAC_STORE
|
|
||||||
[button setHidden:YES];
|
|
||||||
#endif // OS_MAC_STORE
|
|
||||||
NSTextField *goodLabel = [[NSTextField alloc] init];
|
|
||||||
[goodLabel setStringValue:Q2NSString(lng_mac_this_app_can_open(lt_file, NS2QString(name)))];
|
|
||||||
[goodLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
|
||||||
[goodLabel setBezeled:NO];
|
|
||||||
[goodLabel setDrawsBackground:NO];
|
|
||||||
[goodLabel setEditable:NO];
|
|
||||||
[goodLabel setSelectable:NO];
|
|
||||||
[goodLabel sizeToFit];
|
|
||||||
NSRect goodFrame = [goodLabel frame];
|
|
||||||
goodFrame.origin.x = (fullRect.size.width - goodFrame.size.width) / 2.;
|
|
||||||
goodFrame.origin.y = alwaysRect.origin.y - goodFrame.size.height - st::macAppHintTop;
|
|
||||||
[goodLabel setFrame:goodFrame];
|
|
||||||
|
|
||||||
NSTextField *badLabel = [[NSTextField alloc] init];
|
|
||||||
[badLabel setStringValue:Q2NSString(lng_mac_not_known_app(lt_file, NS2QString(name)))];
|
|
||||||
[badLabel setFont:[goodLabel font]];
|
|
||||||
[badLabel setBezeled:NO];
|
|
||||||
[badLabel setDrawsBackground:NO];
|
|
||||||
[badLabel setEditable:NO];
|
|
||||||
[badLabel setSelectable:NO];
|
|
||||||
[badLabel sizeToFit];
|
|
||||||
NSImageView *badIcon = [[NSImageView alloc] init];
|
|
||||||
NSImage *badImage = [NSImage imageNamed:NSImageNameCaution];
|
|
||||||
[badIcon setImage:badImage];
|
|
||||||
[badIcon setFrame:NSMakeRect(0, 0, st::macCautionIconSize, st::macCautionIconSize)];
|
|
||||||
|
|
||||||
NSRect badFrame = [badLabel frame], badIconFrame = [badIcon frame];
|
|
||||||
badFrame.origin.x = (fullRect.size.width - badFrame.size.width + badIconFrame.size.width) / 2.;
|
|
||||||
badIconFrame.origin.x = (fullRect.size.width - badFrame.size.width - badIconFrame.size.width) / 2.;
|
|
||||||
badFrame.origin.y = alwaysRect.origin.y - badFrame.size.height - st::macAppHintTop;
|
|
||||||
badIconFrame.origin.y = badFrame.origin.y;
|
|
||||||
[badLabel setFrame:badFrame];
|
|
||||||
[badIcon setFrame:badIconFrame];
|
|
||||||
|
|
||||||
[openPanel setAccessoryView:accessory];
|
|
||||||
|
|
||||||
ChooseApplicationDelegate *delegate = [[ChooseApplicationDelegate alloc] init:apps withPanel:openPanel withSelector:selector withGood:goodLabel withBad:badLabel withIcon:badIcon withAccessory:accessory];
|
|
||||||
[openPanel setDelegate:delegate];
|
|
||||||
|
|
||||||
[openPanel setCanChooseDirectories:NO];
|
|
||||||
[openPanel setCanChooseFiles:YES];
|
|
||||||
[openPanel setAllowsMultipleSelection:NO];
|
|
||||||
[openPanel setResolvesAliases:YES];
|
|
||||||
[openPanel setTitle:NSlang(lng_mac_choose_app)];
|
|
||||||
[openPanel setMessage:Q2NSString(lng_mac_choose_text(lt_file, NS2QString(name)))];
|
|
||||||
|
|
||||||
NSArray *appsPaths = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationDirectory inDomains:NSLocalDomainMask];
|
|
||||||
if ([appsPaths count]) [openPanel setDirectoryURL:[appsPaths firstObject]];
|
|
||||||
[openPanel beginWithCompletionHandler:^(NSInteger result){
|
|
||||||
if (result == NSFileHandlingPanelOKButton) {
|
|
||||||
if ([[openPanel URLs] count] > 0) {
|
|
||||||
NSURL *app = [[openPanel URLs] objectAtIndex:0];
|
|
||||||
NSString *path = [app path];
|
|
||||||
if ([button state] == NSOnState) {
|
|
||||||
NSArray *UTIs = (NSArray *)UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension,
|
|
||||||
(CFStringRef)ext,
|
|
||||||
nil);
|
|
||||||
for (NSString *UTI in UTIs) {
|
|
||||||
OSStatus result = LSSetDefaultRoleHandlerForContentType((CFStringRef)UTI,
|
|
||||||
kLSRolesAll,
|
|
||||||
(CFStringRef)[[NSBundle bundleWithPath:path] bundleIdentifier]);
|
|
||||||
DEBUG_LOG(("App Info: set default handler for '%1' UTI result: %2").arg(NS2QString(UTI)).arg(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
[UTIs release];
|
|
||||||
}
|
|
||||||
[[NSWorkspace sharedWorkspace] openFile:file withApplication:[app path]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[selector release];
|
|
||||||
[button release];
|
|
||||||
[enableLabel release];
|
|
||||||
[goodLabel release];
|
|
||||||
[badLabel release];
|
|
||||||
[badIcon release];
|
|
||||||
[accessory release];
|
|
||||||
[delegate release];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[NSWorkspace sharedWorkspace] openFile:file];
|
|
||||||
}
|
|
||||||
@finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void objc_start() {
|
void objc_start() {
|
||||||
_sharedDelegate = [[ApplicationDelegate alloc] init];
|
_sharedDelegate = [[ApplicationDelegate alloc] init];
|
||||||
[[NSApplication sharedApplication] setDelegate:_sharedDelegate];
|
[[NSApplication sharedApplication] setDelegate:_sharedDelegate];
|
||||||
|
|
|
@ -525,211 +525,6 @@ int psFixPrevious() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name) {
|
|
||||||
std::wstring zoneFile = QDir::toNativeSeparators(name).toStdWString() + L":Zone.Identifier";
|
|
||||||
HANDLE f = CreateFile(zoneFile.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
||||||
if (f == INVALID_HANDLE_VALUE) { // :(
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char data[] = "[ZoneTransfer]\r\nZoneId=3\r\n";
|
|
||||||
|
|
||||||
DWORD written = 0;
|
|
||||||
BOOL result = WriteFile(f, data, sizeof(data), &written, NULL);
|
|
||||||
CloseHandle(f);
|
|
||||||
|
|
||||||
if (!result || written != sizeof(data)) { // :(
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &, int hbitmapFormat);
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct OpenWithApp {
|
|
||||||
OpenWithApp(const QString &name, HBITMAP icon, IAssocHandler *handler) : name(name), icon(icon), handler(handler) {
|
|
||||||
}
|
|
||||||
OpenWithApp(const QString &name, IAssocHandler *handler) : name(name), icon(0), handler(handler) {
|
|
||||||
}
|
|
||||||
void destroy() {
|
|
||||||
if (icon) DeleteBitmap(icon);
|
|
||||||
if (handler) handler->Release();
|
|
||||||
}
|
|
||||||
QString name;
|
|
||||||
HBITMAP icon;
|
|
||||||
IAssocHandler *handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool OpenWithAppLess(const OpenWithApp &a, const OpenWithApp &b) {
|
|
||||||
return a.name < b.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
HBITMAP _iconToBitmap(LPWSTR icon, int iconindex) {
|
|
||||||
if (!icon) return 0;
|
|
||||||
WCHAR tmpIcon[4096];
|
|
||||||
if (icon[0] == L'@' && SUCCEEDED(SHLoadIndirectString(icon, tmpIcon, 4096, 0))) {
|
|
||||||
icon = tmpIcon;
|
|
||||||
}
|
|
||||||
int32 w = GetSystemMetrics(SM_CXSMICON), h = GetSystemMetrics(SM_CYSMICON);
|
|
||||||
|
|
||||||
HICON ico = ExtractIcon(0, icon, iconindex);
|
|
||||||
if (!ico) {
|
|
||||||
if (!iconindex) { // try to read image
|
|
||||||
QImage img(QString::fromWCharArray(icon));
|
|
||||||
if (!img.isNull()) {
|
|
||||||
return qt_pixmapToWinHBITMAP(App::pixmapFromImageInPlace(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)), /* HBitmapAlpha */ 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HDC screenDC = GetDC(0), hdc = CreateCompatibleDC(screenDC);
|
|
||||||
HBITMAP result = CreateCompatibleBitmap(screenDC, w, h);
|
|
||||||
HGDIOBJ was = SelectObject(hdc, result);
|
|
||||||
DrawIconEx(hdc, 0, 0, ico, w, h, 0, NULL, DI_NORMAL);
|
|
||||||
SelectObject(hdc, was);
|
|
||||||
DeleteDC(hdc);
|
|
||||||
ReleaseDC(0, screenDC);
|
|
||||||
|
|
||||||
DestroyIcon(ico);
|
|
||||||
|
|
||||||
return (HBITMAP)CopyImage(result, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION);
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool psShowOpenWithMenu(int x, int y, const QString &file) {
|
|
||||||
if (!useOpenWith || !App::wnd()) return false;
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
QList<OpenWithApp> handlers;
|
|
||||||
IShellItem* pItem = nullptr;
|
|
||||||
if (SUCCEEDED(Dlls::SHCreateItemFromParsingName(QDir::toNativeSeparators(file).toStdWString().c_str(), nullptr, IID_PPV_ARGS(&pItem)))) {
|
|
||||||
IEnumAssocHandlers *assocHandlers = 0;
|
|
||||||
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_EnumAssocHandlers, IID_PPV_ARGS(&assocHandlers)))) {
|
|
||||||
HRESULT hr = S_FALSE;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
IAssocHandler *handler = 0;
|
|
||||||
ULONG ulFetched = 0;
|
|
||||||
hr = assocHandlers->Next(1, &handler, &ulFetched);
|
|
||||||
if (FAILED(hr) || hr == S_FALSE || !ulFetched) break;
|
|
||||||
|
|
||||||
LPWSTR name = 0;
|
|
||||||
if (SUCCEEDED(handler->GetUIName(&name))) {
|
|
||||||
LPWSTR icon = 0;
|
|
||||||
int iconindex = 0;
|
|
||||||
if (SUCCEEDED(handler->GetIconLocation(&icon, &iconindex)) && icon) {
|
|
||||||
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), _iconToBitmap(icon, iconindex), handler));
|
|
||||||
CoTaskMemFree(icon);
|
|
||||||
} else {
|
|
||||||
handlers.push_back(OpenWithApp(QString::fromWCharArray(name), handler));
|
|
||||||
}
|
|
||||||
CoTaskMemFree(name);
|
|
||||||
} else {
|
|
||||||
handler->Release();
|
|
||||||
}
|
|
||||||
} while (hr != S_FALSE);
|
|
||||||
assocHandlers->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handlers.isEmpty()) {
|
|
||||||
HMENU menu = CreatePopupMenu();
|
|
||||||
std::sort(handlers.begin(), handlers.end(), OpenWithAppLess);
|
|
||||||
for (int32 i = 0, l = handlers.size(); i < l; ++i) {
|
|
||||||
MENUITEMINFO menuInfo = { 0 };
|
|
||||||
menuInfo.cbSize = sizeof(menuInfo);
|
|
||||||
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
|
|
||||||
menuInfo.fType = MFT_STRING;
|
|
||||||
menuInfo.wID = i + 1;
|
|
||||||
if (handlers.at(i).icon) {
|
|
||||||
menuInfo.fMask |= MIIM_BITMAP;
|
|
||||||
menuInfo.hbmpItem = handlers.at(i).icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString name = handlers.at(i).name;
|
|
||||||
if (name.size() > 512) name = name.mid(0, 512);
|
|
||||||
WCHAR nameArr[1024];
|
|
||||||
name.toWCharArray(nameArr);
|
|
||||||
nameArr[name.size()] = 0;
|
|
||||||
menuInfo.dwTypeData = nameArr;
|
|
||||||
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
|
|
||||||
}
|
|
||||||
MENUITEMINFO sepInfo = { 0 };
|
|
||||||
sepInfo.cbSize = sizeof(sepInfo);
|
|
||||||
sepInfo.fMask = MIIM_STRING | MIIM_DATA;
|
|
||||||
sepInfo.fType = MFT_SEPARATOR;
|
|
||||||
InsertMenuItem(menu, GetMenuItemCount(menu), true, &sepInfo);
|
|
||||||
|
|
||||||
MENUITEMINFO menuInfo = { 0 };
|
|
||||||
menuInfo.cbSize = sizeof(menuInfo);
|
|
||||||
menuInfo.fMask = MIIM_STRING | MIIM_DATA | MIIM_ID;
|
|
||||||
menuInfo.fType = MFT_STRING;
|
|
||||||
menuInfo.wID = handlers.size() + 1;
|
|
||||||
|
|
||||||
QString name = lang(lng_wnd_choose_program_menu);
|
|
||||||
if (name.size() > 512) name = name.mid(0, 512);
|
|
||||||
WCHAR nameArr[1024];
|
|
||||||
name.toWCharArray(nameArr);
|
|
||||||
nameArr[name.size()] = 0;
|
|
||||||
menuInfo.dwTypeData = nameArr;
|
|
||||||
InsertMenuItem(menu, GetMenuItemCount(menu), TRUE, &menuInfo);
|
|
||||||
|
|
||||||
int sel = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, x, y, 0, App::wnd()->psHwnd(), 0);
|
|
||||||
DestroyMenu(menu);
|
|
||||||
|
|
||||||
if (sel > 0) {
|
|
||||||
if (sel <= handlers.size()) {
|
|
||||||
IDataObject *dataObj = 0;
|
|
||||||
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_DataObject, IID_PPV_ARGS(&dataObj))) && dataObj) {
|
|
||||||
handlers.at(sel - 1).handler->Invoke(dataObj);
|
|
||||||
dataObj->Release();
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
for (int i = 0, l = handlers.size(); i < l; ++i) {
|
|
||||||
handlers[i].destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pItem->Release();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void psOpenFile(const QString &name, bool openWith) {
|
|
||||||
base::TaskQueue::Main().Put([name, openWith] {
|
|
||||||
bool mailtoScheme = name.startsWith(qstr("mailto:"));
|
|
||||||
std::wstring wname = mailtoScheme ? name.toStdWString() : QDir::toNativeSeparators(name).toStdWString();
|
|
||||||
|
|
||||||
if (openWith && useOpenAs) {
|
|
||||||
if (Dlls::SHOpenWithDialog) {
|
|
||||||
OPENASINFO info;
|
|
||||||
info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC;
|
|
||||||
if (mailtoScheme) info.oaifInFlags |= OAIF_FILE_IS_URI | OAIF_URL_PROTOCOL;
|
|
||||||
info.pcszClass = NULL;
|
|
||||||
info.pcszFile = wname.c_str();
|
|
||||||
Dlls::SHOpenWithDialog(0, &info);
|
|
||||||
} else {
|
|
||||||
Dlls::OpenAs_RunDLL(0, 0, wname.c_str(), SW_SHOWNORMAL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ShellExecute(0, L"open", wname.c_str(), 0, 0, SW_SHOWNORMAL);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void psShowInFolder(const QString &name) {
|
|
||||||
base::TaskQueue::Main().Put([name] {
|
|
||||||
auto nameEscaped = QDir::toNativeSeparators(name).replace('"', qsl("\"\""));
|
|
||||||
ShellExecute(0, 0, qsl("explorer").toStdWString().c_str(), (qsl("/select,") + nameEscaped).toStdWString().c_str(), 0, SW_SHOWNORMAL);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
|
|
@ -63,12 +63,6 @@ int psFixPrevious();
|
||||||
void psExecUpdater();
|
void psExecUpdater();
|
||||||
void psExecTelegram(const QString &arg = QString());
|
void psExecTelegram(const QString &arg = QString());
|
||||||
|
|
||||||
bool psShowOpenWithMenu(int x, int y, const QString &file);
|
|
||||||
|
|
||||||
void psPostprocessFile(const QString &name);
|
|
||||||
void psOpenFile(const QString &name, bool openWith = false);
|
|
||||||
void psShowInFolder(const QString &name);
|
|
||||||
|
|
||||||
QAbstractNativeEventFilter *psNativeEventFilter();
|
QAbstractNativeEventFilter *psNativeEventFilter();
|
||||||
|
|
||||||
void psNewVersion();
|
void psNewVersion();
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "settings/settings_block_widget.h"
|
#include "settings/settings_block_widget.h"
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/observer.h"
|
#include "core/observer.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
#include "settings/settings_block_widget.h"
|
#include "settings/settings_block_widget.h"
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/languagebox.h"
|
#include "boxes/languagebox.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/aboutbox.h"
|
#include "boxes/aboutbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "langloaderplain.h"
|
#include "langloaderplain.h"
|
||||||
#include "autoupdater.h"
|
#include "autoupdater.h"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "settings/settings_block_widget.h"
|
#include "settings/settings_block_widget.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
|
@ -30,6 +30,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "boxes/notifications_box.h"
|
#include "boxes/notifications_box.h"
|
||||||
|
#include "platform/platform_notifications_manager.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
@ -72,16 +73,14 @@ void NotificationsWidget::createNotificationsControls() {
|
||||||
style::margins margin(0, 0, 0, st::settingsSkip);
|
style::margins margin(0, 0, 0, st::settingsSkip);
|
||||||
style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2));
|
style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2));
|
||||||
|
|
||||||
QString nativeNotificationsLabel;
|
auto nativeNotificationsLabel = QString();
|
||||||
|
if (Platform::Notifications::Supported()) {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (App::wnd()->psHasNativeNotifications()) {
|
|
||||||
nativeNotificationsLabel = lang(lng_settings_use_windows);
|
nativeNotificationsLabel = lang(lng_settings_use_windows);
|
||||||
}
|
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32 // Q_OS_WIN
|
||||||
#elif defined Q_OS_LINUX64 || defined Q_OS_LINUX32
|
|
||||||
if (App::wnd()->psHasNativeNotifications()) {
|
|
||||||
nativeNotificationsLabel = lang(lng_settings_use_native_notifications);
|
nativeNotificationsLabel = lang(lng_settings_use_native_notifications);
|
||||||
|
#endif // Q_OS_WIN || Q_OS_LINUX64 || Q_OS_LINUX32
|
||||||
}
|
}
|
||||||
#endif // Q_OS_WIN
|
|
||||||
if (!nativeNotificationsLabel.isEmpty()) {
|
if (!nativeNotificationsLabel.isEmpty()) {
|
||||||
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, SLOT(onNativeNotifications()), Global::NativeNotifications());
|
addChildRow(_nativeNotifications, margin, nativeNotificationsLabel, SLOT(onNativeNotifications()), Global::NativeNotifications());
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/themes/window_theme_editor.h"
|
#include "window/themes/window_theme_editor.h"
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ void fillCodes() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Codes.insert(qsl("loadcolors"), []() {
|
Codes.insert(qsl("loadcolors"), []() {
|
||||||
FileDialog::askOpenPath("Open palette file", "Palette (*.tdesktop-palette)", [](const FileDialog::OpenResult &result) {
|
FileDialog::GetOpenPath("Open palette file", "Palette (*.tdesktop-palette)", [](const FileDialog::OpenResult &result) {
|
||||||
if (!result.paths.isEmpty()) {
|
if (!result.paths.isEmpty()) {
|
||||||
Window::Theme::Apply(result.paths.front());
|
Window::Theme::Apply(result.paths.front());
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
@ -1191,16 +1191,14 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, HistoryItem *context,
|
||||||
} else {
|
} else {
|
||||||
auto filepath = location.name();
|
auto filepath = location.name();
|
||||||
if (documentIsValidMediaFile(filepath)) {
|
if (documentIsValidMediaFile(filepath)) {
|
||||||
psOpenFile(filepath);
|
File::Launch(filepath);
|
||||||
} else {
|
|
||||||
psShowInFolder(filepath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (App::main()) App::main()->mediaMarkRead(data);
|
if (App::main()) App::main()->mediaMarkRead(data);
|
||||||
} else if (data->voice() || data->song() || data->isVideo()) {
|
} else if (data->voice() || data->song() || data->isVideo()) {
|
||||||
auto filepath = location.name();
|
auto filepath = location.name();
|
||||||
if (documentIsValidMediaFile(filepath)) {
|
if (documentIsValidMediaFile(filepath)) {
|
||||||
psOpenFile(filepath);
|
File::Launch(filepath);
|
||||||
}
|
}
|
||||||
if (App::main()) App::main()->mediaMarkRead(data);
|
if (App::main()) App::main()->mediaMarkRead(data);
|
||||||
} else if (data->size < App::kImageSizeLimit) {
|
} else if (data->size < App::kImageSizeLimit) {
|
||||||
|
@ -1218,14 +1216,14 @@ void DocumentOpenClickHandler::doOpen(DocumentData *data, HistoryItem *context,
|
||||||
App::wnd()->showDocument(data, context);
|
App::wnd()->showDocument(data, context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(location.name());
|
File::Launch(location.name());
|
||||||
}
|
}
|
||||||
location.accessDisable();
|
location.accessDisable();
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(location.name());
|
File::Launch(location.name());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(location.name());
|
File::Launch(location.name());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1256,10 +1254,7 @@ void DocumentSaveClickHandler::doSave(DocumentData *data, bool forceSavingAs) {
|
||||||
|
|
||||||
auto filepath = data->filepath(DocumentData::FilePathResolveSaveFromDataSilent, forceSavingAs);
|
auto filepath = data->filepath(DocumentData::FilePathResolveSaveFromDataSilent, forceSavingAs);
|
||||||
if (!filepath.isEmpty() && !forceSavingAs) {
|
if (!filepath.isEmpty() && !forceSavingAs) {
|
||||||
auto pos = QCursor::pos();
|
File::OpenWith(filepath, QCursor::pos());
|
||||||
if (!psShowOpenWithMenu(pos.x(), pos.y(), filepath)) {
|
|
||||||
psOpenFile(filepath, true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
auto fileinfo = QFileInfo(filepath);
|
auto fileinfo = QFileInfo(filepath);
|
||||||
auto filedir = filepath.isEmpty() ? QDir() : fileinfo.dir();
|
auto filedir = filepath.isEmpty() ? QDir() : fileinfo.dir();
|
||||||
|
@ -1499,14 +1494,11 @@ void DocumentData::performActionOnLoad() {
|
||||||
if (already.isEmpty()) return;
|
if (already.isEmpty()) return;
|
||||||
|
|
||||||
if (_actionOnLoad == ActionOnLoadOpenWith) {
|
if (_actionOnLoad == ActionOnLoadOpenWith) {
|
||||||
QPoint pos(QCursor::pos());
|
File::OpenWith(already, QCursor::pos());
|
||||||
if (!psShowOpenWithMenu(pos.x(), pos.y(), already)) {
|
|
||||||
psOpenFile(already, true);
|
|
||||||
}
|
|
||||||
} else if (_actionOnLoad == ActionOnLoadOpen || _actionOnLoad == ActionOnLoadPlayInline) {
|
} else if (_actionOnLoad == ActionOnLoadOpen || _actionOnLoad == ActionOnLoadPlayInline) {
|
||||||
if (voice() || song() || isVideo()) {
|
if (voice() || song() || isVideo()) {
|
||||||
if (documentIsValidMediaFile(already)) {
|
if (documentIsValidMediaFile(already)) {
|
||||||
psOpenFile(already);
|
File::Launch(already);
|
||||||
}
|
}
|
||||||
if (App::main()) App::main()->mediaMarkRead(this);
|
if (App::main()) App::main()->mediaMarkRead(this);
|
||||||
} else if (loc.accessEnable()) {
|
} else if (loc.accessEnable()) {
|
||||||
|
@ -1517,11 +1509,11 @@ void DocumentData::performActionOnLoad() {
|
||||||
App::wnd()->showDocument(this, item);
|
App::wnd()->showDocument(this, item);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(already);
|
File::Launch(already);
|
||||||
}
|
}
|
||||||
loc.accessDisable();
|
loc.accessDisable();
|
||||||
} else {
|
} else {
|
||||||
psOpenFile(already);
|
File::Launch(already);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "core/task_queue.h"
|
#include "core/task_queue.h"
|
||||||
#include "core/zlib_help.h"
|
#include "core/zlib_help.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/filedialog.h"
|
#include "core/file_utilities.h"
|
||||||
#include "boxes/editcolorbox.h"
|
#include "boxes/editcolorbox.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
|
@ -635,7 +635,7 @@ void ThemeExportBox::updateThumbnail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeExportBox::chooseBackgroundFromFile() {
|
void ThemeExportBox::chooseBackgroundFromFile() {
|
||||||
FileDialog::askOpenPath(lang(lng_theme_editor_choose_image), "Image files (*.jpeg *.jpg *.png)", base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) {
|
FileDialog::GetOpenPath(lang(lng_theme_editor_choose_image), "Image files (*.jpeg *.jpg *.png)", base::lambda_guarded(this, [this](const FileDialog::OpenResult &result) {
|
||||||
auto content = result.remoteContent;
|
auto content = result.remoteContent;
|
||||||
if (!result.paths.isEmpty()) {
|
if (!result.paths.isEmpty()) {
|
||||||
QFile f(result.paths.front());
|
QFile f(result.paths.front());
|
||||||
|
@ -664,7 +664,7 @@ void ThemeExportBox::exportTheme() {
|
||||||
auto caption = lang(lng_theme_editor_choose_name);
|
auto caption = lang(lng_theme_editor_choose_name);
|
||||||
auto filter = "Themes (*.tdesktop-theme)";
|
auto filter = "Themes (*.tdesktop-theme)";
|
||||||
auto name = "awesome.tdesktop-theme";
|
auto name = "awesome.tdesktop-theme";
|
||||||
FileDialog::askWritePath(caption, filter, name, base::lambda_guarded(this, [this](const QString &path) {
|
FileDialog::GetWritePath(caption, filter, name, base::lambda_guarded(this, [this](const QString &path) {
|
||||||
zlib::FileToWrite zip;
|
zlib::FileToWrite zip;
|
||||||
|
|
||||||
zip_fileinfo zfi = { { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 };
|
zip_fileinfo zfi = { { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 };
|
||||||
|
@ -798,7 +798,7 @@ void Editor::paintEvent(QPaintEvent *e) {
|
||||||
void Editor::Start() {
|
void Editor::Start() {
|
||||||
auto palettePath = Local::themePaletteAbsolutePath();
|
auto palettePath = Local::themePaletteAbsolutePath();
|
||||||
if (palettePath.isEmpty()) {
|
if (palettePath.isEmpty()) {
|
||||||
FileDialog::askWritePath(lang(lng_theme_editor_save_palette), "Palette (*.tdesktop-palette)", "colors.tdesktop-palette", [](const QString &path) {
|
FileDialog::GetWritePath(lang(lng_theme_editor_save_palette), "Palette (*.tdesktop-palette)", "colors.tdesktop-palette", [](const QString &path) {
|
||||||
if (!Local::copyThemeColorsToPalette(path)) {
|
if (!Local::copyThemeColorsToPalette(path)) {
|
||||||
writeDefaultPalette(path);
|
writeDefaultPalette(path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,8 @@
|
||||||
'<(src_loc)/core/click_handler.h',
|
'<(src_loc)/core/click_handler.h',
|
||||||
'<(src_loc)/core/click_handler_types.cpp',
|
'<(src_loc)/core/click_handler_types.cpp',
|
||||||
'<(src_loc)/core/click_handler_types.h',
|
'<(src_loc)/core/click_handler_types.h',
|
||||||
|
'<(src_loc)/core/file_utilities.cpp',
|
||||||
|
'<(src_loc)/core/file_utilities.h',
|
||||||
'<(src_loc)/core/lambda.h',
|
'<(src_loc)/core/lambda.h',
|
||||||
'<(src_loc)/core/observer.cpp',
|
'<(src_loc)/core/observer.cpp',
|
||||||
'<(src_loc)/core/observer.h',
|
'<(src_loc)/core/observer.h',
|
||||||
|
@ -563,8 +565,6 @@
|
||||||
'<(src_loc)/ui/countryinput.h',
|
'<(src_loc)/ui/countryinput.h',
|
||||||
'<(src_loc)/ui/emoji_config.cpp',
|
'<(src_loc)/ui/emoji_config.cpp',
|
||||||
'<(src_loc)/ui/emoji_config.h',
|
'<(src_loc)/ui/emoji_config.h',
|
||||||
'<(src_loc)/ui/filedialog.cpp',
|
|
||||||
'<(src_loc)/ui/filedialog.h',
|
|
||||||
'<(src_loc)/ui/images.cpp',
|
'<(src_loc)/ui/images.cpp',
|
||||||
'<(src_loc)/ui/images.h',
|
'<(src_loc)/ui/images.h',
|
||||||
'<(src_loc)/ui/twidget.cpp',
|
'<(src_loc)/ui/twidget.cpp',
|
||||||
|
|
Loading…
Add table
Reference in a new issue