wasm: Add saveFileContent()
Saves a file by file download, where the user can choose the file name and location using a file dialog. Change-Id: I4d2ecc76fc33bb65fdf3d7ca3fcd9566c62547dd Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
parent
9f082b4e03
commit
d46415c0af
@ -164,6 +164,43 @@ void openFile(const std::string &accept,
|
||||
openFiles(accept, FileSelectMode::SingleFile, fileDialogClosedWithInt, acceptFile, fileDataReady);
|
||||
}
|
||||
|
||||
void saveFile(const char *content, size_t size, const std::string &fileNameHint)
|
||||
{
|
||||
// Save a file by creating programatically clicking a download
|
||||
// link to an object url to a Blob containing the file content.
|
||||
// File content is copied once, so that the passed in content
|
||||
// buffer can be released as soon as this function returns - we
|
||||
// don't know for how long the browser will retain the TypedArray
|
||||
// view used to create the Blob.
|
||||
|
||||
emscripten::val document = emscripten::val::global("document");
|
||||
emscripten::val window = emscripten::val::global("window");
|
||||
|
||||
emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view(size, content));
|
||||
emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(size);
|
||||
emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy);
|
||||
fileContentCopyView.call<void>("set", fileContentView);
|
||||
|
||||
emscripten::val contentArray = emscripten::val::array();
|
||||
contentArray.call<void>("push", fileContentCopyView);
|
||||
emscripten::val type = emscripten::val::object();
|
||||
type.set("type","application/octet-stream");
|
||||
emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type);
|
||||
|
||||
emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob);
|
||||
emscripten::val contentLink = document.call<emscripten::val>("createElement", std::string("a"));
|
||||
contentLink.set("href", contentUrl);
|
||||
contentLink.set("download", fileNameHint);
|
||||
contentLink.set("style", "display:none");
|
||||
|
||||
emscripten::val body = document["body"];
|
||||
body.call<void>("appendChild", contentLink);
|
||||
contentLink.call<void>("click");
|
||||
body.call<void>("removeChild", contentLink);
|
||||
|
||||
window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl);
|
||||
}
|
||||
|
||||
} // namespace QWasmLocalFileAccess
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -71,6 +71,8 @@ void openFile(const std::string &accept,
|
||||
const std::function<char *(uint64_t size, const std::string name)> &acceptFile,
|
||||
const std::function<void()> &fileDataReady);
|
||||
|
||||
void saveFile(const char *content, size_t size, const std::string &fileNameHint);
|
||||
|
||||
} // namespace QWasmLocalFileAccess
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -2447,6 +2447,51 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
This is a convenience static function that saves \a fileContent to a file, using
|
||||
a file name and location chosen by the user. \a fileNameHint can be provided to
|
||||
suggest a file name to the user.
|
||||
|
||||
This function is used to save files to the local file system on Qt for WebAssembly, where
|
||||
the web sandbox places restrictions on how such access may happen. Its implementation will
|
||||
make the browser display a native file dialog, where the user makes the file selection.
|
||||
|
||||
It can also be used on other platforms, where it will fall back to using QFileDialog.
|
||||
|
||||
The function is asynchronous and returns immediately.
|
||||
|
||||
\snippet code/src_gui_dialogs_qfiledialog.cpp 16
|
||||
\since 5.14
|
||||
*/
|
||||
void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint)
|
||||
{
|
||||
#ifdef Q_OS_WASM
|
||||
QWasmLocalFileAccess::saveFile(fileContent.constData(), fileContent.size(), fileNameHint.toStdString());
|
||||
#else
|
||||
QFileDialog *dialog = new QFileDialog();
|
||||
dialog->setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog->setFileMode(QFileDialog::AnyFile);
|
||||
dialog->selectFile(fileNameHint);
|
||||
|
||||
auto fileSelected = [=](const QString &fileName) {
|
||||
if (!fileName.isNull()) {
|
||||
QFile selectedFile(fileName);
|
||||
if (selectedFile.open(QIODevice::WriteOnly))
|
||||
selectedFile.write(fileContent);
|
||||
}
|
||||
};
|
||||
|
||||
auto dialogClosed = [=](int code) {
|
||||
Q_UNUSED(code);
|
||||
delete dialog;
|
||||
};
|
||||
|
||||
connect(dialog, &QFileDialog::fileSelected, fileSelected);
|
||||
connect(dialog, &QFileDialog::finished, dialogClosed);
|
||||
dialog->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
This is a convenience static function that will return a file name selected
|
||||
by the user. The file does not have to exist.
|
||||
|
@ -284,6 +284,7 @@ public:
|
||||
|
||||
static void getOpenFileContent(const QString &nameFilter,
|
||||
const std::function<void(const QString &, const QByteArray &)> &fileContentsReady);
|
||||
static void saveFileContent(const QByteArray &fileContent, const QString &fileNameHint = QString());
|
||||
|
||||
protected:
|
||||
QFileDialog(const QFileDialogArgs &args);
|
||||
|
@ -155,3 +155,8 @@ auto fileOpenCompleted = [](const QString &fileName, const QByteArray &fileConte
|
||||
}
|
||||
QFileDialog::getOpenFileContent("Images (*.png *.xpm *.jpg)", fileContentReady);
|
||||
//! [15]
|
||||
|
||||
//! [16]
|
||||
QByteArray imageData; // obtained from e.g. QImage::save()
|
||||
QFileDialog::saveFile("myimage.png", imageData);
|
||||
//! [16]
|
||||
|
Loading…
x
Reference in New Issue
Block a user