diff --git a/CMakeLists.txt b/CMakeLists.txt index a9092645c..05f815ad6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,6 +220,10 @@ add_library(${CORE_WIDGETS_ADDON} SHARED "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QTextEdit/ntextedit.hpp" "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QSvgWidget/nsvgwidget.hpp" "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtWidgets/QHeaderView/nheaderview.hpp" + # Test + "${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/test/CacheTestQObject.h" + "${PROJECT_SOURCE_DIR}/src/cpp/lib/test/CacheTestQObject.cpp" + "${PROJECT_SOURCE_DIR}/src/cpp/lib/test/cachetestqobject_wrap.cpp" ) AddCommonConfig(${CORE_WIDGETS_ADDON}) diff --git a/src/cpp/include/nodegui/test/CacheTestQObject.h b/src/cpp/include/nodegui/test/CacheTestQObject.h new file mode 100644 index 000000000..6e47348e8 --- /dev/null +++ b/src/cpp/include/nodegui/test/CacheTestQObject.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "Extras/Export/export.h" + +class CacheTestQObject; + +class DLL_EXPORT CacheTestQObject : public QObject { + Q_OBJECT + private: + CacheTestQObject* _foo; + CacheTestQObject* _bar; + + public: + CacheTestQObject(); + CacheTestQObject* foo(); + void clearFoo(); + CacheTestQObject* bar(); +}; diff --git a/src/cpp/include/nodegui/test/cachetestqobject_wrap.h b/src/cpp/include/nodegui/test/cachetestqobject_wrap.h new file mode 100644 index 000000000..f888a7a36 --- /dev/null +++ b/src/cpp/include/nodegui/test/cachetestqobject_wrap.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include + +#include "Extras/Export/export.h" +#include "QtCore/QObject/qobject_macro.h" +#include "test/CacheTestQObject.h" + +class DLL_EXPORT CacheTestQObjectWrap + : public Napi::ObjectWrap, + public EventWidget { + QOBJECT_WRAPPED_METHODS_DECLARATION_WITH_EVENT_SOURCE(this) + + private: + QPointer instance; + + public: + // class constructor + static Napi::FunctionReference constructor; + + static Napi::Object init(Napi::Env env, Napi::Object exports); + + CacheTestQObjectWrap(const Napi::CallbackInfo& info); + CacheTestQObject* getInternalInstance(); + + virtual void connectSignalsToEventEmitter(); + + // wrapped methods + Napi::Value foo(const Napi::CallbackInfo& info); + Napi::Value clearFoo(const Napi::CallbackInfo& info); + Napi::Value bar(const Napi::CallbackInfo& info); +}; diff --git a/src/cpp/lib/test/CacheTestQObject.cpp b/src/cpp/lib/test/CacheTestQObject.cpp new file mode 100644 index 000000000..21f735730 --- /dev/null +++ b/src/cpp/lib/test/CacheTestQObject.cpp @@ -0,0 +1,28 @@ +#include "test/CacheTestQObject.h" + +CacheTestQObject::CacheTestQObject() : _foo(0), _bar(0) {} + +CacheTestQObject* CacheTestQObject::foo() { + if (_foo) { + return _foo; + } + _foo = new CacheTestQObject(); + _foo->setParent(this); + return _foo; +} + +void CacheTestQObject::clearFoo() { + if (_foo) { + delete _foo; + _foo = nullptr; + } +} + +CacheTestQObject* CacheTestQObject::bar() { + if (_bar) { + return _bar; + } + _bar = new CacheTestQObject(); + _bar->setParent(this); + return _bar; +} diff --git a/src/cpp/lib/test/cachetestqobject_wrap.cpp b/src/cpp/lib/test/cachetestqobject_wrap.cpp new file mode 100644 index 000000000..f8d301993 --- /dev/null +++ b/src/cpp/lib/test/cachetestqobject_wrap.cpp @@ -0,0 +1,71 @@ +#include "test/cachetestqobject_wrap.h" + +#include "Extras/Utils/nutils.h" +#include "core/WrapperCache/wrappercache.h" + +Napi::FunctionReference CacheTestQObjectWrap::constructor; + +Napi::Object CacheTestQObjectWrap::init(Napi::Env env, Napi::Object exports) { + Napi::HandleScope scope(env); + char CLASSNAME[] = "CacheTestQObject"; + Napi::Function func = DefineClass( + env, CLASSNAME, + {InstanceMethod("foo", &CacheTestQObjectWrap::foo), + InstanceMethod("clearFoo", &CacheTestQObjectWrap::clearFoo), + InstanceMethod("bar", &CacheTestQObjectWrap::bar), + QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(CacheTestQObjectWrap)}); + constructor = Napi::Persistent(func); + exports.Set(CLASSNAME, func); + return exports; +} + +CacheTestQObject* CacheTestQObjectWrap::getInternalInstance() { + return this->instance; +} + +CacheTestQObjectWrap::CacheTestQObjectWrap(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + if (info.Length() == 1 && info[0].IsExternal()) { + this->instance = info[0].As>().Data(); + } else { + if (info.Length() == 0) { + this->instance = new CacheTestQObject(); + } else { + Napi::TypeError::New(env, + "Wrong number of arguments to CacheTestQObject.") + .ThrowAsJavaScriptException(); + } + } + this->rawData = extrautils::configureQObject(this->getInternalInstance()); +} + +void CacheTestQObjectWrap::connectSignalsToEventEmitter() { + QOBJECT_SIGNALS_ON_TARGET(this->instance.data()); +} + +Napi::Value CacheTestQObjectWrap::foo(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + CacheTestQObject* foo = this->instance->foo(); + return WrapperCache::instance.get( + env, foo); +} + +Napi::Value CacheTestQObjectWrap::clearFoo(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + this->instance->clearFoo(); + return env.Null(); +} + +Napi::Value CacheTestQObjectWrap::bar(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + CacheTestQObject* bar = this->instance->bar(); + return WrapperCache::instance.get( + env, bar); +} diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 12cb0e0d6..e56134500 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -115,6 +115,7 @@ #include "core/FlexLayout/flexlayout_wrap.h" #include "core/Integration/integration.h" #include "core/WrapperCache/wrappercache.h" +#include "test/cachetestqobject_wrap.h" // These cant be instantiated in JS Side void InitPrivateHelpers(Napi::Env env) { @@ -237,6 +238,10 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) { QStyleFactoryWrap::init(env, exports); QScreenWrap::init(env, exports); QWindowWrap::init(env, exports); + + // Test + CacheTestQObjectWrap::init(env, exports); + return exports; } diff --git a/src/index.ts b/src/index.ts index 6b0d63ac8..07e82f34a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -170,3 +170,6 @@ export { StyleSheet } from './lib/core/Style/StyleSheet'; export { NativeElement, Component } from './lib/core/Component'; export { checkIfNativeElement, checkIfNapiExternal } from './lib/utils/helpers'; export { Margins } from './lib/utils/Margins'; + +// Test: +export { CacheTestQObject } from './lib/core/__test__/CacheTestQObject'; diff --git a/src/lib/QtWidgets/QWidget.ts b/src/lib/QtWidgets/QWidget.ts index 7e160acbe..e07c90208 100644 --- a/src/lib/QtWidgets/QWidget.ts +++ b/src/lib/QtWidgets/QWidget.ts @@ -15,11 +15,12 @@ import { QRect } from '../QtCore/QRect'; import { QObjectSignals } from '../QtCore/QObject'; import { QFont } from '../QtGui/QFont'; import { QAction } from './QAction'; -import { QScreen } from '../QtGui/QScreen'; import memoizeOne from 'memoize-one'; import { QGraphicsEffect } from './QGraphicsEffect'; -import { QSizePolicyPolicy, QStyle, QWindow } from '../..'; import { wrapperCache } from '../core/WrapperCache'; +import { QSizePolicyPolicy } from './QSizePolicy'; +import { QStyle } from '../QtGui/QStyle'; +import { QWindow } from '../QtGui/QWindow'; /** diff --git a/src/lib/core/__test__/CacheTestQObject.ts b/src/lib/core/__test__/CacheTestQObject.ts new file mode 100644 index 000000000..79e42305a --- /dev/null +++ b/src/lib/core/__test__/CacheTestQObject.ts @@ -0,0 +1,30 @@ +import addon from '../../utils/addon'; +import { NativeElement } from '../Component'; +import { NodeObject, QObjectSignals } from '../../QtCore/QObject'; +import { wrapperCache } from '../../core/WrapperCache'; + +export class CacheTestQObject extends NodeObject { + native: NativeElement; + constructor(arg?: NativeElement) { + let native; + if (native == null) { + native = new addon.CacheTestQObject(); + } else { + native = arg; + } + super(native); + this.native = native; + } + + foo(): CacheTestQObject { + return wrapperCache.get(CacheTestQObject, this.native.foo()); + } + + clearFoo(): void { + this.native.clearFoo(); + } + + bar(): CacheTestQObject { + return wrapperCache.get(CacheTestQObject, this.native.bar()); + } +} diff --git a/src/lib/core/__test__/WrapperCache.test.ts b/src/lib/core/__test__/WrapperCache.test.ts new file mode 100644 index 000000000..fe5cde994 --- /dev/null +++ b/src/lib/core/__test__/WrapperCache.test.ts @@ -0,0 +1,47 @@ +import { QApplication } from '../../QtGui/QApplication'; +import { CacheTestQObject } from './CacheTestQObject'; + +describe('WrapperCache using CacheTestQObject', () => { + const qApp = QApplication.instance(); + qApp.setQuitOnLastWindowClosed(true); + + it('Cached foo', () => { + const a = new CacheTestQObject(); + expect(a).not.toBeNull(); + + const foo = a.foo(); + expect(foo).not.toBeNull(); + + const foo2 = a.foo(); + expect(foo).toBe(foo2); + expect(foo.native.__id__()).toBe(foo2.native.__id__()); + }); + + it('clearFoo() and wrapper expiration', () => { + const a = new CacheTestQObject(); + const foo = a.foo(); + a.clearFoo(); + expect(foo.native).toBeNull(); + }); + + it('clearFoo() and new wrapper', () => { + const a = new CacheTestQObject(); + const foo = a.foo(); + const fooId = foo.native.__id__(); + a.clearFoo(); + expect(foo.native).toBeNull(); + + const foo2 = a.foo(); + expect(foo2).not.toBe(foo); + expect(foo2.native.__id__()).not.toBe(fooId); + }); + + it('Cached foo and bar', () => { + const a = new CacheTestQObject(); + const foo = a.foo(); + const bar = a.bar(); + expect(foo).not.toEqual(bar); + expect(foo.native.__id__()).not.toEqual(bar.native.__id__()); + }); + qApp.quit(); +});