Bring back native dialogs for Windows XP.
The CLSID_FileOpenDialog, CLSID_FileSaveDialog-based dialogs are available from Windows Vista on only, the old Shell-function based ones are required for Windows XP. Add a command line argument to switch dialog types. Extract some common functionality for both dialog types. Task-number: QTBUG-27621 Change-Id: I224c5c4574c2ff54daf354f00d3d1f82abc6f459 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>bb10
parent
edfb24009c
commit
d402d0c3e3
|
|
@ -43,12 +43,9 @@
|
|||
|
||||
#include "qwindowscontext.h"
|
||||
#include "qwindowswindow.h"
|
||||
#include "qwindowsintegration.h"
|
||||
#include "qwindowstheme.h" // Color conversion helpers
|
||||
|
||||
#include <QtWidgets/QColorDialog>
|
||||
#include <QtWidgets/QFontDialog>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QColor>
|
||||
|
||||
|
|
@ -60,6 +57,7 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QSysInfo>
|
||||
#include <QtCore/private/qsystemlibrary_p.h>
|
||||
|
||||
#include "qtwindows_additional.h"
|
||||
|
|
@ -384,9 +382,10 @@ void eatMouseMove()
|
|||
\class QWindowsNativeDialogBase
|
||||
\brief Base class for Windows native dialogs.
|
||||
|
||||
Base clases for native dialogs that mimick the
|
||||
behaviour of their QDialog counterparts as close as
|
||||
possible.
|
||||
Base classes for native dialogs (using the CLSID-based
|
||||
dialog interfaces "IFileDialog", etc. available from Windows
|
||||
Vista on) that mimick the behaviour of their QDialog
|
||||
counterparts as close as possible.
|
||||
|
||||
A major difference is that there is only an exec(), which
|
||||
is a modal, blocking call; there is no non-blocking show().
|
||||
|
|
@ -862,12 +861,45 @@ int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items,
|
|||
return itemCount;
|
||||
}
|
||||
|
||||
// Copy a string to an Utf16 buffer.
|
||||
static inline void toBuffer(const QString &what, WCHAR **ptr)
|
||||
// Split a list of name filters into description and actual filters
|
||||
struct FilterSpec
|
||||
{
|
||||
const int length = 1 + what.size();
|
||||
memcpy(*ptr, what.utf16(), length * sizeof(WCHAR));
|
||||
*ptr += length;
|
||||
QString description;
|
||||
QString filter;
|
||||
};
|
||||
|
||||
static QList<FilterSpec> filterSpecs(const QStringList &filters,
|
||||
bool hideFilterDetails,
|
||||
int *totalStringLength)
|
||||
{
|
||||
QList<FilterSpec> result;
|
||||
result.reserve(filters.size());
|
||||
*totalStringLength = 0;
|
||||
|
||||
const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+"));
|
||||
const QString separator = QStringLiteral(";");
|
||||
Q_ASSERT(filterSeparatorRE.isValid());
|
||||
// Split filter specification as 'Texts (*.txt[;] *.doc)'
|
||||
// into description and filters specification as '*.txt;*.doc'
|
||||
foreach (const QString &filterString, filters) {
|
||||
const int openingParenPos = filterString.lastIndexOf(QLatin1Char('('));
|
||||
const int closingParenPos = openingParenPos != -1 ?
|
||||
filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1;
|
||||
FilterSpec filterSpec;
|
||||
filterSpec.filter = closingParenPos == -1 ?
|
||||
QString(QLatin1Char('*')) :
|
||||
filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed();
|
||||
filterSpec.filter.replace(filterSeparatorRE, separator);
|
||||
filterSpec.description = filterString;
|
||||
if (hideFilterDetails && openingParenPos != -1) { // Do not show pattern in description
|
||||
filterSpec.description.truncate(openingParenPos);
|
||||
while (filterSpec.description.endsWith(QLatin1Char(' ')))
|
||||
filterSpec.description.truncate(filterSpec.description.size() - 1);
|
||||
}
|
||||
*totalStringLength += filterSpec.filter.size() + filterSpec.description.size();
|
||||
result.push_back(filterSpec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
|
||||
|
|
@ -875,48 +907,30 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
|
|||
/* Populates an array of COMDLG_FILTERSPEC from list of filters,
|
||||
* store the strings in a flat, contiguous buffer. */
|
||||
m_nameFilters = filters;
|
||||
const int size = filters.size();
|
||||
int totalStringLength = 0;
|
||||
for (int i = 0; i < size; ++i)
|
||||
totalStringLength += filters.at(i).size();
|
||||
const QList<FilterSpec> specs = filterSpecs(filters, m_hideFiltersDetails, &totalStringLength);
|
||||
const int size = specs.size();
|
||||
|
||||
QScopedArrayPointer<WCHAR> buffer(new WCHAR[totalStringLength * 2 + 2 * size]);
|
||||
QScopedArrayPointer<WCHAR> buffer(new WCHAR[totalStringLength + 2 * size]);
|
||||
QScopedArrayPointer<COMDLG_FILTERSPEC> comFilterSpec(new COMDLG_FILTERSPEC[size]);
|
||||
|
||||
const QString matchesAll = QStringLiteral(" (*)");
|
||||
const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+"));
|
||||
const QString separator = QStringLiteral(";");
|
||||
Q_ASSERT(filterSeparatorRE.isValid());
|
||||
|
||||
WCHAR *ptr = buffer.data();
|
||||
// Split filter specification as 'Texts (*.txt[;] *.doc)'
|
||||
// into description and filters specification as '*.txt;*.doc'
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
QString filterString = filters.at(i);
|
||||
const int openingParenPos = filterString.lastIndexOf(QLatin1Char('('));
|
||||
const int closingParenPos = openingParenPos != -1 ?
|
||||
filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1;
|
||||
QString filterSpec = closingParenPos == -1 ?
|
||||
QString(QLatin1Char('*')) :
|
||||
filterString.mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).trimmed();
|
||||
filterSpec.replace(filterSeparatorRE, separator);
|
||||
if (m_hideFiltersDetails) {
|
||||
// Do not show pattern in description
|
||||
if (openingParenPos != -1) {
|
||||
filterString.truncate(openingParenPos);
|
||||
while (filterString.endsWith(QLatin1Char(' ')))
|
||||
filterString.truncate(filterString.size() - 1);
|
||||
}
|
||||
} else {
|
||||
// Display glitch: 'All files (*)' shows up as 'All files (*) (*)'
|
||||
if (filterString.endsWith(matchesAll))
|
||||
filterString.truncate(filterString.size() - matchesAll.size());
|
||||
}
|
||||
// Display glitch (CLSID only): 'All files (*)' shows up as 'All files (*) (*)'
|
||||
QString description = specs[i].description;
|
||||
if (!m_hideFiltersDetails && description.endsWith(matchesAll))
|
||||
description.truncate(description.size() - matchesAll.size());
|
||||
// Add to buffer.
|
||||
comFilterSpec[i].pszName = ptr;
|
||||
toBuffer(filterString, &ptr);
|
||||
ptr += description.toWCharArray(ptr);
|
||||
*ptr++ = 0;
|
||||
comFilterSpec[i].pszSpec = ptr;
|
||||
toBuffer(filterSpec, &ptr);
|
||||
ptr += specs[i].filter.toWCharArray(ptr);
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
m_fileDialog->SetFileTypes(size, comFilterSpec.data());
|
||||
|
|
@ -947,9 +961,23 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
|
|||
}
|
||||
}
|
||||
|
||||
// Return the index of the selected filter, accounting for QFileDialog
|
||||
// sometimes stripping the filter specification depending on the
|
||||
// hideFilterDetails setting.
|
||||
static int indexOfNameFilter(const QStringList &filters, const QString &needle)
|
||||
{
|
||||
const int index = filters.indexOf(needle);
|
||||
if (index >= 0)
|
||||
return index;
|
||||
for (int i = 0; i < filters.size(); ++i)
|
||||
if (filters.at(i).startsWith(needle))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter)
|
||||
{
|
||||
const int index = m_nameFilters.indexOf(filter);
|
||||
const int index = indexOfNameFilter(m_nameFilters, filter);
|
||||
if (index >= 0) {
|
||||
m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
|
||||
} else {
|
||||
|
|
@ -1270,6 +1298,380 @@ QString QWindowsFileDialogHelper::selectedNameFilter() const
|
|||
return QString();
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WINCE
|
||||
|
||||
/*!
|
||||
\class QWindowsXpNativeFileDialog
|
||||
\brief Native Windows directory dialog for Windows XP using SHlib-functions.
|
||||
|
||||
Uses the synchronous GetOpenFileNameW(), GetSaveFileNameW() from ComDlg32
|
||||
or SHBrowseForFolder() for directories.
|
||||
|
||||
\internal
|
||||
\sa QWindowsXpFileDialogHelper
|
||||
|
||||
\ingroup qt-lighthouse-win
|
||||
*/
|
||||
|
||||
class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QSharedPointer<QFileDialogOptions> OptionsPtr;
|
||||
|
||||
static QWindowsXpNativeFileDialog *create(const OptionsPtr &options);
|
||||
|
||||
virtual void setWindowTitle(const QString &t) { m_title = t; }
|
||||
virtual void exec(HWND owner = 0);
|
||||
virtual QPlatformDialogHelper::DialogCode result() const { return m_result; }
|
||||
|
||||
void setDirectory(const QString &d) { m_directory = d; }
|
||||
QString directory() const { return m_directory; }
|
||||
void selectFile(const QString &f) { m_initialFile = f; }
|
||||
QStringList selectedFiles() const { return m_selectedFiles; }
|
||||
void setNameFilters(const QStringList &n) { m_nameFilters = n; }
|
||||
void selectNameFilter(const QString &f);
|
||||
QString selectedNameFilter() const { return m_selectedNameFilter; }
|
||||
|
||||
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
|
||||
|
||||
public slots:
|
||||
virtual void close() {}
|
||||
|
||||
private:
|
||||
typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
|
||||
typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW);
|
||||
|
||||
explicit QWindowsXpNativeFileDialog(const OptionsPtr &options);
|
||||
void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const;
|
||||
QStringList execExistingDir(HWND owner);
|
||||
QStringList execFileNames(HWND owner, int *selectedFilterIndex) const;
|
||||
|
||||
const OptionsPtr m_options;
|
||||
QString m_title;
|
||||
QString m_directory;
|
||||
QString m_initialFile;
|
||||
QStringList m_selectedFiles;
|
||||
QString m_selectedNameFilter;
|
||||
QStringList m_nameFilters;
|
||||
QPlatformDialogHelper::DialogCode m_result;
|
||||
|
||||
static PtrGetOpenFileNameW m_getOpenFileNameW;
|
||||
static PtrGetSaveFileNameW m_getSaveFileNameW;
|
||||
};
|
||||
|
||||
QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0;
|
||||
QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0;
|
||||
|
||||
QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options)
|
||||
{
|
||||
// GetOpenFileNameW() GetSaveFileName() are resolved
|
||||
// dynamically as not to create a dependency on Comdlg32, which
|
||||
// is used on XP only.
|
||||
if (!m_getOpenFileNameW) {
|
||||
QSystemLibrary library(QStringLiteral("Comdlg32"));
|
||||
m_getOpenFileNameW = (PtrGetOpenFileNameW)(library.resolve("GetOpenFileNameW"));
|
||||
m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW"));
|
||||
}
|
||||
if (m_getOpenFileNameW && m_getSaveFileNameW)
|
||||
return new QWindowsXpNativeFileDialog(options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options) :
|
||||
m_options(options), m_result(QPlatformDialogHelper::Rejected)
|
||||
{
|
||||
const QStringList nameFilters = m_options->nameFilters();
|
||||
if (!nameFilters.isEmpty())
|
||||
setNameFilters(nameFilters);
|
||||
const QString initialDirectory = m_options->initialDirectory();
|
||||
if (!initialDirectory.isEmpty())
|
||||
setDirectory(initialDirectory);
|
||||
const QString initialNameFilter = m_options->initiallySelectedNameFilter();
|
||||
if (!initialNameFilter.isEmpty())
|
||||
selectNameFilter(initialNameFilter);
|
||||
const QStringList selectedFiles = m_options->initiallySelectedFiles();
|
||||
if (!selectedFiles.isEmpty())
|
||||
selectFile(selectedFiles.front());
|
||||
setWindowTitle(m_options->windowTitle());
|
||||
}
|
||||
|
||||
void QWindowsXpNativeFileDialog::selectNameFilter(const QString &f)
|
||||
{
|
||||
const int index = indexOfNameFilter(m_nameFilters, f);
|
||||
if (index >= 0)
|
||||
m_selectedNameFilter = m_nameFilters.at(index);
|
||||
}
|
||||
|
||||
void QWindowsXpNativeFileDialog::exec(HWND owner)
|
||||
{
|
||||
int selectedFilterIndex = -1;
|
||||
m_selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
|
||||
execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex);
|
||||
QWindowsDialogs::eatMouseMove();
|
||||
if (m_selectedFiles.isEmpty()) {
|
||||
m_result = QPlatformDialogHelper::Rejected;
|
||||
emit rejected();
|
||||
} else {
|
||||
if (selectedFilterIndex >= 0 && selectedFilterIndex < m_nameFilters.size()) {
|
||||
m_selectedNameFilter = m_nameFilters.at(selectedFilterIndex);
|
||||
} else {
|
||||
m_selectedNameFilter.clear();
|
||||
}
|
||||
m_directory = QFileInfo(m_selectedFiles.front()).absolutePath();
|
||||
m_result = QPlatformDialogHelper::Accepted;
|
||||
emit accepted();
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for QWindowsNativeXpFileDialog directory dialog.
|
||||
// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
|
||||
|
||||
static int CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
QWindowsXpNativeFileDialog *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData);
|
||||
return dialog->existingDirCallback(hwnd, uMsg, lParam);
|
||||
}
|
||||
|
||||
#ifdef Q_CC_MINGW
|
||||
typedef ITEMIDLIST *qt_LpItemIdList;
|
||||
#else
|
||||
typedef PIDLIST_ABSOLUTE qt_LpItemIdList;
|
||||
#endif
|
||||
|
||||
int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg) {
|
||||
case BFFM_INITIALIZED:
|
||||
if (!m_initialFile.isEmpty())
|
||||
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(m_initialFile.utf16()));
|
||||
break;
|
||||
case BFFM_SELCHANGED: {
|
||||
wchar_t path[MAX_PATH];
|
||||
const bool ok = SHGetPathFromIDList(reinterpret_cast<qt_LpItemIdList>(lParam), path)
|
||||
&& path[0];
|
||||
SendMessage(hwnd, BFFM_ENABLEOK, ok ? 1 : 0, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QStringList QWindowsXpNativeFileDialog::execExistingDir(HWND owner)
|
||||
{
|
||||
BROWSEINFO bi;
|
||||
wchar_t initPath[MAX_PATH];
|
||||
initPath[0] = 0;
|
||||
bi.hwndOwner = owner;
|
||||
bi.pidlRoot = NULL;
|
||||
//### This does not seem to be respected? - the dialog always displays "Browse for folder"
|
||||
bi.lpszTitle = (wchar_t*)m_title.utf16();
|
||||
bi.pszDisplayName = initPath;
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
|
||||
bi.lpfn = xpFileDialogGetExistingDirCallbackProc;
|
||||
bi.lParam = LPARAM(this);
|
||||
QStringList selectedFiles;
|
||||
if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) {
|
||||
wchar_t path[MAX_PATH];
|
||||
path[0] = 0;
|
||||
if (SHGetPathFromIDList(pItemIDList, path) && path[0])
|
||||
selectedFiles.push_back(QDir::cleanPath(QString::fromWCharArray(path)));
|
||||
IMalloc *pMalloc;
|
||||
if (SHGetMalloc(&pMalloc) == NOERROR) {
|
||||
pMalloc->Free(pItemIDList);
|
||||
pMalloc->Release();
|
||||
}
|
||||
}
|
||||
return selectedFiles;
|
||||
}
|
||||
|
||||
// Return an allocated wchar_t array from a QString, reserve more memory if desired.
|
||||
static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0)
|
||||
{
|
||||
const size_t stringSize = s.size();
|
||||
wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)];
|
||||
s.toWCharArray(result);
|
||||
result[stringSize] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Open/Save files
|
||||
void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND owner) const
|
||||
{
|
||||
ZeroMemory(ofn, sizeof(OPENFILENAME));
|
||||
ofn->lStructSize = sizeof(OPENFILENAME);
|
||||
ofn->hwndOwner = owner;
|
||||
|
||||
// Create a buffer with the filter strings.
|
||||
int totalStringLength = 0;
|
||||
QList<FilterSpec> specs =
|
||||
filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength);
|
||||
const int size = specs.size();
|
||||
wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1];
|
||||
ofn->lpstrFilter = ptr;
|
||||
foreach (const FilterSpec &spec, specs) {
|
||||
ptr += spec.description.toWCharArray(ptr);
|
||||
*ptr++ = 0;
|
||||
ptr += spec.filter.toWCharArray(ptr);
|
||||
*ptr++ = 0;
|
||||
}
|
||||
*ptr = 0;
|
||||
const int nameFilterIndex = indexOfNameFilter(m_nameFilters, m_selectedNameFilter);
|
||||
if (nameFilterIndex >= 0)
|
||||
ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based.
|
||||
// lpstrFile receives the initial selection and is the buffer
|
||||
// for the target. If it contains any invalid character, the dialog
|
||||
// will not show.
|
||||
ofn->nMaxFile = 65535;
|
||||
const QString initiallySelectedFile =
|
||||
QDir::toNativeSeparators(m_initialFile).remove(QLatin1Char('<')).
|
||||
remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|'));
|
||||
ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile);
|
||||
ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_directory));
|
||||
ofn->lpstrTitle = (wchar_t*)m_title.utf16();
|
||||
// Determine lpstrDefExt. Note that the current MSDN docs document this
|
||||
// member wrong. It should rather be documented as "the default extension
|
||||
// if no extension was given and if the current filter does not have an
|
||||
// extension (e.g (*)). If the current filter has an extension, use
|
||||
// the extension of the current filter".
|
||||
if (m_options->acceptMode() == QFileDialogOptions::AcceptSave) {
|
||||
QString defaultSuffix = m_options->defaultSuffix();
|
||||
if (defaultSuffix.startsWith(QLatin1Char('.')))
|
||||
defaultSuffix.remove(0, 1);
|
||||
if (!defaultSuffix.isEmpty())
|
||||
ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix);
|
||||
}
|
||||
// Flags.
|
||||
ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
|
||||
if (m_options->fileMode() == QFileDialogOptions::ExistingFile
|
||||
|| m_options->fileMode() == QFileDialogOptions::ExistingFiles)
|
||||
ofn->Flags |= (OFN_FILEMUSTEXIST);
|
||||
if (m_options->fileMode() == QFileDialogOptions::ExistingFiles)
|
||||
ofn->Flags |= (OFN_ALLOWMULTISELECT);
|
||||
if (!(m_options->options() & QFileDialogOptions::DontConfirmOverwrite))
|
||||
ofn->Flags |= OFN_OVERWRITEPROMPT;
|
||||
}
|
||||
|
||||
QStringList QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedFilterIndex) const
|
||||
{
|
||||
*selectedFilterIndex = -1;
|
||||
OPENFILENAME ofn;
|
||||
populateOpenFileName(&ofn, owner);
|
||||
QStringList result;
|
||||
const bool isSave = m_options->acceptMode() == QFileDialogOptions::AcceptSave;
|
||||
if (isSave ? m_getSaveFileNameW(&ofn) : m_getOpenFileNameW(&ofn)) {
|
||||
*selectedFilterIndex = ofn.nFilterIndex - 1;
|
||||
result.push_back(QDir::cleanPath(QString::fromWCharArray(ofn.lpstrFile)));
|
||||
// For multiselection, the first item is the path followed
|
||||
// by "\0<file1>\0<file2>\0\0".
|
||||
if (ofn.Flags & (OFN_ALLOWMULTISELECT)) {
|
||||
wchar_t *ptr = ofn.lpstrFile + result.front().size() + 1;
|
||||
if (*ptr) {
|
||||
const QString path = result.takeAt(0) + QLatin1Char('/');
|
||||
while (*ptr) {
|
||||
const QString fileName = QString::fromWCharArray(ptr);
|
||||
result.push_back(path + fileName);
|
||||
ptr += fileName.size() + 1;
|
||||
} // extract multiple files
|
||||
} // has multiple files
|
||||
} // multiple flag set
|
||||
}
|
||||
delete [] ofn.lpstrFile;
|
||||
delete [] ofn.lpstrInitialDir;
|
||||
delete [] ofn.lpstrFilter;
|
||||
delete [] ofn.lpstrDefExt;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QWindowsXpFileDialogHelper
|
||||
\brief Dialog helper using QWindowsXpNativeFileDialog
|
||||
|
||||
\sa QWindowsXpNativeFileDialog
|
||||
\internal
|
||||
\ingroup qt-lighthouse-win
|
||||
*/
|
||||
|
||||
class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDialogHelper>
|
||||
{
|
||||
public:
|
||||
QWindowsXpFileDialogHelper() {}
|
||||
virtual bool supportsNonModalDialog() const { return false; }
|
||||
|
||||
virtual bool defaultNameFilterDisables() const
|
||||
{ return true; }
|
||||
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 setNameFilters(const QStringList &);
|
||||
virtual void selectNameFilter(const QString &);
|
||||
virtual QString selectedNameFilter() const;
|
||||
|
||||
private:
|
||||
virtual QWindowsNativeDialogBase *createNativeDialog();
|
||||
inline QWindowsXpNativeFileDialog *nativeFileDialog() const
|
||||
{ return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); }
|
||||
};
|
||||
|
||||
QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
|
||||
{
|
||||
if (QWindowsNativeDialogBase *result = QWindowsXpNativeFileDialog::create(options())) {
|
||||
QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
|
||||
QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject()));
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QWindowsXpFileDialogHelper::setDirectory(const QString &directory)
|
||||
{
|
||||
if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
nfd->setDirectory(directory);
|
||||
}
|
||||
|
||||
QString QWindowsXpFileDialogHelper::directory() const
|
||||
{
|
||||
if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
return nfd->directory();
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QWindowsXpFileDialogHelper::selectFile(const QString &filename)
|
||||
{
|
||||
if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
nfd->selectFile(filename);
|
||||
}
|
||||
|
||||
QStringList QWindowsXpFileDialogHelper::selectedFiles() const
|
||||
{
|
||||
if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
return nfd->selectedFiles();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &n)
|
||||
{
|
||||
if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
nfd->setNameFilters(n);
|
||||
}
|
||||
|
||||
void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f)
|
||||
{
|
||||
if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
nfd->selectNameFilter(f);
|
||||
}
|
||||
|
||||
QString QWindowsXpFileDialogHelper::selectedNameFilter() const
|
||||
{
|
||||
if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
|
||||
return nfd->selectedNameFilter();
|
||||
return QString();
|
||||
}
|
||||
|
||||
#endif // Q_OS_WINCE
|
||||
|
||||
/*!
|
||||
\class QWindowsNativeColorDialog
|
||||
\brief Native Windows color dialog.
|
||||
|
|
@ -1399,10 +1801,11 @@ namespace QWindowsDialogs {
|
|||
// QWindowsDialogHelperBase creation functions
|
||||
bool useHelper(QPlatformTheme::DialogType type)
|
||||
{
|
||||
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
|
||||
return false;
|
||||
switch (type) {
|
||||
case QPlatformTheme::FileDialog:
|
||||
return true;
|
||||
break;
|
||||
return QSysInfo::windowsVersion() >= QSysInfo::WV_XP;
|
||||
case QPlatformTheme::ColorDialog:
|
||||
#ifdef USE_NATIVE_COLOR_DIALOG
|
||||
return true;
|
||||
|
|
@ -1417,9 +1820,20 @@ bool useHelper(QPlatformTheme::DialogType type)
|
|||
|
||||
QPlatformDialogHelper *createHelper(QPlatformTheme::DialogType type)
|
||||
{
|
||||
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::NoNativeDialogs)
|
||||
return 0;
|
||||
switch (type) {
|
||||
case QPlatformTheme::FileDialog:
|
||||
#ifndef Q_OS_WINCE
|
||||
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::XpNativeDialogs
|
||||
|| QSysInfo::windowsVersion() == QSysInfo::WV_XP) {
|
||||
return new QWindowsXpFileDialogHelper();
|
||||
}
|
||||
if (QSysInfo::windowsVersion() > QSysInfo::WV_XP)
|
||||
return new QWindowsFileDialogHelper();
|
||||
#else
|
||||
return new QWindowsFileDialogHelper();
|
||||
#endif // Q_OS_WINCE
|
||||
case QPlatformTheme::ColorDialog:
|
||||
#ifdef USE_NATIVE_COLOR_DIALOG
|
||||
return new QWindowsColorDialogHelper();
|
||||
|
|
|
|||
|
|
@ -279,6 +279,12 @@ static inline unsigned parseOptions(const QStringList ¶mList)
|
|||
} else if (param.endsWith(QLatin1String("native"))) {
|
||||
options |= QWindowsIntegration::FontDatabaseNative;
|
||||
}
|
||||
} else if (param.startsWith(QLatin1String("dialogs="))) {
|
||||
if (param.endsWith(QLatin1String("xp"))) {
|
||||
options |= QWindowsIntegration::XpNativeDialogs;
|
||||
} else if (param.endsWith(QLatin1String("none"))) {
|
||||
options |= QWindowsIntegration::NoNativeDialogs;
|
||||
}
|
||||
} else if (param == QLatin1String("gl=gdi")) {
|
||||
options |= QWindowsIntegration::DisableArb;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,9 @@ public:
|
|||
enum Options { // Options to be passed on command line.
|
||||
FontDatabaseFreeType = 0x1,
|
||||
FontDatabaseNative = 0x2,
|
||||
DisableArb = 0x4
|
||||
DisableArb = 0x4,
|
||||
NoNativeDialogs = 0x8,
|
||||
XpNativeDialogs = 0x10
|
||||
};
|
||||
|
||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||
|
|
|
|||
Loading…
Reference in New Issue