Widgets: Remove remains of Windows file dialog.

Also remove Windows-specific binary compatility hack from Qt4.

Change-Id: I4b6914b357f21737e392745f907c770db9f7a641
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
bb10
Friedemann Kleint 2011-11-08 16:40:30 +01:00 committed by Qt by Nokia
parent 124044613d
commit 635cf1badf
4 changed files with 2 additions and 1225 deletions

View File

@ -42,13 +42,8 @@ false:mac {
}
win32 {
HEADERS += dialogs/qwizard_win_p.h \
dialogs/qfiledialog_win_p.h
SOURCES += dialogs/qdialogsbinarycompat_win.cpp \
dialogs/qfiledialog_win.cpp \
dialogs/qwizard_win.cpp
!win32-borland:!wince*: LIBS += -lshell32 # the filedialog needs this library
HEADERS += dialogs/qwizard_win_p.h
SOURCES += dialogs/qwizard_win.cpp
}
wince*: FORMS += dialogs/qfiledialog_embedded.ui

View File

@ -1,137 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qglobal.h>
// ### Qt 5: eliminate this file
/*
This is evil. MSVC doesn't let us remove private symbols, nor change their
visibility; yet there are some symbols we really needed to make public, e.g.,
~QColorDialog(), and then there were some totally needless symbols in our
header files, e.g., setSelectedAlpha(). So we define a new version of
QColorDialog & Co. with only the private symbols that we removed from the
public header files. The friends are there only to prevent potential compiler
warnings.
It would have been nicer to export the missing symbols as mangled "C" symbols
instead but unfortunately MSVC uses out-of-reach characters like @ and . in
their mangled C++ symbols.
*/
#if QT_VERSION < 0x050000 && defined(Q_CC_MSVC)
QT_BEGIN_NAMESPACE
#include <QtGui/QColor>
#include <QtGui/QFont>
class QColorDialogPrivate;
class QFontDialogPrivate;
class QInputDialogPrivate;
class QWidget;
class Q_WIDGETS_EXPORT QColorDialog
{
private:
explicit QColorDialog(QWidget *, bool);
~QColorDialog();
void setColor(const QColor &);
QColor color() const;
bool selectColor(const QColor &);
void setSelectedAlpha(int);
int selectedAlpha() const;
friend class QColorDialogPrivate;
};
QColorDialog::QColorDialog(QWidget *, bool) {}
QColorDialog::~QColorDialog() {}
void QColorDialog::setColor(const QColor &) {}
QColor QColorDialog::color() const { return QColor(); }
bool QColorDialog::selectColor(const QColor &) { return false; }
void QColorDialog::setSelectedAlpha(int) {}
int QColorDialog::selectedAlpha() const { return 0; }
class Q_WIDGETS_EXPORT QFontDialog
{
private:
explicit QFontDialog(QWidget *, bool, Qt::WindowFlags);
~QFontDialog();
QFont font() const;
void setFont(const QFont &);
void updateFamilies();
void updateStyles();
void updateSizes();
static QFont getFont(bool *, const QFont *, QWidget *);
friend class QFontDialogPrivate;
};
QFontDialog::QFontDialog(QWidget *, bool, Qt::WindowFlags) {}
QFontDialog::~QFontDialog() {}
QFont QFontDialog::font() const { return QFont(); }
void QFontDialog::setFont(const QFont &) { }
void QFontDialog::updateFamilies() {}
void QFontDialog::updateStyles() {}
void QFontDialog::updateSizes() {}
QFont QFontDialog::getFont(bool *, const QFont *, QWidget *) { return QFont(); }
class Q_WIDGETS_EXPORT QInputDialog
{
private:
enum Type { LineEdit, SpinBox, DoubleSpinBox, ComboBox, EditableComboBox };
QInputDialog(const QString &, QWidget *, Type, Qt::WindowFlags);
QInputDialog(const QString &, const QString &, QWidget *, QWidget *, Qt::WindowFlags);
~QInputDialog();
};
QInputDialog::QInputDialog(const QString &, QWidget *, Type, Qt::WindowFlags) {}
QInputDialog::QInputDialog(const QString &, const QString &, QWidget *, QWidget *, Qt::WindowFlags) {}
QInputDialog::~QInputDialog() {}
QT_END_NAMESPACE
#endif

View File

@ -1,838 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qfiledialog.h"
#ifndef QT_NO_FILEDIALOG
#include <private/qfiledialog_p.h>
#include <qapplication.h>
#include <private/qapplication_p.h>
#include <qt_windows.h>
#include <qglobal.h>
#include <qregexp.h>
#include <qbuffer.h>
#include <qdir.h>
#include <qstringlist.h>
#include <private/qsystemlibrary_p.h>
#include "qfiledialog_win_p.h"
#include "qplatformnativeinterface_qpa.h"
#ifndef QT_NO_THREAD
# include <private/qmutexpool_p.h>
#endif
#ifdef Q_WS_WINCE
#include <commdlg.h>
bool qt_priv_ptr_valid = false;
#else
//we have to declare them here because they're not present for all SDK/compilers
static const IID QT_IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60} };
static const IID QT_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe} };
static const CLSID QT_CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} };
#endif
typedef qt_LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(qt_BROWSEINFO*);
static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0;
typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR);
static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0;
typedef HRESULT (WINAPI *PtrSHGetMalloc)(LPMALLOC *);
static PtrSHGetMalloc ptrSHGetMalloc = 0;
QT_BEGIN_NAMESPACE
static void qt_win_resolve_libs()
{
static bool triedResolve = false;
if (!triedResolve) {
#ifndef QT_NO_THREAD
// protect initialization
QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
// check triedResolve again, since another thread may have already
// done the initialization
if (triedResolve) {
// another thread did initialize the security function pointers,
// so we shouldn't do it again.
return;
}
#endif
triedResolve = true;
#if !defined(Q_WS_WINCE)
QSystemLibrary lib(L"shell32");
ptrSHBrowseForFolder = (PtrSHBrowseForFolder)lib.resolve("SHBrowseForFolderW");
ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)lib.resolve("SHGetPathFromIDListW");
ptrSHGetMalloc = (PtrSHGetMalloc)lib.resolve("SHGetMalloc");
#else
// CE stores them in a different lib and does not use unicode version
HINSTANCE handle = LoadLibrary(L"Ceshell");
ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
ptrSHGetMalloc = (PtrSHGetMalloc)GetProcAddress(handle, L"SHGetMalloc");
if (ptrSHBrowseForFolder && ptrSHGetPathFromIDList && ptrSHGetMalloc)
qt_priv_ptr_valid = true;
#endif
}
}
extern QStringList qt_make_filter_list(const QString &filter);
const int maxNameLen = 1023;
const int maxMultiLen = 65535;
// Returns the wildcard part of a filter.
static QString qt_win_extract_filter(const QString &rawFilter)
{
QString result = rawFilter;
QRegExp r(QString::fromLatin1(QFileDialogPrivate::qt_file_dialog_filter_reg_exp));
int index = r.indexIn(result);
if (index >= 0)
result = r.cap(2);
QStringList list = result.split(QLatin1Char(' '));
for(QStringList::iterator it = list.begin(); it < list.end(); ++it) {
if (*it == QLatin1String("*")) {
*it = QLatin1String("*.*");
break;
}
}
return list.join(QLatin1String(";"));
}
static QStringList qt_win_make_filters_list(const QString &filter)
{
QString f(filter);
if (f.isEmpty())
f = QFileDialog::tr("All Files (*.*)");
return qt_make_filter_list(f);
}
// Makes a NUL-oriented Windows filter from a Qt filter.
static QString qt_win_filter(const QString &filter, bool hideFiltersDetails)
{
QStringList filterLst = qt_win_make_filters_list(filter);
QStringList::Iterator it = filterLst.begin();
QString winfilters;
QRegExp r(QString::fromLatin1(QFileDialogPrivate::qt_file_dialog_filter_reg_exp));
for (; it != filterLst.end(); ++it) {
QString subfilter = *it;
if (!subfilter.isEmpty()) {
if (hideFiltersDetails) {
int index = r.indexIn(subfilter);
if (index >= 0)
winfilters += r.cap(1);
} else {
winfilters += subfilter;
}
winfilters += QChar();
winfilters += qt_win_extract_filter(subfilter);
winfilters += QChar();
}
}
winfilters += QChar();
return winfilters;
}
static QString qt_win_selected_filter(const QString &filter, DWORD idx)
{
return qt_win_make_filters_list(filter).at((int)idx - 1);
}
static QString tFilters, tTitle, tInitDir;
static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
const QString& initialSelection,
const QString& initialDirectory,
const QString& title,
const QString& filters,
QFileDialog::FileMode mode,
QFileDialog::Options options)
{
if (parent)
parent = parent->window();
else
parent = QApplication::activeWindow();
tInitDir = QDir::toNativeSeparators(initialDirectory);
tFilters = filters;
tTitle = title;
QString initSel = QDir::toNativeSeparators(initialSelection);
if (!initSel.isEmpty()) {
initSel.remove(QLatin1Char('<'));
initSel.remove(QLatin1Char('>'));
initSel.remove(QLatin1Char('\"'));
initSel.remove(QLatin1Char('|'));
}
int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
wchar_t *tInitSel = new wchar_t[maxLen + 1];
if (initSel.length() > 0 && initSel.length() <= maxLen)
memcpy(tInitSel, initSel.utf16(), (initSel.length()+1)*sizeof(QChar));
else
tInitSel[0] = 0;
OPENFILENAME* ofn = new OPENFILENAME;
memset(ofn, 0, sizeof(OPENFILENAME));
ofn->lStructSize = sizeof(OPENFILENAME);
ofn->hwndOwner = QApplicationPrivate::getHWNDForWidget(parent);
ofn->lpstrFilter = (wchar_t*)tFilters.utf16();
ofn->lpstrFile = tInitSel;
ofn->nMaxFile = maxLen;
ofn->lpstrInitialDir = (wchar_t*)tInitDir.utf16();
ofn->lpstrTitle = (wchar_t*)tTitle.utf16();
ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
if (mode == QFileDialog::ExistingFile ||
mode == QFileDialog::ExistingFiles)
ofn->Flags |= (OFN_FILEMUSTEXIST);
if (mode == QFileDialog::ExistingFiles)
ofn->Flags |= (OFN_ALLOWMULTISELECT);
if (!(options & QFileDialog::DontConfirmOverwrite))
ofn->Flags |= OFN_OVERWRITEPROMPT;
return ofn;
}
static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
{
delete [] (*ofn)->lpstrFile;
delete *ofn;
*ofn = 0;
}
void qt_win_eatMouseMove()
{
// after closing a windows dialog with a double click (i.e. open a file)
// the message queue still contains a dubious WM_MOUSEMOVE message where
// the left button is reported to be down (wParam != 0).
// remove all those messages (usually 1) and post the last one with a
// reset button state
MSG msg = {0, 0, 0, 0, 0, {0, 0} };
while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
;
if (msg.message == WM_MOUSEMOVE)
PostMessage(msg.hwnd, msg.message, 0, msg.lParam);
}
QString qt_win_get_open_file_name(const QFileDialogArgs &args,
QString *initialDirectory,
QString *selectedFilter)
{
QString result;
QString isel = args.selection;
if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
initialDirectory->remove(0, 5);
QFileInfo fi(*initialDirectory);
if (initialDirectory && !fi.isDir()) {
*initialDirectory = fi.absolutePath();
if (isel.isEmpty())
isel = fi.fileName();
}
if (!fi.exists())
*initialDirectory = QDir::homePath();
DWORD selFilIdx = 0;
int idx = 0;
if (selectedFilter) {
QStringList filterLst = qt_win_make_filters_list(args.filter);
idx = filterLst.indexOf(*selectedFilter);
}
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(args.parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
args.directory, args.caption,
qt_win_filter(args.filter, hideFiltersDetails),
QFileDialog::ExistingFile,
args.options);
if (idx)
ofn->nFilterIndex = idx + 1;
if (GetOpenFileName(ofn)) {
result = QString::fromWCharArray(ofn->lpstrFile);
selFilIdx = ofn->nFilterIndex;
}
qt_win_clean_up_OFN(&ofn);
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (result.isEmpty())
return result;
fi = result;
*initialDirectory = fi.path();
if (selectedFilter)
*selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
return fi.absoluteFilePath();
}
QString qt_win_get_save_file_name(const QFileDialogArgs &args,
QString *initialDirectory,
QString *selectedFilter)
{
QString result;
QString isel = args.selection;
if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
initialDirectory->remove(0, 5);
QFileInfo fi(*initialDirectory);
if (initialDirectory && !fi.isDir()) {
*initialDirectory = fi.absolutePath();
if (isel.isEmpty())
isel = fi.fileName();
}
if (!fi.exists())
*initialDirectory = QDir::homePath();
DWORD selFilIdx = 0;
int idx = 0;
if (selectedFilter) {
QStringList filterLst = qt_win_make_filters_list(args.filter);
idx = filterLst.indexOf(*selectedFilter);
}
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(args.parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
// This block is used below for the lpstrDefExt member.
// 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 a extension (e.g (*)). If the current filter have an extension, use
// the extension of the current filter"
QString defaultSaveExt;
if (selectedFilter && !selectedFilter->isEmpty()) {
defaultSaveExt = qt_win_extract_filter(*selectedFilter);
// make sure we only have the extension
int firstDot = defaultSaveExt.indexOf(QLatin1Char('.'));
if (firstDot != -1) {
defaultSaveExt.remove(0, firstDot + 1);
} else {
defaultSaveExt.clear();
}
}
OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
args.directory, args.caption,
qt_win_filter(args.filter, hideFiltersDetails),
QFileDialog::AnyFile,
args.options);
ofn->lpstrDefExt = (wchar_t*)defaultSaveExt.utf16();
if (idx)
ofn->nFilterIndex = idx + 1;
if (GetSaveFileName(ofn)) {
result = QString::fromWCharArray(ofn->lpstrFile);
selFilIdx = ofn->nFilterIndex;
}
qt_win_clean_up_OFN(&ofn);
#if defined(Q_WS_WINCE)
int semIndex = result.indexOf(QLatin1Char(';'));
if (semIndex >= 0)
result = result.left(semIndex);
#endif
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (result.isEmpty())
return result;
fi = result;
*initialDirectory = fi.path();
if (selectedFilter)
*selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
return fi.absoluteFilePath();
}
#ifndef Q_WS_WINCE
typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0;
static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd,
const QString& initialSelection,
const QString& initialDirectory,
const QString& title,
const QStringList& filterLst,
QFileDialog::FileMode mode,
QFileDialog::Options options)
{
if (!pSHCreateItemFromParsingName) {
// This function is available only in Vista & above.
QSystemLibrary shellLib(QLatin1String("Shell32"));
pSHCreateItemFromParsingName = (PtrSHCreateItemFromParsingName)
shellLib.resolve("SHCreateItemFromParsingName");
if (!pSHCreateItemFromParsingName)
return false;
}
HRESULT hr;
QString winfilters;
int numFilters = 0;
quint32 currentOffset = 0;
QList<quint32> offsets;
QStringList::ConstIterator it = filterLst.begin();
// Create the native filter string and save offset to each entry.
for (; it != filterLst.end(); ++it) {
QString subfilter = *it;
if (!subfilter.isEmpty()) {
offsets<<currentOffset;
//Here the COMMON_ITEM_DIALOG API always add the details for the filter (e.g. *.txt)
//so we don't need to handle the flag HideNameFilterDetails.
winfilters += subfilter; // The name of the filter.
winfilters += QChar();
currentOffset += subfilter.size()+1;
offsets<<currentOffset;
QString spec = qt_win_extract_filter(subfilter);
winfilters += spec; // The actual filter spec.
winfilters += QChar();
currentOffset += spec.size()+1;
numFilters++;
}
}
// Add the filters to the file dialog.
if (numFilters) {
wchar_t *szData = (wchar_t*)winfilters.utf16();
qt_COMDLG_FILTERSPEC *filterSpec = new qt_COMDLG_FILTERSPEC[numFilters];
for(int i = 0; i<numFilters; i++) {
filterSpec[i].pszName = szData+offsets[i*2];
filterSpec[i].pszSpec = szData+offsets[(i*2)+1];
}
hr = pfd->SetFileTypes(numFilters, filterSpec);
delete []filterSpec;
}
// Set the starting folder.
tInitDir = QDir::toNativeSeparators(initialDirectory);
if (!tInitDir.isEmpty()) {
IShellItem *psiDefaultFolder;
hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), NULL, QT_IID_IShellItem,
reinterpret_cast<void**>(&psiDefaultFolder));
if (SUCCEEDED(hr)) {
hr = pfd->SetFolder(psiDefaultFolder);
psiDefaultFolder->Release();
}
}
// Set the currently selected file.
QString initSel = QDir::toNativeSeparators(initialSelection);
if (!initSel.isEmpty()) {
initSel.remove(QLatin1Char('<'));
initSel.remove(QLatin1Char('>'));
initSel.remove(QLatin1Char('\"'));
initSel.remove(QLatin1Char('|'));
}
if (!initSel.isEmpty()) {
hr = pfd->SetFileName((wchar_t*)initSel.utf16());
}
// Set the title for the file dialog.
if (!title.isEmpty()) {
hr = pfd->SetTitle((wchar_t*)title.utf16());
}
// Set other flags for the dialog.
DWORD newOptions;
hr = pfd->GetOptions(&newOptions);
if (SUCCEEDED(hr)) {
newOptions |= FOS_NOCHANGEDIR;
if (mode == QFileDialog::ExistingFile ||
mode == QFileDialog::ExistingFiles)
newOptions |= (FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST);
if (mode == QFileDialog::ExistingFiles)
newOptions |= FOS_ALLOWMULTISELECT;
if (!(options & QFileDialog::DontConfirmOverwrite))
newOptions |= FOS_OVERWRITEPROMPT;
hr = pfd->SetOptions(newOptions);
}
return SUCCEEDED(hr);
}
static QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
QString *initialDirectory,
const QStringList &filterList,
QString *selectedFilter,
int selectedFilterIndex)
{
QStringList result;
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(args.parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
// Multiple selection is allowed only in IFileOpenDialog.
IFileOpenDialog *pfd = 0;
HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, QT_IID_IFileOpenDialog,
reinterpret_cast<void**>(&pfd));
if (SUCCEEDED(hr)) {
qt_win_set_IFileDialogOptions(pfd, args.selection,
args.directory, args.caption,
filterList, QFileDialog::ExistingFiles,
args.options);
// Set the currently selected filter (one-based index).
hr = pfd->SetFileTypeIndex(selectedFilterIndex+1);
QWidget *parentWindow = args.parent;
if (parentWindow)
parentWindow = parentWindow->window();
else
parentWindow = QApplication::activeWindow();
// Show the file dialog.
hr = pfd->Show(QApplicationPrivate::getHWNDForWidget(parentWindow));
if (SUCCEEDED(hr)) {
// Retrieve the results.
IShellItemArray *psiaResults;
hr = pfd->GetResults(&psiaResults);
if (SUCCEEDED(hr)) {
DWORD numItems = 0;
psiaResults->GetCount(&numItems);
for (DWORD i = 0; i<numItems; i++) {
IShellItem *psi = 0;
hr = psiaResults->GetItemAt(i, &psi);
if (SUCCEEDED(hr)) {
// Retrieve the file name from shell item.
wchar_t *pszPath;
hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr)) {
QString fileName = QString::fromWCharArray(pszPath);
result.append(fileName);
CoTaskMemFree(pszPath);
}
psi->Release(); // Free the current item.
}
}
psiaResults->Release(); // Free the array of items.
}
}
}
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (!result.isEmpty()) {
// Retrieve the current folder name.
IShellItem *psi = 0;
hr = pfd->GetFolder(&psi);
if (SUCCEEDED(hr)) {
wchar_t *pszPath;
hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr)) {
*initialDirectory = QString::fromWCharArray(pszPath);
CoTaskMemFree(pszPath);
}
psi->Release();
}
// Retrieve the currently selected filter.
if (selectedFilter) {
quint32 filetype = 0;
hr = pfd->GetFileTypeIndex(&filetype);
if (SUCCEEDED(hr) && filetype && filetype <= (quint32)filterList.length()) {
// This is a one-based index, not zero-based.
*selectedFilter = filterList[filetype-1];
}
}
}
if (pfd)
pfd->Release();
return result;
}
QString qt_win_CID_get_existing_directory(const QFileDialogArgs &args)
{
QString result;
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(args.parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
IFileOpenDialog *pfd = 0;
HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
QT_IID_IFileOpenDialog, reinterpret_cast<void**>(&pfd));
if (SUCCEEDED(hr)) {
qt_win_set_IFileDialogOptions(pfd, args.selection,
args.directory, args.caption,
QStringList(), QFileDialog::ExistingFiles,
args.options);
// Set the FOS_PICKFOLDERS flag
DWORD newOptions;
hr = pfd->GetOptions(&newOptions);
newOptions |= (FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);
if (SUCCEEDED(hr) && SUCCEEDED((hr = pfd->SetOptions(newOptions)))) {
QWidget *parentWindow = args.parent;
if (parentWindow)
parentWindow = parentWindow->window();
else
parentWindow = QApplication::activeWindow();
// Show the file dialog.
hr = pfd->Show(QApplicationPrivate::getHWNDForWidget(parentWindow));
if (SUCCEEDED(hr)) {
// Retrieve the result
IShellItem *psi = 0;
hr = pfd->GetResult(&psi);
if (SUCCEEDED(hr)) {
// Retrieve the file name from shell item.
wchar_t *pszPath;
hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr)) {
result = QString::fromWCharArray(pszPath);
CoTaskMemFree(pszPath);
}
psi->Release(); // Free the current item.
}
}
}
}
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (pfd)
pfd->Release();
return result;
}
#endif
QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
QString *initialDirectory,
QString *selectedFilter)
{
QFileInfo fi;
QDir dir;
if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
initialDirectory->remove(0, 5);
fi = QFileInfo(*initialDirectory);
if (initialDirectory && !fi.isDir()) {
*initialDirectory = fi.absolutePath();
}
if (!fi.exists())
*initialDirectory = QDir::homePath();
DWORD selFilIdx = 0;
QStringList filterLst = qt_win_make_filters_list(args.filter);
int idx = 0;
if (selectedFilter) {
idx = filterLst.indexOf(*selectedFilter);
}
// Windows Vista (& above) allows users to search from file dialogs. If user selects
// multiple files belonging to different folders from these search results, the
// GetOpenFileName() will return only one folder name for all the files. To retrieve
// the correct path for all selected files, we have to use Common Item Dialog interfaces.
#ifndef Q_WS_WINCE
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx);
#endif
QStringList result;
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(args.parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
args.directory, args.caption,
qt_win_filter(args.filter, hideFiltersDetails),
QFileDialog::ExistingFiles,
args.options);
if (idx)
ofn->nFilterIndex = idx + 1;
if (GetOpenFileName(ofn)) {
QString fileOrDir = QString::fromWCharArray(ofn->lpstrFile);
selFilIdx = ofn->nFilterIndex;
int offset = fileOrDir.length() + 1;
if (ofn->lpstrFile[offset] == 0) {
// Only one file selected; has full path
fi.setFile(fileOrDir);
QString res = fi.absoluteFilePath();
if (!res.isEmpty())
result.append(res);
}
else {
// Several files selected; first string is path
dir.setPath(fileOrDir);
QString f;
while(!(f = QString::fromWCharArray(ofn->lpstrFile + offset)).isEmpty()) {
fi.setFile(dir, f);
QString res = fi.absoluteFilePath();
if (!res.isEmpty())
result.append(res);
offset += f.length() + 1;
}
}
}
qt_win_clean_up_OFN(&ofn);
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (!result.isEmpty()) {
*initialDirectory = fi.path(); // only save the path if there is a result
if (selectedFilter)
*selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
}
return result;
}
// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
UINT uMsg,
LPARAM lParam,
LPARAM lpData)
{
if (uMsg == BFFM_INITIALIZED && lpData != 0) {
QString *initDir = (QString *)(lpData);
if (!initDir->isEmpty()) {
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
}
} else if (uMsg == BFFM_SELCHANGED) {
qt_win_resolve_libs();
if (ptrSHGetPathFromIDList) {
wchar_t path[MAX_PATH];
ptrSHGetPathFromIDList(qt_LPITEMIDLIST(lParam), path);
QString tmpStr = QString::fromWCharArray(path);
if (!tmpStr.isEmpty())
SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
else
SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
}
}
return 0;
}
QString qt_win_get_existing_directory(const QFileDialogArgs &args)
{
#ifndef Q_WS_WINCE
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
return qt_win_CID_get_existing_directory(args);
#endif
QString currentDir = QDir::currentPath();
QString result;
QWidget *parent = args.parent;
if (parent)
parent = parent->window();
else
parent = QApplication::activeWindow();
if (parent)
parent->createWinId();
QDialog modal_widget;
modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
modal_widget.setParent(parent, Qt::Window);
QApplicationPrivate::enterModal(&modal_widget);
QString initDir = QDir::toNativeSeparators(args.directory);
wchar_t path[MAX_PATH];
wchar_t initPath[MAX_PATH];
initPath[0] = 0;
path[0] = 0;
tTitle = args.caption;
qt_BROWSEINFO bi;
Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
bi.hwndOwner = QApplicationPrivate::getHWNDForWidget(parent);
bi.pidlRoot = NULL;
//### This does not seem to be respected? - the dialog always displays "Browse for folder"
bi.lpszTitle = (wchar_t*)tTitle.utf16();
bi.pszDisplayName = initPath;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
bi.lpfn = winGetExistDirCallbackProc;
bi.lParam = LPARAM(&initDir);
qt_win_resolve_libs();
if (ptrSHBrowseForFolder) {
qt_LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
if (pItemIDList) {
ptrSHGetPathFromIDList(pItemIDList, path);
IMalloc *pMalloc;
if (ptrSHGetMalloc(&pMalloc) == NOERROR) {
pMalloc->Free(pItemIDList);
pMalloc->Release();
result = QString::fromWCharArray(path);
}
}
}
tTitle = QString();
QApplicationPrivate::leaveModal(&modal_widget);
qt_win_eatMouseMove();
if (!result.isEmpty())
result.replace(QLatin1Char('\\'), QLatin1Char('/'));
return result;
}
QT_END_NAMESPACE
#endif

View File

@ -1,243 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <objbase.h>
#ifndef QFILEDIAG_WIN_P_H
#define QFILEDIAG_WIN_P_H
//these are the interface declarations needed for the file dialog on Vista and up
//At some point we can hope that all compilers/sdk will support that interface
//and we won't have to declare it ourselves
//declarations
#define FOS_OVERWRITEPROMPT 0x2
#define FOS_STRICTFILETYPES 0x4
#define FOS_NOCHANGEDIR 0x8
#define FOS_PICKFOLDERS 0x20
#define FOS_FORCEFILESYSTEM 0x40
#define FOS_ALLNONSTORAGEITEMS 0x80
#define FOS_NOVALIDATE 0x100
#define FOS_ALLOWMULTISELECT 0x200
#define FOS_PATHMUSTEXIST 0x800
#define FOS_FILEMUSTEXIST 0x1000
#define FOS_CREATEPROMPT 0x2000
#define FOS_SHAREAWARE 0x4000
#define FOS_NOREADONLYRETURN 0x8000
#define FOS_NOTESTFILECREATE 0x10000
#define FOS_HIDEMRUPLACES 0x20000
#define FOS_HIDEPINNEDPLACES 0x40000
#define FOS_NODEREFERENCELINKS 0x100000
#define FOS_DONTADDTORECENT 0x2000000
#define FOS_FORCESHOWHIDDEN 0x10000000
#define FOS_DEFAULTNOMINIMODE 0x20000000
#define FOS_FORCEPREVIEWPANEON 0x40000000
typedef int GETPROPERTYSTOREFLAGS;
#define GPS_DEFAULT 0x00000000
#define GPS_HANDLERPROPERTIESONLY 0x00000001
#define GPS_READWRITE 0x00000002
#define GPS_TEMPORARY 0x00000004
#define GPS_FASTPROPERTIESONLY 0x00000008
#define GPS_OPENSLOWITEM 0x00000010
#define GPS_DELAYCREATION 0x00000020
#define GPS_BESTEFFORT 0x00000040
#define GPS_MASK_VALID 0x0000007F
typedef int (QT_WIN_CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
// message from browser
#define BFFM_INITIALIZED 1
#define BFFM_SELCHANGED 2
#define BFFM_ENABLEOK (WM_USER + 101)
#define BFFM_SETSELECTION (WM_USER + 103)
#define BFFM_SETSTATUSTEXT (WM_USER + 104)
// Browsing for directory.
#define BIF_RETURNONLYFSDIRS 0x0001
#define BIF_DONTGOBELOWDOMAIN 0x0002
#define BIF_STATUSTEXT 0x0004
#define BIF_RETURNFSANCESTORS 0x0008
#define BIF_EDITBOX 0x0010
#define BIF_VALIDATE 0x0020
#define BIF_NEWDIALOGSTYLE 0x0040
#define BIF_BROWSEINCLUDEURLS 0x0080
#define BIF_UAHINT 0x0100
#define BIF_NONEWFOLDERBUTTON 0x0200
#define BIF_NOTRANSLATETARGETS 0x0400
#define BIF_BROWSEFORCOMPUTER 0x1000
#define BIF_BROWSEFORPRINTER 0x2000
#define BIF_BROWSEINCLUDEFILES 0x4000
#define BIF_SHAREABLE 0x8000
//the enums
typedef enum {
SIATTRIBFLAGS_AND = 0x1,
SIATTRIBFLAGS_OR = 0x2,
SIATTRIBFLAGS_APPCOMPAT = 0x3,
SIATTRIBFLAGS_MASK = 0x3
} SIATTRIBFLAGS;
typedef enum {
SIGDN_NORMALDISPLAY = 0x00000000,
SIGDN_PARENTRELATIVEPARSING = 0x80018001,
SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
SIGDN_PARENTRELATIVEEDITING = 0x80031001,
SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
SIGDN_FILESYSPATH = 0x80058000,
SIGDN_URL = 0x80068000
} SIGDN;
typedef enum {
FDAP_BOTTOM = 0x00000000,
FDAP_TOP = 0x00000001
} FDAP;
typedef enum {
FDESVR_DEFAULT = 0x00000000,
FDESVR_ACCEPT = 0x00000001,
FDESVR_REFUSE = 0x00000002
} FDE_SHAREVIOLATION_RESPONSE;
typedef FDE_SHAREVIOLATION_RESPONSE FDE_OVERWRITE_RESPONSE;
//the structs
typedef struct {
LPCWSTR pszName;
LPCWSTR pszSpec;
} qt_COMDLG_FILTERSPEC;
typedef struct {
GUID fmtid;
DWORD pid;
} qt_PROPERTYKEY;
typedef struct {
USHORT cb;
BYTE abID[1];
} qt_SHITEMID, *qt_LPSHITEMID;
typedef struct {
qt_SHITEMID mkid;
} qt_ITEMIDLIST, *qt_LPITEMIDLIST;
typedef const qt_ITEMIDLIST *qt_LPCITEMIDLIST;
typedef struct {
HWND hwndOwner;
qt_LPCITEMIDLIST pidlRoot;
LPWSTR pszDisplayName;
LPCWSTR lpszTitle;
UINT ulFlags;
BFFCALLBACK lpfn;
LPARAM lParam;
int iImage;
} qt_BROWSEINFO;
DECLARE_INTERFACE(IFileDialogEvents);
DECLARE_INTERFACE_(IShellItem, IUnknown)
{
STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv) PURE;
STDMETHOD(GetParent)(THIS_ IShellItem **ppsi) PURE;
STDMETHOD(GetDisplayName)(THIS_ SIGDN sigdnName, LPWSTR *ppszName) PURE;
STDMETHOD(GetAttributes)(THIS_ ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
STDMETHOD(Compare)(THIS_ IShellItem *psi, DWORD hint, int *piOrder) PURE;
};
DECLARE_INTERFACE_(IShellItemFilter, IUnknown)
{
STDMETHOD(IncludeItem)(THIS_ IShellItem *psi) PURE;
STDMETHOD(GetEnumFlagsForItem)(THIS_ IShellItem *psi, DWORD *pgrfFlags) PURE;
};
DECLARE_INTERFACE_(IEnumShellItems, IUnknown)
{
STDMETHOD(Next)(THIS_ ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) PURE;
STDMETHOD(Skip)(THIS_ ULONG celt) PURE;
STDMETHOD(Reset)(THIS_) PURE;
STDMETHOD(Clone)(THIS_ IEnumShellItems **ppenum) PURE;
};
DECLARE_INTERFACE_(IShellItemArray, IUnknown)
{
STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) PURE;
STDMETHOD(GetPropertyStore)(THIS_ GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) PURE;
STDMETHOD(GetPropertyDescriptionList)(THIS_ const qt_PROPERTYKEY *keyType, REFIID riid, void **ppv) PURE;
STDMETHOD(GetAttributes)(THIS_ SIATTRIBFLAGS dwAttribFlags, ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
STDMETHOD(GetCount)(THIS_ DWORD *pdwNumItems) PURE;
STDMETHOD(GetItemAt)(THIS_ DWORD dwIndex, IShellItem **ppsi) PURE;
STDMETHOD(EnumItems)(THIS_ IEnumShellItems **ppenumShellItems) PURE;
};
DECLARE_INTERFACE_(IModalWindow, IUnknown)
{
STDMETHOD(Show)(THIS_ HWND hwndParent) PURE;
};
DECLARE_INTERFACE_(IFileDialog, IModalWindow)
{
STDMETHOD(SetFileTypes)(THIS_ UINT cFileTypes, const qt_COMDLG_FILTERSPEC *rgFilterSpec) PURE;
STDMETHOD(SetFileTypeIndex)(THIS_ UINT iFileType) PURE;
STDMETHOD(GetFileTypeIndex)(THIS_ UINT *piFileType) PURE;
STDMETHOD(Advise)(THIS_ IFileDialogEvents *pfde, DWORD *pdwCookie) PURE;
STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE;
STDMETHOD(SetOptions)(THIS_ DWORD fos) PURE;
STDMETHOD(GetOptions)(THIS_ DWORD *pfos) PURE;
STDMETHOD(SetDefaultFolder)(THIS_ IShellItem *psi) PURE;
STDMETHOD(SetFolder)(THIS_ IShellItem *psi) PURE;
STDMETHOD(GetFolder)(THIS_ IShellItem **ppsi) PURE;
STDMETHOD(GetCurrentSelection)(THIS_ IShellItem **ppsi) PURE;
STDMETHOD(SetFileName)(THIS_ LPCWSTR pszName) PURE;
STDMETHOD(GetFileName)(THIS_ LPWSTR *pszName) PURE;
STDMETHOD(SetTitle)(THIS_ LPCWSTR pszTitle) PURE;
STDMETHOD(SetOkButtonLabel)(THIS_ LPCWSTR pszText) PURE;
STDMETHOD(SetFileNameLabel)(THIS_ LPCWSTR pszLabel) PURE;
STDMETHOD(GetResult)(THIS_ IShellItem **ppsi) PURE;
STDMETHOD(AddPlace)(THIS_ IShellItem *psi, FDAP fdap) PURE;
STDMETHOD(SetDefaultExtension)(THIS_ LPCWSTR pszDefaultExtension) PURE;
STDMETHOD(Close)(THIS_ HRESULT hr) PURE;
STDMETHOD(SetClientGuid)(THIS_ REFGUID guid) PURE;
STDMETHOD(ClearClientData)(THIS_) PURE;
STDMETHOD(SetFilter)(THIS_ IShellItemFilter *pFilter) PURE;
};
DECLARE_INTERFACE_(IFileDialogEvents, IUnknown)
{
STDMETHOD(OnFileOk)(THIS_ IFileDialog *pfd) PURE;
STDMETHOD(OnFolderChanging)(THIS_ IFileDialog *pfd, IShellItem *psiFolder) PURE;
STDMETHOD(OnFolderChange)(THIS_ IFileDialog *pfd) PURE;
STDMETHOD(OnSelectionChange)(THIS_ IFileDialog *pfd) PURE;
STDMETHOD(OnShareViolation)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) PURE;
STDMETHOD(OnTypeChange)(THIS_ IFileDialog *pfd) PURE;
STDMETHOD(OnOverwrite)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) PURE;
};
DECLARE_INTERFACE_(IFileOpenDialog, IFileDialog)
{
STDMETHOD(GetResults)(THIS_ IShellItemArray **ppenum) PURE;
STDMETHOD(GetSelectedItems)(THIS_ IShellItemArray **ppsai) PURE;
};
#endif