[Qt][WK2] Support multi-file upload
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 02:29:41 +0000 (02:29 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 02:29:41 +0000 (02:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=81589

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

Source/WebKit2:

Added 'allowMutipleFiles' property to filePicker context property to indicate whether to allow
multiple file selections.

* UIProcess/API/qt/qquickwebview.cpp:
(QQuickWebViewPrivate::chooseFiles):
* UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro:
* UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_multiFileUpload.qml: Added.
* UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml:
* UIProcess/API/qt/tests/qmltests/common/multifileupload.html: Added.
* UIProcess/API/qt/tests/qmltests/common/singlefileupload.html:
* UIProcess/API/qt/tests/qmltests/common/titleupdate.js: Added.
(updateTitle):
* UIProcess/qt/QtDialogRunner.cpp:
(FilePickerContextObject):
(FilePickerContextObject::FilePickerContextObject):
(FilePickerContextObject::allowMultipleFiles):
(FilePickerContextObject::accept):
(QtDialogRunner::initForFilePicker):
* UIProcess/qt/QtDialogRunner.h:
(QtDialogRunner):

Tools:

Modified filePicker to support multi-file upload.

* MiniBrowser/qt/MiniBrowser.qrc:
* MiniBrowser/qt/icons/checkbox_checked.png: Added.
* MiniBrowser/qt/icons/checkbox_unchecked.png: Added.
* MiniBrowser/qt/js/MultiSelect.js: Added.
(values):
(isSelected):
(removeValue):
* MiniBrowser/qt/qml/CheckBox.qml: Added.
* MiniBrowser/qt/qml/FilePicker.qml:

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

17 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_multiFileUpload.qml [new file with mode: 0644]
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml
Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/multifileupload.html [new file with mode: 0644]
Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/singlefileupload.html
Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/titleupdate.js [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/checkbox_checked.png [new file with mode: 0644]
Tools/MiniBrowser/qt/icons/checkbox_unchecked.png [new file with mode: 0644]
Tools/MiniBrowser/qt/js/MultiSelect.js [new file with mode: 0644]
Tools/MiniBrowser/qt/qml/CheckBox.qml [new file with mode: 0644]
Tools/MiniBrowser/qt/qml/FilePicker.qml

index 5153bae..da984cc 100644 (file)
@@ -1,3 +1,31 @@
+2012-03-26  Dinu Jacob  <dinu.jacob@nokia.com>
+
+        [Qt][WK2] Support multi-file upload
+        https://bugs.webkit.org/show_bug.cgi?id=81589
+
+        Reviewed by Simon Hausmann.
+
+        Added 'allowMutipleFiles' property to filePicker context property to indicate whether to allow
+        multiple file selections.
+
+        * UIProcess/API/qt/qquickwebview.cpp:
+        (QQuickWebViewPrivate::chooseFiles):
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior.pro:
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_multiFileUpload.qml: Added.
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_singleFileUpload.qml:
+        * UIProcess/API/qt/tests/qmltests/common/multifileupload.html: Added.
+        * UIProcess/API/qt/tests/qmltests/common/singlefileupload.html:
+        * UIProcess/API/qt/tests/qmltests/common/titleupdate.js: Added.
+        (updateTitle):
+        * UIProcess/qt/QtDialogRunner.cpp:
+        (FilePickerContextObject):
+        (FilePickerContextObject::FilePickerContextObject):
+        (FilePickerContextObject::allowMultipleFiles):
+        (FilePickerContextObject::accept):
+        (QtDialogRunner::initForFilePicker):
+        * UIProcess/qt/QtDialogRunner.h:
+        (QtDialogRunner):
+
 2012-03-26  Adam Barth  <abarth@webkit.org>
 
         FrameLoader::shouldAllowNavigation uses Frame for context rather than Document
index 03124d9..486578d 100644 (file)
@@ -364,11 +364,11 @@ void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef,
 {
     Q_Q(QQuickWebView);
 
-    if (!filePicker || type == QtWebPageUIClient::MultipleFilesSelection)
+    if (!filePicker)
         return;
 
     QtDialogRunner dialogRunner;
-    if (!dialogRunner.initForFilePicker(filePicker, q, selectedFileNames))
+    if (!dialogRunner.initForFilePicker(filePicker, q, selectedFileNames, (type == QtWebPageUIClient::MultipleFilesSelection)))
         return;
 
     execDialogRunner(dialogRunner);
index 5cf46cb..59a3ca5 100644 (file)
@@ -20,4 +20,5 @@ OTHER_FILES += \
     DesktopBehavior/tst_loadHtml.qml \
     DesktopBehavior/tst_messaging.qml \
     DesktopBehavior/tst_navigationRequested.qml \
-    DesktopBehavior/tst_singlefileupload.qml
+    DesktopBehavior/tst_singleFileupload.qml \
+    DesktopBehavior/tst_multiFileupload.qml
diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_multiFileUpload.qml b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_multiFileUpload.qml
new file mode 100644 (file)
index 0000000..f43f656
--- /dev/null
@@ -0,0 +1,66 @@
+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: {
+                var selectedFiles = ["filename1", "filename2"]
+                if (selectFile)
+                    model.accept(selectedFiles)
+                else
+                    model.reject();
+            }
+        }
+    }
+
+    SignalSpy {
+        id: titleSpy
+        target: webView
+        signalName: "titleChanged"
+    }
+
+    TestCase {
+        id: test
+        name: "WebViewMultiFilePicker"
+        when: windowShown
+
+        function init() {
+            webView.url = Qt.resolvedUrl("../common/multifileupload.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, "filename1,filename2")
+        }
+
+        function test_reject() {
+            var oldTitle = webView.title
+            webView.selectFile = false;
+            openItemSelector()
+            compare(webView.title, oldTitle)
+        }
+    }
+}
index ce495ea..7ca9efa 100644 (file)
@@ -13,14 +13,20 @@ TestWebView {
     height: 400
 
     property bool selectFile
+    property bool acceptMultiple: false
 
     experimental.filePicker: Item {
         Timer {
             running: true
             interval: 1
             onTriggered: {
-                if (selectFile)
-                    model.accept("acceptedfilename");
+                var selectedFiles = ["filename1", "filename2"]
+                if (selectFile) {
+                    if (acceptMultiple)
+                        model.accept(selectedFiles)
+                    else
+                        model.accept("acceptedfilename");
+                }
                 else
                     model.reject();
             }
@@ -55,6 +61,14 @@ TestWebView {
             compare(webView.title, "acceptedfilename")
         }
 
+        function test_multiple() {
+            webView.selectFile = true;
+            webView.acceptMultiple = true;
+            openItemSelector()
+            titleSpy.wait()
+            compare(webView.title, "filename1")
+        }
+
         function test_reject() {
             var oldTitle = webView.title
             webView.selectFile = false;
diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/multifileupload.html b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/multifileupload.html
new file mode 100644 (file)
index 0000000..7701ed4
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<meta name="viewport" initial-scale=1">
+<title> Mutli-file Upload </title>
+<script src = "./titleupdate.js">
+</script>
+
+<body>
+<input type="file" name="file" id="upfile" onchange="updateTitle()" multiple/>
+</body>
+</html>
index 580b999..38e345f 100644 (file)
@@ -1,23 +1,8 @@
 <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;
-}
+<title> Single File Upload </title>
+<script src = "./titleupdate.js">
 </script>
 
 <body>
diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/titleupdate.js b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/titleupdate.js
new file mode 100644 (file)
index 0000000..2a5bac0
--- /dev/null
@@ -0,0 +1,15 @@
+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;
+}
index d9385e8..8f62896 100644 (file)
@@ -163,25 +163,36 @@ private:
 class FilePickerContextObject : public QObject {
     Q_OBJECT
     Q_PROPERTY(QStringList fileList READ fileList CONSTANT)
+    Q_PROPERTY(bool allowMultipleFiles READ allowMultipleFiles CONSTANT)
 
 public:
-    FilePickerContextObject(const QStringList& selectedFiles)
+    FilePickerContextObject(const QStringList& selectedFiles, bool allowMultiple)
         : QObject()
+        , m_allowMultiple(allowMultiple)
         , m_fileList(selectedFiles)
     {
     }
 
     QStringList fileList() const { return m_fileList; }
+    bool allowMultipleFiles() const { return m_allowMultiple;}
 
 public slots:
     void reject() { emit rejected();}
-    void accept(const QVariant& path) { emit fileSelected(path.toStringList()); }
+    void accept(const QVariant& path)
+    {
+        QStringList filesPath = path.toStringList();
+        // For single file upload, send only the first element if there are more than one file paths
+        if (!m_allowMultiple && filesPath.count() > 1)
+            filesPath = QStringList(filesPath.at(0));
+        emit fileSelected(filesPath);
+    }
 
 signals:
     void rejected();
     void fileSelected(const QStringList&);
 
 private:
+    bool m_allowMultiple;
     QStringList m_fileList;
 };
 
@@ -312,9 +323,9 @@ bool QtDialogRunner::initForCertificateVerification(QDeclarativeComponent* compo
     return true;
 }
 
-bool QtDialogRunner::initForFilePicker(QDeclarativeComponent* component, QQuickItem* dialogParent, const QStringList& selectedFiles)
+bool QtDialogRunner::initForFilePicker(QDeclarativeComponent* component, QQuickItem* dialogParent, const QStringList& selectedFiles, bool allowMultiple)
 {
-    FilePickerContextObject* contextObject = new FilePickerContextObject(selectedFiles);
+    FilePickerContextObject* contextObject = new FilePickerContextObject(selectedFiles, allowMultiple);
     if (!createDialog(component, dialogParent, contextObject))
         return false;
 
index 0e584aa..e96600e 100644 (file)
@@ -43,7 +43,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);
+    bool initForFilePicker(QDeclarativeComponent*, QQuickItem*, const QStringList& selectedFiles, bool allowMultiple);
     bool initForDatabaseQuotaDialog(QDeclarativeComponent*, QQuickItem*, const QString& databaseName, const QString& displayName, WKSecurityOriginRef, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage);
 
     QQuickItem* dialog() const { return m_dialog.get(); }
index 12110c7..a03748f 100644 (file)
@@ -1,3 +1,22 @@
+2012-03-26  Dinu Jacob  <dinu.jacob@nokia.com>
+
+        [Qt][WK2] Support multi-file upload
+        https://bugs.webkit.org/show_bug.cgi?id=81589
+
+        Reviewed by Simon Hausmann.
+
+        Modified filePicker to support multi-file upload.
+
+        * MiniBrowser/qt/MiniBrowser.qrc:
+        * MiniBrowser/qt/icons/checkbox_checked.png: Added.
+        * MiniBrowser/qt/icons/checkbox_unchecked.png: Added.
+        * MiniBrowser/qt/js/MultiSelect.js: Added.
+        (values):
+        (isSelected):
+        (removeValue):
+        * MiniBrowser/qt/qml/CheckBox.qml: Added.
+        * MiniBrowser/qt/qml/FilePicker.qml:
+
 2012-03-26  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Retry crashing tests serially at the end of NRWT on Apple Mac
index e81132a..b5490be 100644 (file)
@@ -1,5 +1,7 @@
 <RCC>
     <qresource prefix="/">
+        <file>icons/checkbox_checked.png</file>
+        <file>icons/checkbox_unchecked.png</file>
         <file>icons/favicon.png</file>
         <file>icons/folder.png</file>
         <file>icons/info.png</file>
         <file>icons/touch.png</file>
         <file>icons/touchpoint.png</file>
         <file>icons/up.png</file>
+        <file>js/MultiSelect.js</file>
         <file>qml/AlertDialog.qml</file>
         <file>qml/AuthenticationDialog.qml</file>
         <file>qml/BrowserWindow.qml</file>
+        <file>qml/CheckBox.qml</file>
         <file>qml/ConfirmDialog.qml</file>
         <file>qml/Dialog.qml</file>
         <file>qml/DialogButton.qml</file>
diff --git a/Tools/MiniBrowser/qt/icons/checkbox_checked.png b/Tools/MiniBrowser/qt/icons/checkbox_checked.png
new file mode 100644 (file)
index 0000000..cbf06f6
Binary files /dev/null and b/Tools/MiniBrowser/qt/icons/checkbox_checked.png differ
diff --git a/Tools/MiniBrowser/qt/icons/checkbox_unchecked.png b/Tools/MiniBrowser/qt/icons/checkbox_unchecked.png
new file mode 100644 (file)
index 0000000..5f54655
Binary files /dev/null and b/Tools/MiniBrowser/qt/icons/checkbox_unchecked.png differ
diff --git a/Tools/MiniBrowser/qt/js/MultiSelect.js b/Tools/MiniBrowser/qt/js/MultiSelect.js
new file mode 100644 (file)
index 0000000..9e87f5d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+
+
+var values = []
+
+function selectedValues() {
+    return values
+}
+
+function isSelected(value) {
+    return (values.indexOf(value) != -1)
+}
+
+function addValue(value) {
+    if (values.indexOf(value) != -1)
+        return
+    values.push(value)
+}
+
+function removeValue(value) {
+    var index = values.indexOf(value)
+
+    if (index == -1)
+        return
+    values.splice(index, 1)
+}
diff --git a/Tools/MiniBrowser/qt/qml/CheckBox.qml b/Tools/MiniBrowser/qt/qml/CheckBox.qml
new file mode 100644 (file)
index 0000000..085b811
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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
+
+Item {
+    id: checkbox
+    width: 50
+    height: parent.height
+    property bool checked
+
+    Image {
+        width: 24
+        height: 24
+        source: parent.checked ? '../icons/checkbox_checked.png' : '../icons/checkbox_unchecked.png'
+        anchors.verticalCenter: parent.verticalCenter
+    }
+}
index 5beb86a..222d4c3 100644 (file)
@@ -20,6 +20,7 @@
 
 import QtQuick 2.0
 import Qt.labs.folderlistmodel 1.0
+import "../js/MultiSelect.js" as MultiSelect
 
 Rectangle {
     id: filePicker
@@ -109,8 +110,19 @@ Rectangle {
                 function selected() {
                     if (folders.isFolder(index))
                         openFolder(filePath);
-                    else
-                        fileModel.accept(filePath);
+                    else {
+
+                        if (fileModel.allowMultipleFiles) {
+                            checkbox.checked = !checkbox.checked
+
+                            if (checkbox.checked)
+                                MultiSelect.addValue(filePath)
+                            else
+                                MultiSelect.removeValue(filePath)
+                        }
+                        else
+                            fileModel.accept(filePath)
+                    }
                 }
 
                 height: 50
@@ -118,7 +130,7 @@ Rectangle {
                 color: folders.isFolder(index) ? "lightgray": "darkgray"
 
                 Item {
-                    width: 48;
+                    width: 50
                     height: 48
                     Image {
                         source: "../icons/folder.png"
@@ -128,9 +140,22 @@ Rectangle {
                 }
 
                 Text {
+                    id: fileNameText
                     anchors.centerIn: parent
-                    anchors.leftMargin: 50
+                    anchors.leftMargin: 20
+                    width: 300
                     text: fileName
+                    elide: Text.ElideLeft;
+                }
+
+                CheckBox {
+                    id: checkbox
+
+                    anchors.right: parent.right
+                    anchors.verticalCenter: parent.verticalCenter
+
+                    checked: MultiSelect.isSelected(filePath)
+                    visible: fileModel.allowMultipleFiles && !folders.isFolder(index)
                 }
 
                 MouseArea {
@@ -160,15 +185,25 @@ Rectangle {
             right: parent.right
         }
 
-        DialogButton {
-            id: cancel
-            text: "Cancel"
-            anchors {
-                horizontalCenter: parent.horizontalCenter;
-                verticalCenter:  parent.verticalCenter
+        Row {
+            id: buttonRow
+            spacing: 10
+            anchors.horizontalCenter: parent.horizontalCenter
+            anchors.verticalCenter: parent.verticalCenter
+
+            DialogButton {
+                id: cancel
+                text: "Cancel"
+                onClicked: fileModel.reject()
             }
 
-            onClicked: fileModel.reject()
+            DialogButton {
+                id: accept
+                text: "Ok"
+                visible: fileModel.allowMultipleFiles
+                onClicked:
+                    fileModel.accept(MultiSelect.selectedValues());
+            }
         }
     }