Add basic QAbstractItemModel and QAbstractTableModel

This commit is contained in:
Simon Edwards 2021-08-14 15:18:06 +02:00
parent 080bb3626d
commit 25e0d61e01
15 changed files with 405 additions and 8 deletions

View File

@ -65,6 +65,7 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QMovie/qmovie_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QPalette/qpalette_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtGui/QStyle/qstyle_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QAbstractItemModel/qabstractitemmodel_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QDate/qdate_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QDateTime/qdatetime_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtCore/QModelIndex/qmodelindex_wrap.cpp"
@ -144,6 +145,7 @@ add_library(${CORE_WIDGETS_ADDON} SHARED
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QSvgWidget/qsvgwidget_wrap.cpp"
"${PROJECT_SOURCE_DIR}/src/cpp/lib/QtWidgets/QDesktopWidget/qdesktopwidget_wrap.cpp"
# Custom widgets (include them for automoc since they contain Q_OBJECT)
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtCore/QAbstractItemModel/nabstractitemmodel.hpp"
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtCore/QObject/nobject.hpp"
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/core/FlexLayout/flexlayout.hpp"
"${PROJECT_SOURCE_DIR}/src/cpp/include/nodegui/QtGui/QMovie/nmovie.hpp"

View File

@ -24,7 +24,8 @@
"lint:ts": "cross-env tsc --noEmit && cross-env eslint './src/**/*.{ts,tsx,js,jsx}' --fix",
"docs": "cross-env typedoc && node ./website/docs/scripts/fixdocs.js",
"qode": "cross-env node ./scripts/qode.js",
"prepublishOnly": "cross-env npm run build"
"prepublishOnly": "cross-env npm run build",
"example-modelview_1_readonly": "node ./scripts/qode.js dist/examples/modelview_1_readonly.js"
},
"engines": {
"node": ">=14.x.x"

View File

@ -0,0 +1,93 @@
#pragma once
#include <QAbstractItemModel>
#include "Extras/Export/export.h"
#include "QtCore/QObject/qobject_macro.h"
#include "core/NodeWidget/nodewidget.h"
#include "QtCore/QModelIndex/qmodelindex_wrap.h"
#include "napi.h"
class DLL_EXPORT NAbstractItemModel : public QAbstractItemModel, public EventWidget {
Q_OBJECT
EVENTWIDGET_IMPLEMENTATIONS(QAbstractItemModel)
public:
Napi::FunctionReference dispatchOnNode;
void connectSignalsToEventEmitter() {
// Qt Connects: Implement all signal connects here
QOBJECT_SIGNALS
}
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto parentModelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(parent))});
Napi::Value modelIndexNapiWrap = this->dispatchOnNode.Call(
{Napi::String::New(env, "index"), Napi::Value::From(env, row), Napi::Value::From(env, column), parentModelIndexWrap});
QModelIndexWrap* modelIndexWrap = Napi::ObjectWrap<QModelIndexWrap>::Unwrap(modelIndexNapiWrap.As<Napi::Object>());
QModelIndex* newIndex = modelIndexWrap->getInternalInstance();
return *newIndex;
}
QModelIndex parent(const QModelIndex &child) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto childModelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(child))});
Napi::Value modelIndexNapiWrap = this->dispatchOnNode.Call({Napi::String::New(env, "parent"), childModelIndexWrap});
QModelIndexWrap* modelIndexWrap = Napi::ObjectWrap<QModelIndexWrap>::Unwrap(modelIndexNapiWrap.As<Napi::Object>());
QModelIndex* parentIndex = modelIndexWrap->getInternalInstance();
return *parentIndex;
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto modelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(parent))});
Napi::Value result = this->dispatchOnNode.Call({Napi::String::New(env, "rowCount"), modelIndexWrap});
return result.As<Napi::Number>().Int32Value();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto modelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(parent))});
Napi::Value result = this->dispatchOnNode.Call({Napi::String::New(env, "columnCount"), modelIndexWrap});
return result.As<Napi::Number>().Int32Value();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto modelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(index))});
auto roleValue = Napi::Value::From(env, role);
Napi::Value variantJsObject = this->dispatchOnNode.Call({Napi::String::New(env, "data"), modelIndexWrap, roleValue});
QVariantWrap* variantWrap = Napi::ObjectWrap<QVariantWrap>::Unwrap(variantJsObject.As<Napi::Object>());
QVariant* variant = variantWrap->getInternalInstance();
return *variant;
}
Qt::ItemFlags flags(const QModelIndex &index) const override {
Napi::Env env = this->dispatchOnNode.Env();
Napi::HandleScope scope(env);
auto modelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(index))});
Napi::Value numberJs = this->dispatchOnNode.Call({Napi::String::New(env, "flags"), modelIndexWrap});
auto result = static_cast<Qt::ItemFlags>(numberJs.As<Napi::Number>().Uint32Value());
return result;
}
QModelIndex _protected_createIndex(int row, int column) const {
return createIndex(row, column);
}
};

View File

@ -0,0 +1,30 @@
#pragma once
#include <napi.h>
#include <QPointer>
#include "Extras/Export/export.h"
#include "QtCore/QObject/qobject_macro.h"
#include "nabstractitemmodel.hpp"
class DLL_EXPORT QAbstractItemModelWrap : public Napi::ObjectWrap<QAbstractItemModelWrap> {
QOBJECT_WRAPPED_METHODS_DECLARATION
private:
QPointer<NAbstractItemModel> instance;
public:
static Napi::Object init(Napi::Env env, Napi::Object exports);
QAbstractItemModelWrap(const Napi::CallbackInfo& info);
~QAbstractItemModelWrap();
NAbstractItemModel* getInternalInstance();
// class constructor
static Napi::FunctionReference constructor;
// wrapped methods
Napi::Value initNodeDispatcher(const Napi::CallbackInfo& info);
Napi::Value hasIndex(const Napi::CallbackInfo& info);
Napi::Value createIndex(const Napi::CallbackInfo& info);
Napi::Value _super_flags(const Napi::CallbackInfo& info);
};

View File

@ -27,5 +27,5 @@ class DLL_EXPORT QVariantWrap : public Napi::ObjectWrap<QVariantWrap> {
};
namespace StaticQVariantWrapMethods {
DLL_EXPORT Napi::Value converToQVariant(const Napi::CallbackInfo& info);
DLL_EXPORT Napi::Value convertToQVariant(const Napi::CallbackInfo& info);
} // namespace StaticQVariantWrapMethods

View File

@ -1,6 +1,7 @@
#pragma once
#include "QtCore/QModelIndex/qmodelindex_wrap.h"
#include "QtCore/QAbstractItemModel/qabstractitemmodel_wrap.h"
#include "QtWidgets/QAbstractScrollArea/qabstractscrollarea_macro.h"
#include "QtWidgets/QWidget/qwidget_wrap.h"
@ -88,6 +89,16 @@
Napi::HandleScope scope(env); \
this->instance->scrollToTop(); \
return env.Null(); \
} \
Napi::Value setModel(const Napi::CallbackInfo& info) { \
Napi::Env env = info.Env(); \
Napi::HandleScope scope(env); \
Napi::Object modelObject = info[0].As<Napi::Object>(); \
QAbstractItemModelWrap* modelWrap = \
Napi::ObjectWrap<QAbstractItemModelWrap>::Unwrap(modelObject); \
QAbstractItemView* instance= this->instance; \
instance->setModel(modelWrap->getInternalInstance()); \
return env.Null(); \
}
#endif // QABSTRACTITEMVIEW_WRAPPED_METHODS_DECLARATION
@ -105,7 +116,8 @@
&WidgetWrapName::resetVerticalScrollMode), \
InstanceMethod("rootIndex", &WidgetWrapName::rootIndex), \
InstanceMethod("scrollToBottom", &WidgetWrapName::scrollToBottom), \
InstanceMethod("scrollToTop", &WidgetWrapName::scrollToTop),
InstanceMethod("scrollToTop", &WidgetWrapName::scrollToTop), \
InstanceMethod("setModel", &WidgetWrapName::setModel),
#endif // QABSTRACTITEMVIEW_WRAPPED_METHODS_EXPORT_DEFINE

View File

@ -0,0 +1,76 @@
#include "QtCore/QAbstractItemModel/qabstractitemmodel_wrap.h"
#include "Extras/Utils/nutils.h"
Napi::FunctionReference QAbstractItemModelWrap::constructor;
Napi::Object QAbstractItemModelWrap::init(Napi::Env env, Napi::Object exports) {
Napi::HandleScope scope(env);
char CLASSNAME[] = "QAbstractItemModel";
Napi::Function func = DefineClass(
env, CLASSNAME,
{InstanceMethod("initNodeDispatcher", &QAbstractItemModelWrap::initNodeDispatcher),
InstanceMethod("hasIndex", &QAbstractItemModelWrap::hasIndex),
InstanceMethod("createIndex", &QAbstractItemModelWrap::createIndex),
InstanceMethod("_super_flags", &QAbstractItemModelWrap::_super_flags),
QOBJECT_WRAPPED_METHODS_EXPORT_DEFINE(QAbstractItemModelWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
return exports;
}
NAbstractItemModel* QAbstractItemModelWrap::getInternalInstance() { return this->instance; }
QAbstractItemModelWrap::~QAbstractItemModelWrap() { extrautils::safeDelete(this->instance); }
QAbstractItemModelWrap::QAbstractItemModelWrap(const Napi::CallbackInfo& info)
: Napi::ObjectWrap<QAbstractItemModelWrap>(info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
this->instance = new NAbstractItemModel();
}
Napi::Value QAbstractItemModelWrap::initNodeDispatcher(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
this->instance->dispatchOnNode = Napi::Persistent(info[0].As<Napi::Function>());
return env.Null();
}
Napi::Value QAbstractItemModelWrap::hasIndex(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
int row = info[0].As<Napi::Number>().Int32Value();
int column = info[1].As<Napi::Number>().Int32Value();
QModelIndexWrap* modelIndexWrap = Napi::ObjectWrap<QModelIndexWrap>::Unwrap(info[2].As<Napi::Object>());
QModelIndex* parentIndex = modelIndexWrap->getInternalInstance();
auto result = Napi::Value::From(env, this->instance->hasIndex(row, column, *parentIndex));
return result;
}
Napi::Value QAbstractItemModelWrap::createIndex(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
int row = info[0].As<Napi::Number>().Int32Value();
int column = info[1].As<Napi::Number>().Int32Value();
QModelIndex resultIndex = this->instance->_protected_createIndex(row, column);
auto resultModelIndexWrap = QModelIndexWrap::constructor.New({Napi::External<QModelIndex>::New(env, new QModelIndex(resultIndex))});
return resultModelIndexWrap;
}
Napi::Value QAbstractItemModelWrap::_super_flags(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);
QModelIndexWrap* modelIndexWrap = Napi::ObjectWrap<QModelIndexWrap>::Unwrap(info[0].As<Napi::Object>());
QModelIndex* index = modelIndexWrap->getInternalInstance();
auto result = Napi::Value::From(env, static_cast<uint>(this->instance->QAbstractItemModel::flags(*index)));
return result;
}

View File

@ -14,8 +14,8 @@ Napi::Object QVariantWrap::init(Napi::Env env, Napi::Object exports) {
InstanceMethod("toDouble", &QVariantWrap::toDouble),
InstanceMethod("toBool", &QVariantWrap::toBool),
InstanceMethod("toStringList", &QVariantWrap::toStringList),
StaticMethod("converToQVariant",
&StaticQVariantWrapMethods::converToQVariant),
StaticMethod("convertToQVariant",
&StaticQVariantWrapMethods::convertToQVariant),
COMPONENT_WRAPPED_METHODS_EXPORT_DEFINE(QVariantWrap)});
constructor = Napi::Persistent(func);
exports.Set(CLASSNAME, func);
@ -72,7 +72,7 @@ Napi::Value QVariantWrap::toStringList(const Napi::CallbackInfo& info) {
return result;
}
Napi::Value StaticQVariantWrapMethods::converToQVariant(
Napi::Value StaticQVariantWrapMethods::convertToQVariant(
const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::HandleScope scope(env);

View File

@ -1,6 +1,7 @@
#include <napi.h>
#include "Extras/Utils/nutils.h"
#include "QtCore/QAbstractItemModel/qabstractitemmodel_wrap.h"
#include "QtCore/QDate/qdate_wrap.h"
#include "QtCore/QDateTime/qdatetime_wrap.h"
#include "QtCore/QMimeData/qmimedata_wrap.h"
@ -220,6 +221,7 @@ Napi::Object Main(Napi::Env env, Napi::Object exports) {
QDesktopWidgetWrap::init(env, exports);
QPaintEventWrap::init(env, exports);
QPaletteWrap::init(env, exports);
QAbstractItemModelWrap::init(env, exports);
return exports;
}

View File

@ -0,0 +1,30 @@
import { ItemDataRole, QAbstractTableModel, QModelIndex, QTableView, QVariant } from '..';
function main(): void {
const tableView = new QTableView();
const model = new MyModel();
tableView.setModel(model);
tableView.show();
(global as any).win = tableView;
}
class MyModel extends QAbstractTableModel {
rowCount(parent = new QModelIndex()): number {
return 2;
}
columnCount(parent = new QModelIndex()): number {
return 2;
}
data(index: QModelIndex, role = ItemDataRole.DisplayRole): QVariant {
if (role === ItemDataRole.DisplayRole) {
return new QVariant(`Row${index.row() + 1}, Column${index.column() + 1}`);
}
return new QVariant();
}
}
main();

View File

@ -128,6 +128,8 @@ export {
WrapMode,
} from './lib/QtWidgets/QTextEdit';
// Core
export { QAbstractItemModel } from './lib/QtCore/QAbstractItemModel';
export { QAbstractTableModel } from './lib/QtCore/QAbstractTableModel';
export { QDate } from './lib/QtCore/QDate';
export { QDateTime } from './lib/QtCore/QDateTime';
export { QModelIndex } from './lib/QtCore/QModelIndex';

View File

@ -0,0 +1,113 @@
import addon from '../utils/addon';
import { NativeElement } from '../core/Component';
import { NodeObject, QObjectSignals } from '../QtCore/QObject';
import { QModelIndex } from './QModelIndex';
import { QVariant } from './QVariant';
import { ItemDataRole, ItemFlag } from '../QtEnums';
export interface QAbstractItemSignals extends QObjectSignals {
// itemChanged: (item: QStandardItem) => void;
}
export class QAbstractItemModel extends NodeObject<any> {
native: NativeElement;
constructor() {
const native = new addon.QAbstractItemModel();
super(native);
this.native = native;
const dispatcher = (methodName: string, ...args: any[]): any => {
switch (methodName) {
case 'index':
try {
return this.index(args[0], args[1], new QModelIndex(args[2])).native;
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'index':`);
console.log(e);
}
return new QModelIndex().native;
case 'parent':
try {
return this.parent(new QModelIndex(args[0])).native;
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'parent':`);
console.log(e);
}
return new QModelIndex().native;
case 'rowCount':
try {
return this.columnCount(new QModelIndex(args[0]));
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'rowCount':`);
console.log(e);
}
return 0;
case 'columnCount':
try {
return this.columnCount(new QModelIndex(args[0]));
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'columnCount':`);
console.log(e);
}
return 0;
case 'data':
try {
return this.data(new QModelIndex(args[0]), args[1]).native;
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'data':`);
console.log(e);
}
return new QVariant().native;
case 'flags':
try {
return this.flags(new QModelIndex(args[0]));
} catch (e) {
console.log(`An exception was thrown while dispatching to method 'flags':`);
console.log(e);
}
return ItemFlag.NoItemFlags;
default:
return null;
}
};
this.native.initNodeDispatcher(dispatcher);
}
index(row: number, column: number, parent = new QModelIndex()): QModelIndex {
return new QModelIndex();
}
parent(child: QModelIndex): QModelIndex {
return new QModelIndex();
}
rowCount(parent = new QModelIndex()): number {
return 0;
}
columnCount(parent = new QModelIndex()): number {
return 0;
}
data(index: QModelIndex, role = ItemDataRole.DisplayRole): QVariant {
return new QVariant();
}
hasIndex(row: number, column: number, parent = new QModelIndex()): boolean {
return this.native.hasIndex(row, column, parent.native);
}
createIndex(row: number, column: number): QModelIndex {
const result = this.native.createIndex(row, column);
return new QModelIndex(result);
}
flags(index: QModelIndex): ItemFlag {
return this.native._super_flags(index.native);
}
}

View File

@ -0,0 +1,32 @@
import { ItemFlag } from '../QtEnums';
import { QAbstractItemModel } from './QAbstractItemModel';
import { QModelIndex } from './QModelIndex';
export class QAbstractTableModel extends QAbstractItemModel {
index(row: number, column: number, parent = new QModelIndex()): QModelIndex {
return this.hasIndex(row, column, parent) ? this.createIndex(row, column) : new QModelIndex();
}
parent(child: QModelIndex): QModelIndex {
return new QModelIndex();
}
sibling(row: number, column: number, index: QModelIndex): QModelIndex {
return this.index(row, column);
}
hasChildren(parent: QModelIndex): boolean {
if (!parent.isValid()) {
return this.rowCount(parent) > 0 && this.columnCount(parent) > 0;
}
return false;
}
flags(index: QModelIndex): ItemFlag {
let f = super.flags(index);
if (index.isValid()) {
f |= ItemFlag.ItemNeverHasChildren;
}
return f;
}
}

View File

@ -14,7 +14,7 @@ export class QVariant extends Component {
if (checkIfNativeElement(arg) && arg instanceof addon.QVariant) {
this.native = arg as NativeElement;
} else if (arg) {
this.native = new addon.QVariant.converToQVariant(arg);
this.native = new addon.QVariant.convertToQVariant(arg);
} else {
this.native = new addon.QVariant();
}

View File

@ -4,9 +4,10 @@ import { QModelIndex } from '../QtCore/QModelIndex';
import { QSize } from '../QtCore/QSize';
import { DropAction } from '../QtEnums/DropAction';
import { TextElideMode } from '../QtEnums/TextElideMode';
import { QAbstractItemModel } from '../QtCore/QAbstractItemModel';
/**
> This is the abstract base class of button widgets, providing their functionality.
* **This class is a JS wrapper around Qt's [QAbstractItemView class](https://doc.qt.io/qt-5/qabstractitemview.html)**
@ -138,6 +139,9 @@ export abstract class QAbstractItemView<Signals extends QAbstractItemViewSignals
resetVerticalScrollMode(): void {
this.native.resetVerticalScrollMode();
}
setModel(model: QAbstractItemModel): void {
this.native.setModel(model.native);
}
}
export enum DragDropMode {