Revision control

Copy as Markdown

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qohoswindowmanager.h"
#include <QtCore/private/qcore_ohos_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/private/qnapi_p.h>
#include <QtCore/private/qohoscommon_p.h>
#include <QtCore/private/qohoslogger_p.h>
#include <QtCore/private/qohospathutils_p.h>
#include <QtCore/qurl.h>
#include <algorithm>
#include <iterator>
#include <vector>
#include "qohosplatformwindow.h"
QT_BEGIN_NAMESPACE
namespace {
struct FilePickerResult
{
std::vector<std::string> resultPaths;
int selectedIndex;
};
std::optional<QNapi::Object> tryGetQAbilityForQWindow(
QOhosJsState &jsState, QtOhos::QObjectThreadSafeRef qWindowRef)
{
auto optQAbility = jsState.tryGetQAbilityByQWindow(qWindowRef);
return optQAbility ? optQAbility : jsState.defaultQAbility();
}
QNapi::Object makeDocumentViewPicker(
QOhosJsState &jsState, QNapi::Object qAbility,
QtOhos::QObjectThreadSafeRef contextWindowRef)
{
auto optContextJsWindow = jsState.tryGetJsWindowByQWindow(contextWindowRef);
std::vector<QNapi::ValueWrapper> constructorParams = {qAbility.get("context")};
if (optContextJsWindow)
constructorParams.push_back(optContextJsWindow.value());
return jsState.eval<QNapi::Object>(
"@ohos.file.picker.DocumentViewPicker<new>(*)", constructorParams);
}
void startOhosFilePicker(
QOhosJsState &jsState, QtOhos::QObjectThreadSafeRef contextWindowRef,
const std::string &pickerActionName, QNapi::Object pickerActionOptions,
QOhosConsumer<std::optional<FilePickerResult>> resultConsumer)
{
auto sharedResultConsumer = QtOhos::moveToSharedPtr(std::move(resultConsumer));
auto optQAbility = tryGetQAbilityForQWindow(jsState, contextWindowRef);
if (!optQAbility) {
qOhosPrintfError(
"Cannot call DocumentViewPicker.%s(): no UIAbility to use", pickerActionName.c_str());
(*sharedResultConsumer)(std::nullopt);
return;
}
qOhosPrintfDebug(
"Calling DocumentViewPicker.%s() with options: %s",
pickerActionName.c_str(), QNapi::toJsonString(pickerActionOptions).c_str());
auto documentViewPicker = QtOhos::moveToSharedPtr(
QNapi::Reference<>::makePersistentFrom(
makeDocumentViewPicker(jsState, optQAbility.value(), contextWindowRef)));
documentViewPicker->evalToPromiseOrRejectOnThrow(pickerActionName + "(*)", {pickerActionOptions}).onThen(
[documentViewPicker, pickerActionName, sharedResultConsumer](const QOhosCallbackInfo &cbInfo) {
auto actionResult = cbInfo.getFirstArg<QNapi::Array>(Q_FUNC_INFO);
auto resultOhosUris = QNapi::getArrayElements<std::vector<std::string>, QNapi::String>(actionResult);
qOhosPrintfDebug(
"Called DocumentViewPicker.%s() callback with result: %s",
pickerActionName.c_str(), QNapi::toJsonString(actionResult).c_str());
std::vector<std::string> resultPaths;
std::transform(
resultOhosUris.cbegin(), resultOhosUris.cend(), std::back_inserter(resultPaths),
[&](const auto &uri) {
return tryMapOhosFileUriToPath(uri).value_or("");
});
(*sharedResultConsumer)(
std::optional<FilePickerResult>(
{
.resultPaths = std::move(resultPaths),
.selectedIndex = documentViewPicker->eval<QNapi::Number>("getSelectedIndex()"),
}));
},
[pickerActionName, sharedResultConsumer]() {
qOhosPrintfError("DocumentViewPicker.%s() call failed", pickerActionName.c_str());
(*sharedResultConsumer)({});
});
}
QStringList mapFilePathsToQtUrls(const std::vector<std::string> &filePaths)
{
QStringList qtUrls;
std::transform(
filePaths.cbegin(), filePaths.cend(), std::back_inserter(qtUrls),
[&](const auto &path) {
return QUrl::fromLocalFile(QString::fromStdString(path)).toString();
});
return qtUrls;
}
}
namespace QOhosWindowManager {
void showFileDialogOpen(
QtOhos::QObjectThreadSafeRef contextWindowRef, QStringList filters, QString defaultPath,
DocumentSelectMode documentSelectMode, ResultMultiplicity resultMultiplicity,
QOhosConsumer<std::optional<OpenResult>> resultCallback)
{
auto sharedResultCallback = QtOhos::moveToSharedPtr(std::move(resultCallback));
QOhosJsThreadGateway::invoke(
[contextWindowRef, filters, defaultPath, documentSelectMode, resultMultiplicity, sharedResultCallback](QOhosJsState &jsState) {
constexpr auto ohosMaxValueForMaxSelectNumber = 500;
auto *env = jsState.env();
auto documentSelectOptions = QNapi::makeObject(
env,
{
{"maxSelectNumber", resultMultiplicity == ResultMultiplicity::SINGLE ? 1 : ohosMaxValueForMaxSelectNumber},
{"fileSuffixFilters", QNapi::makeArray(env, filters, std::mem_fn(&QString::toStdString))},
{"defaultFilePathUri", tryMapPathToOhosFileUri(defaultPath.toStdString()).value_or("")},
{"selectMode", jsState.mapOhosEnumToJs(documentSelectMode)},
});
startOhosFilePicker(
jsState, contextWindowRef, "select", documentSelectOptions,
[sharedResultCallback](auto optResult) {
auto optQtOpenResult = qTransform(
optResult,
[](const auto &result) {
return OpenResult{
.selectedUrls = mapFilePathsToQtUrls(result.resultPaths),
};
});
QtOhos::invokeInQtThread(
[sharedResultCallback, optQtOpenResult]() {
(*sharedResultCallback)(optQtOpenResult);
});
});
});
}
void showFileDialogSave(
QtOhos::QObjectThreadSafeRef contextWindowRef, QStringList newFileNames,
QString defaultFilePath, QStringList fileSuffixChoices,
QOhosConsumer<std::optional<SaveResult>> resultCallback)
{
auto sharedResultCallback = QtOhos::moveToSharedPtr(std::move(resultCallback));
QOhosJsThreadGateway::invoke(
[contextWindowRef, newFileNames, defaultFilePath, fileSuffixChoices, sharedResultCallback](QOhosJsState &jsState) {
auto *env = jsState.env();
auto documentSaveOptions = QNapi::Object::New(env);
if (!newFileNames.isEmpty())
documentSaveOptions.Set("newFileNames", QNapi::makeArray(env, newFileNames, std::mem_fn(&QString::toStdString)));
if (!defaultFilePath.isEmpty())
documentSaveOptions.Set("defaultFilePathUri", tryMapPathToOhosFileUri(defaultFilePath.toStdString()).value_or(""));
if (!fileSuffixChoices.isEmpty())
documentSaveOptions.Set("fileSuffixChoices", QNapi::makeArray(env, fileSuffixChoices, std::mem_fn(&QString::toStdString)));
documentSaveOptions.Set("autoCreateEmptyFile", false);
startOhosFilePicker(
jsState, contextWindowRef, "save", documentSaveOptions,
[sharedResultCallback](auto optResult) {
auto optQtSaveResult = qTransform(
optResult,
[](const auto &result) {
return SaveResult{
.savedUrls = mapFilePathsToQtUrls(result.resultPaths),
.selectedFileSuffixChoiceIndex = result.selectedIndex,
};
});
QtOhos::invokeInQtThread(
[sharedResultCallback, optQtSaveResult]() {
(*sharedResultCallback)(optQtSaveResult);
});
});
});
}
}
QT_END_NAMESPACE