4#define QT_NO_URL_CAST_FROM_STRING 1
6#include <QtCore/qt_windows.h>
14#include <QtGui/qguiapplication.h>
15#include <QtGui/qcolor.h>
17#include <QtCore/qdebug.h>
18#if QT_CONFIG(regularexpression)
19# include <QtCore/qregularexpression.h>
21#include <QtCore/qtimer.h>
22#include <QtCore/qdir.h>
23#include <QtCore/qscopedpointer.h>
24#include <QtCore/qsharedpointer.h>
25#include <QtCore/qobject.h>
26#include <QtCore/qthread.h>
27#include <QtCore/qsysinfo.h>
28#include <QtCore/qshareddata.h>
29#include <QtCore/qshareddata.h>
30#include <QtCore/qmutex.h>
31#include <QtCore/quuid.h>
32#include <QtCore/qtemporaryfile.h>
33#include <QtCore/private/qfunctions_win_p.h>
34#include <QtCore/private/qsystemerror_p.h>
35#include <QtCore/private/qcomobject_p.h>
49 const size_t stringSize =
s.size();
50 wchar_t *
result =
new wchar_t[
qMax(stringSize + 1, reserveSize)];
71 MSG msg = {
nullptr, 0, 0, 0, 0, {0, 0} };
72 while (PeekMessage(&msg,
nullptr, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
74 if (msg.message == WM_MOUSEMOVE)
75 PostMessage(msg.hwnd, msg.message, 0, msg.lParam);
76 qCDebug(lcQpaDialogs) << __FUNCTION__ <<
"triggered=" << (msg.message == WM_MOUSEMOVE);
81 IOleWindow *oleWindow =
nullptr;
82 if (FAILED(fileDialog->QueryInterface(IID_IOleWindow,
reinterpret_cast<void **
>(&oleWindow)))) {
83 qCWarning(lcQpaDialogs,
"Native file dialog: unable to query IID_IOleWindow interface.");
88 if (FAILED(oleWindow->GetWindow(&
result)))
89 qCWarning(lcQpaDialogs,
"Native file dialog: unable to get dialog's window.");
133 void exec(HWND owner =
nullptr) {
doExec(owner); m_executed =
true; }
146 virtual void doExec(HWND owner =
nullptr) = 0;
166template <
class BaseClass>
173template <
class BaseClass>
182 if (m_thread->wait(500))
185 qCCritical(lcQpaDialogs) <<__FUNCTION__ <<
"Thread failed to finish.";
190template <
class BaseClass>
193 if (m_nativeDialog.isNull()) {
194 qWarning(
"%s invoked with no native dialog present.", __FUNCTION__);
197 return m_nativeDialog.data();
200template <
class BaseClass>
206template <
class BaseClass>
211 if (m_nativeDialog.isNull() || m_nativeDialog->executed())
213 return m_nativeDialog.data();
230 : m_dialog(
d), m_owner(owner) {}
234 const QWindowsNativeDialogBasePtr m_dialog;
240 qCDebug(lcQpaDialogs) <<
'>' << __FUNCTION__;
241 QComHelper comInit(COINIT_APARTMENTTHREADED);
242 m_dialog->exec(m_owner);
243 qCDebug(lcQpaDialogs) <<
'<' << __FUNCTION__;
246template <
class BaseClass>
257 m_ownerWindow =
nullptr;
259 qCDebug(lcQpaDialogs) << __FUNCTION__ <<
"modal=" << modal
260 <<
" modal supported? " << supportsNonModalDialog(parent)
261 <<
"native=" << m_nativeDialog.data() <<
"owner" << m_ownerWindow;
262 if (!modal && !supportsNonModalDialog(parent))
264 if (!ensureNativeDialog())
272 m_timerId = this->startTimer(0);
279template <
class BaseClass>
289template <
class BaseClass>
293 this->killTimer(m_timerId);
298template <
class BaseClass>
301 if (m_nativeDialog) {
302 m_nativeDialog->close();
303 m_nativeDialog.clear();
305 m_ownerWindow =
nullptr;
308template <
class BaseClass>
311 qCDebug(lcQpaDialogs) << __FUNCTION__;
314 nd->exec(m_ownerWindow);
315 m_nativeDialog.clear();
336 void fromOptions(
const QSharedPointer<QFileDialogOptions> &
o);
339 void setDirectory(
const QUrl &);
340 QString selectedNameFilter()
const;
341 void setSelectedNameFilter(
const QString &);
342 QList<QUrl> selectedFiles()
const;
343 void setSelectedFiles(
const QList<QUrl> &);
351 QList<QUrl> selectedFiles;
354 QExplicitlySharedDataPointer<Data>
m_data;
382 m_data->selectedNameFilter =
f;
395 const auto files = selectedFiles();
402 m_data->selectedFiles = urls;
408 m_data->directory =
o->initialDirectory();
409 m_data->selectedFiles =
o->initiallySelectedFiles();
410 m_data->selectedNameFilter =
o->initiallySelectedNameFilter();
433 IFACEMETHODIMP OnFileOk(IFileDialog *)
override;
435 IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *)
override;
436 IFACEMETHODIMP OnSelectionChange(IFileDialog *)
override;
438 FDE_SHAREVIOLATION_RESPONSE *)
override
442 IFACEMETHODIMP OnTypeChange(IFileDialog *)
override;
443 IFACEMETHODIMP
OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *)
override
449 m_nativeFileDialog(nativeFileDialog) {}
457 IFileDialogEvents *
result;
459 if (FAILED(eventHandler->QueryInterface(IID_IFileDialogEvents,
reinterpret_cast<void **
>(&
result)))) {
463 eventHandler->Release();
483 {
return displayName(m_item, SIGDN_NORMALDISPLAY); }
489 {
return displayName(m_item, SIGDN_DESKTOPABSOLUTEPARSING); }
493 bool isFileSystem()
const {
return (m_attributes & SFGAO_FILESYSTEM) != 0; }
494 bool isDir()
const {
return (m_attributes & SFGAO_FOLDER) != 0; }
496 bool canStream()
const {
return (m_attributes & SFGAO_STREAM) != 0; }
500 static IShellItems itemsFromItemArray(IShellItemArray *
items);
502#ifndef QT_NO_DEBUG_STREAM
508 static QString libraryItemDefaultSaveFolder(IShellItem *
item);
509 QUrl urlValue()
const;
519 SFGAOF
mask = (SFGAO_CAPABILITYMASK | SFGAO_CONTENTSMASK | SFGAO_STORAGECAPMASK);
522 if (FAILED(
item->GetAttributes((SFGAO_STREAM | SFGAO_COMPRESSED), &m_attributes))) {
526 if (m_attributes & (SFGAO_STREAM | SFGAO_COMPRESSED))
527 mask &= ~SFGAO_HASSUBFOLDER;
528 if (FAILED(
item->GetAttributes(
mask, &m_attributes)))
536 return QDir::cleanPath(QWindowsShellItem::displayName(m_item, SIGDN_FILESYSPATH));
539 return QWindowsShellItem::libraryItemDefaultSaveFolder(m_item);
543QUrl QWindowsShellItem::urlValue() const
552 qWarning(
"%s: Unable to decode URL \"%s\": %s", __FUNCTION__,
563 if (!fsPath.isEmpty())
565 const QUrl urlV = urlValue();
576 LPWSTR
name =
nullptr;
589 if (FAILED(
items->GetCount(&itemCount)) || itemCount == 0)
591 result.reserve(itemCount);
592 for (DWORD
i = 0;
i < itemCount; ++
i) {
593 IShellItem *
item =
nullptr;
606 IStream *istream =
nullptr;
607 HRESULT hr = m_item->BindToHandler(
nullptr, BHID_Stream, IID_PPV_ARGS(&istream));
610 + QSystemError::windowsComString(hr);
613 enum : ULONG {
bufSize = 102400 };
619 if ((hr == S_OK || hr == S_FALSE) && bytesRead)
625 if (hr != S_OK && hr != S_FALSE) {
627 + QSystemError::windowsComString(hr);
641 static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}};
642 static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}};
644 IShellLibrary *helper =
nullptr;
645 IShellLibrary *
result =
nullptr;
646 if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary,
nullptr, CLSCTX_INPROC_SERVER, iId_IShellLibrary,
reinterpret_cast<void **
>(&helper))))
647 if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem,
mode)))
648 helper->QueryInterface(iId_IShellLibrary,
reinterpret_cast<void **
>(&
result));
655QString QWindowsShellItem::libraryItemDefaultSaveFolder(IShellItem *
item)
659 IShellItem *
item =
nullptr;
660 if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
reinterpret_cast<void **
>(&
item)))) {
669#ifndef QT_NO_DEBUG_STREAM
683 if (!pathS.isEmpty())
684 d <<
", path=\"" << pathS <<
'"';
685 const QUrl urlV = urlValue();
687 d <<
"\", url=" << urlV;
706 d <<
"IShellItem(" <<
static_cast<const void *
>(
i);
741 void doExec(HWND owner =
nullptr)
override;
770 void close()
override;
774 bool init(
const CLSID &clsId,
const IID &iid);
776 inline IFileDialog *
fileDialog()
const {
return m_fileDialog; }
783 IFileDialog *m_fileDialog =
nullptr;
784 IFileDialogEvents *m_dialogEvents =
nullptr;
787 bool m_hideFiltersDetails =
false;
788 bool m_hasDefaultSuffix =
false;
800 if (m_dialogEvents && m_fileDialog)
801 m_fileDialog->Unadvise(m_cookie);
803 m_dialogEvents->Release();
805 m_fileDialog->Release();
810 HRESULT hr = CoCreateInstance(clsId,
nullptr, CLSCTX_INPROC_SERVER,
811 iid,
reinterpret_cast<void **
>(&m_fileDialog));
820 hr = m_fileDialog->Advise(m_dialogEvents, &m_cookie);
825 qCDebug(lcQpaDialogs) << __FUNCTION__ << m_fileDialog << m_dialogEvents << m_cookie;
833 m_fileDialog->SetTitle(
reinterpret_cast<const wchar_t *
>(
title.
utf16()));
839 IShellItem *
result =
nullptr;
842 SHCreateItemFromParsingName(
reinterpret_cast<const wchar_t *
>(native.
utf16()),
843 nullptr, IID_IShellItem,
844 reinterpret_cast<void **
>(&
result));
854 IShellItem *
result =
nullptr;
860 PIDLIST_ABSOLUTE idList;
861 HRESULT hr = SHGetKnownFolderIDList(uuid, 0,
nullptr, &idList);
866 hr = SHCreateItemFromIDList(idList, IID_IShellItem,
reinterpret_cast<void **
>(&
result));
867 CoTaskMemFree(idList);
883 m_fileDialog->SetFolder(psi);
892 IShellItem *
item =
nullptr;
893 if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&
item)) &&
item) {
902 qCDebug(lcQpaDialogs) <<
'>' << __FUNCTION__;
905 const HRESULT hr = m_fileDialog->Show(owner);
907 qCDebug(lcQpaDialogs) <<
'<' << __FUNCTION__ <<
" returns " <<
Qt::hex << hr;
919 QFileDialogOptions::FileDialogOptions options)
921 DWORD
flags = FOS_PATHMUSTEXIST;
923 flags |= FOS_FORCESHOWHIDDEN;
925 flags |= FOS_NODEREFERENCELINKS;
929 flags |= FOS_NOREADONLYRETURN;
931 flags |= FOS_OVERWRITEPROMPT;
934 flags |= FOS_FILEMUSTEXIST;
940 flags |= FOS_PICKFOLDERS | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM;
943 flags |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
946 qCDebug(lcQpaDialogs) << __FUNCTION__ <<
"mode=" <<
mode
947 <<
"acceptMode=" << acceptMode <<
"options=" << options
950 if (FAILED(m_fileDialog->SetOptions(
flags)))
962 bool hideFilterDetails,
963 int *totalStringLength)
967 *totalStringLength = 0;
969#if QT_CONFIG(regularexpression)
972 Q_ASSERT(filterSeparatorRE.isValid());
978 const int openingParenPos = filterString.lastIndexOf(u
'(');
979 const int closingParenPos = openingParenPos != -1 ?
980 filterString.indexOf(u
')', openingParenPos + 1) : -1;
982 filterSpec.
filter = closingParenPos == -1 ?
984 filterString.
mid(openingParenPos + 1, closingParenPos - openingParenPos - 1).
trimmed();
985 if (filterSpec.filter.isEmpty())
986 filterSpec.filter += u
'*';
987#if QT_CONFIG(regularexpression)
988 filterSpec.filter.replace(filterSeparatorRE, separator);
990 filterSpec.filter.replace(u
' ', u
';');
992 filterSpec.description = filterString;
993 if (hideFilterDetails && openingParenPos != -1) {
994 filterSpec.description.truncate(openingParenPos);
995 while (filterSpec.description.endsWith(u
' '))
996 filterSpec.description.truncate(filterSpec.description.size() - 1);
998 *totalStringLength += filterSpec.filter.size() + filterSpec.description.size();
999 result.push_back(filterSpec);
1009 int totalStringLength = 0;
1010 const QList<FilterSpec> specs =
filterSpecs(
filters, m_hideFiltersDetails, &totalStringLength);
1011 const int size = specs.size();
1013 QScopedArrayPointer<WCHAR>
buffer(
new WCHAR[totalStringLength + 2 *
size]);
1014 QScopedArrayPointer<COMDLG_FILTERSPEC> comFilterSpec(
new COMDLG_FILTERSPEC[
size]);
1020 for (
int i = 0;
i <
size; ++
i) {
1024 QString description = specs[
i].description;
1026 if (!m_hideFiltersDetails && !
filter.startsWith(u
"*.")) {
1030 while (!description.
isEmpty() && description.
back().isSpace())
1031 description.
chop(1);
1035 comFilterSpec[
i].pszName =
ptr;
1038 comFilterSpec[
i].pszSpec =
ptr;
1039 ptr += specs[
i].filter.toWCharArray(
ptr);
1043 m_fileDialog->SetFileTypes(
size, comFilterSpec.data());
1049 m_hasDefaultSuffix = !
s.isEmpty();
1057 auto *wSuffix =
const_cast<wchar_t *
>(
reinterpret_cast<const wchar_t *
>(
s.utf16()));
1058 m_fileDialog->SetDefaultExtension(wSuffix);
1064 return SUCCEEDED(fileDialog->QueryInterface(IID_IFileDialog2,
reinterpret_cast<void **
>(&
result)))
1070 auto *wText =
const_cast<wchar_t *
>(
reinterpret_cast<const wchar_t *
>(
text.
utf16()));
1073 m_fileDialog->SetFileNameLabel(wText);
1076 m_fileDialog->SetOkButtonLabel(wText);
1080 dialog2->SetCancelButtonLabel(wText);
1096 || (
ch >= u
'a' &&
ch <= u
'f')
1097 || (
ch >= u
'A' &&
ch <= u
'F')))
1106 const QChar dash(u
'-');
1107 return s.size() == 36
1124 m_fileDialog->SetFileName((
wchar_t*)
fileName.utf16());
1136 if (
filters.at(
i).startsWith(needle))
1147 qWarning(
"%s: Invalid parameter '%s' not found in '%s'.",
1152 m_fileDialog->SetFileTypeIndex(
index + 1);
1158 if (SUCCEEDED(m_fileDialog->GetFileTypeIndex(&uIndex))) {
1159 const int index = uIndex - 1;
1160 if (
index < m_nameFilters.size())
1161 return m_nameFilters.at(
index);
1179 qCDebug(lcQpaDialogs) << __FUNCTION__ << current << current.size();
1181 if (current.size() == 1)
1201 m_fileDialog->Close(S_OK);
1205 qCDebug(lcQpaDialogs) << __FUNCTION__ <<
"closing" << hwnd;
1206 if (hwnd && IsWindowVisible(hwnd))
1207 PostMessageW(hwnd, WM_CLOSE, 0, 0);
1230 return m_nativeFileDialog->
onFileOk() ? S_OK : S_FALSE;
1257 int suffixPos =
filter.indexOf(u
"*.");
1261 int endPos =
filter.indexOf(u
' ', suffixPos + 1);
1263 endPos =
filter.indexOf(u
';', suffixPos + 1);
1265 endPos =
filter.indexOf(u
')', suffixPos + 1);
1268 return filter.mid(suffixPos, endPos - suffixPos);
1291 IShellItem *
item =
nullptr;
1300 IShellItem *
item =
nullptr;
1302 if (SUCCEEDED(hr) &&
item) {
1327 inline IFileOpenDialog *openFileDialog()
const
1328 {
return static_cast<IFileOpenDialog *
>(
fileDialog()); }
1340 for (
const QString &
file : std::as_const(*temporaryItemCopies()))
1349 return c.isLetterOrNumber() ||
c == u
'_' ||
c == u
'-';
1354 const int lastSlash =
qMax(
name.lastIndexOf(u
'/'),
1355 name.lastIndexOf(u
'\\'));
1356 if (lastSlash != -1)
1357 name.remove(0, lastSlash + 1);
1359 int lastDot =
name.lastIndexOf(u
'.');
1361 lastDot =
name.size();
1362 name.insert(lastDot,
"_XXXXXX"_L1);
1364 for (
int i = lastDot - 1;
i >= 0; --
i) {
1375 if (!qItem.canStream()) {
1381 targetFile.setAutoRemove(
false);
1382 if (!targetFile.open()) {
1384 + targetFile.errorString();
1390 if (temporaryItemCopies()->isEmpty())
1392 temporaryItemCopies()->append(
result);
1402 if (
path.isEmpty() && !qItem.isDir() && qItem.canStream()) {
1404 if (temporaryCopy.isEmpty()) {
1419 IShellItemArray *
items =
nullptr;
1420 if (SUCCEEDED(openFileDialog()->GetResults(&
items)) &&
items) {
1439 IShellItemArray *
items =
nullptr;
1440 const HRESULT hr = openFileDialog()->GetSelectedItems(&
items);
1441 if (SUCCEEDED(hr) &&
items) {
1448 qWarning().nospace() << __FUNCTION__<<
": Unable to obtain URL of " << qItem;
1466 if (!
result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) {
1472 if (!
result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) {
1529 const QSharedPointer<QFileDialogOptions> &opts =
options();
1532 result->setWindowTitle(opts->windowTitle());
1533 result->setMode(
mode, opts->acceptMode(), opts->options());
1535 const QStringList nameFilters = opts->nameFilters();
1536 if (!nameFilters.isEmpty())
1537 result->setNameFilters(nameFilters);
1544 result->updateDirectory();
1545 result->updateSelectedNameFilter();
1546 const QList<QUrl> initialSelection = opts->initiallySelectedFiles();
1547 if (!initialSelection.empty()) {
1548 const QUrl &
url = initialSelection.constFirst();
1559 const QString initialNameFilter = opts->initiallySelectedNameFilter();
1560 if (!initialNameFilter.isEmpty())
1561 result->selectNameFilter(initialNameFilter);
1563 const QString defaultSuffix = opts->defaultSuffix();
1565 result->setDefaultSuffix(defaultSuffix);
1598 qCDebug(lcQpaDialogs) << __FUNCTION__;
1634 void doExec(HWND owner =
nullptr)
override;
1643 void populateOpenFileName(OPENFILENAME *ofn, HWND owner)
const;
1644 QList<QUrl> execExistingDir(HWND owner);
1645 QList<QUrl> execFileNames(HWND owner,
int *selectedFilterIndex)
const;
1658QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(
const OptionsPtr &options,
1667 int selectedFilterIndex = -1;
1668 const QList<QUrl> selectedFiles =
1670 execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex);
1673 if (selectedFiles.isEmpty()) {
1678 if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size())
1680 const QUrl &firstFile = selectedFiles.constFirst();
1693 return dialog->existingDirCallback(hwnd, uMsg, lParam);
1699 case BFFM_INITIALIZED: {
1701 SetWindowText(hwnd,
reinterpret_cast<const wchar_t *
>(m_title.
utf16()));
1703 if (!initialFile.isEmpty())
1704 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16()));
1707 case BFFM_SELCHANGED: {
1709 const bool ok = SHGetPathFromIDList(
reinterpret_cast<PIDLIST_ABSOLUTE
>(lParam),
path)
1711 SendMessage(hwnd, BFFM_ENABLEOK,
ok ? 1 : 0, 1);
1718QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner)
1723 bi.hwndOwner = owner;
1724 bi.pidlRoot =
nullptr;
1725 bi.lpszTitle =
nullptr;
1726 bi.pszDisplayName = initPath;
1727 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
1729 bi.lParam = LPARAM(
this);
1730 QList<QUrl> selectedFiles;
1731 if (
const auto pItemIDList = SHBrowseForFolder(&bi)) {
1734 if (SHGetPathFromIDList(pItemIDList,
path) &&
path[0])
1737 if (SHGetMalloc(&pMalloc) == NOERROR) {
1738 pMalloc->Free(pItemIDList);
1742 return selectedFiles;
1746void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND owner)
const
1748 ZeroMemory(ofn,
sizeof(OPENFILENAME));
1749 ofn->lStructSize =
sizeof(OPENFILENAME);
1750 ofn->hwndOwner = owner;
1753 int totalStringLength = 0;
1754 const QList<FilterSpec> specs =
1756 const int size = specs.size();
1757 auto *
ptr =
new wchar_t[totalStringLength + 2 *
size + 1];
1758 ofn->lpstrFilter =
ptr;
1760 ptr += spec.description.toWCharArray(
ptr);
1762 ptr += spec.filter.toWCharArray(
ptr);
1767 if (nameFilterIndex >= 0)
1768 ofn->nFilterIndex = nameFilterIndex + 1;
1772 ofn->nMaxFile = 65535;
1774 initiallySelectedFile.
remove(u
'<');
1775 initiallySelectedFile.
remove(u
'>');
1776 initiallySelectedFile.
remove(u
'"');
1777 initiallySelectedFile.
remove(u
'|');
1780 ofn->lpstrTitle = (
wchar_t*)m_title.
utf16();
1789 defaultSuffix.
remove(0, 1);
1794 ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
1797 ofn->Flags |= (OFN_FILEMUSTEXIST);
1799 ofn->Flags |= (OFN_ALLOWMULTISELECT);
1801 ofn->Flags |= OFN_OVERWRITEPROMPT;
1804QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner,
int *selectedFilterIndex)
const
1806 *selectedFilterIndex = -1;
1808 populateOpenFileName(&ofn, owner);
1811 if (isSave ? GetSaveFileNameW(&ofn) : GetOpenFileNameW(&ofn)) {
1812 *selectedFilterIndex = ofn.nFilterIndex - 1;
1817 if (ofn.Flags & (OFN_ALLOWMULTISELECT)) {
1818 wchar_t *
ptr = ofn.lpstrFile +
dir.
size() + 1;
1830 delete [] ofn.lpstrFile;
1831 delete [] ofn.lpstrInitialDir;
1832 delete [] ofn.lpstrFilter;
1833 delete [] ofn.lpstrDefExt;
1923#ifdef USE_NATIVE_COLOR_DIALOG
1928 enum { CustomColorCount = 16 };
1932 void setWindowTitle(
const QString &)
override {}
1935 void close()
override {}
1938 void doExec(HWND owner = 0)
override;
1940 COLORREF m_customColors[CustomColorCount];
1948 std::fill(m_customColors, m_customColors + 16, COLORREF(0));
1951void QWindowsNativeColorDialog::doExec(HWND owner)
1953 CHOOSECOLOR chooseColor;
1954 ZeroMemory(&chooseColor,
sizeof(chooseColor));
1955 chooseColor.lStructSize =
sizeof(chooseColor);
1956 chooseColor.hwndOwner = owner;
1957 chooseColor.lpCustColors = m_customColors;
1958 QRgb *qCustomColors = QColorDialogOptions::customColors();
1959 const int customColorCount =
qMin(QColorDialogOptions::customColorCount(),
1960 int(CustomColorCount));
1961 for (
int c= 0;
c < customColorCount; ++
c)
1962 m_customColors[
c] = qColorToCOLORREF(
QColor(qCustomColors[
c]));
1963 chooseColor.rgbResult = qColorToCOLORREF(*m_color);
1964 chooseColor.Flags = CC_FULLOPEN | CC_RGBINIT;
1965 m_code = ChooseColorW(&chooseColor) ?
1969 *m_color = COLORREFToQColor(chooseColor.rgbResult);
1970 for (
int c= 0;
c < customColorCount; ++
c)
1971 qCustomColors[
c] = COLORREFToQColor(m_customColors[
c]).rgb();
1992 QWindowsColorDialogHelper() : m_currentColor(new
QColor) {}
1994 virtual bool supportsNonModalDialog()
1997 virtual QColor currentColor()
const {
return *m_currentColor; }
1998 virtual void setCurrentColor(
const QColor &
c) { *m_currentColor =
c; }
2011 nativeDialog->setWindowTitle(options()->
windowTitle());
2014 return nativeDialog;
2029#ifdef USE_NATIVE_COLOR_DIALOG
2053#ifdef USE_NATIVE_COLOR_DIALOG
2054 return new QWindowsColorDialogHelper();
2070#include "qwindowsdialoghelpers.moc"
The QColor class provides colors based on RGB, HSV or CMYK values.
static QString tempPath()
Returns the absolute canonical path of the system's temporary directory.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
static QString toNativeSeparators(const QString &pathName)
AcceptMode acceptMode() const
QString defaultSuffix() const
QStringList nameFilters() const
FileDialogOptions options() const
FileMode fileMode() const
QString windowTitle() const
bool remove()
Removes the file specified by fileName().
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
\inmodule QtCore \reentrant
bool isEmpty() const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void deleteLater()
\threadsafe
\inmodule QtCore \reentrant
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
qsizetype toWCharArray(wchar_t *array) const
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
void chop(qsizetype n)
Removes n characters from the end of the string.
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
void truncate(qsizetype pos)
Truncates the string at the given position index.
QString mid(qsizetype position, qsizetype n=-1) const &
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
QString & append(QChar c)
QString trimmed() const &
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
QString scheme() const
Returns the scheme of the URL.
QString errorString() const
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
static QUuid fromString(QAnyStringView string) noexcept
static HWND handleOf(const QWindow *w)
static DWORD readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
Helper for native Windows dialogs.
bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override
void timerEvent(QTimerEvent *) override
bool hasNativeDialog() const
~QWindowsDialogHelperBase()
QWindowsNativeDialogBase * nativeDialog() const
Run a non-modal native dialog in a separate thread.
QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner)
Helper for native Windows file dialogs.
QWindowsFileDialogHelper()
void setFilter() override
QWindowsNativeDialogBase * createNativeDialog() override
QString selectedNameFilter() const override
bool supportsNonModalDialog(const QWindow *=nullptr) const override
bool defaultNameFilterDisables() const override
QUrl directory() const override
void setDirectory(const QUrl &directory) override
void selectFile(const QUrl &filename) override
QList< QUrl > selectedFiles() const override
void selectNameFilter(const QString &filter) override
Explicitly shared file dialog parameters that are not in QFileDialogOptions.
QString selectedNameFilter() const
void fromOptions(const QSharedPointer< QFileDialogOptions > &o)
void setSelectedNameFilter(const QString &)
QString selectedFile() const
void setDirectory(const QUrl &)
QWindowsFileDialogSharedData()
QList< QUrl > selectedFiles() const
void setSelectedFiles(const QList< QUrl > &)
static QWindowsIntegration * instance()
Native Windows color dialog.
Base class for Windows native dialogs.
virtual void setWindowTitle(const QString &title)=0
void exec(HWND owner=nullptr)
virtual void doExec(HWND owner=nullptr)=0
QWindowsNativeDialogBase()
Windows native file dialog wrapper around IFileOpenDialog, IFileSaveDialog.
void setDefaultSuffix(const QString &s)
bool hasDefaultSuffix() const
QWindowsFileDialogSharedData & data()
void setDirectory(const QUrl &directory)
void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text)
void selectFile(const QString &fileName) const
void currentChanged(const QUrl &file)
bool hideFiltersDetails() const
QString selectedNameFilter() const
QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data)
void setHideFiltersDetails(bool h)
virtual void setNameFilters(const QStringList &f)
static IShellItem * shellItem(const QUrl &url)
IFileDialog * fileDialog() const
virtual QList< QUrl > selectedFiles() const =0
void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options)
void selectNameFilter(const QString &filter)
~QWindowsNativeFileDialogBase() override
static QWindowsNativeFileDialogBase * create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data)
Factory method for QWindowsNativeFileDialogBase returning QWindowsNativeOpenFileDialog or QWindowsNat...
const QWindowsFileDialogSharedData & data() const
void directoryEntered(const QUrl &directory)
void setWindowTitle(const QString &title) override
void updateSelectedNameFilter()
bool init(const CLSID &clsId, const IID &iid)
QString directory() const
void setDefaultSuffixSys(const QString &s)
void filterSelected(const QString &filter)
void doExec(HWND owner=nullptr) override
virtual QList< QUrl > dialogResult() const =0
void onFolderChange(IShellItem *)
Listens to IFileDialog events and forwards them to QWindowsNativeFileDialogBase.
IFACEMETHODIMP OnFileOk(IFileDialog *) override
IFACEMETHODIMP OnFolderChange(IFileDialog *) override
QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog)
IFACEMETHODIMP OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) override
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) override
static IFileDialogEvents * create(QWindowsNativeFileDialogBase *nativeFileDialog)
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *) override
IFACEMETHODIMP OnSelectionChange(IFileDialog *) override
IFACEMETHODIMP OnTypeChange(IFileDialog *) override
Windows native file save dialog wrapper around IFileOpenDialog.
QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data)
QList< QUrl > dialogResult() const override
QList< QUrl > selectedFiles() const override
Windows native file save dialog wrapper around IFileSaveDialog.
void setNameFilters(const QStringList &f) override
QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data)
QList< QUrl > dialogResult() const override
QList< QUrl > selectedFiles() const override
bool isFileSystem() const
SFGAOF attributes() const
QWindowsShellItem(IShellItem *item)
QString normalDisplay() const
static IShellItems itemsFromItemArray(IShellItemArray *items)
QString urlString() const
QString fileSysPath() const
void format(QDebug &d) const
bool copyData(QIODevice *out, QString *errorMessage)
QString desktopAbsoluteParsing() const
std::vector< IShellItem * > IShellItems
Dialog helper using QWindowsXpNativeFileDialog.
void selectNameFilter(const QString &) override
void selectFile(const QUrl &url) override
bool defaultNameFilterDisables() const override
QList< QUrl > selectedFiles() const override
QWindowsXpFileDialogHelper()=default
void setFilter() override
bool supportsNonModalDialog(const QWindow *=nullptr) const override
QWindowsNativeDialogBase * createNativeDialog() override
QUrl directory() const override
QString selectedNameFilter() const override
void setDirectory(const QUrl &directory) override
Native Windows directory dialog for Windows XP using SHlib-functions.
QSharedPointer< QFileDialogOptions > OptionsPtr
static QWindowsXpNativeFileDialog * create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data)
void setWindowTitle(const QString &t) override
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
void doExec(HWND owner=nullptr) override
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
bool useHelper(QPlatformTheme::DialogType type)
QPlatformDialogHelper * createHelper(QPlatformTheme::DialogType type)
HWND getHWND(IFileDialog *fileDialog)
void eatMouseMove()
After closing a windows dialog with a double click (i.e.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & showbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() | QTextStream::ShowBase) on stream and r...
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
SharedPointerFileDialogOptions m_options
static QString displayName(CGDirectDisplayID displayID)
void qAddPostRoutine(QtCleanUpFunction p)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCCritical(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLsizei const GLchar *const * path
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
#define qPrintable(string)
#define QStringLiteral(str)
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
static QString windowTitle(HWND hwnd)
static bool validFileNameCharacter(QChar c)
static IFileDialog2 * getFileDialog2(IFileDialog *fileDialog)
QDebug operator<<(QDebug d, const QWindowsShellItem &i)
static int indexOfNameFilter(const QStringList &filters, const QString &needle)
static void cleanupTemporaryItemCopies()
static bool isClsid(const QString &s)
static QList< FilterSpec > filterSpecs(const QStringList &filters, bool hideFilterDetails, int *totalStringLength)
static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorMessage)
QSharedPointer< QColor > SharedPointerColor
static IShellLibrary * sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode)
static wchar_t * qStringToWCharArray(const QString &s, size_t reserveSize=0)
static bool isHexRange(const QString &s, int start, int end)
static QUrl itemToDialogUrl(QWindowsShellItem &qItem, QString *errorMessage)
static QString suffixFromFilter(const QString &filter)
static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
QTextStream out(stdout)
[7]
QUrl url("example.com")
[constructor-url-reference]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QFileDialog dialog(this)
[1]
const QStringList filters({"Image files (*.png *.xpm *.jpg)", "Text files (*.txt)", "Any files (*)" })
[6]
static char * tempFilePattern()