mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-17 20:43:58 +02:00
Currently the build without implicitly included precompiled header is not supported anyway (because Qt MOC source files do not include stdafx.h, they include plain headers). So when we decide to support building without implicitly included precompiled headers we'll have to fix all the headers anyway.
602 lines
20 KiB
C++
602 lines
20 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|
*/
|
|
#include "platform/linux/file_utilities_linux.h"
|
|
|
|
#include <private/qguiapplication_p.h>
|
|
#include "platform/linux/linux_libs.h"
|
|
#include "platform/linux/linux_gdk_helper.h"
|
|
#include "mainwindow.h"
|
|
#include "localstorage.h"
|
|
|
|
QStringList qt_make_filter_list(const QString &filter);
|
|
|
|
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 {
|
|
|
|
// GTK file chooser image preview: thanks to Chromium
|
|
|
|
// The size of the preview we display for selected image files. We set height
|
|
// larger than width because generally there is more free space vertically
|
|
// than horiztonally (setting the preview image will alway expand the width of
|
|
// the dialog, but usually not the height). The image's aspect ratio will always
|
|
// be preserved.
|
|
constexpr auto kPreviewWidth = 256;
|
|
constexpr auto kPreviewHeight = 512;
|
|
|
|
using Type = ::FileDialog::internal::Type;
|
|
|
|
bool NativeSupported() {
|
|
return Platform::internal::GdkHelperLoaded()
|
|
&& (Libs::gtk_widget_hide_on_delete != nullptr)
|
|
&& (Libs::gtk_clipboard_store != nullptr)
|
|
&& (Libs::gtk_clipboard_get != nullptr)
|
|
&& (Libs::gtk_widget_destroy != nullptr)
|
|
&& (Libs::gtk_dialog_get_type != nullptr)
|
|
&& (Libs::gtk_dialog_run != nullptr)
|
|
&& (Libs::gtk_widget_realize != nullptr)
|
|
&& (Libs::gdk_window_set_modal_hint != nullptr)
|
|
&& (Libs::gtk_widget_show != nullptr)
|
|
&& (Libs::gdk_window_focus != nullptr)
|
|
&& (Libs::gtk_widget_hide != nullptr)
|
|
&& (Libs::gtk_widget_hide_on_delete != nullptr)
|
|
&& (Libs::gtk_file_chooser_dialog_new != nullptr)
|
|
&& (Libs::gtk_file_chooser_get_type != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_current_folder != nullptr)
|
|
&& (Libs::gtk_file_chooser_get_current_folder != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_current_name != nullptr)
|
|
&& (Libs::gtk_file_chooser_select_filename != nullptr)
|
|
&& (Libs::gtk_file_chooser_get_filenames != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_filter != nullptr)
|
|
&& (Libs::gtk_file_chooser_get_filter != nullptr)
|
|
&& (Libs::gtk_window_get_type != nullptr)
|
|
&& (Libs::gtk_window_set_title != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_local_only != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_action != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_select_multiple != nullptr)
|
|
&& (Libs::gtk_file_chooser_set_do_overwrite_confirmation != nullptr)
|
|
&& (Libs::gtk_file_chooser_remove_filter != nullptr)
|
|
&& (Libs::gtk_file_filter_set_name != nullptr)
|
|
&& (Libs::gtk_file_filter_add_pattern != nullptr)
|
|
&& (Libs::gtk_file_chooser_add_filter != nullptr)
|
|
&& (Libs::gtk_file_filter_new != nullptr);
|
|
}
|
|
|
|
bool PreviewSupported() {
|
|
return NativeSupported()
|
|
&& (Libs::gdk_pixbuf_new_from_file_at_size != nullptr);
|
|
}
|
|
|
|
bool GetNative(QStringList &files, QByteArray &remoteContent, const QString &caption, const QString &filter, Type type, QString startFile) {
|
|
auto parent = App::wnd() ? App::wnd()->filedialogParent() : nullptr;
|
|
internal::GtkFileDialog dialog(parent, caption, QString(), 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) {
|
|
dialog.setAcceptMode(QFileDialog::AcceptOpen);
|
|
dialog.setFileMode(QFileDialog::Directory);
|
|
dialog.setOption(QFileDialog::ShowDirsOnly);
|
|
} else {
|
|
dialog.setFileMode(QFileDialog::AnyFile);
|
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
}
|
|
if (startFile.isEmpty() || startFile.at(0) != '/') {
|
|
startFile = cDialogLastPath() + '/' + startFile;
|
|
}
|
|
dialog.selectFile(startFile);
|
|
|
|
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);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
files = QStringList();
|
|
remoteContent = QByteArray();
|
|
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 {
|
|
|
|
QGtkDialog::QGtkDialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) {
|
|
Libs::g_signal_connect_swapped_helper(Libs::g_object_cast(gtkWidget), "response", GCallback(onResponse), this);
|
|
Libs::g_signal_connect_helper(Libs::g_object_cast(gtkWidget), "delete-event", GCallback(Libs::gtk_widget_hide_on_delete), nullptr);
|
|
if (PreviewSupported()) {
|
|
_preview = Libs::gtk_image_new();
|
|
Libs::g_signal_connect_swapped_helper(Libs::g_object_cast(gtkWidget), "update-preview", GCallback(onUpdatePreview), this);
|
|
Libs::gtk_file_chooser_set_preview_widget(Libs::gtk_file_chooser_cast(gtkWidget), _preview);
|
|
}
|
|
}
|
|
|
|
QGtkDialog::~QGtkDialog() {
|
|
Libs::gtk_clipboard_store(Libs::gtk_clipboard_get(GDK_SELECTION_CLIPBOARD));
|
|
Libs::gtk_widget_destroy(gtkWidget);
|
|
}
|
|
|
|
GtkDialog *QGtkDialog::gtkDialog() const {
|
|
return Libs::gtk_dialog_cast(gtkWidget);
|
|
}
|
|
|
|
void QGtkDialog::exec() {
|
|
if (auto w = App::wnd()) {
|
|
w->reActivateWindow();
|
|
}
|
|
if (modality() == Qt::ApplicationModal) {
|
|
// block input to the whole app, including other GTK dialogs
|
|
Libs::gtk_dialog_run(gtkDialog());
|
|
} else {
|
|
// block input to the window, allow input to other GTK dialogs
|
|
QEventLoop loop;
|
|
connect(this, SIGNAL(accept()), &loop, SLOT(quit()));
|
|
connect(this, SIGNAL(reject()), &loop, SLOT(quit()));
|
|
loop.exec();
|
|
}
|
|
}
|
|
|
|
void QGtkDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) {
|
|
connect(parent, &QWindow::destroyed, this, &QGtkDialog::onParentWindowDestroyed,
|
|
Qt::UniqueConnection);
|
|
setParent(parent);
|
|
setFlags(flags);
|
|
setModality(modality);
|
|
|
|
Libs::gtk_widget_realize(gtkWidget); // creates X window
|
|
|
|
if (parent) {
|
|
Platform::internal::XSetTransientForHint(Libs::gtk_widget_get_window(gtkWidget), parent->winId());
|
|
}
|
|
|
|
if (modality != Qt::NonModal) {
|
|
Libs::gdk_window_set_modal_hint(Libs::gtk_widget_get_window(gtkWidget), true);
|
|
QGuiApplicationPrivate::showModalWindow(this);
|
|
}
|
|
|
|
Libs::gtk_widget_show(gtkWidget);
|
|
Libs::gdk_window_focus(Libs::gtk_widget_get_window(gtkWidget), 0);
|
|
}
|
|
|
|
void QGtkDialog::hide() {
|
|
QGuiApplicationPrivate::hideModalWindow(this);
|
|
Libs::gtk_widget_hide(gtkWidget);
|
|
}
|
|
|
|
void QGtkDialog::onResponse(QGtkDialog *dialog, int response) {
|
|
if (response == GTK_RESPONSE_OK)
|
|
emit dialog->accept();
|
|
else
|
|
emit dialog->reject();
|
|
}
|
|
|
|
void QGtkDialog::onUpdatePreview(QGtkDialog* dialog) {
|
|
auto filename = Libs::gtk_file_chooser_get_preview_filename(Libs::gtk_file_chooser_cast(dialog->gtkWidget));
|
|
if (!filename) {
|
|
Libs::gtk_file_chooser_set_preview_widget_active(Libs::gtk_file_chooser_cast(dialog->gtkWidget), false);
|
|
return;
|
|
}
|
|
|
|
// Don't attempt to open anything which isn't a regular file. If a named pipe,
|
|
// this may hang. See https://crbug.com/534754.
|
|
struct stat stat_buf;
|
|
if (stat(filename, &stat_buf) != 0 || !S_ISREG(stat_buf.st_mode)) {
|
|
Libs::g_free(filename);
|
|
Libs::gtk_file_chooser_set_preview_widget_active(Libs::gtk_file_chooser_cast(dialog->gtkWidget), false);
|
|
return;
|
|
}
|
|
|
|
// This will preserve the image's aspect ratio.
|
|
auto pixbuf = Libs::gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth, kPreviewHeight, nullptr);
|
|
Libs::g_free(filename);
|
|
if (pixbuf) {
|
|
Libs::gtk_image_set_from_pixbuf(Libs::gtk_image_cast(dialog->_preview), pixbuf);
|
|
Libs::g_object_unref(pixbuf);
|
|
}
|
|
Libs::gtk_file_chooser_set_preview_widget_active(Libs::gtk_file_chooser_cast(dialog->gtkWidget), pixbuf ? true : false);
|
|
}
|
|
|
|
void QGtkDialog::onParentWindowDestroyed() {
|
|
// The Gtk*DialogHelper classes own this object. Make sure the parent doesn't delete it.
|
|
setParent(nullptr);
|
|
}
|
|
|
|
namespace {
|
|
|
|
const char *filterRegExp =
|
|
"^(.*)\\(([a-zA-Z0-9_.,*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
|
|
|
|
// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
|
|
QStringList cleanFilterList(const QString &filter) {
|
|
QRegExp regexp(QString::fromLatin1(filterRegExp));
|
|
Q_ASSERT(regexp.isValid());
|
|
QString f = filter;
|
|
int i = regexp.indexIn(f);
|
|
if (i >= 0)
|
|
f = regexp.cap(2);
|
|
return f.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
GtkFileDialog::GtkFileDialog(QWidget *parent, const QString &caption, const QString &directory, const QString &filter) : QDialog(parent)
|
|
, _windowTitle(caption)
|
|
, _initialDirectory(directory) {
|
|
auto filters = qt_make_filter_list(filter);
|
|
const int numFilters = filters.count();
|
|
_nameFilters.reserve(numFilters);
|
|
for (int i = 0; i < numFilters; ++i) {
|
|
_nameFilters << filters[i].simplified();
|
|
}
|
|
|
|
d.reset(new QGtkDialog(Libs::gtk_file_chooser_dialog_new("", nullptr,
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL)));
|
|
connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
|
|
connect(d.data(), SIGNAL(reject()), this, SLOT(onRejected()));
|
|
|
|
Libs::g_signal_connect_helper(Libs::gtk_file_chooser_cast(d->gtkDialog()), "selection-changed", G_CALLBACK(onSelectionChanged), this);
|
|
Libs::g_signal_connect_swapped_helper(Libs::gtk_file_chooser_cast(d->gtkDialog()), "current-folder-changed", G_CALLBACK(onCurrentFolderChanged), this);
|
|
}
|
|
|
|
GtkFileDialog::~GtkFileDialog() {
|
|
}
|
|
|
|
void GtkFileDialog::showHelper(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) {
|
|
_dir.clear();
|
|
_selection.clear();
|
|
|
|
applyOptions();
|
|
return d->show(flags, modality, parent);
|
|
}
|
|
|
|
void GtkFileDialog::setVisible(bool visible) {
|
|
if (visible) {
|
|
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) {
|
|
return;
|
|
}
|
|
} else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) {
|
|
return;
|
|
}
|
|
|
|
if (visible) {
|
|
showHelper(windowFlags(), windowModality(), parentWidget() ? parentWidget()->windowHandle() : nullptr);
|
|
} else {
|
|
hideHelper();
|
|
}
|
|
|
|
// Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
|
|
// updates the state correctly, but skips showing the non-native version:
|
|
setAttribute(Qt::WA_DontShowOnScreen);
|
|
|
|
QDialog::setVisible(visible);
|
|
}
|
|
|
|
int GtkFileDialog::exec() {
|
|
d->setModality(windowModality());
|
|
|
|
bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
|
|
setAttribute(Qt::WA_DeleteOnClose, false);
|
|
|
|
bool wasShowModal = testAttribute(Qt::WA_ShowModal);
|
|
setAttribute(Qt::WA_ShowModal, true);
|
|
setResult(0);
|
|
|
|
show();
|
|
|
|
QPointer<QDialog> guard = this;
|
|
d->exec();
|
|
if (guard.isNull())
|
|
return QDialog::Rejected;
|
|
|
|
setAttribute(Qt::WA_ShowModal, wasShowModal);
|
|
|
|
return result();
|
|
}
|
|
|
|
void GtkFileDialog::hideHelper() {
|
|
// After GtkFileChooserDialog has been hidden, gtk_file_chooser_get_current_folder()
|
|
// & gtk_file_chooser_get_filenames() will return bogus values -> cache the actual
|
|
// values before hiding the dialog
|
|
_dir = directory().absolutePath();
|
|
_selection = selectedFiles();
|
|
|
|
d->hide();
|
|
}
|
|
|
|
bool GtkFileDialog::defaultNameFilterDisables() const {
|
|
return false;
|
|
}
|
|
|
|
void GtkFileDialog::setDirectory(const QString &directory) {
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
Libs::gtk_file_chooser_set_current_folder(Libs::gtk_file_chooser_cast(gtkDialog), directory.toUtf8());
|
|
}
|
|
|
|
QDir GtkFileDialog::directory() const {
|
|
// While GtkFileChooserDialog is hidden, gtk_file_chooser_get_current_folder()
|
|
// returns a bogus value -> return the cached value before hiding
|
|
if (!_dir.isEmpty())
|
|
return _dir;
|
|
|
|
QString ret;
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
gchar *folder = Libs::gtk_file_chooser_get_current_folder(Libs::gtk_file_chooser_cast(gtkDialog));
|
|
if (folder) {
|
|
ret = QString::fromUtf8(folder);
|
|
Libs::g_free(folder);
|
|
}
|
|
return QDir(ret);
|
|
}
|
|
|
|
void GtkFileDialog::selectFile(const QString &filename) {
|
|
_initialFiles.clear();
|
|
_initialFiles.append(filename);
|
|
}
|
|
|
|
QStringList GtkFileDialog::selectedFiles() const {
|
|
// While GtkFileChooserDialog is hidden, gtk_file_chooser_get_filenames()
|
|
// returns a bogus value -> return the cached value before hiding
|
|
if (!_selection.isEmpty())
|
|
return _selection;
|
|
|
|
QStringList selection;
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
GSList *filenames = Libs::gtk_file_chooser_get_filenames(Libs::gtk_file_chooser_cast(gtkDialog));
|
|
for (GSList *it = filenames; it; it = it->next)
|
|
selection += QString::fromUtf8((const char*)it->data);
|
|
Libs::g_slist_free(filenames);
|
|
return selection;
|
|
}
|
|
|
|
void GtkFileDialog::setFilter() {
|
|
applyOptions();
|
|
}
|
|
|
|
void GtkFileDialog::selectNameFilter(const QString &filter) {
|
|
GtkFileFilter *gtkFilter = _filters.value(filter);
|
|
if (gtkFilter) {
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
Libs::gtk_file_chooser_set_filter(Libs::gtk_file_chooser_cast(gtkDialog), gtkFilter);
|
|
}
|
|
}
|
|
|
|
QString GtkFileDialog::selectedNameFilter() const {
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
GtkFileFilter *gtkFilter = Libs::gtk_file_chooser_get_filter(Libs::gtk_file_chooser_cast(gtkDialog));
|
|
return _filterNames.value(gtkFilter);
|
|
}
|
|
|
|
void GtkFileDialog::onAccepted() {
|
|
emit accept();
|
|
|
|
// QString filter = selectedNameFilter();
|
|
// if (filter.isEmpty())
|
|
// emit filterSelected(filter);
|
|
|
|
// QList<QUrl> files = selectedFiles();
|
|
// emit filesSelected(files);
|
|
// if (files.count() == 1)
|
|
// emit fileSelected(files.first());
|
|
}
|
|
|
|
void GtkFileDialog::onRejected() {
|
|
emit reject();
|
|
|
|
//
|
|
}
|
|
|
|
void GtkFileDialog::onSelectionChanged(GtkDialog *gtkDialog, GtkFileDialog *helper) {
|
|
// QString selection;
|
|
// gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gtkDialog));
|
|
// if (filename) {
|
|
// selection = QString::fromUtf8(filename);
|
|
// g_free(filename);
|
|
// }
|
|
// emit helper->currentChanged(QUrl::fromLocalFile(selection));
|
|
}
|
|
|
|
void GtkFileDialog::onCurrentFolderChanged(GtkFileDialog *dialog) {
|
|
// emit dialog->directoryEntered(dialog->directory());
|
|
}
|
|
|
|
GtkFileChooserAction gtkFileChooserAction(QFileDialog::FileMode fileMode, QFileDialog::AcceptMode acceptMode) {
|
|
switch (fileMode) {
|
|
case QFileDialog::AnyFile:
|
|
case QFileDialog::ExistingFile:
|
|
case QFileDialog::ExistingFiles:
|
|
if (acceptMode == QFileDialog::AcceptOpen)
|
|
return GTK_FILE_CHOOSER_ACTION_OPEN;
|
|
else
|
|
return GTK_FILE_CHOOSER_ACTION_SAVE;
|
|
case QFileDialog::Directory:
|
|
case QFileDialog::DirectoryOnly:
|
|
default:
|
|
if (acceptMode == QFileDialog::AcceptOpen)
|
|
return GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
|
else
|
|
return GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
|
|
}
|
|
}
|
|
|
|
bool CustomButtonsSupported() {
|
|
return (Libs::gtk_dialog_get_widget_for_response != nullptr)
|
|
&& (Libs::gtk_button_set_label != nullptr)
|
|
&& (Libs::gtk_button_get_type != nullptr);
|
|
}
|
|
|
|
void GtkFileDialog::applyOptions() {
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
|
|
Libs::gtk_window_set_title(Libs::gtk_window_cast(gtkDialog), _windowTitle.toUtf8());
|
|
Libs::gtk_file_chooser_set_local_only(Libs::gtk_file_chooser_cast(gtkDialog), true);
|
|
|
|
const GtkFileChooserAction action = gtkFileChooserAction(_fileMode, _acceptMode);
|
|
Libs::gtk_file_chooser_set_action(Libs::gtk_file_chooser_cast(gtkDialog), action);
|
|
|
|
const bool selectMultiple = (_fileMode == QFileDialog::ExistingFiles);
|
|
Libs::gtk_file_chooser_set_select_multiple(Libs::gtk_file_chooser_cast(gtkDialog), selectMultiple);
|
|
|
|
const bool confirmOverwrite = !_options.testFlag(QFileDialog::DontConfirmOverwrite);
|
|
Libs::gtk_file_chooser_set_do_overwrite_confirmation(Libs::gtk_file_chooser_cast(gtkDialog), confirmOverwrite);
|
|
|
|
if (!_nameFilters.isEmpty())
|
|
setNameFilters(_nameFilters);
|
|
|
|
if (!_initialDirectory.isEmpty())
|
|
setDirectory(_initialDirectory);
|
|
|
|
for_const (const auto &filename, _initialFiles) {
|
|
if (_acceptMode == QFileDialog::AcceptSave) {
|
|
QFileInfo fi(filename);
|
|
Libs::gtk_file_chooser_set_current_folder(Libs::gtk_file_chooser_cast(gtkDialog), fi.path().toUtf8());
|
|
Libs::gtk_file_chooser_set_current_name(Libs::gtk_file_chooser_cast(gtkDialog), fi.fileName().toUtf8());
|
|
} else if (filename.endsWith('/')) {
|
|
Libs::gtk_file_chooser_set_current_folder(Libs::gtk_file_chooser_cast(gtkDialog), filename.toUtf8());
|
|
} else {
|
|
Libs::gtk_file_chooser_select_filename(Libs::gtk_file_chooser_cast(gtkDialog), filename.toUtf8());
|
|
}
|
|
}
|
|
|
|
const QString initialNameFilter = _nameFilters.isEmpty() ? QString() : _nameFilters.front();
|
|
if (!initialNameFilter.isEmpty())
|
|
selectNameFilter(initialNameFilter);
|
|
|
|
if (CustomButtonsSupported()) {
|
|
GtkWidget *acceptButton = Libs::gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_OK);
|
|
if (acceptButton) {
|
|
/*if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
|
|
Libs::gtk_button_set_label(Libs::gtk_button_cast(acceptButton), opts->labelText(QFileDialogOptions::Accept).toUtf8());
|
|
else*/ if (_acceptMode == QFileDialog::AcceptOpen)
|
|
Libs::gtk_button_set_label(Libs::gtk_button_cast(acceptButton), GTK_STOCK_OPEN);
|
|
else
|
|
Libs::gtk_button_set_label(Libs::gtk_button_cast(acceptButton), GTK_STOCK_SAVE);
|
|
}
|
|
|
|
GtkWidget *rejectButton = Libs::gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_CANCEL);
|
|
if (rejectButton) {
|
|
/*if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
|
|
Libs::gtk_button_set_label(Libs::gtk_button_cast(rejectButton), opts->labelText(QFileDialogOptions::Reject).toUtf8());
|
|
else*/
|
|
Libs::gtk_button_set_label(Libs::gtk_button_cast(rejectButton), GTK_STOCK_CANCEL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GtkFileDialog::setNameFilters(const QStringList &filters) {
|
|
GtkDialog *gtkDialog = d->gtkDialog();
|
|
foreach (GtkFileFilter *filter, _filters)
|
|
Libs::gtk_file_chooser_remove_filter(Libs::gtk_file_chooser_cast(gtkDialog), filter);
|
|
|
|
_filters.clear();
|
|
_filterNames.clear();
|
|
|
|
for_const (auto &filter, filters) {
|
|
GtkFileFilter *gtkFilter = Libs::gtk_file_filter_new();
|
|
auto name = filter;//.left(filter.indexOf(QLatin1Char('(')));
|
|
auto extensions = cleanFilterList(filter);
|
|
|
|
Libs::gtk_file_filter_set_name(gtkFilter, name.isEmpty() ? extensions.join(QStringLiteral(", ")).toUtf8() : name.toUtf8());
|
|
for_const (auto &ext, extensions) {
|
|
auto caseInsensitiveExt = QString();
|
|
caseInsensitiveExt.reserve(4 * ext.size());
|
|
for_const (auto ch, ext) {
|
|
auto chLower = ch.toLower();
|
|
auto chUpper = ch.toUpper();
|
|
if (chLower != chUpper) {
|
|
caseInsensitiveExt.append('[').append(chLower).append(chUpper).append(']');
|
|
} else {
|
|
caseInsensitiveExt.append(ch);
|
|
}
|
|
}
|
|
|
|
Libs::gtk_file_filter_add_pattern(gtkFilter, caseInsensitiveExt.toUtf8());
|
|
}
|
|
|
|
Libs::gtk_file_chooser_add_filter(Libs::gtk_file_chooser_cast(gtkDialog), gtkFilter);
|
|
|
|
_filters.insert(filter, gtkFilter);
|
|
_filterNames.insert(gtkFilter, filter);
|
|
}
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace FileDialog
|
|
} // namespace Platform
|