From 22c7acd74ee18148e2bd85e78b6377d5ae9002fe Mon Sep 17 00:00:00 2001 From: Atul R Date: Sun, 24 Nov 2019 23:05:53 +0100 Subject: [PATCH] Methods and exports needed for Webview support (#217) * Adds basic qurl support * allows building with custom qt installation using the env variable * cleans up * cleanup --- CMakeLists.txt | 1 + config/qt.cmake | 25 +++--- .../include/nodegui/QtCore/QUrl/qurl_wrap.h | 29 +++++++ src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp | 79 +++++++++++++++++++ src/cpp/main.cpp | 2 + src/index.ts | 2 + src/lib/QtCore/QSize.ts | 2 +- src/lib/QtCore/QUrl.ts | 35 ++++++++ src/lib/QtCore/__tests__/QUrl.test.ts | 24 ++++++ src/lib/QtGui/QIcon.ts | 2 +- src/lib/QtGui/QPixmap.ts | 2 +- 11 files changed, 185 insertions(+), 18 deletions(-) create mode 100644 src/cpp/include/nodegui/QtCore/QUrl/qurl_wrap.h create mode 100644 src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp create mode 100644 src/lib/QtCore/QUrl.ts create mode 100644 src/lib/QtCore/__tests__/QUrl.test.ts diff --git a/CMakeLists.txt b/CMakeLists.txt index 61ffcd228..8c5809f74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(${CORE_WIDGETS_ADDON} SHARED "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QObject/qobject_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QVariant/qvariant_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QSize/qsize_wrap.cpp" + "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QWidget/qwidget_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QGridLayout/qgridlayout_wrap.cpp" "${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QDial/qdial_wrap.cpp" diff --git a/config/qt.cmake b/config/qt.cmake index 4db0ad4b1..83ecf92b9 100644 --- a/config/qt.cmake +++ b/config/qt.cmake @@ -12,10 +12,17 @@ function(AddQtSupport addonName) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE QT_HOME_DIR ) + + if(DEFINED ENV{QT_INSTALL_DIR}) + # Allows to use custom Qt installation via QT_INSTALL_DIR env variable + message(STATUS "Using Custom QT installation for ${addonName} QT_INSTALL_DIR:$ENV{QT_INSTALL_DIR}") + set(QT_HOME_DIR "$ENV{QT_INSTALL_DIR}") + endif() + string(REPLACE "\n" "" QT_HOME_DIR "${QT_HOME_DIR}") string(REPLACE "\"" "" QT_HOME_DIR "${QT_HOME_DIR}") - if (APPLE) - # createQtMacSymlinks() + + if(APPLE) set(CUSTOM_QT_MOC_PATH "${QT_HOME_DIR}/bin/moc") target_include_directories(${addonName} PRIVATE @@ -65,20 +72,8 @@ function(AddQtSupport addonName) "${QT_HOME_DIR}/lib/libQt5Widgets.so" ) endif() - + # set custom moc executable location set_target_properties(Qt5::moc PROPERTIES IMPORTED_LOCATION "${CUSTOM_QT_MOC_PATH}") endfunction(AddQtSupport addonName) - -# function(createQtMacSymlinks) -# message("Creating qt symlinks") -# execute_process( -# COMMAND 'mkdir -p ${QT_HOME_DIR}/include' -# COMMAND 'ln -sfn ${QT_HOME_DIR}/lib/QtCore.framework/Versions/5/Headers ${QT_HOME_DIR}/include/QtCore' -# COMMAND 'ln -sfn ${QT_HOME_DIR}/lib/QtGui.framework/Versions/5/Headers ${QT_HOME_DIR}/include/QtGui' -# COMMAND 'ln -sfn ${QT_HOME_DIR}/lib/QtWidgets.framework/Versions/5/Headers ${QT_HOME_DIR}/include/QtWidgets' -# WORKING_DIRECTORY ${QT_HOME_DIR} -# ) -# endfunction() - diff --git a/src/cpp/include/nodegui/QtCore/QUrl/qurl_wrap.h b/src/cpp/include/nodegui/QtCore/QUrl/qurl_wrap.h new file mode 100644 index 000000000..b57f6b5a0 --- /dev/null +++ b/src/cpp/include/nodegui/QtCore/QUrl/qurl_wrap.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include + +#include "core/Component/component_macro.h" + +class QUrlWrap : public Napi::ObjectWrap { + private: + std::unique_ptr instance; + + public: + static Napi::FunctionReference constructor; + static Napi::Object init(Napi::Env env, Napi::Object exports); + QUrlWrap(const Napi::CallbackInfo& info); + ~QUrlWrap(); + QUrl* getInternalInstance(); + // Wrapped methods + Napi::Value setUrl(const Napi::CallbackInfo& info); + Napi::Value toString(const Napi::CallbackInfo& info); + + COMPONENT_WRAPPED_METHODS_DECLARATION +}; + +namespace StaticQUrlWrapMethods { +Napi::Value fromQVariant(const Napi::CallbackInfo& info); +} // namespace StaticQUrlWrapMethods \ No newline at end of file diff --git a/src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp b/src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp new file mode 100644 index 000000000..dfe807274 --- /dev/null +++ b/src/cpp/lib/QtCore/QUrl/qurl_wrap.cpp @@ -0,0 +1,79 @@ +#include "QtCore/QUrl/qurl_wrap.h" + +#include "Extras/Utils/nutils.h" +#include "QtCore/QVariant/qvariant_wrap.h" + +Napi::FunctionReference QUrlWrap::constructor; + +Napi::Object QUrlWrap::init(Napi::Env env, Napi::Object exports) { + Napi::HandleScope scope(env); + char CLASSNAME[] = "QUrl"; + Napi::Function func = DefineClass( + env, CLASSNAME, + {InstanceMethod("setUrl", &QUrlWrap::setUrl), + InstanceMethod("toString", &QUrlWrap::toString), + StaticMethod("fromQVariant", &StaticQUrlWrapMethods::fromQVariant), + COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE}); + constructor = Napi::Persistent(func); + exports.Set(CLASSNAME, func); + return exports; +} + +QUrlWrap::QUrlWrap(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + if (info.Length() == 2) { + std::string url = info[0].As().Utf8Value(); + int parseMode = info[1].As().Int32Value(); + this->instance = std::make_unique( + QString::fromStdString(url), static_cast(parseMode)); + } else if (info.Length() == 1) { + if (info[0].IsExternal()) { + this->instance = + std::unique_ptr(info[0].As>().Data()); + } else { + std::string url = info[0].As().Utf8Value(); + this->instance = std::make_unique(QString::fromStdString(url)); + } + } else if (info.Length() == 0) { + this->instance = std::make_unique(); + } else { + Napi::TypeError::New(env, "Wrong number of arguments") + .ThrowAsJavaScriptException(); + } + this->rawData = extrautils::configureComponent(this->getInternalInstance()); +} + +QUrlWrap::~QUrlWrap() { this->instance.reset(); } + +QUrl* QUrlWrap::getInternalInstance() { return this->instance.get(); } + +Napi::Value QUrlWrap::setUrl(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + std::string url = info[0].As().Utf8Value(); + this->instance->setUrl(QString::fromStdString(url)); + return env.Null(); +} +Napi::Value QUrlWrap::toString(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + QString url = this->instance->toString(); + return Napi::Value::From(env, url.toStdString()); +} + +Napi::Value StaticQUrlWrapMethods::fromQVariant( + const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + Napi::Object variantObject = info[0].As(); + QVariantWrap* variantWrap = + Napi::ObjectWrap::Unwrap(variantObject); + QVariant* variant = variantWrap->getInternalInstance(); + QUrl url = variant->value(); + auto instance = QUrlWrap::constructor.New( + {Napi::External::New(env, new QUrl(url))}); + return instance; +} diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 2bb262db9..041d7f68d 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -2,6 +2,7 @@ #include "QtCore/QObject/qobject_wrap.h" #include "QtCore/QSize/qsize_wrap.h" +#include "QtCore/QUrl/qurl_wrap.h" #include "QtCore/QVariant/qvariant_wrap.h" #include "QtGui/QApplication/qapplication_wrap.h" #include "QtGui/QClipboard/qclipboard_wrap.h" @@ -43,6 +44,7 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) { QObjectWrap::init(env, exports); QVariantWrap::init(env, exports); QSizeWrap::init(env, exports); + QUrlWrap::init(env, exports); QClipboardWrap::init(env, exports); QWidgetWrap::init(env, exports); QPixmapWrap::init(env, exports); diff --git a/src/index.ts b/src/index.ts index 0157e2724..589a8e967 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,9 +42,11 @@ export { QShortcut, QShortcutEvents } from './lib/QtWidgets/QShortcut'; export { QObject, NodeObject } from './lib/QtCore/QObject'; export { QVariant } from './lib/QtCore/QVariant'; export { QSize } from './lib/QtCore/QSize'; +export { QUrl, ParsingMode } from './lib/QtCore/QUrl'; // Layouts: export { QGridLayout } from './lib/QtWidgets/QGridLayout'; export { FlexLayout } from './lib/core/FlexLayout'; // Others: export { StyleSheet } from './lib/core/Style/StyleSheet'; export { NativeElement, Component } from './lib/core/Component'; +export { checkIfNativeElement } from './lib/utils/helpers'; diff --git a/src/lib/QtCore/QSize.ts b/src/lib/QtCore/QSize.ts index 70a026738..8e780353d 100644 --- a/src/lib/QtCore/QSize.ts +++ b/src/lib/QtCore/QSize.ts @@ -30,6 +30,6 @@ export class QSize extends Component { return this.native.height(); } static fromQVariant(variant: QVariant): QSize { - return addon.QSize.fromQVariant(variant.native); + return new QSize(addon.QSize.fromQVariant(variant.native)); } } diff --git a/src/lib/QtCore/QUrl.ts b/src/lib/QtCore/QUrl.ts new file mode 100644 index 000000000..831edc8ab --- /dev/null +++ b/src/lib/QtCore/QUrl.ts @@ -0,0 +1,35 @@ +import { NativeElement, Component } from '../core/Component'; +import addon from '../utils/addon'; +import { checkIfNativeElement } from '../utils/helpers'; +import { QVariant } from './QVariant'; + +export enum ParsingMode { + TolerantMode, + StrictMode, + DecodedMode, +} + +type argument = string | NativeElement; + +export class QUrl extends Component { + native: NativeElement; + constructor(arg?: argument, parsingMode: ParsingMode = ParsingMode.TolerantMode) { + super(); + if (!arg) { + this.native = new addon.QUrl(); + } else if (checkIfNativeElement(arg)) { + this.native = arg as NativeElement; + } else { + this.native = new addon.QUrl(arg, parsingMode); + } + } + setUrl(url: string): void { + return this.native.setUrl(url); + } + toString(): string { + return this.native.toString(); + } + static fromQVariant(variant: QVariant): QUrl { + return new QUrl(addon.QUrl.fromQVariant(variant.native)); + } +} diff --git a/src/lib/QtCore/__tests__/QUrl.test.ts b/src/lib/QtCore/__tests__/QUrl.test.ts new file mode 100644 index 000000000..9ffbd1384 --- /dev/null +++ b/src/lib/QtCore/__tests__/QUrl.test.ts @@ -0,0 +1,24 @@ +import { QUrl } from '../QUrl'; +import { QVariant } from '../QVariant'; + +describe('QUrl', () => { + it('initialize empty', () => { + const url = new QUrl(); + expect(url).toBeTruthy(); + }); + it('initialize with url', () => { + const url = new QUrl('https://google.com'); + expect(url).toBeTruthy(); + }); + it('setUrl', () => { + const url = new QUrl(); + url.setUrl('https://yahoo.com'); + expect(url.toString()).toEqual('https://yahoo.com'); + }); + it('initialize from QVariant', () => { + const url = new QUrl('https://google.com'); + const variant = new QVariant(url); + expect(variant).toBeTruthy(); + expect(QUrl.fromQVariant(variant).toString()).toBe('https://google.com'); + }); +}); diff --git a/src/lib/QtGui/QIcon.ts b/src/lib/QtGui/QIcon.ts index 72a3a891f..6bf2aec5e 100644 --- a/src/lib/QtGui/QIcon.ts +++ b/src/lib/QtGui/QIcon.ts @@ -50,6 +50,6 @@ export class QIcon extends Component { return this.native.cacheKey(); } static fromQVariant(variant: QVariant): QIcon { - return addon.QIcon.fromQVariant(variant.native); + return new QIcon(addon.QIcon.fromQVariant(variant.native)); } } diff --git a/src/lib/QtGui/QPixmap.ts b/src/lib/QtGui/QPixmap.ts index 63382e1b1..d843fb3b0 100644 --- a/src/lib/QtGui/QPixmap.ts +++ b/src/lib/QtGui/QPixmap.ts @@ -43,6 +43,6 @@ export class QPixmap extends Component { return this.native.width(); } static fromQVariant(variant: QVariant): QPixmap { - return addon.QPixmap.fromQVariant(variant.native); + return new QPixmap(addon.QPixmap.fromQVariant(variant.native)); } }