├── .gitignore
├── .gitmodules
├── Kpf.pri
├── Kpf.pro
├── README.md
├── bin
├── components
│ ├── KWidgets.json
│ ├── test.json
│ └── test.xml
├── config
│ ├── app.json
│ └── app.xml
├── procdump
└── procdump.exe
├── include
└── Kpf
│ ├── Class.h
│ ├── Common.h
│ ├── Connection.h
│ ├── Constants.h
│ ├── Event.h
│ ├── EventHelper.h
│ ├── InvokeHelper.h
│ ├── Kpf.h
│ ├── KpfCore.h
│ ├── Object.h
│ ├── Thread.h
│ └── Topic.h
└── src
├── app
├── MainWindow.cpp
├── MainWindow.h
├── MainWindow.ui
├── app.pro
└── main.cpp
├── core
├── Class.cpp
├── ClassImpl.h
├── CommonPrivate.cpp
├── CommonPrivate.h
├── Connection.cpp
├── ConnectionImpl.h
├── CoreDump
│ ├── CoreDump.cpp
│ ├── CoreDump.h
│ ├── CoreDump.pri
│ ├── DataSizeHelper.h
│ ├── Dump.h
│ ├── Dump_Unix.cpp
│ ├── Dump_Windows.cpp
│ ├── Library.pro
│ ├── SystemInfo.cpp
│ ├── SystemInfo.h
│ ├── SystemInfo.pri
│ ├── SystemInfoInterface.h
│ ├── SystemInfoPrivate.h
│ ├── SystemInfoType.h
│ ├── SystemInfo_Unix.cpp
│ └── SystemInfo_Windows.cpp
├── Event.cpp
├── EventBus.cpp
├── EventBus.h
├── EventImpl.h
├── InvokeHelper.cpp
├── InvokeHelperPrivate.h
├── KLayout.cpp
├── KLayout.h
├── KWidgets.cpp
├── KWidgets.h
├── KpfCore.cpp
├── KpfCoreImpl.h
├── KpfLog.cpp
├── KpfLogPrivate.h
├── KpfPrivate.h
├── Library.cpp
├── Library.h
├── Object.cpp
├── ObjectImpl.h
├── RegisterQtClasses.h
├── SignalSpy.cpp
├── SignalSpy.h
├── Thread.cpp
├── ThreadImpl.h
├── Topic.cpp
├── TopicImpl.h
└── core.pro
├── plugins
├── plugins.pro
└── test
│ ├── Test.h
│ ├── test.cpp
│ └── test.pro
└── src.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 | *.slo
3 | *.lo
4 | *.o
5 | *.a
6 | *.la
7 | *.lai
8 | *.so
9 | *.dll
10 | *.dylib
11 |
12 | # Qt-es
13 | object_script.*.Release
14 | object_script.*.Debug
15 | *_plugin_import.cpp
16 | /.qmake.cache
17 | /.qmake.stash
18 | *.pro.user
19 | *.pro.user.*
20 | *.qbs.user
21 | *.qbs.user.*
22 | *.moc
23 | moc_*.cpp
24 | moc_*.h
25 | qrc_*.cpp
26 | ui_*.h
27 | *.qmlc
28 | *.jsc
29 | Makefile*
30 | *build-*
31 |
32 | # Qt unit tests
33 | target_wrapper.*
34 |
35 | # QtCreator
36 | *.autosave
37 |
38 | # QtCreator Qml
39 | *.qmlproject.user
40 | *.qmlproject.user.*
41 |
42 | # QtCreator CMake
43 | CMakeLists.txt.user*
44 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "log4qt"]
2 | path = log4qt
3 | url = https://github.com/ZgblKylin/log4qt
4 |
--------------------------------------------------------------------------------
/Kpf.pri:
--------------------------------------------------------------------------------
1 | CONFIG(release, debug|release): LIBS += -L$$PWD/bin/ -lKPF
2 | else:CONFIG(debug, debug|release): LIBS += -L$$PWD/bin/ -lKPFd
3 |
4 | INCLUDEPATH += $$PWD/include
5 |
--------------------------------------------------------------------------------
/Kpf.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | CONFIG += ordered
3 | SUBDIRS += \
4 | src
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KylinPluginFramework
2 | 
3 | 
4 | 
5 | [](https://app.codacy.com/gh/ZgblKylin/KylinPluginFramework?utm_source=github.com&utm_medium=referral&utm_content=ZgblKylin/KylinPluginFramework&utm_campaign=Badge_Grade_Settings)
6 | [](https://deepwiki.com/ZgblKylin/KylinPluginFramework)
7 | [](https://996.icu)
8 | [](https://www.mozilla.org/en-US/MPL/)
9 | [](https://github.com/996icu/996.ICU/blob/master/LICENSE)
10 |
11 | KPF(Kylin Plugin Framework) is a light weight plugin framework for Qt, free to cooperate with 3rd-party library without any code injection.
12 |
13 | # Features
14 | - **Light weight**: Only a single dll file.
15 | - **Dynamic load**: Load any QObject class to build your program architecture by configuration file, just like building LEGO!
16 | - **No injection**: Any QObject classes could be supported with a single line of declaration like `Q_DECL_METATYPE`, you can write it anywhere before loading the object. So you could configure any QObject classes from 3-rd party library without any code injection.
17 | - **EventBus**: Publish/Subscribe mechanism supported to decouple sender and receiver:
18 | - Better performance than signals&slots.
19 | - Easier to write than signals&slots.
20 | - Both synchronized and asynchronized events are supported, just like `Qt::DirectConnection` and `Qt::QueuedConnection`.
21 | - **Better signal&slots**:
22 | - Connect signals and slots by configuration file is also supported, just like eventbus.
23 | - Published event could connect to signals/slots, signals could connect to subscribed event too.
24 | - **Configure everything**:
25 | - QObject's every property could be configured
26 | - QObject's object-tree-hierarchy is also supported.
27 | - Object can be initialized in sub-thread by configuration, you needn't write any code about it.
28 | - **Component**: Separated configuration files are supported -- a `component` file is used to describe a subset of the configuration, and it behaves like a single concrete object, to be configured in other components or main configuration file.
29 | - **Powerful log system**: KPF use [log4qt](https://github.com/ZgblKylin/log4qt)(Not which one migrated from log4j) to record logs.
30 | - **Plentiful APIs**: Advanced user can control every behaviors described above.
31 |
32 | # Docs
33 | Only coments at present, sorry for this.
34 |
35 | # Examples
36 | There's a simply example in `test` folder, which shows the features with configuration file and several classes.
37 |
38 | # Roadmap
39 | 1. Submit code before 2019.7.7
40 | 2. Finish documentation with Doxygen(See [Another repository](https://zgblkylin.github.io/Cpp-Utilities/) for example).
41 | 3. Migrate configuration file format from `json` to `xml`.
42 | 4. Migrate log system to [log4qt](https://github.com/ZgblKylin/log4qt)(The existing logging system in KPF is prototype of my log4qt repo).
43 | 5. Unit tests and CI support for travis, appveyor and coveralls.
44 | 6. Other further maintenance:
45 | 1. Operational monitoring;
46 | 2. Hotswap support.
47 | 3. ...
48 |
--------------------------------------------------------------------------------
/bin/components/KWidgets.json:
--------------------------------------------------------------------------------
1 | {
2 | "_comment": [
3 | "对无法使用父子对象关系嵌套组织界面的Qt界面容器进行了封装"
4 | ],
5 |
6 | "Components": {
7 | "HBoxLayout": {
8 | "_comment": [
9 | "对QHBoxLayout进行封装,通过Items列表组织子节点",
10 | "每个子节点为一个QWidget或QLayout对象",
11 | "可通过Stretch属性设置拉伸比例,默认为0"
12 | ],
13 | "Class": "QHBoxLayout",
14 | "Items": [
15 | {
16 | "Class": "Widget",
17 | "Stretch": 1
18 | },
19 | {
20 | "Class": "Layout"
21 | }
22 | ]
23 | },
24 |
25 | "VBoxLayout": {
26 | "_comment": [
27 | "对QVBoxLayout进行封装,通过Items列表组织子节点",
28 | "每个子节点为一个QWidget或QLayout对象",
29 | "可通过Stretch属性设置拉伸比例,默认为0"
30 | ],
31 | "Class": "QVBoxLayout",
32 | "Items": [
33 | {
34 | "Class": "Widget",
35 | "Stretch": 1
36 | },
37 | {
38 | "Class": "Layout"
39 | }
40 | ]
41 | },
42 |
43 | "FormLayout": {
44 | "_comment": [
45 | "对QFormLayout进行封装,通过Items列表组织子节点",
46 | "每个子节点中,包含Label和Field子节点",
47 | "Label子节点为QWidget对象,可忽略此节点,可用QLabel封装数值",
48 | "Field子节点为QWidget对象"
49 | ],
50 | "Class": "QFormLayout",
51 | "Items": [
52 | {
53 | "Field": {
54 | "Class": "Widget"
55 | }
56 | },
57 | {
58 | "Field": {
59 | "Class": "Layout"
60 | }
61 | },
62 | {
63 | "Label": {
64 | "Class": "QLabel",
65 | "text": "LabelA"
66 | },
67 | "Field": {
68 | "Class": "Widget"
69 | }
70 | }
71 | ]
72 | },
73 |
74 | "GridLayout": {
75 | "_comment": [
76 | "对QFormLayout进行封装,通过Items列表组织子节点",
77 | "每个子节点中,包含Label和Field子节点",
78 | "Label子节点为QWidget对象,可忽略此节点",
79 | "Field子节点为QWidget对象"
80 | ],
81 | "Class": "QGridLayout",
82 | "Items": [
83 | {
84 | "Class": "Widget",
85 | "Row": 0,
86 | "Column": 0
87 | },
88 | {
89 | "Class": "Widget",
90 | "Row": 0,
91 | "Column": 1
92 | },
93 | {
94 | "Class": "Widget",
95 | "Row": 1,
96 | "Column": 0,
97 | "ColumnSpan": 2
98 | }
99 | ]
100 | },
101 |
102 | "StackedLayout": {
103 | "_comment": [
104 | "对QStackedLayout进行封装,通过Items列表组织子节点,每个子节点为QWidget对象"
105 | ],
106 | "Class": "QStackedLayout",
107 | "Items": [
108 | {
109 | "Class": "Widget"
110 | },
111 | {
112 | "Class": "Widget"
113 | }
114 | ]
115 | },
116 |
117 | "StackedWidget": {
118 | "_comment": [
119 | "对QStackedWidget进行封装,通过Items列表组织子节点,每个子节点为QWidget对象"
120 | ],
121 | "Class": "QStackedWidget",
122 | "Items": [
123 | {
124 | "Class": "Widget"
125 | },
126 | {
127 | "Class": "Widget"
128 | }
129 | ]
130 | },
131 |
132 | "TabWidget": {
133 | "_comment": [
134 | "对QTabWidget进行封装,通过Items列表组织子节点",
135 | "每个子节点为QWidget对象,并通过Tab属性指定分页标签,该属性可为布尔/数值/字符串"
136 | ],
137 | "Class": "QTabWidget",
138 | "Items": [
139 | {
140 | "Class": "Widget",
141 | "Tab": "Tab_1"
142 | },
143 | {
144 | "Class": "Widget",
145 | "Tab": "Tab_2"
146 | }
147 | ]
148 | },
149 |
150 | "ListWidget": {
151 | "_comment": [
152 | "对QListWidget进行封装,通过Items列表组织子节点,每个子节点为QWidget对象"
153 | ],
154 | "Class": "QListWidget",
155 | "Items": [
156 | {
157 | "Class": "Widget",
158 | },
159 | {
160 | "Class": "QLabel",
161 | "text": 3.14
162 | }
163 | ]
164 | },
165 |
166 | "TableWidget": {
167 | "_comment": [
168 | "对QListWidget进行封装,通过Items列表组织子节点,每个子节点为QWidget对象",
169 | "子节点需通过Row和Column属性指定所属行列"
170 | ],
171 | "Class": "QTableWidget",
172 | "Items": [
173 | {
174 | "Class": "Widget",
175 | "Row": 0,
176 | "Column": 0
177 | },
178 | {
179 | "Value": "Item_2",
180 | "Row": 0,
181 | "Column": 1
182 | },
183 | {
184 | "Value": false,
185 | "Row": 1,
186 | "Column": 0
187 | },
188 | {
189 | "Value": 3.14,
190 | "Row": 1,
191 | "Column": 1
192 | },
193 | {
194 | "Value": 10086,
195 | "Row": 2,
196 | "Column": 0
197 | }
198 | ]
199 | },
200 |
201 | "MenuBar": {
202 | "_comment": [
203 | "对MenuBar进行封装,通过Items列表组织子节点",
204 | "子节点可以是Menu/Action/Separator/Widget,通过同名属性标识",
205 | "Menu和Action的属性值即为对应的显示文本",
206 | "Menu允许通过Items继续嵌套",
207 | "Action允许通过z在Items子节点中设置一个Menu",
208 | "Menu和Action对应Menu和Action对象,对象名需通过Name属性设置",
209 | "Widget类型中,通过Class属性值标识控件类名,通过Name属性指定对象名"
210 | ],
211 | "Class": "MenuBar",
212 | "Items": [
213 | {
214 | "Menu": "text",
215 | "Name": "menu_1",
216 | "Items": [
217 | {
218 | "Action": "text",
219 | "Name": "action_1"
220 | },
221 | {
222 | "Separator": ""
223 | },
224 | {
225 | "Action": "text",
226 | "Name": "action_2"
227 | }
228 | ]
229 | },
230 | {
231 | "Separator": ""
232 | },
233 | {
234 | "Action": "text",
235 | "Name": "action_3",
236 | "Items": [
237 | {
238 | "Menu": "text",
239 | "Name": "actionMenu",
240 | "Items":[
241 | {
242 | "Action": "text",
243 | "Name": "action_4"
244 | },
245 | {
246 | "Action": "text",
247 | "Name": "action_5"
248 | }
249 | ]
250 | }
251 | ]
252 | },
253 | {
254 | "Widget": "Widget",
255 | "Name": "widget_1"
256 | }
257 | ]
258 | },
259 |
260 | "ToolBar": {
261 | "_comment": [
262 | "对QToolBar进行封装,通过Items列表组织子节点",
263 | "子节点可以是Action/Separator/Widget,通过同名属性标识",
264 | "Menu和Action的属性值即为对应的显示文本",
265 | "Menu允许通过Items继续嵌套,允许继续嵌套Menu",
266 | "Action允许通过z在Items子节点中设置一个Menu",
267 | "Menu和Action对应Menu和Action对象,对象名需通过Name属性设置",
268 | "Widget类型中,通过Class属性值标识控件类名,通过Name属性指定对象名"
269 | ],
270 | "Class": "QToolBar",
271 | "Items": [
272 | {
273 | "Action": "text",
274 | "Name": "action_6",
275 | "Items": [
276 | {
277 | "Menu": "text",
278 | "Name": "menu_2",
279 | "Items": [
280 | {
281 | "Action": "text",
282 | "Name": "action_7"
283 | },
284 | {
285 | "Separator": ""
286 | },
287 | {
288 | "Action": "text",
289 | "Name": "action_8"
290 | }
291 | ]
292 | }
293 | ]
294 | },
295 | {
296 | "Separator": ""
297 | },
298 | {
299 | "Action": "text",
300 | "Name": "action_9"
301 | },
302 | {
303 | "Widget": "Widget",
304 | "Name": "widget_2"
305 | }
306 | ]
307 | },
308 |
309 | "MainWindow": {
310 | "_comment": [
311 | "对QMainWindow进行封装",
312 | "MenuBar子节点:配置一个QMenuBar或其子类的对象",
313 | "ToolBar子节点:通过array配置多个QToolBar或其子类的对象",
314 | "CentralWidget子节点:配置一个QWidget或其子类的对象",
315 | "StatusBar子节点:配置一个QStatusBar或其子类的对象"
316 | ],
317 | "Class":"QMainWindow",
318 | "MenuBar": {
319 | "Class": "QMenuBar"
320 | },
321 | "ToolBar": [
322 | {
323 | "Class": "QToolBar"
324 | }
325 | ],
326 | "CentralWidget": {
327 | "Class": "Widget"
328 | },
329 | "StatusBar": {
330 | "Class": "QStatusBar"
331 | },
332 | "PubEvent": [
333 | {
334 | "Signal": "closed()",
335 | "Topic": "MainWindowClosed"
336 | }
337 | ]
338 | }
339 | }
340 | }
341 |
--------------------------------------------------------------------------------
/bin/components/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "_comment": [
3 | "Components: 组件列表",
4 | " 每个子对象为一个Component组件,对象名为组件名",
5 | " 组件的子节点,会被替换到所有配置文件中,对应Component属性的位置",
6 | " 组件替换时,不会覆盖对应位置的同名内容",
7 | " 组件配置中可以嵌套引用Component",
8 | " 组件子节点也可以为Array数组,此时仅可用于保存Connections"
9 | ],
10 |
11 | "Components": {
12 | "test": {
13 | "Class": "Test",
14 | "Parent": "mainWindow",
15 | "Name": "test",
16 | "SubThread": true,
17 | "PubEvent": [
18 | {
19 | "Signal": "testSignal(quint32)",
20 | "Topic": "TestEvent"
21 | },
22 | {
23 | "EventId": "TestEvent",
24 | "Topic": "TestEvent"
25 | }
26 | ],
27 | "SubEvent": [
28 | {
29 | "EventId": "TestSlot",
30 | "Topic": "TestEvent"
31 | }
32 | ]
33 | },
34 |
35 | "mainWindow": {
36 | "Class": "MainWindow",
37 | "Name": "mainWindow",
38 | "SubEvent": [
39 | {
40 | "EventId": "TestEvent",
41 | "Topic": "TestEvent"
42 | }
43 | ],
44 | "test": {
45 | "Component": "test"
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/bin/components/test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/bin/config/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "_comment": [
3 | "启动顺序为",
4 | " 加载plugins目录下所有动态库",
5 | " 加载config/app.xml和components/*.xml",
6 | " 将配置文件中所有component节点替换为对应组件的子节点",
7 | " 顺序构造objects中所有对象和子对象",
8 | " 顺序连接connections中所有信号槽",
9 | " 顺序初始化对象中声明的事件发布/订阅",
10 | " 顺序初始化objects中所有对象(若有init槽函数),销毁初始化失败对象",
11 | " 顺序设置所有object对象的属性(注意可能触发信号槽)",
12 | " 顺序执行所有initializations中的初始化操作",
13 | "退出顺序为",
14 | " 逆序销毁所有objects中的对象",
15 | " 卸载所有plugins目录下的动态库",
16 | "Objects: 对象列表",
17 | " 可任意嵌套编写,通过如下标识符之一来标识该对象为对象实例",
18 | " Class: 标识对象,值为类名",
19 | " Component: 标识组件,值为组件名,会被对应名称组件内容替换",
20 | " 对象默认属性为:",
21 | " Name: 对象名,若对象位于array中,则可通过此属性指定对象名",
22 | " Parent: 父对象名,若无,则会顺序检索父节点,寻找第一个可用父对象",
23 | " SubThread: 标识该类是否会在一个子线程中初始化",
24 | " ThreadName: 子线程名称,若无则为thread_objectName",
25 | " 子对象会在父对象之后构造",
26 | " 对象节点所有属性会通过setProperty设置为对象属性",
27 | " 对象若包含init(QJsonObject)槽函数,则在对象构造完毕后会自动执行,返回bool",
28 | " 对象可以自定义子节点嵌套,整个Objects树中所有层级的子对象均会被初始化",
29 | " 对象可定义事件发布/订阅,通过PubEvent/SubEvent成员array实现:",
30 | " PubEvent/SubEvent: json列表,每个成员对象为一个事件声明,对象属性如下:",
31 | " EventId:事件名称,与代码中的事件声明一致",
32 | " Signal: 信号名,可使用信号方法签名代替EventId,发送信号时自动发布事件",
33 | " Slot: 槽名称,可使用槽方法签名代替EventId,事件触发时自动执行槽方法",
34 | " Topic:事件隶属的主题名称",
35 | "Connections: 信号槽列表",
36 | " 每一个子对象为一个信号槽连接",
37 | " Sender/Receiver: 为发送/接收者对象名",
38 | " Signal/Slot: 为信号/槽函数名,格式与SiGNAL/SLOT宏内字符串相同",
39 | " Type: 信号槽连接方式,支持以下四种:",
40 | " Auto",
41 | " Direct",
42 | " Queued",
43 | " BlockingQueued",
44 | " 子节点可以为字符串,此时将用同名Component组件替换该子节点",
45 | "Initializations: 初始化列表",
46 | " 每一个子对象为一个初始化配置",
47 | " Object: 对象名",
48 | " Method: 该对象的槽函数,格式与SLot宏内字符串相同"
49 | ],
50 |
51 | "Objects": [
52 | {
53 | "Component": "mainWindow",
54 | "Name": "mainWindow",
55 | "Custom": "custom"
56 | },
57 | {
58 | "Class": "QMainWindow",
59 | "Name": "mainWindow_2",
60 | "CentralWidget": {
61 | "Class": "QWidget",
62 | "Name": "widget_mainWindow_2",
63 | "layout": {
64 | "Class": "QHBoxLayout",
65 | "Items": [
66 | {
67 | "Class": "QPushButton",
68 | "Name": "button1",
69 | "text": "点击修改窗口标题",
70 | "PubEvent": [
71 | {
72 | "Signal": "clicked(bool)",
73 | "Topic": "Button1Clicked"
74 | }
75 | ]
76 | },
77 | {
78 | "Class": "QPushButton",
79 | "Name": "button2",
80 | "text": "button 2"
81 | }
82 | ]
83 | }
84 | },
85 | "SubEvent": [
86 | {
87 | "Slot": "setWindowTitle(QString)",
88 | "Topic": "Button1Clicked"
89 | }
90 | ]
91 | }
92 | ],
93 |
94 | "Connections": [
95 | ],
96 |
97 | "Initializations": [
98 | {
99 | "Object": "mainWindow",
100 | "Method": "show()",
101 | "Arguments": [
102 | ]
103 | },
104 |
105 | {
106 | "Object": "test",
107 | "Method": "start()"
108 | },
109 |
110 | {
111 | "Object": "mainWindow_2",
112 | "Method": "show()"
113 | }
114 | ]
115 | }
116 |
--------------------------------------------------------------------------------
/bin/config/app.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/bin/procdump:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZgblKylin/KylinPluginFramework/4a52fc25f38ba13c0bec905d1bb2af203d8ad05d/bin/procdump
--------------------------------------------------------------------------------
/bin/procdump.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZgblKylin/KylinPluginFramework/4a52fc25f38ba13c0bec905d1bb2af203d8ad05d/bin/procdump.exe
--------------------------------------------------------------------------------
/include/Kpf/Class.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | // ======== API声明 ========
6 |
7 | // 获取ClassManager对象,等同于Kpf::ClassManager::instance()
8 | #define kpfClass
9 | // 注册类型至框架,Class为类型
10 | #define KPF_REGISTER(Class)
11 | // 注册类型至框架,Class为类型,className为配置文件中实际使用的类型名称
12 | #define KPF_REGISTER_CLASS(Class, className)
13 |
14 | namespace Kpf {
15 | struct KPFSHARED_EXPORT MetaClass
16 | {
17 | virtual ~MetaClass();
18 |
19 | QString name;
20 | QMetaObject metaObject;
21 |
22 | protected:
23 | MetaClass();
24 | };
25 |
26 | struct IClassNotifier
27 | {
28 | virtual ~IClassNotifier() = default;
29 |
30 | virtual void classRegistered(const QString& className) { Q_UNUSED(className) }
31 | };
32 |
33 | class KPFSHARED_EXPORT ClassManager : public QObject, virtual public INotifyManager
34 | {
35 | Q_OBJECT
36 |
37 | public:
38 | virtual ~ClassManager() = default;
39 |
40 | static ClassManager& instance();
41 |
42 | // 注册类型至框架,模板类型T为需要注册的类型,className为配置文件中使用的类名
43 | // 类型必须继承自QObject,可以继承自Kpf::Base
44 | template void registerClass(const QString& className);
45 | // 注册类型至框架,模板类型T为需要注册的类型,className默认与T类名相同
46 | // 类型必须继承自QObject,可以继承自Kpf::Base
47 | template void registerClass();
48 |
49 | // 获取当前可用的类名列表
50 | virtual QStringList availableClassNames() const = 0;
51 | // 提供类名,寻找对应的类
52 | virtual QWeakPointer findClass(const QString& className) const = 0;
53 |
54 | protected:
55 | // 注册类型至框架,className为配置文件中使用的类名,constructor为返回类对象的工厂函数
56 | virtual void registerClass(const QString& className, QMetaObject metaObject, const std::function& constructor) = 0;
57 | };
58 | } // namespace Kpf
59 | // ======== API声明 ========
60 |
61 | #undef kpfClass
62 | #define kpfClass Kpf::ClassManager::instance()
63 |
64 | #undef KPF_REGISTER_CLASS
65 | #define KPF_REGISTER_CLASS(Class, className) \
66 | struct KpfRegisterHelper##className \
67 | { \
68 | KpfRegisterHelper##className() \
69 | { \
70 | kpfClass.registerClass(#className); \
71 | } \
72 | }; \
73 | static KpfRegisterHelper##className kpfRegisterHelper##className;
74 |
75 | #undef KPF_REGISTER
76 | #define KPF_REGISTER(Class) KPF_REGISTER_CLASS(Class, Class)
77 |
78 |
79 | namespace Kpf {
80 | template
81 | inline void ClassManager::registerClass(const QString& className)
82 | {
83 | auto constructor = [](Object* object){
84 | T* ptr = new(std::nothrow) T;
85 | object->object = ptr;
86 | object->base = toBase(ptr);
87 | };
88 | registerClass(className, T::staticMetaObject, constructor);
89 | }
90 |
91 | template
92 | inline void ClassManager::registerClass()
93 | {
94 | registerClass(T::staticMetaObject.className());
95 | }
96 | } // namesapce Kpf
97 |
--------------------------------------------------------------------------------
/include/Kpf/Common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #if defined(KPF_LIBRARY)
7 | # define KPFSHARED_EXPORT Q_DECL_EXPORT
8 | #else
9 | # define KPFSHARED_EXPORT Q_DECL_IMPORT
10 | #endif
11 |
12 | namespace Kpf {
13 | template
14 | class INotifyManager
15 | {
16 | public:
17 | using N = T;
18 |
19 | virtual ~INotifyManager() = default;
20 |
21 | // 注册监听器
22 | // 注册后,监听器所有权会转移至框架,由框架负责释放
23 | // 取消注册后,监听器所有权返还用户
24 | virtual void registerNotifier(T* notifier) = 0;
25 | virtual void unregisterNotifier(T* notifier) = 0;
26 | };
27 |
28 | template::value>
29 | struct ToDelivered;
30 | template
31 | struct ToDelivered
32 | {
33 | T* delivered(B* base)
34 | {
35 | return dynamic_cast(base);
36 | }
37 | };
38 | template
39 | struct ToDelivered
40 | {
41 | T* delivered(B*)
42 | {
43 | return nullptr;
44 | }
45 | };
46 | template
47 | T* toDelivered(B* base)
48 | {
49 | return ToDelivered().delivered(base);
50 | }
51 |
52 | template::value>
53 | struct ToBase;
54 | template
55 | struct ToBase
56 | {
57 | T* base(D* delivered)
58 | {
59 | return static_cast(delivered);
60 | }
61 | };
62 | template
63 | struct ToBase
64 | {
65 | T* base(D*)
66 | {
67 | return nullptr;
68 | }
69 | };
70 | template
71 | T* toBase(D* delivered)
72 | {
73 | return ToBase().base(delivered);
74 | }
75 | } // namesapce Kpf
76 |
77 | Q_DECLARE_METATYPE(QDomElement)
78 |
--------------------------------------------------------------------------------
/include/Kpf/Connection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | // ======== API声明 ========
5 |
6 | // 获取事件管理器对象,等同于Kpf::ConnectionManager::instance()
7 | #define kpfConnection
8 |
9 | namespace Kpf {
10 | // 信号槽连接信息对象
11 | struct KPFSHARED_EXPORT Connection
12 | {
13 | virtual ~Connection();
14 |
15 | QString sender; // 发送方对象名
16 | QByteArray signalName; // 信号方法
17 | QString receiver; // 接收方对象名
18 | QByteArray slotName; // 槽方法
19 | Qt::ConnectionType type; // 连接方式
20 | };
21 |
22 | struct IConnectionNotifier
23 | {
24 | virtual ~IConnectionNotifier() = default;
25 |
26 | virtual void connectionCreated(const QString& sender, const QByteArray& signal, const QString& receiver, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { Q_UNUSED(sender) Q_UNUSED(signal) Q_UNUSED(receiver) Q_UNUSED(slot) Q_UNUSED(type) }
27 | virtual void connectionRemoved(const QString& sender, const QByteArray& signal, const QString& receiver, const QByteArray& slot, Qt::ConnectionType type = Qt::AutoConnection) { Q_UNUSED(sender) Q_UNUSED(signal) Q_UNUSED(receiver) Q_UNUSED(slot) Q_UNUSED(type) }
28 | };
29 |
30 | class KPFSHARED_EXPORT ConnectionManager : public QObject, virtual public INotifyManager
31 | {
32 | Q_OBJECT
33 | public:
34 | virtual ~ConnectionManager() = default;
35 |
36 | static ConnectionManager& instance();
37 |
38 | /**
39 | * @brief createConnection 创建信号槽
40 | * @param sender 发送方对象名
41 | * @param signal 信号函数签名
42 | * @param receiver 接收方对象名
43 | * @param slot 槽函数签名
44 | * @param type 连接类型
45 | * @return 创建的信号槽连接信息对象,若创建失败,返回nullptr
46 | */
47 | virtual const QWeakPointer createConnection(const QString& sender, const QString& signal, const QString& receiver, const QString& slot, Qt::ConnectionType type = Qt::AutoConnection) = 0;
48 | // 根据配置节点创建信号槽,格式详见app.json
49 | virtual const QWeakPointer createConnection(const QDomElement& config) = 0;
50 | // 销毁信号槽连接
51 | virtual void removeConnection(QWeakPointer connection) = 0;
52 | // 获取当前已建立的所有信号槽连接
53 | virtual QList> connections(const QString& name) const = 0;
54 | };
55 | } // namespace Kpf
56 | // ======== API声明 ========
57 |
58 | #undef kpfConnection
59 | #define kpfConnection Kpf::ConnectionManager::instance()
60 |
--------------------------------------------------------------------------------
/include/Kpf/Constants.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | namespace Kpf {
5 | // 所有框架内置的配置文件关键字
6 | static const QString TAG_COMPONENTS = QStringLiteral("Components");
7 | static const QString TAG_COMPONENT = QStringLiteral("Component");
8 | static const QString TAG_OBJECTS = QStringLiteral("Objects");
9 | static const QString TAG_CLASS = QStringLiteral("Class");
10 | static const QString TAG_PUBEVENT = QStringLiteral("PubEvent");
11 | static const QString TAG_SUBEVENT = QStringLiteral("SubEvent");
12 | static const QString TAG_CONNECTION = QStringLiteral("Connection");
13 | static const QString TAG_CONNECTIONS = QStringLiteral("Connections");
14 | static const QString TAG_INITIALIZATIONS = QStringLiteral("Initializations");
15 | static const QString TAG_INITIALIZATION = QStringLiteral("Initialization");
16 | static const QString KEY_COMPONENT = QStringLiteral("component");
17 | static const QString KEY_CLASS = QStringLiteral("class");
18 | static const QString KEY_NAME = QStringLiteral("name");
19 | static const QString KEY_TEXT = QStringLiteral("text");
20 | static const QString KEY_QSS = QStringLiteral("qss");
21 | static const QString KEY_PARENT = QStringLiteral("parent");
22 | static const QString KEY_SUBTHREAD = QStringLiteral("subThread");
23 | static const QString KEY_THREADNAME = QStringLiteral("threadName");
24 | static const QString KEY_EVENTID = QStringLiteral("eventId");
25 | static const QString KEY_TOPIC = QStringLiteral("topic");
26 | static const QString KEY_SENDER = QStringLiteral("sender");
27 | static const QString KEY_SIGNAL = QStringLiteral("signal");
28 | static const QString KEY_RECEIVER = QStringLiteral("receiver");
29 | static const QString KEY_SLOT = QStringLiteral("slot");
30 | static const QString KEY_TYPE = QStringLiteral("type");
31 | static const QString KEY_OBJECT = QStringLiteral("object");
32 | static const QString KEY_METHO = QStringLiteral("method");
33 | static const QString KEY_ALREADYEXIST = QStringLiteral("alreadyExist");
34 |
35 | // 信号槽连接中连接方式对应字符串
36 | static const QMap ConnectionTypes =
37 | {
38 | { QStringLiteral("Auto"), Qt::AutoConnection },
39 | { QStringLiteral("Direct"), Qt::DirectConnection },
40 | { QStringLiteral("Queued"), Qt::QueuedConnection },
41 | { QStringLiteral("BlockingQueued"), Qt::BlockingQueuedConnection }
42 | };
43 |
44 | // 初始化函数签名,返回为false,输入参数可加入const和&修饰
45 | static QByteArray INIT_METHOD = "init(QDomElement)";
46 |
47 | // 框架相关的文件和文件夹
48 | static const QString DIR_PLUGINS = QStringLiteral("plugins");
49 | static const QStringList PLUGIN_SUFFIX = {
50 | QStringLiteral("*.dll"),
51 | QStringLiteral("*.so"),
52 | QStringLiteral("*.dylib")
53 | };
54 | static const QString DIR_CONFIG = QStringLiteral("config");
55 | static const QString FILE_APP = QStringLiteral("app.xml");
56 | static const QString DIR_COMPONENTS = QStringLiteral("components");
57 | static const QString DIR_STYLESHEETS = QStringLiteral("stylesheets");
58 | static const QString CONFIG_FILE_SUFFIX = QStringLiteral("xml");
59 | } // namespace Kpf
60 |
--------------------------------------------------------------------------------
/include/Kpf/Event.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | // ======== API声明 ========
5 |
6 | // 获取事件管理器对象,等同于Kpf::EventManager::instance()
7 | #define kpfEvent
8 |
9 | namespace Kpf {
10 | struct Topic;
11 | struct ObjectEvent;
12 | struct Object;
13 |
14 | struct KPFSHARED_EXPORT MetaEvent
15 | {
16 | enum Type { Publish, Subscribe };
17 | virtual ~MetaEvent();
18 |
19 | Type type;
20 | QString name;
21 | QString className;
22 | QSet eventObjects;
23 |
24 | protected:
25 | MetaEvent();
26 | };
27 |
28 | struct KPFSHARED_EXPORT ObjectEvent
29 | {
30 | virtual ~ObjectEvent();
31 |
32 | QWeakPointer event;
33 | QMap> topics;
34 |
35 | QWeakPointer