[Qt][Wk2] Assertion Failure and crash on file upload
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2012 16:16:25 +0000 (16:16 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Mar 2012 16:16:25 +0000 (16:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80854

Patch by Dinu Jacob <dinu.jacob@nokia.com> on 2012-03-16
Reviewed by Simon Hausmann.

Source/WebKit2:

Crash resulted from attempting to create QFileDialog, a QtWidget based dialog from a
QGuiApplication. Replace QFileDialog with a QML implementable component.
Added a new property 'filePicker' to WebView experimental to set the QML component for
file upload triggered by an input file element.

Co-authored with Kasthuri Nallappasoundararajan <kasthuri.n-s@nokia.com>

* UIProcess/API/qt/qquickwebview.cpp:
(QQuickWebViewPrivate::QQuickWebViewPrivate):
(QQuickWebViewPrivate::chooseFiles):
(QQuickWebViewExperimental::filePicker):
(QQuickWebViewExperimental::setFilePicker):
* UIProcess/API/qt/qquickwebview_p.h:
* UIProcess/API/qt/qquickwebview_p_p.h:
(QQuickWebViewPrivate):
* UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro:
* UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml: Added.
* UIProcess/API/qt/tests/qmltests/common/singlefileupload.html: Added.
* UIProcess/qt/QtDialogRunner.cpp:
(FilePickerContextObject):
(FilePickerContextObject::FilePickerContextObject):
(FilePickerContextObject::fileList):
(FilePickerContextObject::reject):
(FilePickerContextObject::accept):
(QtDialogRunner::initForFilePicker):
* UIProcess/qt/QtDialogRunner.h:
(QtDialogRunner):
(QtDialogRunner::filePaths):
(QtDialogRunner::onFileSelected):

Tools:

Added filePicker to WebView using experimental API.

* MiniBrowser/qt/MiniBrowser.qrc:
* MiniBrowser/qt/icons/folder.png: Added.
* MiniBrowser/qt/icons/titlebar.png: Added.
* MiniBrowser/qt/icons/up.png: Added.
* MiniBrowser/qt/qml/BrowserWindow.qml:
* MiniBrowser/qt/qml/FilePicker.qml: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@111012 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp
Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h
Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml [new file with mode: 0644]
Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/singlefileupload.html [new file with mode: 0644]
Source/WebKit2/UIProcess/qt/QtDialogRunner.cpp
Source/WebKit2/UIProcess/qt/QtDialogRunner.h
Tools/ChangeLog
Tools/MiniBrowser/qt/MiniBrowser.qrc
Tools/MiniBrowser/qt/icons/folder.png [new file with mode: 0644]
Tools/MiniBrowser/qt/icons/titlebar.png [new file with mode: 0644]
Tools/MiniBrowser/qt/icons/up.png [new file with mode: 0644]
Tools/MiniBrowser/qt/qml/BrowserWindow.qml
Tools/MiniBrowser/qt/qml/FilePicker.qml [new file with mode: 0644]

index 8d609ce9deb333328115e29c5be1b26cfbb98a7a..7f3cafc2a88ce1ccada449d7c9191902d5135aad 100644 (file)
@@ -1,3 +1,40 @@
+2012-03-16  Dinu Jacob  <dinu.jacob@nokia.com>
+
+        [Qt][Wk2] Assertion Failure and crash on file upload
+        https://bugs.webkit.org/show_bug.cgi?id=80854
+
+        Reviewed by Simon Hausmann.
+
+        Crash resulted from attempting to create QFileDialog, a QtWidget based dialog from a 
+        QGuiApplication. Replace QFileDialog with a QML implementable component.
+        Added a new property 'filePicker' to WebView experimental to set the QML component for
+        file upload triggered by an input file element.
+
+        Co-authored with Kasthuri Nallappasoundararajan <kasthuri.n-s@nokia.com>
+
+        * UIProcess/API/qt/qquickwebview.cpp:
+        (QQuickWebViewPrivate::QQuickWebViewPrivate):
+        (QQuickWebViewPrivate::chooseFiles):
+        (QQuickWebViewExperimental::filePicker):
+        (QQuickWebViewExperimental::setFilePicker):
+        * UIProcess/API/qt/qquickwebview_p.h:
+        * UIProcess/API/qt/qquickwebview_p_p.h:
+        (QQuickWebViewPrivate):
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro:
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml: Added.
+        * UIProcess/API/qt/tests/qmltests/common/singlefileupload.html: Added.
+        * UIProcess/qt/QtDialogRunner.cpp:
+        (FilePickerContextObject):
+        (FilePickerContextObject::FilePickerContextObject):
+        (FilePickerContextObject::fileList):
+        (FilePickerContextObject::reject):
+        (FilePickerContextObject::accept):
+        (QtDialogRunner::initForFilePicker):
+        * UIProcess/qt/QtDialogRunner.h:
+        (QtDialogRunner):
+        (QtDialogRunner::filePaths):
+        (QtDialogRunner::onFileSelected):
+
 2012-03-16  Dinu Jacob  <dinu.jacob@nokia.com>
 
         [Qt][WK2] Build failure when using --no-touch-events
index 6391e496e43eef58c2983d55812c112012e7849f..3b032201a5384c464d30560ba3ca3869b976b7f8 100644 (file)
@@ -47,7 +47,6 @@
 #include <private/qquickflickable_p.h>
 #include <JavaScriptCore/InitializeThreading.h>
 #include <QDeclarativeEngine>
-#include <QFileDialog>
 #include <QtQuick/QQuickCanvas>
 #include <WebCore/IntPoint.h>
 #include <WebCore/IntRect.h>
@@ -76,6 +75,7 @@ QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport)
     , certificateVerificationDialog(0)
     , itemSelector(0)
     , proxyAuthenticationDialog(0)
+    , filePicker(0)
     , userDidOverrideContentWidth(false)
     , userDidOverrideContentHeight(false)
     , m_navigatorQtObjectEnabled(false)
@@ -375,50 +375,28 @@ void QQuickWebViewPrivate::execDialogRunner(QtDialogRunner& dialogRunner)
 
 void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType type)
 {
-#ifndef QT_NO_FILEDIALOG
     Q_Q(QQuickWebView);
-    openPanelResultListener = listenerRef;
 
-    // Qt does not support multiple files suggestion, so we get just the first suggestion.
-    QString selectedFileName;
-    if (!selectedFileNames.isEmpty())
-        selectedFileName = selectedFileNames.at(0);
-
-    Q_ASSERT(!fileDialog);
-
-    QWindow* window = q->canvas();
-    if (!window)
+    if (!filePicker || type == QtWebPageUIClient::MultipleFilesSelection)
         return;
 
-    fileDialog = new QFileDialog(0, QString(), selectedFileName);
-    fileDialog->window()->winId(); // Ensure that the dialog has a window
-    Q_ASSERT(fileDialog->window()->windowHandle());
-    fileDialog->window()->windowHandle()->setTransientParent(window);
-
-    fileDialog->open(q, SLOT(_q_onOpenPanelFilesSelected()));
-
-    q->connect(fileDialog, SIGNAL(finished(int)), SLOT(_q_onOpenPanelFinished(int)));
-#endif
-}
+    QtDialogRunner dialogRunner;
+    if (!dialogRunner.initForFilePicker(filePicker, q, selectedFileNames))
+        return;
 
-void QQuickWebViewPrivate::_q_onOpenPanelFilesSelected()
-{
-    const QStringList fileList = fileDialog->selectedFiles();
-    Vector<RefPtr<APIObject> > wkFiles(fileList.size());
+    execDialogRunner(dialogRunner);
 
-    for (unsigned i = 0; i < fileList.size(); ++i)
-        wkFiles[i] = WebURL::create(QUrl::fromLocalFile(fileList.at(i)).toString());
+    if (dialogRunner.wasAccepted()) {
+        QStringList selectedPaths = dialogRunner.filePaths();
 
-    WKOpenPanelResultListenerChooseFiles(openPanelResultListener, toAPI(ImmutableArray::adopt(wkFiles).leakRef()));
-}
+        Vector<RefPtr<APIObject> > wkFiles(selectedPaths.size());
+        for (unsigned i = 0; i < selectedPaths.size(); ++i)
+            wkFiles[i] = WebURL::create(QUrl::fromLocalFile(selectedPaths.at(i)).toString());            
 
-void QQuickWebViewPrivate::_q_onOpenPanelFinished(int result)
-{
-    if (result == QDialog::Rejected)
-        WKOpenPanelResultListenerCancel(openPanelResultListener);
+        WKOpenPanelResultListenerChooseFiles(listenerRef, toAPI(ImmutableArray::adopt(wkFiles).leakRef()));
+    } else
+        WKOpenPanelResultListenerCancel(listenerRef);
 
-    fileDialog->deleteLater();
-    fileDialog = 0;
 }
 
 void QQuickWebViewPrivate::setViewInAttachedProperties(QObject* object)
@@ -968,6 +946,21 @@ void QQuickWebViewExperimental::setItemSelector(QDeclarativeComponent* itemSelec
     emit itemSelectorChanged();
 }
 
+QDeclarativeComponent* QQuickWebViewExperimental::filePicker() const
+{
+    Q_D(const QQuickWebView);
+    return d->filePicker;
+}
+
+void QQuickWebViewExperimental::setFilePicker(QDeclarativeComponent* filePicker)
+{
+    Q_D(QQuickWebView);
+    if (d->filePicker == filePicker)
+        return;
+    d->filePicker = filePicker;
+    emit filePickerChanged();
+}
+
 QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QDeclarativeListProperty<QQuickUrlSchemeDelegate>* property, int index)
 {
     const QObjectList children = property->object->children();
index 6adab178943f05df788909e73acb8320f200ce03..3ce15281ce2927a6f321d462e958102fe622ac1d 100644 (file)
@@ -191,8 +191,6 @@ private:
     Q_PRIVATE_SLOT(d_func(), void _q_commitPositionChange(const QPointF&));
     Q_PRIVATE_SLOT(d_func(), void _q_commitScaleChange());
 
-    Q_PRIVATE_SLOT(d_func(), void _q_onOpenPanelFilesSelected());
-    Q_PRIVATE_SLOT(d_func(), void _q_onOpenPanelFinished(int result));
     Q_PRIVATE_SLOT(d_func(), void _q_onVisibleChanged());
     Q_PRIVATE_SLOT(d_func(), void _q_onUrlChanged());
     Q_PRIVATE_SLOT(d_func(), void _q_onReceivedResponseFromDownload(QWebDownloadItem*));
@@ -250,6 +248,7 @@ class QWEBKIT_EXPORT QQuickWebViewExperimental : public QObject {
     Q_PROPERTY(QDeclarativeComponent* proxyAuthenticationDialog READ proxyAuthenticationDialog WRITE setProxyAuthenticationDialog NOTIFY proxyAuthenticationDialogChanged)
     Q_PROPERTY(QDeclarativeComponent* certificateVerificationDialog READ certificateVerificationDialog WRITE setCertificateVerificationDialog NOTIFY certificateVerificationDialogChanged)
     Q_PROPERTY(QDeclarativeComponent* itemSelector READ itemSelector WRITE setItemSelector NOTIFY itemSelectorChanged)
+    Q_PROPERTY(QDeclarativeComponent* filePicker READ filePicker WRITE setFilePicker NOTIFY filePickerChanged)
     Q_PROPERTY(QWebPreferences* preferences READ preferences CONSTANT FINAL)
     Q_PROPERTY(QWebViewportInfo* viewportInfo READ viewportInfo CONSTANT FINAL)
     Q_PROPERTY(QDeclarativeListProperty<QQuickUrlSchemeDelegate> urlSchemeDelegates READ schemeDelegates)
@@ -277,6 +276,8 @@ public:
     void setItemSelector(QDeclarativeComponent*);
     QDeclarativeComponent* proxyAuthenticationDialog() const;
     void setProxyAuthenticationDialog(QDeclarativeComponent*);
+    QDeclarativeComponent* filePicker() const;
+    void setFilePicker(QDeclarativeComponent*);
 
     QWebViewportInfo* viewportInfo();
 
@@ -329,6 +330,7 @@ Q_SIGNALS:
     void authenticationDialogChanged();
     void certificateVerificationDialogChanged();
     void itemSelectorChanged();
+    void filePickerChanged();
     void downloadRequested(QWebDownloadItem* downloadItem);
     void permissionRequested(QWebPermissionRequest* permission);
     void messageReceived(const QVariantMap& message);
index 39a14a7a675bc5d367c226b3e42da99944edb052..d53ecda6be1e39b99a4b5add76525150fce7875a 100644 (file)
@@ -50,7 +50,6 @@ class QWebViewportInfo;
 
 QT_BEGIN_NAMESPACE
 class QDeclarativeComponent;
-class QFileDialog;
 QT_END_NAMESPACE
 
 class QQuickWebViewPrivate {
@@ -93,8 +92,6 @@ public:
     virtual void _q_commitScaleChange() { }
     void _q_commitPositionChange(const QPointF&);
 
-    void _q_onOpenPanelFilesSelected();
-    void _q_onOpenPanelFinished(int result);
     void _q_onVisibleChanged();
     void _q_onUrlChanged();
     void _q_onReceivedResponseFromDownload(QWebDownloadItem*);
@@ -158,10 +155,9 @@ protected:
     QDeclarativeComponent* certificateVerificationDialog;
     QDeclarativeComponent* itemSelector;
     QDeclarativeComponent* proxyAuthenticationDialog;
+    QDeclarativeComponent* filePicker;
 
     WebCore::ViewportArguments viewportArguments;
-    QFileDialog* fileDialog;
-    WKOpenPanelResultListenerRef openPanelResultListener;
 
     bool userDidOverrideContentWidth;
     bool userDidOverrideContentHeight;
index 9d16a7bddd656dc793a955d84a1a292116ab1e8c..5cf46cb5ff8a55cebaca4879115e6e6754cee9b0 100644 (file)
@@ -19,4 +19,5 @@ OTHER_FILES += \
     DesktopBehavior/tst_linkHovered.qml \
     DesktopBehavior/tst_loadHtml.qml \
     DesktopBehavior/tst_messaging.qml \
-    DesktopBehavior/tst_navigationRequested.qml
+    DesktopBehavior/tst_navigationRequested.qml \
+    DesktopBehavior/tst_singlefileupload.qml
diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml
new file mode 100644 (file)
index 0000000..ce495ea
--- /dev/null
@@ -0,0 +1,65 @@
+import QtQuick 2.0
+import QtTest 1.0
+import QtWebKit 3.0
+import QtWebKit.experimental 1.0
+import "../common"
+
+// FIXME: Added to Desktop tests because we want to have mouseClick() to open the <input> tag. We can move it back
+// when TestCase starts supporting touch events, see https://bugreports.qt.nokia.com/browse/QTBUG-23083.
+TestWebView {
+    id: webView
+
+    width: 400
+    height: 400
+
+    property bool selectFile
+
+    experimental.filePicker: Item {
+        Timer {
+            running: true
+            interval: 1
+            onTriggered: {
+                if (selectFile)
+                    model.accept("acceptedfilename");
+                else
+                    model.reject();
+            }
+        }
+    }
+
+    SignalSpy {
+        id: titleSpy
+        target: webView
+        signalName: "titleChanged"
+    }
+
+    TestCase {
+        id: test
+        name: "WebViewSingleFilePicker"
+        when: windowShown
+
+        function init() {
+            webView.url = Qt.resolvedUrl("../common/singlefileupload.html")
+            verify(webView.waitForLoadSucceeded())
+            titleSpy.clear()
+        }
+
+        function openItemSelector() {
+            mouseClick(webView, 15, 15, Qt.LeftButton)
+        }
+
+        function test_accept() {
+            webView.selectFile = true;
+            openItemSelector()
+            titleSpy.wait()
+            compare(webView.title, "acceptedfilename")
+        }
+
+        function test_reject() {
+            var oldTitle = webView.title
+            webView.selectFile = false;
+            openItemSelector()
+            compare(webView.title, oldTitle)
+        }
+    }
+}
diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/singlefileupload.html b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/singlefileupload.html
new file mode 100644 (file)
index 0000000..580b999
--- /dev/null
@@ -0,0 +1,26 @@
+<html>
+<head>
+<meta name="viewport" initial-scale=1">
+<title>No file selected</title>
+<script>
+function updateTitle()
+{
+    var inp = document.getElementById("upfile");
+    var allfiles = new String("");
+    var name = new String("");
+    for (var i = 0; i < inp.files.length; ++i)
+    {
+        name = inp.files.item(i).name;
+        if (allfiles.length == 0)
+            allfiles = name;
+        else
+            allfiles = allfiles + "," + name;
+    }
+    document.title = allfiles;
+}
+</script>
+
+<body>
+<input type="file" name="file" id="upfile" onchange="updateTitle()"/>
+</body>
+</html>
index 95bdc21a49ee82245f876738f68f51b5ec4bc67a..0111a73167730208b060ee270bec7aedf893d1fc 100644 (file)
@@ -157,6 +157,31 @@ private:
     QString m_hostname;
 };
 
+class FilePickerContextObject : public QObject {
+    Q_OBJECT
+    Q_PROPERTY(QStringList fileList READ fileList CONSTANT)
+
+public:
+    FilePickerContextObject(const QStringList& selectedFiles)
+        : QObject()
+        , m_fileList(selectedFiles)
+    {
+    }
+
+    QStringList fileList() const { return m_fileList; }
+
+public slots:
+    void reject() { emit rejected();}
+    void accept(const QVariant& path) { emit fileSelected(path.toStringList()); }
+
+signals:
+    void rejected();
+    void fileSelected(const QStringList&);
+
+private:
+    QStringList m_fileList;
+};
+
 bool QtDialogRunner::initForAlert(QDeclarativeComponent* component, QQuickItem* dialogParent, const QString& message)
 {
     DialogContextObject* contextObject = new DialogContextObject(message);
@@ -230,6 +255,19 @@ bool QtDialogRunner::initForCertificateVerification(QDeclarativeComponent* compo
     return true;
 }
 
+bool QtDialogRunner::initForFilePicker(QDeclarativeComponent* component, QQuickItem* dialogParent, const QStringList& selectedFiles)
+{
+    FilePickerContextObject* contextObject = new FilePickerContextObject(selectedFiles);
+    if (!createDialog(component, dialogParent, contextObject))
+        return false;
+
+    connect(contextObject, SIGNAL(fileSelected(QStringList)), SLOT(onFileSelected(QStringList)));
+    connect(contextObject, SIGNAL(fileSelected(QStringList)), SLOT(quit()));
+    connect(contextObject, SIGNAL(rejected()), SLOT(quit()));
+
+    return true;
+}
+
 bool QtDialogRunner::createDialog(QDeclarativeComponent* component, QQuickItem* dialogParent, QObject* contextObject)
 {
     QDeclarativeContext* baseContext = component->creationContext();
index 7fbace1ce843e9560d380c62cd4ef7f2bf009652..0e9481bd93567c79ba7d8df7625b2d1868a389f4 100644 (file)
@@ -22,6 +22,7 @@
 #define QtDialogRunner_h
 
 #include <QtCore/QEventLoop>
+#include <QtCore/QStringList>
 #include <wtf/OwnPtr.h>
 
 class QDeclarativeComponent;
@@ -41,6 +42,7 @@ public:
     bool initForAuthentication(QDeclarativeComponent*, QQuickItem* dialogParent, const QString& hostname, const QString& realm, const QString& prefilledUsername);
     bool initForCertificateVerification(QDeclarativeComponent*, QQuickItem*, const QString& hostname);
     bool initForProxyAuthentication(QDeclarativeComponent*, QQuickItem*, const QString& hostname, uint16_t port, const QString& prefilledUsername);
+    bool initForFilePicker(QDeclarativeComponent*, QQuickItem*, const QStringList& selectedFiles);
 
     QQuickItem* dialog() const { return m_dialog.get(); }
 
@@ -50,6 +52,8 @@ public:
     QString username() const { return m_username; }
     QString password() const { return m_password; }
 
+    QStringList filePaths() const { return m_filepaths; }
+
 public slots:
     void onAccepted(const QString& result = QString())
     {
@@ -63,6 +67,12 @@ public slots:
         m_password = password;
     }
 
+    void onFileSelected(const QStringList& filePaths)
+    {
+        m_wasAccepted = true;
+        m_filepaths = filePaths;
+    }
+
 private:
     bool createDialog(QDeclarativeComponent*, QQuickItem* dialogParent, QObject* contextObject);
 
@@ -73,6 +83,7 @@ private:
 
     QString m_username;
     QString m_password;
+    QStringList m_filepaths;
 };
 
 #endif // QtDialogRunner_h
index e5c9526843b35c78cb75af7c83c5a33a00040398..ea23bc4ebe0dd614af71b9f3d1b9dba835e67d8b 100644 (file)
@@ -1,3 +1,19 @@
+2012-03-16  Dinu Jacob  <dinu.jacob@nokia.com>
+
+        [Qt][Wk2] Assertion Failure and crash on file upload
+        https://bugs.webkit.org/show_bug.cgi?id=80854
+
+        Reviewed by Simon Hausmann.
+
+        Added filePicker to WebView using experimental API.
+
+        * MiniBrowser/qt/MiniBrowser.qrc:
+        * MiniBrowser/qt/icons/folder.png: Added.
+        * MiniBrowser/qt/icons/titlebar.png: Added.
+        * MiniBrowser/qt/icons/up.png: Added.
+        * MiniBrowser/qt/qml/BrowserWindow.qml:
+        * MiniBrowser/qt/qml/FilePicker.qml: Added.
+
 2012-03-16  Mahesh Kulkarni  <mahesh.kulkarni@nokia.com>
 
         Updating email for committer.py script.
index e00c51e926a2f188535a2b27ee239fd0bce7edba..60265b65bbcfaff4926a54f8bcea8709368d5e06 100644 (file)
@@ -1,13 +1,17 @@
 <RCC>
     <qresource prefix="/">
+        <file>icons/favicon.png</file>
+        <file>icons/folder.png</file>
         <file>icons/info.png</file>
         <file>icons/next.png</file>
         <file>icons/plus.png</file>
         <file>icons/previous.png</file>
         <file>icons/refresh.png</file>
         <file>icons/stop.png</file>
+        <file>icons/titlebar.png</file>
         <file>icons/touch.png</file>
         <file>icons/touchpoint.png</file>
+        <file>icons/up.png</file>
         <file>qml/AlertDialog.qml</file>
         <file>qml/AuthenticationDialog.qml</file>
         <file>qml/BrowserWindow.qml</file>
@@ -15,6 +19,7 @@
         <file>qml/Dialog.qml</file>
         <file>qml/DialogButton.qml</file>
         <file>qml/DialogLineInput.qml</file>
+        <file>qml/FilePicker.qml</file>
         <file>qml/ItemSelector.qml</file>
         <file>qml/MockTouchPoint.qml</file>
         <file>qml/PromptDialog.qml</file>
@@ -22,6 +27,5 @@
         <file>qml/ScrollIndicator.qml</file>
         <file>qml/ViewportInfoItem.qml</file>
         <file>useragentlist.txt</file>
-        <file>icons/favicon.png</file>
     </qresource>
 </RCC>
diff --git a/Tools/MiniBrowser/qt/icons/folder.png b/Tools/MiniBrowser/qt/icons/folder.png
new file mode 100644 (file)
index 0000000..e53e2ad
Binary files /dev/null and b/Tools/MiniBrowser/qt/icons/folder.png differ
diff --git a/Tools/MiniBrowser/qt/icons/titlebar.png b/Tools/MiniBrowser/qt/icons/titlebar.png
new file mode 100644 (file)
index 0000000..f3d18aa
Binary files /dev/null and b/Tools/MiniBrowser/qt/icons/titlebar.png differ
diff --git a/Tools/MiniBrowser/qt/icons/up.png b/Tools/MiniBrowser/qt/icons/up.png
new file mode 100644 (file)
index 0000000..b05f802
Binary files /dev/null and b/Tools/MiniBrowser/qt/icons/up.png differ
index b4e6e247a1bae7f7d54cc80400b6bb59f4f17d72..cf74b225a6a136bc67aa48e4e15fe59ef2bad6ee 100644 (file)
@@ -313,6 +313,7 @@ Rectangle {
         experimental.promptDialog: PromptDialog { }
         experimental.authenticationDialog: AuthenticationDialog { }
         experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog { }
+        experimental.filePicker: FilePicker { }
 
         ScrollIndicator {
             flickableItem: webView.experimental.flickable
diff --git a/Tools/MiniBrowser/qt/qml/FilePicker.qml b/Tools/MiniBrowser/qt/qml/FilePicker.qml
new file mode 100644 (file)
index 0000000..5beb86a
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+import QtQuick 2.0
+import Qt.labs.folderlistmodel 1.0
+
+Rectangle {
+    id: filePicker
+
+    property QtObject fileModel: model
+    property alias folder: folders.folder
+
+    color: "white"
+    width: 400
+    height: 500
+
+    smooth: true
+    radius: 5
+    anchors.centerIn: parent
+
+    border {
+        width: 1
+        color: "#bfbfbf"
+    }
+
+    BorderImage {
+        source: "../icons/titlebar.png";
+        width: parent.width;
+        height: 50
+        y: -7
+        id: titleBar
+
+        anchors {
+            top: parent.top
+            bottom: folderListView.top
+        }
+        Rectangle {
+            id: upButton
+            width: 48
+            height: titleBar.height - 7
+            color: "transparent"
+            Image { anchors.centerIn: parent; source: "../icons/up.png" }
+            MouseArea { id: upRegion; anchors.centerIn: parent
+                width: 48
+                height: 48
+                onClicked: if (folders.parentFolder != "") up()
+            }
+        }
+
+        Rectangle {
+            color: "gray"
+            x: 48
+            width: 1
+            height: 44
+        }
+
+        Text {
+            anchors {
+                left: upButton.right
+                right: parent.right
+                leftMargin: 4
+                rightMargin: 4
+            }
+
+            height: parent.height
+            text: folders.folder
+            color: "white"
+            elide: Text.ElideLeft;
+            horizontalAlignment: Text.AlignLeft;
+            verticalAlignment: Text.AlignVCenter
+            font.pixelSize: 24
+        }
+    }
+
+    ListView {
+        id: folderListView
+
+        width: parent.width
+        height: 400
+        anchors.centerIn: parent
+        spacing: 2
+        clip: true
+
+        FolderListModel {
+            id: folders
+        }
+
+        Component {
+            id: fileDelegate
+
+            Rectangle {
+                function selected() {
+                    if (folders.isFolder(index))
+                        openFolder(filePath);
+                    else
+                        fileModel.accept(filePath);
+                }
+
+                height: 50
+                width: parent.width
+                color: folders.isFolder(index) ? "lightgray": "darkgray"
+
+                Item {
+                    width: 48;
+                    height: 48
+                    Image {
+                        source: "../icons/folder.png"
+                        anchors.centerIn: parent
+                        visible: folders.isFolder(index)
+                    }
+                }
+
+                Text {
+                    anchors.centerIn: parent
+                    anchors.leftMargin: 50
+                    text: fileName
+                }
+
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: selected();
+                }
+            }
+        }
+        model: folders
+        delegate: fileDelegate
+    }
+
+    Rectangle {
+        id: button
+
+        height: 50
+
+        border {
+            width: 1
+            color: "#bfbfbf"
+        }
+
+        anchors {
+            bottom: parent.bottom
+            top: folderListView.bottom
+            left: parent.left
+            right: parent.right
+        }
+
+        DialogButton {
+            id: cancel
+            text: "Cancel"
+            anchors {
+                horizontalCenter: parent.horizontalCenter;
+                verticalCenter:  parent.verticalCenter
+            }
+
+            onClicked: fileModel.reject()
+        }
+    }
+
+    function openFolder(path) {
+        folders.folder = path;
+    }
+
+    function up() {
+        folders.folder = folders.parentFolder;
+    }
+}