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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#include "qgtk2dialoghelpers.moc"
|
||||
|
@ -45,6 +45,9 @@
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <qpa/qplatformdialoghelper.h>
|
||||
|
||||
typedef struct _GtkDialog GtkDialog;
|
||||
typedef struct _GtkFileFilter GtkFileFilter;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QGtk2Dialog;
|
||||
@ -74,6 +77,43 @@ private:
|
||||
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
|
||||
|
||||
#endif // QGTK2DIALOGHELPERS_P_H
|
||||
|
@ -56,7 +56,7 @@ QGtk2Theme::QGtk2Theme()
|
||||
|
||||
bool QGtk2Theme::usePlatformNativeDialog(DialogType type) const
|
||||
{
|
||||
return type == ColorDialog;
|
||||
return type == ColorDialog || type == FileDialog;
|
||||
}
|
||||
|
||||
QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) const
|
||||
@ -64,6 +64,8 @@ QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) c
|
||||
switch (type) {
|
||||
case ColorDialog:
|
||||
return new QGtk2ColorDialogHelper;
|
||||
case FileDialog:
|
||||
return new QGtk2FileDialogHelper;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user