/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwasmlocalfileaccess_p.h" #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QWasmLocalFileAccess { void readFiles(const qstdweb::FileList &fileList, const std::function &acceptFile, const std::function &fileDataReady) { auto readFile = std::make_shared>(); *readFile = [=](int fileIndex) mutable { // Stop when all files have been processed if (fileIndex >= fileList.length()) { readFile.reset(); return; } const qstdweb::File file = fileList[fileIndex]; // Ask caller if the file should be accepted char *buffer = acceptFile(file.size(), file.name()); if (buffer == nullptr) { (*readFile)(fileIndex + 1); return; } // Read file data into caller-provided buffer file.stream(buffer, [=]() { fileDataReady(); (*readFile)(fileIndex + 1); }); }; (*readFile)(0); } typedef std::function OpenFileDialogCallback; void openFileDialog(const std::string &accept, FileSelectMode fileSelectMode, const OpenFileDialogCallback &filesSelected) { // Create file input html element which will display a native file dialog // and call back to our onchange handler once the user has selected // one or more files. emscripten::val document = emscripten::val::global("document"); emscripten::val input = document.call("createElement", std::string("input")); input.set("type", "file"); input.set("style", "display:none"); input.set("accept", emscripten::val(accept)); input.set("multiple", emscripten::val(fileSelectMode == MultipleFiles)); // Note: there is no event in case the user cancels the file dialog. static std::unique_ptr changeEvent; auto callback = [=]() { filesSelected(qstdweb::FileList(input["files"])); }; changeEvent.reset(new qstdweb::EventCallback(input, "change", callback)); // Activate file input emscripten::val body = document["body"]; body.call("appendChild", input); input.call("click"); body.call("removeChild", input); } void openFiles(const std::string &accept, FileSelectMode fileSelectMode, const std::function &fileDialogClosed, const std::function &acceptFile, const std::function &fileDataReady) { openFileDialog(accept, fileSelectMode, [=](const qstdweb::FileList &files) { fileDialogClosed(files.length()); readFiles(files, acceptFile, fileDataReady); }); } void openFile(const std::string &accept, const std::function &fileDialogClosed, const std::function &acceptFile, const std::function &fileDataReady) { auto fileDialogClosedWithInt = [=](int fileCount) { fileDialogClosed(fileCount != 0); }; openFiles(accept, FileSelectMode::SingleFile, fileDialogClosedWithInt, acceptFile, fileDataReady); } void saveFile(const char *content, size_t size, const std::string &fileNameHint) { // Save a file by creating programmatically clicking a download // link to an object url to a Blob containing a copy of the file // content. The copy is made so that the passed in content buffer // can be released as soon as this function returns. qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(content, size); emscripten::val document = emscripten::val::global("document"); emscripten::val window = emscripten::val::global("window"); emscripten::val contentUrl = window["URL"].call("createObjectURL", contentBlob.val()); emscripten::val contentLink = document.call("createElement", std::string("a")); contentLink.set("href", contentUrl); contentLink.set("download", fileNameHint); contentLink.set("style", "display:none"); emscripten::val body = document["body"]; body.call("appendChild", contentLink); contentLink.call("click"); body.call("removeChild", contentLink); window["URL"].call("revokeObjectURL", contentUrl); } } // namespace QWasmLocalFileAccess QT_END_NAMESPACE