Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/dialogs/qfiledialog_win.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtGui module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    6060
    6161#include <shlobj.h>
    62 
    63 #ifdef Q_OS_WINCE
     62//At some point we can hope that mingw will support that interface
     63#if !defined(Q_WS_WINCE) && !defined(Q_CC_MINGW)
     64#include <shobjidl.h>
     65#endif
     66
     67#include <objbase.h>
     68
     69#if defined(__IFileDialog_INTERFACE_DEFINED__) \
     70        && defined(__IFileOpenDialog_INTERFACE_DEFINED__)
     71#define USE_COMMON_ITEM_DIALOG
     72#endif
     73
     74#ifdef Q_WS_WINCE
    6475#include <commdlg.h>
    6576#  ifndef BFFM_SETSELECTION
     
    7182    HWND          hwndOwner;
    7283    LPCITEMIDLIST pidlRoot;
    73     LPTSTR        pszDisplayName;
    74     LPCTSTR       lpszTitle;
     84    LPSTR        pszDisplayName;
     85    LPCSTR       lpszTitle;
    7586    UINT          ulFlags;
    7687    BFFCALLBACK   lpfn;
     
    91102typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(LPITEMIDLIST,LPWSTR);
    92103static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0;
     104
     105
     106
    93107
    94108QT_BEGIN_NAMESPACE
     
    112126
    113127        triedResolve = true;
    114         if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
    115 #if !defined(Q_OS_WINCE)
    116             QLibrary lib(QLatin1String("shell32"));
    117             ptrSHBrowseForFolder = (PtrSHBrowseForFolder) lib.resolve("SHBrowseForFolderW");
    118             ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList) lib.resolve("SHGetPathFromIDListW");
     128#if !defined(Q_WS_WINCE)
     129        QLibrary lib(QLatin1String("shell32"));
     130        );
     131        W");
     132        ");
    119133#else
    120             // CE stores them in a different lib and does not use unicode version
    121             HINSTANCE handle = LoadLibraryW(L"Ceshell");
    122             ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
    123             ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
    124             if (ptrSHBrowseForFolder && ptrSHGetPathFromIDList)
    125                 qt_priv_ptr_valid = true;
    126 #endif
    127         }
     134        // CE stores them in a different lib and does not use unicode version
     135        HINSTANCE handle = LoadLibraryW(L"Ceshell");
     136        ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
     137        ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
     138       
     139       
     140            qt_priv_ptr_valid = true;
     141#endif
    128142    }
    129143}
     
    164178
    165179// Makes a NUL-oriented Windows filter from a Qt filter.
    166 static QString qt_win_filter(const QString &filter)
     180static QString qt_win_filter(const QString &filter)
    167181{
    168182    QStringList filterLst = qt_win_make_filters_list(filter);
    169183    QStringList::Iterator it = filterLst.begin();
    170184    QString winfilters;
     185
    171186    for (; it != filterLst.end(); ++it) {
    172187        QString subfilter = *it;
    173188        if (!subfilter.isEmpty()) {
    174             winfilters += subfilter;
     189            if (hideFiltersDetails) {
     190                int index = r.indexIn(subfilter);
     191                if (index >= 0)
     192                    winfilters += r.cap(1);
     193            } else {
     194                winfilters += subfilter;
     195            }
    175196            winfilters += QChar();
    176197            winfilters += qt_win_extract_filter(subfilter);
     
    187208}
    188209
    189 #ifndef Q_OS_WINCE
    190 // Static vars for OFNA funcs:
    191 static QByteArray aInitDir;
    192 static QByteArray aInitSel;
    193 static QByteArray aTitle;
    194 static QByteArray aFilter;
    195 // Use ANSI strings and API
    196 
    197 // If you change this, then make sure you change qt_win_make_OFN (below) too
    198 static OPENFILENAMEA *qt_win_make_OFNA(QWidget *parent,
    199                                        const QString &initialSelection,
    200                                        const QString &initialDirectory,
    201                                        const QString &title,
    202                                        const QString &filters,
    203                                        QFileDialog::FileMode mode,
    204                                        QFileDialog::Options options)
    205 {
    206     if (parent)
    207         parent = parent->window();
    208     else
    209         parent = qApp->activeWindow();
    210 
    211     aTitle = title.toLocal8Bit();
    212     aInitDir = QDir::toNativeSeparators(initialDirectory).toLocal8Bit();
    213     if (initialSelection.isEmpty()) {
    214         aInitSel = "";
    215     } else {
    216         aInitSel = QDir::toNativeSeparators(initialSelection).toLocal8Bit();
    217         aInitSel.replace("<", "");
    218         aInitSel.replace(">", "");
    219         aInitSel.replace("\"", "");
    220         aInitSel.replace("|", "");
    221     }
    222     int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
    223     aInitSel.resize(maxLen + 1);                // make room for return value
    224     aFilter = filters.toLocal8Bit();
    225 
    226     OPENFILENAMEA* ofn = new OPENFILENAMEA;
    227     memset(ofn, 0, sizeof(OPENFILENAMEA));
    228 
    229 #if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
    230     // according to the MSDN, this should also be necessary for MSVC, but
    231     // OPENFILENAME_SIZE_VERSION_400A is in not Microsoft header, as it seems
    232     if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
    233         ofn->lStructSize = OPENFILENAME_SIZE_VERSION_400A;
    234     } else {
    235         ofn->lStructSize = sizeof(OPENFILENAMEA);
    236     }
    237 #else
    238     ofn->lStructSize = sizeof(OPENFILENAMEA);
    239 #endif
    240     Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
    241     ofn->hwndOwner = parent ? parent->winId() : 0;
    242     ofn->lpstrFilter = aFilter;
    243     ofn->lpstrFile = aInitSel.data();
    244     ofn->nMaxFile = maxLen;
    245     ofn->lpstrInitialDir = aInitDir.data();
    246     ofn->lpstrTitle = aTitle.data();
    247     ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER);
    248 
    249     if (mode == QFileDialog::ExistingFile ||
    250          mode == QFileDialog::ExistingFiles)
    251         ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
    252     if (mode == QFileDialog::ExistingFiles)
    253         ofn->Flags |= (OFN_ALLOWMULTISELECT);
    254     if (!(options & QFileDialog::DontConfirmOverwrite))
    255         ofn->Flags |= OFN_OVERWRITEPROMPT;
    256 
    257     return ofn;
    258 }
    259 
    260 static void qt_win_clean_up_OFNA(OPENFILENAMEA **ofn)
    261 {
    262     delete *ofn;
    263     *ofn = 0;
    264 }
    265 #endif
    266 
    267210static QString tFilters, tTitle, tInitDir;
    268211
    269 #ifdef UNICODE
    270 // If you change this, then make sure you change qt_win_make_OFNA (above) too
    271212static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
    272213                                     const QString& initialSelection,
     
    275216                                     const QString& filters,
    276217                                     QFileDialog::FileMode mode,
    277                                      QFileDialog::Options options)
     218     QFileDialog::Options options)
    278219{
    279220    if (parent)
    280221        parent = parent->window();
    281222    else
    282         parent = qApp->activeWindow();
     223        parent = activeWindow();
    283224
    284225    tInitDir = QDir::toNativeSeparators(initialDirectory);
     
    287228    QString initSel = QDir::toNativeSeparators(initialSelection);
    288229    if (!initSel.isEmpty()) {
    289         initSel.replace(QLatin1String("<"), QLatin1String(""));
    290         initSel.replace(QLatin1String(">"), QLatin1String(""));
    291         initSel.replace(QLatin1String("\""), QLatin1String(""));
    292         initSel.replace(QLatin1String("|"), QLatin1String(""));
     230));
     231));
     232));
     233));
    293234    }
    294235
    295236    int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
    296     TCHAR *tInitSel = new TCHAR[maxLen+1];
     237    1];
    297238    if (initSel.length() > 0 && initSel.length() <= maxLen)
    298239        memcpy(tInitSel, initSel.utf16(), (initSel.length()+1)*sizeof(QChar));
     
    303244    memset(ofn, 0, sizeof(OPENFILENAME));
    304245
    305 #if defined(Q_CC_BOR) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0500)
    306     // according to the MSDN, this should also be necessary for MSVC, but
    307     // OPENFILENAME_SIZE_VERSION_400 is in not Microsoft header, as it seems
    308     if (QApplication::winVersion()==Qt::WV_NT || QApplication::winVersion()&Qt::WV_DOS_based) {
    309         ofn->lStructSize= OPENFILENAME_SIZE_VERSION_400;
    310     } else {
    311         ofn->lStructSize = sizeof(OPENFILENAME);
    312     }
    313 #else
    314246    ofn->lStructSize = sizeof(OPENFILENAME);
    315 #endif
    316247    Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
    317248    ofn->hwndOwner = parent ? parent->winId() : 0;
    318     ofn->lpstrFilter = (TCHAR *)tFilters.utf16();
     249    ofn->lpstrFilter = (*)tFilters.utf16();
    319250    ofn->lpstrFile = tInitSel;
    320251    ofn->nMaxFile = maxLen;
    321     ofn->lpstrInitialDir = (TCHAR *)tInitDir.utf16();
    322     ofn->lpstrTitle = (TCHAR *)tTitle.utf16();
    323     ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER);
     252    ofn->lpstrInitialDir = (*)tInitDir.utf16();
     253    ofn->lpstrTitle = (*)tTitle.utf16();
     254    ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER);
    324255    if (mode == QFileDialog::ExistingFile ||
    325256         mode == QFileDialog::ExistingFiles)
    326         ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
     257        ofn->Flags |= (OFN_FILEMUSTEXIST);
    327258    if (mode == QFileDialog::ExistingFiles)
    328259        ofn->Flags |= (OFN_ALLOWMULTISELECT);
     
    333264}
    334265
    335 
    336266static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
    337267{
     
    340270    *ofn = 0;
    341271}
    342 
    343 #endif // UNICODE
    344272
    345273extern void qt_win_eatMouseMove();
     
    378306    modal_widget.setParent(args.parent, Qt::Window);
    379307    QApplicationPrivate::enterModal(&modal_widget);
    380     QT_WA({
    381         // Use Unicode strings and API
    382         OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
    383                                             args.directory, args.caption,
    384                                             qt_win_filter(args.filter),
    385                                             QFileDialog::ExistingFile,
    386                                             args.options);
    387         if (idx)
    388             ofn->nFilterIndex = idx + 1;
    389         if (GetOpenFileName(ofn)) {
    390             result = QString::fromUtf16((ushort*)ofn->lpstrFile);
    391             selFilIdx = ofn->nFilterIndex;
    392         }
    393         qt_win_clean_up_OFN(&ofn);
    394     } , {
    395         // Use ANSI strings and API
    396         OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection,
    397                                               args.directory, args.caption,
    398                                               qt_win_filter(args.filter),
    399                                               QFileDialog::ExistingFile,
    400                                               args.options);
    401         if (idx)
    402             ofn->nFilterIndex = idx + 1;
    403         if (GetOpenFileNameA(ofn)) {
    404             result = QString::fromLocal8Bit(ofn->lpstrFile);
    405             selFilIdx = ofn->nFilterIndex;
    406         }
    407         qt_win_clean_up_OFNA(&ofn);
    408     });
     308
     309    bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
     310    OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
     311                                        args.directory, args.caption,
     312                                        qt_win_filter(args.filter, hideFiltersDetails),
     313                                        QFileDialog::ExistingFile,
     314                                        args.options);
     315    if (idx)
     316        ofn->nFilterIndex = idx + 1;
     317    if (GetOpenFileName(ofn)) {
     318        result = QString::fromWCharArray(ofn->lpstrFile);
     319        selFilIdx = ofn->nFilterIndex;
     320    }
     321    qt_win_clean_up_OFN(&ofn);
     322
    409323    QApplicationPrivate::leaveModal(&modal_widget);
    410324
     
    423337QString qt_win_get_save_file_name(const QFileDialogArgs &args,
    424338                                  QString *initialDirectory,
    425                                   QString *selectedFilter)
     339  QString *selectedFilter)
    426340{
    427341    QString result;
     
    453367    modal_widget.setParent(args.parent, Qt::Window);
    454368    QApplicationPrivate::enterModal(&modal_widget);
    455 
     369    bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
    456370    // This block is used below for the lpstrDefExt member.
    457371    // Note that the current MSDN docs document this member wrong.
     
    471385    }
    472386
    473     QT_WA({
    474         // Use Unicode strings and API
    475         OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
    476                                             args.directory, args.caption,
    477                                             qt_win_filter(args.filter),
    478                                             QFileDialog::AnyFile,
    479                                             args.options);
    480 
    481         ofn->lpstrDefExt = (TCHAR *)defaultSaveExt.utf16();
    482 
    483         if (idx)
    484             ofn->nFilterIndex = idx + 1;
    485         if (GetSaveFileName(ofn)) {
    486             result = QString::fromUtf16((ushort*)ofn->lpstrFile);
    487             selFilIdx = ofn->nFilterIndex;
    488         }
    489         qt_win_clean_up_OFN(&ofn);
    490     } , {
    491         // Use ANSI strings and API
    492         OPENFILENAMEA *ofn = qt_win_make_OFNA(args.parent, args.selection,
    493                                               args.directory, args.caption,
    494                                               qt_win_filter(args.filter),
    495                                               QFileDialog::AnyFile,
    496                                               args.options);
    497         QByteArray asciiExt = defaultSaveExt.toAscii();
    498         ofn->lpstrDefExt = asciiExt.data();
    499 
    500         if (idx)
    501             ofn->nFilterIndex = idx + 1;
    502         if (GetSaveFileNameA(ofn)) {
    503             result = QString::fromLocal8Bit(ofn->lpstrFile);
    504             selFilIdx = ofn->nFilterIndex;
    505         }
    506         qt_win_clean_up_OFNA(&ofn);
    507     });
    508 #if defined(Q_OS_WINCE)
     387    OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
     388                                        args.directory, args.caption,
     389                                        qt_win_filter(args.filter, hideFiltersDetails),
     390                                        QFileDialog::AnyFile,
     391                                        args.options);
     392
     393    ofn->lpstrDefExt = (wchar_t*)defaultSaveExt.utf16();
     394
     395    if (idx)
     396        ofn->nFilterIndex = idx + 1;
     397    if (GetSaveFileName(ofn)) {
     398        result = QString::fromWCharArray(ofn->lpstrFile);
     399        selFilIdx = ofn->nFilterIndex;
     400    }
     401    qt_win_clean_up_OFN(&ofn);
     402
     403#if defined(Q_WS_WINCE)
    509404    int semIndex = result.indexOf(QLatin1Char(';'));
    510405    if (semIndex >= 0)
     
    526421}
    527422
    528 QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
     423
     424#if defined(USE_COMMON_ITEM_DIALOG)
     425
     426typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
     427static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0;
     428
     429static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd,
     430                                          const QString& initialSelection,
     431                                          const QString& initialDirectory,
     432                                          const QString& title,
     433                                          const QStringList& filterLst,
     434                                          QFileDialog::FileMode mode,
     435                                          QFileDialog::Options options)
     436{
     437    if (!pSHCreateItemFromParsingName) {
     438        // This function is available only in Vista & above.
     439        QLibrary shellLib(QLatin1String("Shell32"));
     440        pSHCreateItemFromParsingName = (PtrSHCreateItemFromParsingName)
     441            shellLib.resolve("SHCreateItemFromParsingName");
     442        if (!pSHCreateItemFromParsingName)
     443            return false;
     444    }
     445    HRESULT hr;
     446    QString winfilters;
     447    int numFilters = 0;
     448    quint32 currentOffset = 0;
     449    QList<quint32> offsets;
     450    QStringList::ConstIterator it = filterLst.begin();
     451    // Create the native filter string and save offset to each entry.
     452    for (; it != filterLst.end(); ++it) {
     453        QString subfilter = *it;
     454        if (!subfilter.isEmpty()) {
     455            offsets<<currentOffset;
     456            //Here the COMMON_ITEM_DIALOG API always add the details for the filter (e.g. *.txt)
     457            //so we don't need to handle the flag HideNameFilterDetails.
     458            winfilters += subfilter; // The name of the filter.
     459            winfilters += QChar();
     460            currentOffset += subfilter.size()+1;
     461            offsets<<currentOffset;
     462            QString spec = qt_win_extract_filter(subfilter);
     463            winfilters += spec; // The actual filter spec.
     464            winfilters += QChar();
     465            currentOffset += spec.size()+1;
     466            numFilters++;
     467        }
     468    }
     469    // Add the filters to the file dialog.
     470    if (numFilters) {
     471        wchar_t *szData = (wchar_t*)winfilters.utf16();
     472        COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[numFilters];
     473        for(int i = 0; i<numFilters; i++) {
     474            filterSpec[i].pszName = szData+offsets[i*2];
     475            filterSpec[i].pszSpec = szData+offsets[(i*2)+1];
     476        }
     477        hr = pfd->SetFileTypes(numFilters, filterSpec);
     478        delete []filterSpec;
     479    }
     480    // Set the starting folder.
     481    tInitDir = QDir::toNativeSeparators(initialDirectory);
     482    if (!tInitDir.isEmpty()) {
     483        IShellItem *psiDefaultFolder;
     484        hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(),
     485                                      NULL,
     486                                      IID_PPV_ARGS(&psiDefaultFolder));
     487
     488        if (SUCCEEDED(hr)) {
     489            hr = pfd->SetFolder(psiDefaultFolder);
     490            psiDefaultFolder->Release();
     491        }
     492    }
     493    // Set the currently selected file.
     494    QString initSel = QDir::toNativeSeparators(initialSelection);
     495    if (!initSel.isEmpty()) {
     496        initSel.remove(QLatin1Char('<'));
     497        initSel.remove(QLatin1Char('>'));
     498        initSel.remove(QLatin1Char('\"'));
     499        initSel.remove(QLatin1Char('|'));
     500    }
     501    if (!initSel.isEmpty()) {
     502        hr = pfd->SetFileName((wchar_t*)initSel.utf16());
     503    }
     504    // Set the title for the file dialog.
     505    if (!title.isEmpty()) {
     506        hr = pfd->SetTitle((wchar_t*)title.utf16());
     507    }
     508    // Set other flags for the dialog.
     509    DWORD newOptions;
     510    hr = pfd->GetOptions(&newOptions);
     511    if (SUCCEEDED(hr)) {
     512        newOptions |= FOS_NOCHANGEDIR;
     513        if (mode == QFileDialog::ExistingFile ||
     514             mode == QFileDialog::ExistingFiles)
     515            newOptions |= (FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST);
     516        if (mode == QFileDialog::ExistingFiles)
     517            newOptions |= FOS_ALLOWMULTISELECT;
     518        if (!(options & QFileDialog::DontConfirmOverwrite))
     519            newOptions |= FOS_OVERWRITEPROMPT;
     520        hr = pfd->SetOptions(newOptions);
     521    }
     522    return SUCCEEDED(hr);
     523}
     524
     525QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
    529526                                       QString *initialDirectory,
    530                                        QString *selectedFilter)
     527                                       const QStringList &filterList,
     528                                       QString *selectedFilter,
     529                                       int selectedFilterIndex)
    531530{
    532531    QStringList result;
    533     QFileInfo fi;
    534     QDir dir;
    535     QString isel;
    536 
    537     if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
    538         initialDirectory->remove(0, 5);
    539     fi = QFileInfo(*initialDirectory);
    540 
    541     if (initialDirectory && !fi.isDir()) {
    542         *initialDirectory = fi.absolutePath();
    543         isel = fi.fileName();
    544     }
    545 
    546     if (!fi.exists())
    547         *initialDirectory = QDir::homePath();
    548 
    549     DWORD selFilIdx = 0;
    550 
    551     int idx = 0;
    552     if (selectedFilter) {
    553         QStringList filterLst = qt_win_make_filters_list(args.filter);
    554         idx = filterLst.indexOf(*selectedFilter);
    555     }
    556 
    557532    QDialog modal_widget;
    558533    modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
    559534    modal_widget.setParent(args.parent, Qt::Window);
    560535    QApplicationPrivate::enterModal(&modal_widget);
    561     QT_WA({
    562         OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
    563                                             args.directory, args.caption,
    564                                             qt_win_filter(args.filter),
    565                                             QFileDialog::ExistingFiles,
    566                                             args.options);
    567         if (idx)
    568             ofn->nFilterIndex = idx + 1;
    569         if (GetOpenFileName(ofn)) {
    570             QString fileOrDir = QString::fromUtf16((ushort*)ofn->lpstrFile);
    571             selFilIdx = ofn->nFilterIndex;
    572             int offset = fileOrDir.length() + 1;
    573             if (ofn->lpstrFile[offset] == 0) {
    574                 // Only one file selected; has full path
    575                 fi.setFile(fileOrDir);
     536    // Multiple selection is allowed only in IFileOpenDialog.
     537    IFileOpenDialog *pfd = 0;
     538    HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
     539                                  NULL,
     540                                  CLSCTX_INPROC_SERVER,
     541                                  IID_PPV_ARGS(&pfd));
     542
     543    if (SUCCEEDED(hr)) {
     544        qt_win_set_IFileDialogOptions(pfd, args.selection,
     545                                      args.directory, args.caption,
     546                                      filterList, QFileDialog::ExistingFiles,
     547                                      args.options);
     548        // Set the currently selected filter (one-based index).
     549        hr = pfd->SetFileTypeIndex(selectedFilterIndex+1);
     550        QWidget *parentWindow = args.parent;
     551        if (parentWindow)
     552            parentWindow = parentWindow->window();
     553        else
     554            parentWindow = QApplication::activeWindow();
     555        // Show the file dialog.
     556        hr = pfd->Show(parentWindow ? parentWindow->winId() : 0);
     557        if (SUCCEEDED(hr)) {
     558            // Retrieve the results.
     559            IShellItemArray *psiaResults;
     560            hr = pfd->GetResults(&psiaResults);
     561            if (SUCCEEDED(hr)) {
     562                DWORD numItems = 0;
     563                psiaResults->GetCount(&numItems);
     564                for (DWORD i = 0; i<numItems; i++) {
     565                    IShellItem *psi = 0;
     566                    hr = psiaResults->GetItemAt(i, &psi);
     567                    if (SUCCEEDED(hr)) {
     568                        // Retrieve the file name from shell item.
     569                        wchar_t *pszPath;
     570                        hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
     571                        if (SUCCEEDED(hr)) {
     572                            QString fileName = QString::fromWCharArray(pszPath);
     573                            result.append(fileName);
     574                            CoTaskMemFree(pszPath);
     575                        }
     576                        psi->Release(); // Free the current item.
     577                    }
     578                }
     579                psiaResults->Release(); // Free the array of items.
     580            }
     581        }
     582    }
     583    QApplicationPrivate::leaveModal(&modal_widget);
     584
     585    qt_win_eatMouseMove();
     586
     587    if (!result.isEmpty()) {
     588        // Retrieve the current folder name.
     589        IShellItem *psi = 0;
     590        hr = pfd->GetFolder(&psi);
     591        if (SUCCEEDED(hr)) {
     592            wchar_t *pszPath;
     593            hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
     594            if (SUCCEEDED(hr)) {
     595                *initialDirectory = QString::fromWCharArray(pszPath);
     596                CoTaskMemFree(pszPath);
     597            }
     598            psi->Release();
     599        }
     600        // Retrieve the currently selected filter.
     601        if (selectedFilter) {
     602            quint32 filetype = 0;
     603            hr = pfd->GetFileTypeIndex(&filetype);
     604            if (SUCCEEDED(hr) && filetype && filetype <= (quint32)filterList.length()) {
     605                // This is a one-based index, not zero-based.
     606                *selectedFilter = filterList[filetype-1];
     607            }
     608        }
     609    }
     610    if (pfd)
     611        pfd->Release();
     612    return result;
     613}
     614
     615#endif
     616
     617QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
     618                                       QString *initialDirectory,
     619                                       QString *selectedFilter)
     620{
     621    QFileInfo fi;
     622    QDir dir;
     623
     624    if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
     625        initialDirectory->remove(0, 5);
     626    fi = QFileInfo(*initialDirectory);
     627
     628    if (initialDirectory && !fi.isDir()) {
     629        *initialDirectory = fi.absolutePath();
     630    }
     631
     632    if (!fi.exists())
     633        *initialDirectory = QDir::homePath();
     634
     635    DWORD selFilIdx = 0;
     636
     637    QStringList filterLst = qt_win_make_filters_list(args.filter);
     638    int idx = 0;
     639    if (selectedFilter) {
     640        idx = filterLst.indexOf(*selectedFilter);
     641    }
     642    // Windows Vista (& above) allows users to search from file dialogs. If user selects
     643    // multiple files belonging to different folders from these search results, the
     644    // GetOpenFileName() will return only one folder name for all the files. To retrieve
     645    // the correct path for all selected files, we have to use Common Item Dialog interfaces.
     646#if defined(USE_COMMON_ITEM_DIALOG)
     647    if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
     648        return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx);
     649#endif
     650
     651    QStringList result;
     652    QDialog modal_widget;
     653    modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
     654    modal_widget.setParent(args.parent, Qt::Window);
     655    QApplicationPrivate::enterModal(&modal_widget);
     656
     657    bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
     658    OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
     659                                        args.directory, args.caption,
     660                                        qt_win_filter(args.filter, hideFiltersDetails),
     661                                        QFileDialog::ExistingFiles,
     662                                        args.options);
     663    if (idx)
     664        ofn->nFilterIndex = idx + 1;
     665    if (GetOpenFileName(ofn)) {
     666        QString fileOrDir = QString::fromWCharArray(ofn->lpstrFile);
     667        selFilIdx = ofn->nFilterIndex;
     668        int offset = fileOrDir.length() + 1;
     669        if (ofn->lpstrFile[offset] == 0) {
     670            // Only one file selected; has full path
     671            fi.setFile(fileOrDir);
     672            QString res = fi.absoluteFilePath();
     673            if (!res.isEmpty())
     674                result.append(res);
     675        }
     676        else {
     677            // Several files selected; first string is path
     678            dir.setPath(fileOrDir);
     679            QString f;
     680            while(!(f = QString::fromWCharArray(ofn->lpstrFile + offset)).isEmpty()) {
     681                fi.setFile(dir, f);
    576682                QString res = fi.absoluteFilePath();
    577683                if (!res.isEmpty())
    578684                    result.append(res);
     685
    579686            }
    580             else {
    581                 // Several files selected; first string is path
    582                 dir.setPath(fileOrDir);
    583                 QString f;
    584                 while(!(f = QString::fromUtf16((ushort*)ofn->lpstrFile+offset)).isEmpty()) {
    585                     fi.setFile(dir, f);
    586                     QString res = fi.absoluteFilePath();
    587                     if (!res.isEmpty())
    588                         result.append(res);
    589                     offset += f.length() + 1;
    590                 }
    591             }
    592         }
    593         qt_win_clean_up_OFN(&ofn);
    594     } , {
    595         OPENFILENAMEA* ofn = qt_win_make_OFNA(args.parent, args.selection,
    596                                               args.directory, args.caption,
    597                                               qt_win_filter(args.filter),
    598                                               QFileDialog::ExistingFiles,
    599                                               args.options);
    600         if (idx)
    601             ofn->nFilterIndex = idx + 1;
    602         if (GetOpenFileNameA(ofn)) {
    603             QByteArray fileOrDir(ofn->lpstrFile);
    604             selFilIdx = ofn->nFilterIndex;
    605             int offset = fileOrDir.length() + 1;
    606             if (ofn->lpstrFile[offset] == '\0') {
    607                 // Only one file selected; has full path
    608                 fi.setFile(QString::fromLocal8Bit(fileOrDir));
    609                 QString res = fi.absoluteFilePath();
    610                 if (!res.isEmpty())
    611                     result.append(res);
    612             }
    613             else {
    614                 // Several files selected; first string is path
    615                 dir.setPath(QString::fromLocal8Bit(fileOrDir));
    616                 QByteArray f;
    617                 while (!(f = QByteArray(ofn->lpstrFile + offset)).isEmpty()) {
    618                     fi.setFile(dir, QString::fromLocal8Bit(f));
    619                     QString res = fi.absoluteFilePath();
    620                     if (!res.isEmpty())
    621                         result.append(res);
    622                     offset += f.length() + 1;
    623                 }
    624             }
    625             qt_win_clean_up_OFNA(&ofn);
    626         }
    627     });
     687        }
     688    }
     689    qt_win_clean_up_OFN(&ofn);
     690
    628691    QApplicationPrivate::leaveModal(&modal_widget);
    629692
     
    648711        QString *initDir = (QString *)(lpData);
    649712        if (!initDir->isEmpty()) {
    650             // ### Lars asks: is this correct for the A version????
    651             QT_WA({
    652                 SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
    653             } , {
    654                 SendMessageA(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
    655             });
     713            SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
    656714        }
    657715    } else if (uMsg == BFFM_SELCHANGED) {
    658         QT_WA({
    659             qt_win_resolve_libs();
    660             TCHAR path[MAX_PATH];
     716       
     717       
     718            path[MAX_PATH];
    661719            ptrSHGetPathFromIDList(LPITEMIDLIST(lParam), path);
    662             QString tmpStr = QString::fromUtf16((ushort*)path);
     720            QString tmpStr = QString::frompath);
    663721            if (!tmpStr.isEmpty())
    664722                SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
     
    666724                SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
    667725            SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
    668         } , {
    669             char path[MAX_PATH];
    670             SHGetPathFromIDListA(LPITEMIDLIST(lParam), path);
    671             QString tmpStr = QString::fromLocal8Bit(path);
    672             if (!tmpStr.isEmpty())
    673                 SendMessageA(hwnd, BFFM_ENABLEOK, 1, 1);
    674             else
    675                 SendMessageA(hwnd, BFFM_ENABLEOK, 0, 0);
    676             SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
    677         });
     726        }
    678727    }
    679728    return 0;
     
    693742        parent = parent->window();
    694743    else
    695         parent = qApp->activeWindow();
     744        parent = activeWindow();
    696745    if (parent)
    697746        parent->createWinId();
     
    701750    modal_widget.setParent(parent, Qt::Window);
    702751    QApplicationPrivate::enterModal(&modal_widget);
    703 #if !defined(Q_OS_WINCE)
    704     QT_WA({
    705         qt_win_resolve_libs();
    706         QString initDir = QDir::toNativeSeparators(args.directory);
    707         TCHAR path[MAX_PATH];
    708         TCHAR initPath[MAX_PATH];
    709         initPath[0] = 0;
    710         path[0] = 0;
    711         tTitle = args.caption;
    712         BROWSEINFO bi;
    713         Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
    714         bi.hwndOwner = (parent ? parent->winId() : 0);
    715         bi.pidlRoot = NULL;
    716         //### This does not seem to be respected? - the dialog always displays "Browse for folder"
    717         bi.lpszTitle = (TCHAR*)tTitle.utf16();
    718         bi.pszDisplayName = initPath;
    719         bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
    720         bi.lpfn = winGetExistDirCallbackProc;
    721         bi.lParam = LPARAM(&initDir);
    722         if (ptrSHBrowseForFolder) {
    723             LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
    724             if (pItemIDList && ptrSHGetPathFromIDList) {
    725                 ptrSHGetPathFromIDList(pItemIDList, path);
    726                 IMalloc *pMalloc;
    727                 if (SHGetMalloc(&pMalloc) != NOERROR)
    728                     result = QString();
    729                 else {
    730                     pMalloc->Free(pItemIDList);
    731                     pMalloc->Release();
    732                     result = QString::fromUtf16((ushort*)path);
    733                 }
    734             } else
    735                 result = QString();
    736         }
    737         tTitle = QString();
    738     } , {
    739         QString initDir = QDir::toNativeSeparators(args.directory);
    740         char path[MAX_PATH];
    741         char initPath[MAX_PATH];
    742         QByteArray ctitle = args.caption.toLocal8Bit();
    743         initPath[0]=0;
    744         path[0]=0;
    745         BROWSEINFOA bi;
    746         Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
    747         bi.hwndOwner = (parent ? parent->winId() : 0);
    748         bi.pidlRoot = NULL;
    749         bi.lpszTitle = ctitle;
    750         bi.pszDisplayName = initPath;
    751         bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
    752         bi.lpfn = winGetExistDirCallbackProc;
    753         bi.lParam = LPARAM(&initDir);
    754         LPITEMIDLIST pItemIDList = SHBrowseForFolderA(&bi);
    755         if (pItemIDList) {
    756             SHGetPathFromIDListA(pItemIDList, path);
    757             IMalloc *pMalloc;
    758             if (SHGetMalloc(&pMalloc) != NOERROR)
    759                 result = QString();
    760             else {
    761                 pMalloc->Free(pItemIDList);
    762                 pMalloc->Release();
    763                 result = QString::fromLocal8Bit(path);
    764             }
    765         } else
    766             result = QString();
    767     });
     752
     753    QString initDir = QDir::toNativeSeparators(args.directory);
     754    wchar_t path[MAX_PATH];
     755    wchar_t initPath[MAX_PATH];
     756    initPath[0] = 0;
     757    path[0] = 0;
     758    tTitle = args.caption;
     759
     760#if !defined(Q_WS_WINCE)
     761    BROWSEINFO bi;
    768762#else
    769     qt_win_resolve_libs();
    770     QString initDir = QDir::toNativeSeparators(args.directory);
    771     TCHAR path[MAX_PATH];
    772     TCHAR initPath[MAX_PATH];
    773     memset(initPath, 0 , MAX_PATH*sizeof(TCHAR));
    774     memset(path, 0, MAX_PATH*sizeof(TCHAR));
    775     tTitle = args.caption;
    776763    qt_BROWSEINFO bi;
     764
     765
    777766    Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
    778767    bi.hwndOwner = (parent ? parent->winId() : 0);
    779768    bi.pidlRoot = NULL;
    780     bi.lpszTitle = (TCHAR*)tTitle.utf16();
     769    //### This does not seem to be respected? - the dialog always displays "Browse for folder"
     770    bi.lpszTitle = (wchar_t*)tTitle.utf16();
    781771    bi.pszDisplayName = initPath;
    782772    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
    783773    bi.lpfn = winGetExistDirCallbackProc;
    784774    bi.lParam = LPARAM(&initDir);
     775
     776
    785777    if (ptrSHBrowseForFolder) {
    786778        LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder((BROWSEINFO*)&bi);
    787         if (pItemIDList && ptrSHGetPathFromIDList) {
     779        if (pItemIDList) {
    788780            ptrSHGetPathFromIDList(pItemIDList, path);
    789781            IMalloc *pMalloc;
    790             if (SHGetMalloc(&pMalloc) != NOERROR)
    791                 result = QString();
    792             else {
     782            if (ptrSHGetMalloc(&pMalloc) == NOERROR) {
    793783                pMalloc->Free(pItemIDList);
    794784                pMalloc->Release();
    795                 result = QString::fromUtf16((ushort*)path);
     785                result = QString::frompath);
    796786            }
    797         } else
    798             result = QString();
     787        }
    799788    }
    800789    tTitle = QString();
    801790
    802 #endif
    803791    QApplicationPrivate::leaveModal(&modal_widget);
    804792
    805793    qt_win_eatMouseMove();
    806794
    807     // Due to a bug on Windows Me, we need to reset the current
    808     // directory
    809     if ((QSysInfo::WindowsVersion == QSysInfo::WV_98 || QSysInfo::WindowsVersion == QSysInfo::WV_Me)
    810         && QDir::currentPath() != currentDir)
    811         QDir::setCurrent(currentDir);
    812 
    813795    if (!result.isEmpty())
    814         result.replace(QLatin1String("\\"), QLatin1String("/"));
     796        result.replace(QLatin1));
    815797    return result;
    816798}
Note: See TracChangeset for help on using the changeset viewer.