Git commit cf804b42cb313d53729a4535622bda66951e6e42 by Cyrille Berger. Committed on 30/06/2014 at 07:54. Pushed by berger into branch 'calligra/2.8'.
Fix: no file formats shown in save dialogs Backports KoFileDialog from master. Tested on several applications, seem to work, but if someone else could test and confirm ? CCMAIL: calligra-devel@kde.org M +261 -208 libs/widgets/KoFileDialog.cpp M +62 -19 libs/widgets/KoFileDialog.h http://commits.kde.org/calligra/cf804b42cb313d53729a4535622bda66951e6e42 diff --git a/libs/widgets/KoFileDialog.cpp b/libs/widgets/KoFileDialog.cpp index 534ab9e..eb02a00 100644 --- a/libs/widgets/KoFileDialog.cpp +++ b/libs/widgets/KoFileDialog.cpp @@ -21,12 +21,12 @@ #include <QDebug> #include <QFileDialog> #include <QApplication> +#include <QImageReader> #include <kconfiggroup.h> #include <kmimetype.h> #include <klocale.h> - class KoFileDialog::Private { public: @@ -34,34 +34,61 @@ public: KoFileDialog::DialogType dialogType_, const QString caption_, const QString defaultDir_, - const QString uniqueName_) + const QString dialogName_) : parent(parent_) , type(dialogType_) - , uniqueName(uniqueName_) + , dialogName(dialogName_) , caption(caption_) - , directory(defaultDir_) - , filterType(KoFileDialog::NameFilter) + , defaultDirectory(defaultDir_) , filterList(QStringList()) , defaultFilter(QString()) , fileDialog(0) + , mimeType(0) + , useStaticForNative(false) + , hideDetails(false) { + // Force the native file dialogs on Windows. Except for KDE, the native file dialogs are only possible + // using the static methods. The Qt documentation is wrong here, if it means what it says " By default, + // the native file dialog is used unless you use a subclass of QFileDialog that contains the Q_OBJECT + // macro." +#ifdef Q_OS_WIN + useStaticForNative = true; +#endif + // Non-static KDE file is broken when called with QFileDialog::AcceptSave: + // then the directory above defaultdir is opened, and defaultdir is given as the default file name... + // + // So: in X11, use static methods inside KDE, which give working native dialogs, but non-static outside + // KDE, which gives working Qt dialogs. + // + // Only show the GTK dialog in Gnome, where people deserve it +#ifdef Q_WS_X11 + if (qgetenv("KDE_FULL_SESSION").size() > 0) { + useStaticForNative = true; + } + if (qgetenv("XDG_CURRENT_DESKTOP") == "GNOME") { + useStaticForNative = true; + } + +#endif } QWidget *parent; KoFileDialog::DialogType type; - QString uniqueName; + QString dialogName; QString caption; - QString directory; - KoFileDialog::FilterType filterType; + QString defaultDirectory; QStringList filterList; QString defaultFilter; QFileDialog *fileDialog; + KMimeType::Ptr mimeType; + bool useStaticForNative; + bool hideDetails; }; KoFileDialog::KoFileDialog(QWidget *parent, KoFileDialog::DialogType type, - const QString uniqueName) - : d(new Private(parent, type, "", getUsedDir(uniqueName), uniqueName)) + const QString dialogName) + : d(new Private(parent, type, "", getUsedDir(dialogName), dialogName)) { } @@ -78,40 +105,99 @@ void KoFileDialog::setCaption(const QString &caption) void KoFileDialog::setDefaultDir(const QString &defaultDir) { - if (d->directory.isEmpty() || d->directory.isNull()) - d->directory = defaultDir; + if (d->defaultDirectory.isEmpty() || !QDir(d->defaultDirectory).exists()) { + d->defaultDirectory = defaultDir; + } +} + +void KoFileDialog::setOverrideDir(const QString &overrideDir) +{ + d->defaultDirectory = overrideDir; +} + +void KoFileDialog::setImageFilters() +{ + QStringList imageFilters; + // add filters for all formats supported by QImage + foreach(const QByteArray &format, QImageReader::supportedImageFormats()) { + imageFilters << "image/" + format; + } + setMimeTypeFilters(imageFilters); } void KoFileDialog::setNameFilter(const QString &filter) { - d->filterType = KoFileDialog::NameFilter; d->filterList.clear(); - d->filterList << filter; - d->defaultFilter.clear(); + if (d->type == KoFileDialog::SaveFile) { + d->filterList << splitNameFilter(filter); + d->defaultFilter = d->filterList.first(); + } + else { + d->filterList << filter; + } } void KoFileDialog::setNameFilters(const QStringList &filterList, - const QString &defaultFilter) + QString defaultFilter) { - d->filterType = KoFileDialog::NameFilter; - d->filterList = filterList; + d->filterList.clear(); + + if (d->type == KoFileDialog::SaveFile) { + foreach(const QString &filter, filterList) { + d->filterList << splitNameFilter(filter); + } + + if (!defaultFilter.isEmpty()) { + QStringList defaultFilters = splitNameFilter(defaultFilter); + if (defaultFilters.size() > 0) { + defaultFilter = defaultFilters.first(); + } + } + } + else { + d->filterList = filterList; + } d->defaultFilter = defaultFilter; + } void KoFileDialog::setMimeTypeFilters(const QStringList &filterList, - const QString &defaultFilter) + QString defaultFilter) { - d->filterType = KoFileDialog::MimeFilter; - d->filterList = filterList; + d->filterList = getFilterStringListFromMime(filterList, true); + + if (!defaultFilter.isEmpty()) { + QStringList defaultFilters = getFilterStringListFromMime(QStringList() << defaultFilter, false); + if (defaultFilters.size() > 0) { + defaultFilter = defaultFilters.first(); + } + } d->defaultFilter = defaultFilter; } void KoFileDialog::setHideNameFilterDetailsOption() { - if (!d->fileDialog) { - createFileDialog(); + d->hideDetails = true; +} + +QString KoFileDialog::selectedNameFilter() const +{ + if (!d->useStaticForNative) { + return d->fileDialog->selectedNameFilter(); + } + else { + return d->defaultFilter; + } +} + +QString KoFileDialog::selectedMimeType() const +{ + if (d->mimeType) { + return d->mimeType->name(); + } + else { + return ""; } - d->fileDialog->setOption(QFileDialog::HideNameFilterDetails); } void KoFileDialog::createFileDialog() @@ -120,198 +206,209 @@ void KoFileDialog::createFileDialog() delete d->fileDialog; } - d->fileDialog = new QFileDialog(d->parent, d->caption, d->directory); + d->fileDialog = new QFileDialog(d->parent, d->caption, d->defaultDirectory); - if (d->type == SaveFile || d->type == SaveFiles) { + if (d->type == SaveFile) { d->fileDialog->setAcceptMode(QFileDialog::AcceptSave); d->fileDialog->setFileMode(QFileDialog::AnyFile); - } else { // open / import + } + else { // open / import + d->fileDialog->setAcceptMode(QFileDialog::AcceptOpen); - if (d->type == ImportDirectory || d->type == ImportDirectories || - d->type == OpenDirectory || d->type == OpenDirectories) { + + if (d->type == ImportDirectory + || d->type == OpenDirectory) + { d->fileDialog->setFileMode(QFileDialog::Directory); d->fileDialog->setOption(QFileDialog::ShowDirsOnly, true); - } else { // open / import file(s) - if (d->type == OpenFile || d->type == ImportFile) { + } + else { // open / import file(s) + if (d->type == OpenFile + || d->type == ImportFile) + { d->fileDialog->setFileMode(QFileDialog::ExistingFile); - } else { // files + } + else { // files d->fileDialog->setFileMode(QFileDialog::ExistingFiles); } } } - // add "All Supported Formats" filter - if (d->type == OpenFile || d->type == OpenFiles || - d->type == ImportFile || d->type == ImportFiles) { - if (d->filterType == MimeFilter) { - d->filterType = NameFilter; - d->filterList = getFilterStringList(d->filterList, true); - d->defaultFilter = getFilterString(d->defaultFilter); - } - } - - if (d->filterType = MimeFilter) { -#if QT_VERSION >= 0x050200 - d->fileDialog->setMimeTypeFilters(d->filterList); - if (!d->defaultFilter.isEmpty()) - d->fileDialog->selectMimeTypeFilter(d->defaultFilter); -#else - d->fileDialog->setNameFilters(getFilterStringList(d->filterList)); - if (!d->defaultFilter.isEmpty()) - d->fileDialog->selectNameFilter(getFilterString(d->defaultFilter)); -#endif - } else { - d->fileDialog->setNameFilters(d->filterList); - if (!d->defaultFilter.isEmpty()) - d->fileDialog->selectNameFilter(d->defaultFilter); + d->fileDialog->setNameFilters(d->filterList); + if (!d->defaultFilter.isEmpty()) { + d->fileDialog->selectNameFilter(d->defaultFilter); } - if (d->type == ImportDirectory || d->type == ImportDirectories || + if (d->type == ImportDirectory || d->type == ImportFile || d->type == ImportFiles || - d->type == SaveFile || d->type == SaveFiles) { + d->type == SaveFile) { d->fileDialog->setWindowModality(Qt::WindowModal); } -#ifdef Q_WS_X11 - if (qgetenv("KDE_FULL_SESSION").size() == 0) { - d->fileDialog->setOption(QFileDialog::DontUseNativeDialog); + if (d->hideDetails) { + d->fileDialog->setOption(QFileDialog::HideNameFilterDetails); } -#endif connect(d->fileDialog, SIGNAL(filterSelected(QString)), this, SLOT(filterSelected(QString))); } QString KoFileDialog::url() { -#ifndef Q_OS_WIN - if (!d->fileDialog) { - createFileDialog(); - } QString url; - if (d->fileDialog->exec() == QDialog::Accepted) { - url = d->fileDialog->selectedFiles().first(); - saveUsedDir(url, d->uniqueName); - } - return url; -#else - QString url; - switch (d->type) { - case OpenFile: - { - url = QFileDialog::getOpenFileName(d->parent, - d->caption, - d->directory, - getFilterString(d->filterList), - &d->defaultFilter); - break; - } - case OpenDirectory: - { - url = QFileDialog::getExistingDirectory(d->parent, - d->caption, - "", - QFileDialog::ShowDirsOnly); - break; - } - case ImportFile: - { - url = QFileDialog::getOpenFileName(d->parent, - d->caption, - d->directory, - getFilterString(d->filterList), - &d->defaultFilter); - break; - } - case ImportDirectory: - { - url = QFileDialog::getExistingDirectory(d->parent, - d->caption, - d->directory, - QFileDialog::ShowDirsOnly); - break; - } - case SaveFile: - { - url = QFileDialog::getSaveFileName(d->parent, - d->caption, - d->directory, - getFilterString(d->filterList), - &d->defaultFilter); - break; + if (!d->useStaticForNative) { + + if (!d->fileDialog) { + createFileDialog(); + } + + if (d->fileDialog->exec() == QDialog::Accepted) { + url = d->fileDialog->selectedFiles().first(); + } } - default: - ; + else { + switch (d->type) { + case OpenFile: + { + url = QFileDialog::getOpenFileName(d->parent, + d->caption, + d->defaultDirectory, + d->filterList.join(";;"), + &d->defaultFilter); + break; + } + case OpenDirectory: + { + url = QFileDialog::getExistingDirectory(d->parent, + d->caption, + d->defaultDirectory, + QFileDialog::ShowDirsOnly); + break; + } + case ImportFile: + { + url = QFileDialog::getOpenFileName(d->parent, + d->caption, + d->defaultDirectory, + d->filterList.join(";;"), + &d->defaultFilter); + break; + } + case ImportDirectory: + { + url = QFileDialog::getExistingDirectory(d->parent, + d->caption, + d->defaultDirectory, + QFileDialog::ShowDirsOnly); + break; + } + case SaveFile: + { + url = QFileDialog::getSaveFileName(d->parent, + d->caption, + d->defaultDirectory, + d->filterList.join(";;"), + &d->defaultFilter); + break; + } + default: + ; + } } - qDebug() << url << "," << d->defaultFilter; - if (d->type == SaveFile && QFileInfo(url).suffix().isEmpty()) { - int start = d->defaultFilter.lastIndexOf("*.") + 2; - int end = d->defaultFilter.lastIndexOf(" )"); - int n = end - start; - QString extension = d->defaultFilter.mid(start, n); - url.append(extension); + + if (!url.isEmpty()) { + + if (d->type == SaveFile && QFileInfo(url).suffix().isEmpty()) { + int start = d->defaultFilter.lastIndexOf("*.") + 1; + int end = d->defaultFilter.lastIndexOf(" )"); + int n = end - start; + QString extension = d->defaultFilter.mid(start, n); + url.append(extension); + } + + d->mimeType = KMimeType::findByUrl(KUrl(url), 0, true, true); + saveUsedDir(url, d->dialogName); + } return url; -#endif } QStringList KoFileDialog::urls() { -#ifndef Q_OS_WIN - if (!d->fileDialog) { - createFileDialog(); - } QStringList urls; - if (d->fileDialog->exec() == QDialog::Accepted) { - urls = d->fileDialog->selectedFiles(); - saveUsedDir(urls.first(), d->uniqueName); - } - return urls; -#else - switch (d->type) { - case OpenFiles: - case ImportFiles: - { - return QFileDialog::getOpenFileNames(d->parent, - d->caption, - d->directory, - getFilterString(d->filterList), - &d->defaultFilter); - } - case OpenDirectories: - case ImportDirectories: - case SaveFiles: - { - // These don't exist as a static method. They aren't used in Calligra either, afaict + + if (!d->useStaticForNative) { if (!d->fileDialog) { createFileDialog(); } - QStringList urls; if (d->fileDialog->exec() == QDialog::Accepted) { urls = d->fileDialog->selectedFiles(); - saveUsedDir(urls.first(), d->uniqueName); } - return urls; - } - default: - return QStringList(); + else { + switch (d->type) { + case OpenFiles: + case ImportFiles: + { + urls = QFileDialog::getOpenFileNames(d->parent, + d->caption, + d->defaultDirectory, + d->filterList.join(";;"), + &d->defaultFilter); + break; + } + default: + ; + } } -#endif + if (urls.size() > 0) { + saveUsedDir(urls.first(), d->dialogName); + } + return urls; } void KoFileDialog::filterSelected(const QString &filter) { - "Windows BMP image ( *.bmp )"; + // "Windows BMP image ( *.bmp )"; int start = filter.lastIndexOf("*.") + 2; int end = filter.lastIndexOf(" )"); int n = end - start; QString extension = filter.mid(start, n); - + d->defaultFilter = filter; d->fileDialog->setDefaultSuffix(extension); } -const QStringList KoFileDialog::getFilterStringList(const QStringList &mimeList, - bool withAllSupportedEntry) +QStringList KoFileDialog::splitNameFilter(const QString &nameFilter) +{ + QStringList filters; + QString description; + + if (nameFilter.contains("(")) { + description = nameFilter.left(nameFilter.indexOf("(") -1).trimmed(); + } + + + QStringList entries = nameFilter.mid(nameFilter.indexOf("(") + 1).split(" ",QString::SkipEmptyParts ); + + + foreach(QString entry, entries) { + + entry = entry.remove("*"); + entry = entry.remove(")"); + + KMimeType::Ptr mime = KMimeType::findByUrl(KUrl("bla" + entry), 0, true, true); + if (mime->name() != "application/octet-stream") { + filters.append(mime->comment() + "( *" + entry + " )"); + } + else { + filters.append(entry.remove(".").toUpper() + " " + description + " ( " + entry + " )"); + } + } + + return filters; +} + +const QStringList KoFileDialog::getFilterStringListFromMime(const QStringList &mimeList, + bool withAllSupportedEntry) { QStringList ret; if (withAllSupportedEntry) { @@ -339,37 +436,23 @@ const QStringList KoFileDialog::getFilterStringList(const QStringList &mimeList, if (withAllSupportedEntry) { ret[0].append(")"); } - return ret; } -const QString KoFileDialog::getFilterString(const QString &defaultMime) -{ - QString filter; - KMimeType::Ptr type = KMimeType::mimeType(defaultMime); - if(type) { - filter.append(type->comment() + " ("); - QStringList patterns = type->patterns(); - QStringList::ConstIterator jt; - for (jt = patterns.begin(); jt != patterns.end(); ++jt) - filter.append(*jt + " "); - filter.append(")"); - } - return filter; -} - const QString KoFileDialog::getUsedDir(const QString &dialogName) { if (dialogName.isEmpty()) return ""; KConfigGroup group = KGlobal::config()->group("File Dialogs"); QString dir = group.readEntry(dialogName); + return dir; } void KoFileDialog::saveUsedDir(const QString &fileName, const QString &dialogName) { + if (dialogName.isEmpty()) return; QFileInfo fileInfo(fileName); @@ -378,33 +461,3 @@ void KoFileDialog::saveUsedDir(const QString &fileName, } -const QString KoFileDialog::getFilterString(const QStringList &mimeList, - bool withAllSupported) -{ - QString allSupportedFilter; - if (withAllSupported) { - allSupportedFilter = QString(i18n("All supported formats") + " ( "); - } - QString restFilters; - for (QStringList::ConstIterator it = mimeList.begin(); it != mimeList.end(); ++it) { - KMimeType::Ptr type = KMimeType::mimeType( *it ); - if(!type) - continue; - restFilters.append(";;" + type->comment() + " ( "); - QStringList patterns = type->patterns(); - QStringList::ConstIterator jt; - for (jt = patterns.begin(); jt != patterns.end(); ++jt) { - restFilters.append(*jt + " "); - if (withAllSupported) { - allSupportedFilter.append(*jt + " "); - } - } - restFilters.append(")"); - } - - if (withAllSupported) { - return allSupportedFilter + ")" + restFilters; - } else { - return restFilters.remove(0, 2); - } -} diff --git a/libs/widgets/KoFileDialog.h b/libs/widgets/KoFileDialog.h index 87d6457..e446c52 100644 --- a/libs/widgets/KoFileDialog.h +++ b/libs/widgets/KoFileDialog.h @@ -42,65 +42,108 @@ public: OpenFile, OpenFiles, OpenDirectory, - OpenDirectories, ImportFile, ImportFiles, ImportDirectory, - ImportDirectories, - SaveFile, - SaveFiles + SaveFile }; /** * @brief constructor * @param parent The parent of the file dialog * @param dialogType usage of the file dialog - * @param uniqueName the name for the file dialog. This will be used to open + * @param dialogName the name for the file dialog. This will be used to open * the filedialog in the last open location, instead the specified directory. * * @return The name of the entry user selected in the file dialog * */ - KoFileDialog(QWidget *parent = 0, - KoFileDialog::DialogType type = OpenFile, - const QString uniqueName = QString()); + KoFileDialog(QWidget *parent, + KoFileDialog::DialogType type, + const QString dialogName = QString()); ~KoFileDialog(); void setCaption(const QString &caption); + + /** + * @brief setDefaultDir set the default directory to defaultDir + * + * @param defaultDir a path to a file or directory + */ void setDefaultDir(const QString &defaultDir); + + /** + * @brief setOverrideDir override both the default dir and the saved dir found by dialogName + * @param overrideDir a path to a file or directory + */ + void setOverrideDir(const QString &overrideDir); + + /** + * @brief setImageFilters sets the name filters for the file dialog to all + * image formats Qt's QImageReader supports. + */ + void setImageFilters(); + void setNameFilter(const QString &filter); + + /** + * @brief setNameFilters set a list of description/extension pairs. + * + * These are not registered mimetypes. In contrast with Qt's filedialog namefilters, + * you can only have _one_ pair per line. I.e. + * + * Gif Image (*gif) + * Tiff Image (*tif) + * + * And NOT Images (*gif *tif) + * + * @param filterList + * @param defaultFilter + */ void setNameFilters(const QStringList &filterList, - const QString &defaultFilter = QString()); + QString defaultFilter = QString()); void setMimeTypeFilters(const QStringList &filterList, - const QString &defaultFilter = QString()); + QString defaultFilter = QString()); void setHideNameFilterDetailsOption(); QStringList urls(); QString url(); + /** + * @brief selectedNameFilter returns the name filter the user selected, either + * directory or by clicking on it. + * @return + */ + QString selectedNameFilter() const; + + QString selectedMimeType() const; + private slots: void filterSelected(const QString &filter); private: - enum FilterType { - MimeFilter, - NameFilter - }; + /** + * @brief splitNameFilter take a single line of a QDialog name filter and split it + * into several lines. This is needed because a single line name filter can contain + * more than one mimetype, making it impossible to figure out the correct extension. + * + * The methods takes care of some duplicated extensions, like jpeg and jpg. + * @param nameFilter the namefilter to be split + * @return a stringlist of all name filters. + */ + QStringList splitNameFilter(const QString &nameFilter); void createFileDialog(); const QString getUsedDir(const QString &dialogName); void saveUsedDir(const QString &fileName, const QString &dialogName); - const QStringList getFilterStringList(const QStringList &mimeList, - bool withAllSupportedEntry = false); + const QStringList getFilterStringListFromMime(const QStringList &mimeList, + bool withAllSupportedEntry = false); - const QString getFilterString(const QStringList &mimeList, - bool withAllSupportedEntry = false); - const QString getFilterString(const QString &defaultMime); class Private; Private * const d; _______________________________________________ calligra-devel mailing list calligra-devel@kde.org https://mail.kde.org/mailman/listinfo/calligra-devel