src/qt3support/dialogs/q3filedialog_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/dialogs/q3filedialog_win.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3filedialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include "qapplication.h"
+#include "private/qapplication_p.h"
+#include "qt_windows.h"
+#include "qregexp.h"
+#include "qbuffer.h"
+#include "qdir.h"
+#include "qstringlist.h"
+#include "qlibrary.h"
+
+#ifndef QT_NO_THREAD
+#  include "private/qmutexpool_p.h"
+#endif
+
+#include <shlobj.h>
+
+#ifdef Q_OS_WINCE
+#include <commdlg.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern const char qt3_file_dialog_filter_reg_exp[]; // defined in qfiledialog.cpp
+
+const int maxNameLen = 1023;
+const int maxMultiLen = 65535;
+
+// Returns the wildcard part of a filter.
+static QString extractFilter(const QString& rawFilter)
+{
+    QString result = rawFilter;
+    QRegExp r(QString::fromLatin1(qt3_file_dialog_filter_reg_exp));
+    int index = r.indexIn(result);
+    if (index >= 0)
+        result = r.cap(2);
+    return result.replace(QLatin1Char(' '), QLatin1Char(';'));
+}
+
+// Makes a list of filters from ;;-separated text.
+static QStringList makeFiltersList(const QString &filter)
+{
+    QString f(filter);
+
+    if (f.isEmpty())
+        f = Q3FileDialog::tr("All Files (*.*)");
+
+    if (f.isEmpty())
+        return QStringList();
+
+    int i = f.find(QLatin1String(";;"), 0);
+    QString sep(QLatin1String(";;"));
+    if (i == -1) {
+        if (f.find(QLatin1String("\n"), 0) != -1) {
+            sep = QLatin1String("\n");
+            i = f.find(sep, 0);
+        }
+    }
+
+    return QStringList::split(sep, f );
+}
+
+// Makes a NUL-oriented Windows filter from a Qt filter.
+static QString winFilter(const QString& filter)
+{
+    QStringList filterLst = makeFiltersList(filter);
+    QStringList::Iterator it = filterLst.begin();
+    QString winfilters;
+    for (; it != filterLst.end(); ++it) {
+        winfilters += *it;
+        winfilters += QChar::null;
+        winfilters += extractFilter(*it);
+        winfilters += QChar::null;
+    }
+    winfilters += QChar::null;
+    return winfilters;
+}
+
+static QString selFilter(const QString& filter, DWORD idx)
+{
+    QStringList filterLst = makeFiltersList(filter);
+    return filterLst[(int)idx - 1];
+}
+
+static QString tFilters, tTitle, tInitDir;
+
+static
+OPENFILENAME* makeOFN(QWidget* parent,
+                       const QString& initialSelection,
+                       const QString& initialDirectory,
+                       const QString& title,
+                       const QString& filters,
+                       Q3FileDialog::Mode mode)
+{
+    if (parent)
+        parent = parent->window();
+    else
+        parent = qApp->activeWindow();
+
+    tInitDir = QDir::toNativeSeparators(initialDirectory);
+    tFilters = filters;
+    tTitle = title;
+    QString initSel = QDir::toNativeSeparators(initialSelection);
+
+    int maxLen = mode == Q3FileDialog::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(wchar_t));
+    else
+        tInitSel[0] = 0;
+
+    OPENFILENAME* ofn = new OPENFILENAME;
+    memset(ofn, 0, sizeof(OPENFILENAME));
+
+    ofn->lStructSize     = sizeof(OPENFILENAME);
+    ofn->hwndOwner       = parent ? parent->winId() : 0;
+    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);
+
+    if (mode == Q3FileDialog::ExistingFile ||
+         mode == Q3FileDialog::ExistingFiles)
+        ofn->Flags |= (OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST);
+    if (mode == Q3FileDialog::ExistingFiles)
+        ofn->Flags |= (OFN_ALLOWMULTISELECT | OFN_EXPLORER);
+
+    return ofn;
+}
+
+static void cleanUpOFN(OPENFILENAME** ofn)
+{
+    delete (*ofn)->lpstrFile;
+    delete *ofn;
+    *ofn = 0;
+}
+
+QString Q3FileDialog::winGetOpenFileName(const QString &initialSelection,
+                                         const QString &filter,
+                                         QString* initialDirectory,
+                                         QWidget *parent, const char* /*name*/,
+                                         const QString& caption,
+                                         QString* selectedFilter)
+{
+    QString result;
+
+    QString isel = initialSelection;
+
+    if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+        initialDirectory->remove(0, 5);
+    QFileInfo fi(*initialDirectory);
+
+    if (initialDirectory && !fi.isDir()) {
+        *initialDirectory = fi.dirPath(true);
+        if (isel.isEmpty())
+            isel = fi.fileName();
+    }
+
+    if (!fi.exists())
+        *initialDirectory = QDir::homeDirPath();
+
+    QString title = caption;
+    if (title.isNull())
+        title = tr("Open");
+
+    DWORD selFilIdx = 0;
+
+    int idx = 0;
+    if (selectedFilter && !selectedFilter->isEmpty()) {
+        QStringList filterLst = makeFiltersList(filter);
+        idx = filterLst.findIndex(*selectedFilter);
+    }
+
+    if (parent) {
+        QEvent e(QEvent::WindowBlocked);
+        QApplication::sendEvent(parent, &e);
+        QApplicationPrivate::enterModal(parent);
+    }
+
+    OPENFILENAME* ofn = makeOFN(parent, isel,
+                                *initialDirectory, title,
+                                winFilter(filter), ExistingFile);
+    if (idx)
+        ofn->nFilterIndex = idx + 1;
+    if (GetOpenFileName(ofn)) {
+        result = QString::fromWCharArray(ofn->lpstrFile);
+        selFilIdx = ofn->nFilterIndex;
+    }
+    cleanUpOFN(&ofn);
+
+    if (parent) {
+        QApplicationPrivate::leaveModal(parent);
+        QEvent e(QEvent::WindowUnblocked);
+        QApplication::sendEvent(parent, &e);
+    }
+
+    if (result.isEmpty()) {
+        return result;
+    }
+    else {
+        QFileInfo fi(result);
+        *initialDirectory = fi.dirPath();
+        if (selectedFilter)
+            *selectedFilter = selFilter(filter, selFilIdx);
+        return fi.absFilePath();
+    }
+}
+
+
+QString Q3FileDialog::winGetSaveFileName(const QString &initialSelection,
+                                         const QString &filter,
+                                         QString* initialDirectory,
+                                         QWidget *parent, const char* /*name*/,
+                                         const QString& caption,
+                                         QString* selectedFilter)
+{
+    QString result;
+
+    QString isel = initialSelection;
+    if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+        initialDirectory->remove(0, 5);
+    QFileInfo fi(*initialDirectory);
+
+    if (initialDirectory && !fi.isDir()) {
+        *initialDirectory = fi.dirPath(true);
+        if (isel.isEmpty())
+            isel = fi.fileName();
+    }
+
+    if (!fi.exists())
+        *initialDirectory = QDir::homeDirPath();
+
+    QString title = caption;
+    if (title.isNull())
+        title = tr("Save As");
+
+    DWORD selFilIdx = 0;
+
+    int idx = 0;
+    if (selectedFilter && !selectedFilter->isEmpty()) {
+        QStringList filterLst = makeFiltersList(filter);
+        idx = filterLst.findIndex(*selectedFilter);
+    }
+
+    if (parent) {
+        QEvent e(QEvent::WindowBlocked);
+        QApplication::sendEvent(parent, &e);
+        QApplicationPrivate::enterModal(parent);
+    }
+
+    OPENFILENAME* ofn = makeOFN(parent, isel,
+                                 *initialDirectory, title,
+                                 winFilter(filter), AnyFile);
+    if (idx)
+        ofn->nFilterIndex = idx + 1;
+    if (GetSaveFileName(ofn)) {
+        result = QString::fromWCharArray(ofn->lpstrFile);
+        selFilIdx = ofn->nFilterIndex;
+    }
+    cleanUpOFN(&ofn);
+
+    if (parent) {
+        QApplicationPrivate::leaveModal(parent);
+        QEvent e(QEvent::WindowUnblocked);
+        QApplication::sendEvent(parent, &e);
+    }
+
+    if (result.isEmpty()) {
+        return result;
+    }
+    else {
+        QFileInfo fi(result);
+        *initialDirectory = fi.dirPath();
+        if (selectedFilter)
+            *selectedFilter = selFilter(filter, selFilIdx);
+        return fi.absFilePath();
+    }
+}
+
+
+
+QStringList Q3FileDialog::winGetOpenFileNames(const QString &filter,
+                                              QString* initialDirectory,
+                                              QWidget *parent,
+                                              const char* /*name*/,
+                                              const QString& caption,
+                                              QString* selectedFilter)
+{
+    QStringList result;
+    QFileInfo fi;
+    QDir dir;
+    QString isel;
+
+    if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+        initialDirectory->remove(0, 5);
+    fi = QFileInfo(*initialDirectory);
+
+    if (initialDirectory && !fi.isDir()) {
+        *initialDirectory = fi.dirPath(true);
+        isel = fi.fileName();
+    }
+
+    if (!fi.exists())
+        *initialDirectory = QDir::homeDirPath();
+
+    QString title = caption;
+    if (title.isNull())
+        title = tr("Open ");
+
+    DWORD selFilIdx = 0;
+
+    int idx = 0;
+    if (selectedFilter && !selectedFilter->isEmpty()) {
+        QStringList filterLst = makeFiltersList(filter);
+        idx = filterLst.findIndex(*selectedFilter);
+    }
+
+    if (parent) {
+        QEvent e(QEvent::WindowBlocked);
+        QApplication::sendEvent(parent, &e);
+        QApplicationPrivate::enterModal(parent);
+    }
+
+    OPENFILENAME* ofn = makeOFN(parent, isel,
+                                 *initialDirectory, title,
+                                 winFilter(filter), ExistingFiles);
+    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.absFilePath();
+            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.absFilePath();
+                if (!res.isEmpty())
+                    result.append(res);
+                offset += f.length() + 1;
+            }
+        }
+    }
+    cleanUpOFN(&ofn);
+
+    if (parent) {
+        QApplicationPrivate::leaveModal(parent);
+        QEvent e(QEvent::WindowUnblocked);
+        QApplication::sendEvent(parent, &e);
+    }
+
+    if (!result.isEmpty()) {
+        *initialDirectory = fi.dirPath();    // only save the path if there is a result
+        if (selectedFilter)
+            *selectedFilter = selFilter(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)
+{
+#ifndef Q_OS_WINCE
+    if (uMsg == BFFM_INITIALIZED && lpData != 0) {
+        QString *initDir = (QString *)(lpData);
+        if (!initDir->isEmpty()) {
+            SendMessage(hwnd, BFFM_SETSELECTION, TRUE, Q_ULONG(initDir->utf16()));
+        }
+    } else if (uMsg == BFFM_SELCHANGED) {
+        wchar_t path[MAX_PATH];
+        SHGetPathFromIDList(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, Q_ULONG(path));
+    }
+#endif
+    return 0;
+}
+
+#ifndef BIF_NEWDIALOGSTYLE
+#define BIF_NEWDIALOGSTYLE     0x0040   // Use the new dialog layout with the ability to resize
+#endif
+
+
+QString Q3FileDialog::winGetExistingDirectory(const QString& initialDirectory,
+                                             QWidget *parent,
+                                             const char* /*name*/,
+                                             const QString& caption)
+{
+#ifndef Q_OS_WINCE
+    QString currentDir = QDir::currentDirPath();
+    QString result;
+    if (parent)
+        parent = parent->window();
+    else
+        parent = qApp->activeWindow();
+    QString title = caption;
+    if (title.isNull())
+        title = tr("Select a Directory");
+
+    if (parent) {
+        QEvent e(QEvent::WindowBlocked);
+        QApplication::sendEvent(parent, &e);
+        QApplicationPrivate::enterModal(parent);
+    }
+
+    QString initDir = QDir::toNativeSeparators(initialDirectory);
+    wchar_t path[MAX_PATH];
+    wchar_t initPath[MAX_PATH];
+    initPath[0] = 0;
+    path[0] = 0;
+    tTitle = title;
+    BROWSEINFO bi;
+    bi.hwndOwner = (parent ? parent->winId() : 0);
+    bi.pidlRoot = NULL;
+    bi.lpszTitle = (wchar_t*)tTitle.utf16();
+    bi.pszDisplayName = initPath;
+    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
+    bi.lpfn = winGetExistDirCallbackProc;
+    bi.lParam = Q_ULONG(&initDir);
+    LPITEMIDLIST pItemIDList = SHBrowseForFolder(&bi);
+    if (pItemIDList) {
+        SHGetPathFromIDList(pItemIDList, path);
+        IMalloc *pMalloc;
+        if (SHGetMalloc(&pMalloc) != NOERROR)
+            result.clear();
+        else {
+            pMalloc->Free(pItemIDList);
+            pMalloc->Release();
+            result = QString::fromWCharArray(path);
+        }
+    } else
+        result.clear();
+    tTitle.clear();
+
+    if (parent) {
+        QApplicationPrivate::leaveModal(parent);
+        QEvent e(QEvent::WindowUnblocked);
+        QApplication::sendEvent(parent, &e);
+    }
+
+    if (!result.isEmpty())
+        result.replace(QLatin1Char('\\'), QLatin1Char('/'));
+    return result;
+#else
+    return QString();
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif