Introduce a native file dialog for GTK+ 2.x
Change-Id: I3cb29218a54b9120c2ab6e2e32b810a111a7bf3d Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com> Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
parent
e88011357e
commit
468d010fdf
@ -233,6 +233,245 @@ void QGtk2ColorDialogHelper::applyOptions()
|
|||||||
gtk_widget_hide(helpButton);
|
gtk_widget_hide(helpButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QGtk2FileDialogHelper::QGtk2FileDialogHelper()
|
||||||
|
{
|
||||||
|
d.reset(new QGtk2Dialog(gtk_file_chooser_dialog_new("", 0,
|
||||||
|
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, SIGNAL(reject()));
|
||||||
|
|
||||||
|
g_signal_connect(GTK_FILE_CHOOSER(d->gtkDialog()), "selection-changed", G_CALLBACK(onSelectionChanged), this);
|
||||||
|
g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "current-folder-changed", G_CALLBACK(onCurrentFolderChanged), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QGtk2FileDialogHelper::~QGtk2FileDialogHelper()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QGtk2FileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
|
||||||
|
{
|
||||||
|
_dir.clear();
|
||||||
|
_selection.clear();
|
||||||
|
|
||||||
|
applyOptions();
|
||||||
|
return d->show(flags, modality, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::exec()
|
||||||
|
{
|
||||||
|
d->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::hide()
|
||||||
|
{
|
||||||
|
// 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();
|
||||||
|
_selection = selectedFiles();
|
||||||
|
|
||||||
|
d->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QGtk2FileDialogHelper::defaultNameFilterDisables() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::setDirectory(const QString &directory)
|
||||||
|
{
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QGtk2FileDialogHelper::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 = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(gtkDialog));
|
||||||
|
if (folder) {
|
||||||
|
ret = QString::fromUtf8(folder);
|
||||||
|
g_free(folder);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::selectFile(const QString &filename)
|
||||||
|
{
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList QGtk2FileDialogHelper::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 = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(gtkDialog));
|
||||||
|
for (GSList *it = filenames; it; it = it->next)
|
||||||
|
selection += QString::fromUtf8((const char*)it->data);
|
||||||
|
g_slist_free(filenames);
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::setFilter()
|
||||||
|
{
|
||||||
|
applyOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::selectNameFilter(const QString &filter)
|
||||||
|
{
|
||||||
|
GtkFileFilter *gtkFilter = _filters.value(filter);
|
||||||
|
if (gtkFilter) {
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QGtk2FileDialogHelper::selectedNameFilter() const
|
||||||
|
{
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
GtkFileFilter *gtkFilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(gtkDialog));
|
||||||
|
return _filterNames.value(gtkFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::onAccepted()
|
||||||
|
{
|
||||||
|
emit accept();
|
||||||
|
|
||||||
|
QString filter = selectedNameFilter();
|
||||||
|
if (filter.isEmpty())
|
||||||
|
emit filterSelected(filter);
|
||||||
|
|
||||||
|
QStringList files = selectedFiles();
|
||||||
|
emit filesSelected(files);
|
||||||
|
if (files.count() == 1)
|
||||||
|
emit fileSelected(files.first());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk2FileDialogHelper *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(selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::onCurrentFolderChanged(QGtk2FileDialogHelper *dialog)
|
||||||
|
{
|
||||||
|
emit dialog->directoryEntered(dialog->directory());
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QFileDialogOptions> &options)
|
||||||
|
{
|
||||||
|
switch (options->fileMode()) {
|
||||||
|
case QFileDialogOptions::AnyFile:
|
||||||
|
case QFileDialogOptions::ExistingFile:
|
||||||
|
case QFileDialogOptions::ExistingFiles:
|
||||||
|
if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
|
||||||
|
return GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||||
|
else
|
||||||
|
return GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||||
|
case QFileDialogOptions::Directory:
|
||||||
|
case QFileDialogOptions::DirectoryOnly:
|
||||||
|
default:
|
||||||
|
if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
|
||||||
|
return GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||||
|
else
|
||||||
|
return GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::applyOptions()
|
||||||
|
{
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
const QSharedPointer<QFileDialogOptions> &opts = options();
|
||||||
|
|
||||||
|
gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
|
||||||
|
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(gtkDialog), true);
|
||||||
|
|
||||||
|
const GtkFileChooserAction action = gtkFileChooserAction(opts);
|
||||||
|
gtk_file_chooser_set_action(GTK_FILE_CHOOSER(gtkDialog), action);
|
||||||
|
|
||||||
|
const bool selectMultiple = opts->fileMode() == QFileDialogOptions::ExistingFiles;
|
||||||
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(gtkDialog), selectMultiple);
|
||||||
|
|
||||||
|
const bool confirmOverwrite = !opts->testOption(QFileDialogOptions::DontConfirmOverwrite);
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(gtkDialog), confirmOverwrite);
|
||||||
|
|
||||||
|
const QStringList nameFilters = opts->nameFilters();
|
||||||
|
if (!nameFilters.isEmpty())
|
||||||
|
setNameFilters(nameFilters);
|
||||||
|
|
||||||
|
const QString initialDirectory = opts->initialDirectory();
|
||||||
|
if (!initialDirectory.isEmpty())
|
||||||
|
setDirectory(initialDirectory);
|
||||||
|
|
||||||
|
foreach (const QString &filename, opts->initiallySelectedFiles())
|
||||||
|
selectFile(filename);
|
||||||
|
|
||||||
|
const QString initialNameFilter = opts->initiallySelectedNameFilter();
|
||||||
|
if (!initialNameFilter.isEmpty())
|
||||||
|
selectNameFilter(initialNameFilter);
|
||||||
|
|
||||||
|
GtkWidget *acceptButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_OK);
|
||||||
|
if (acceptButton) {
|
||||||
|
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
|
||||||
|
gtk_button_set_label(GTK_BUTTON(acceptButton), opts->labelText(QFileDialogOptions::Accept).toUtf8());
|
||||||
|
else if (opts->acceptMode() == QFileDialogOptions::AcceptOpen)
|
||||||
|
gtk_button_set_label(GTK_BUTTON(acceptButton), GTK_STOCK_OPEN);
|
||||||
|
else
|
||||||
|
gtk_button_set_label(GTK_BUTTON(acceptButton), GTK_STOCK_SAVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *rejectButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_CANCEL);
|
||||||
|
if (rejectButton) {
|
||||||
|
if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
|
||||||
|
gtk_button_set_label(GTK_BUTTON(rejectButton), opts->labelText(QFileDialogOptions::Reject).toUtf8());
|
||||||
|
else
|
||||||
|
gtk_button_set_label(GTK_BUTTON(rejectButton), GTK_STOCK_CANCEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGtk2FileDialogHelper::setNameFilters(const QStringList& filters)
|
||||||
|
{
|
||||||
|
GtkDialog *gtkDialog = d->gtkDialog();
|
||||||
|
foreach (GtkFileFilter *filter, _filters)
|
||||||
|
gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter);
|
||||||
|
|
||||||
|
_filters.clear();
|
||||||
|
_filterNames.clear();
|
||||||
|
|
||||||
|
foreach (const QString &filter, filters) {
|
||||||
|
GtkFileFilter *gtkFilter = gtk_file_filter_new();
|
||||||
|
const QString name = filter.left(filter.indexOf(QLatin1Char('(')));
|
||||||
|
const QStringList extensions = cleanFilterList(filter);
|
||||||
|
|
||||||
|
gtk_file_filter_set_name(gtkFilter, name.isEmpty() ? extensions.join(QStringLiteral(", ")).toUtf8() : name.toUtf8());
|
||||||
|
foreach (const QString &ext, extensions)
|
||||||
|
gtk_file_filter_add_pattern(gtkFilter, ext.toUtf8());
|
||||||
|
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
|
||||||
|
|
||||||
|
_filters.insert(filter, gtkFilter);
|
||||||
|
_filterNames.insert(gtkFilter, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "qgtk2dialoghelpers.moc"
|
#include "qgtk2dialoghelpers.moc"
|
||||||
|
@ -45,6 +45,9 @@
|
|||||||
#include <QtCore/qscopedpointer.h>
|
#include <QtCore/qscopedpointer.h>
|
||||||
#include <qpa/qplatformdialoghelper.h>
|
#include <qpa/qplatformdialoghelper.h>
|
||||||
|
|
||||||
|
typedef struct _GtkDialog GtkDialog;
|
||||||
|
typedef struct _GtkFileFilter GtkFileFilter;
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QGtk2Dialog;
|
class QGtk2Dialog;
|
||||||
@ -74,6 +77,43 @@ private:
|
|||||||
mutable QScopedPointer<QGtk2Dialog> d;
|
mutable QScopedPointer<QGtk2Dialog> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QGtk2FileDialogHelper : public QPlatformFileDialogHelper
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QGtk2FileDialogHelper();
|
||||||
|
~QGtk2FileDialogHelper();
|
||||||
|
|
||||||
|
virtual bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
|
||||||
|
virtual void exec();
|
||||||
|
virtual void hide();
|
||||||
|
|
||||||
|
virtual bool defaultNameFilterDisables() const;
|
||||||
|
virtual void setDirectory(const QString &directory);
|
||||||
|
virtual QString directory() const;
|
||||||
|
virtual void selectFile(const QString &filename);
|
||||||
|
virtual QStringList selectedFiles() const;
|
||||||
|
virtual void setFilter();
|
||||||
|
virtual void selectNameFilter(const QString &filter);
|
||||||
|
virtual QString selectedNameFilter() const;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onAccepted();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void onSelectionChanged(GtkDialog *dialog, QGtk2FileDialogHelper *helper);
|
||||||
|
static void onCurrentFolderChanged(QGtk2FileDialogHelper *helper);
|
||||||
|
void applyOptions();
|
||||||
|
void setNameFilters(const QStringList &filters);
|
||||||
|
|
||||||
|
QString _dir;
|
||||||
|
QStringList _selection;
|
||||||
|
QHash<QString, GtkFileFilter*> _filters;
|
||||||
|
QHash<GtkFileFilter*, QString> _filterNames;
|
||||||
|
mutable QScopedPointer<QGtk2Dialog> d;
|
||||||
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QGTK2DIALOGHELPERS_P_H
|
#endif // QGTK2DIALOGHELPERS_P_H
|
||||||
|
@ -56,7 +56,7 @@ QGtk2Theme::QGtk2Theme()
|
|||||||
|
|
||||||
bool QGtk2Theme::usePlatformNativeDialog(DialogType type) const
|
bool QGtk2Theme::usePlatformNativeDialog(DialogType type) const
|
||||||
{
|
{
|
||||||
return type == ColorDialog;
|
return type == ColorDialog || type == FileDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) const
|
QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) const
|
||||||
@ -64,6 +64,8 @@ QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) c
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case ColorDialog:
|
case ColorDialog:
|
||||||
return new QGtk2ColorDialogHelper;
|
return new QGtk2ColorDialogHelper;
|
||||||
|
case FileDialog:
|
||||||
|
return new QGtk2FileDialogHelper;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user