├── .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 | ![Build Status](https://img.shields.io/badge/TODO-travis-red.svg) 3 | ![Build Status](https://img.shields.io/badge/TODO-appveyor-red.svg) 4 | ![Coverage Status](https://img.shields.io/badge/TODO-coveralls-red.svg) 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/b8371eee6d744b778fb1a74c8368f42c)](https://app.codacy.com/gh/ZgblKylin/KylinPluginFramework?utm_source=github.com&utm_medium=referral&utm_content=ZgblKylin/KylinPluginFramework&utm_campaign=Badge_Grade_Settings) 6 | [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ZgblKylin/KylinPluginFramework) 7 | [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) 8 | [![LICENSE](https://img.shields.io/badge/license-MPL-green.svg)](https://www.mozilla.org/en-US/MPL/) 9 | [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](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 object; 36 | std::function func; 37 | 38 | QMap send(const QVariantList& args); 39 | void post(const QVariantList& args); 40 | }; 41 | 42 | struct IEventNotifier 43 | { 44 | virtual ~IEventNotifier() = default; 45 | 46 | virtual void pubEventRegistered(const QString& eventName) { Q_UNUSED(eventName) } 47 | virtual void subEventRegistered(const QString& eventName) { Q_UNUSED(eventName) } 48 | 49 | virtual void pubEventAdded(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignal = false) { Q_UNUSED(objectName) Q_UNUSED(eventName) Q_UNUSED(topicName) Q_UNUSED(isSignal) } 50 | virtual void subEventAdded(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignalOrSlot = false) { Q_UNUSED(objectName) Q_UNUSED(eventName) Q_UNUSED(topicName) Q_UNUSED(isSignalOrSlot) } 51 | 52 | virtual void sendEvent(const ObjectEvent& event, const QVariantList& args) { Q_UNUSED(event) Q_UNUSED(args) } 53 | virtual void postEvent(const ObjectEvent& event, const QVariantList& args) { Q_UNUSED(event) Q_UNUSED(args) } 54 | }; 55 | 56 | class KPFSHARED_EXPORT EventManager : public QObject, virtual public INotifyManager 57 | { 58 | Q_OBJECT 59 | public: 60 | virtual ~EventManager() = default; 61 | 62 | static EventManager& instance(); 63 | 64 | /** 65 | * @brief addPubEvent 添加事件发布 66 | * @param objectName 发布事件的对象名 67 | * @param event 事件标识 68 | * @param topic 事件的目标主题 69 | */ 70 | virtual void addPubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignal = false) = 0; 71 | /** 72 | * @brief addSubEvent 添加事件订阅 73 | * @param objectName 订阅事件的对象名 74 | * @param event 事件标识 75 | * @param topic 事件的来源主题 76 | */ 77 | virtual void addSubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignalOrSlot = false) = 0; 78 | 79 | virtual void registerPubEvent(const QString& eventName, ObjectEvent* eventObject) = 0; 80 | virtual void registerSubEvent(const QString& eventName, ObjectEvent* eventObject) = 0; 81 | }; 82 | } // namespace Kpf 83 | // ======== API声明 ======== 84 | 85 | #undef kpfEvent 86 | #define kpfEvent Kpf::EventManager::instance() 87 | -------------------------------------------------------------------------------- /include/Kpf/EventHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | // ======== API声明 ======== 7 | // 在类内部声明发布事件,eventId为事件名称 8 | #define KPF_PUBEVENT(eventId) 9 | // 在类内部声明订阅事件,eventId为事件名称,method为对应的函数 10 | // 若编译出错,检查method输入/输出是否无法转换为QVariant 11 | #define KPF_SUBEVENT(eventId, method) 12 | // 同步发布事件的宏函数,eventId为事件名称,后续为输入参数列表,返回QVariant 13 | #define kSendEvent(eventId, ...) 14 | // 异步发布事件的宏函数 15 | #define kPostEvent(eventId, ...) 16 | // ======== API声明 ======== 17 | 18 | #undef KPF_PUBEVENT 19 | #define KPF_PUBEVENT(eventId) \ 20 | struct KPF_PUBEVENT_##eventId : public Kpf::ObjectEvent \ 21 | { \ 22 | KPF_PUBEVENT_##eventId() \ 23 | { \ 24 | kpfEvent.registerPubEvent(#eventId, this); \ 25 | } \ 26 | }; \ 27 | KPF_PUBEVENT_##eventId kpf_pubevent_##eventId; 28 | 29 | //Q_SIGNAL QVariant kpfSendEvent_##eventId (const QVariantList& args); 30 | //Q_SIGNAL QVariant kpfPostEvent_##eventId (const QVariantList& args); 31 | 32 | #undef KPF_SUBEVENT 33 | #define KPF_SUBEVENT(eventId, method) \ 34 | struct KPF_SUBEVENT_##eventId : public Kpf::ObjectEvent \ 35 | { \ 36 | template \ 37 | KPF_SUBEVENT_##eventId(T* self) \ 38 | { \ 39 | func = [self](const QVariantList& args)->QVariant \ 40 | { \ 41 | using KpfSelf = typename std::remove_reference::type>::type; \ 42 | Kpf::EventHelper helper = \ 43 | Kpf::EventHelper(self, &KpfSelf::method); \ 44 | return helper.invoke(args); \ 45 | }; \ 46 | kpfEvent.registerSubEvent(#eventId, this); \ 47 | } \ 48 | }; \ 49 | KPF_SUBEVENT_##eventId kpf_subevent_##eventId = KPF_SUBEVENT_##eventId(this); 50 | 51 | #undef kSendEvent 52 | #define kSendEvent(eventId, ...) \ 53 | kpf_pubevent_##eventId.send(Kpf::packParams(__VA_ARGS__)); 54 | 55 | #undef kPostEvent 56 | #define kPostEvent(eventId, ...) \ 57 | kpf_pubevent_##eventId.post(Kpf::packParams(__VA_ARGS__)); 58 | 59 | namespace Kpf { 60 | 61 | /* 62 | * copy from qobjectdefs_impl.h 63 | * trick to set the return value of a slot that works even if the signal or the slot returns void 64 | * to be used like function(), ApplyReturnValue(ret.data()urn_value) 65 | * if function() returns a value, the operator,(T, ApplyReturnValue) is called, but if it 66 | * returns void, the builtin one is used without an error. 67 | */ 68 | template 69 | struct ApplyReturnValue 70 | { 71 | void *data; 72 | explicit ApplyReturnValue(void *data_) : data(data_) {} 73 | }; 74 | template 75 | void operator,(const T &value, const ApplyReturnValue &container) 76 | { 77 | if (container.data) { 78 | *reinterpret_cast(container.data) = value; 79 | } 80 | } 81 | template 82 | void operator,(T &&value, const ApplyReturnValue &container) 83 | { 84 | if (container.data) { 85 | *reinterpret_cast(container.data) = value; 86 | } 87 | } 88 | 89 | template 90 | inline QVariant resultGenerator() 91 | { 92 | int typeId = qMetaTypeId(); 93 | return QVariant(QVariant::Type(typeId)); 94 | } 95 | template<> 96 | inline QVariant resultGenerator() 97 | { 98 | return QVariant(); 99 | } 100 | 101 | template 102 | struct EventHelper; 103 | 104 | #define REMOVE_CONST_REF(T) typename std::remove_const::type>::type 105 | 106 | template 107 | struct EventHelper 108 | { 109 | using Func = Result(KpfSelf::*)(void); 110 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 111 | QVariant invoke(const QVariantList& args) { 112 | Q_UNUSED(args) 113 | QVariant ret = resultGenerator(); 114 | emit (s->*f)(), ApplyReturnValue(ret.data()); 115 | return ret; 116 | } 117 | protected: 118 | KpfSelf* s; 119 | Func f; 120 | }; 121 | 122 | template 123 | struct EventHelper 124 | { 125 | using Func = Result(KpfSelf::*)(Arg1); 126 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 127 | QVariant invoke(const QVariantList& args) { 128 | QVariant ret = resultGenerator(); 129 | if (args.count() >= 1) { 130 | emit (s->*f)(args.at(0).value()), 131 | ApplyReturnValue(ret.data()); 132 | } 133 | return ret; 134 | } 135 | protected: 136 | KpfSelf* s; 137 | Func f; 138 | }; 139 | 140 | template 141 | struct EventHelper 142 | { 143 | using Func = Result(KpfSelf::*)(Arg1, Arg2); 144 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 145 | QVariant invoke(const QVariantList& args) { 146 | QVariant ret = resultGenerator(); 147 | if (args.count() >= 2) { 148 | emit (s->*f)(args.at(0).value(), 149 | args.at(1).value()), 150 | ApplyReturnValue(ret.data()); 151 | } 152 | return ret; 153 | } 154 | protected: 155 | KpfSelf* s; 156 | Func f; 157 | }; 158 | 159 | template 160 | struct EventHelper 161 | { 162 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3); 163 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 164 | QVariant invoke(const QVariantList& args) { 165 | QVariant ret = resultGenerator(); 166 | if (args.count() >= 3) { 167 | emit (s->*f)(args.at(0).value(), 168 | args.at(1).value(), 169 | args.at(2).value()), 170 | ApplyReturnValue(ret.data()); 171 | } 172 | return ret; 173 | } 174 | protected: 175 | KpfSelf* s; 176 | Func f; 177 | }; 178 | 179 | template 180 | struct EventHelper 181 | { 182 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4); 183 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 184 | QVariant invoke(const QVariantList& args) { 185 | QVariant ret = resultGenerator(); 186 | if (args.count() >= 4) { 187 | emit (s->*f)(args.at(0).value(), 188 | args.at(1).value(), 189 | args.at(2).value(), 190 | args.at(3).value()), 191 | ApplyReturnValue(ret.data()); 192 | } 193 | return ret; 194 | } 195 | protected: 196 | KpfSelf* s; 197 | Func f; 198 | }; 199 | 200 | template 201 | struct EventHelper 202 | { 203 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4, Arg5); 204 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 205 | QVariant invoke(const QVariantList& args) { 206 | QVariant ret = resultGenerator(); 207 | if (args.count() >= 5) { 208 | emit (s->*f)(args.at(0).value(), 209 | args.at(1).value(), 210 | args.at(2).value(), 211 | args.at(3).value(), 212 | args.at(4).value()), 213 | ApplyReturnValue(ret.data()); 214 | } 215 | return ret; 216 | } 217 | protected: 218 | KpfSelf* s; 219 | Func f; 220 | }; 221 | 222 | template 223 | struct EventHelper 224 | { 225 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); 226 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 227 | QVariant invoke(const QVariantList& args) { 228 | QVariant ret = resultGenerator(); 229 | if (args.count() >= 6) { 230 | emit (s->*f)(args.at(0).value(), 231 | args.at(1).value(), 232 | args.at(2).value(), 233 | args.at(3).value(), 234 | args.at(4).value(), 235 | args.at(5).value()), 236 | ApplyReturnValue(ret.data()); 237 | } 238 | return ret; 239 | } 240 | protected: 241 | KpfSelf* s; 242 | Func f; 243 | }; 244 | 245 | template 246 | struct EventHelper 247 | { 248 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); 249 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 250 | QVariant invoke(const QVariantList& args) { 251 | QVariant ret = resultGenerator(); 252 | if (args.count() >= 7) { 253 | emit (s->*f)(args.at(0).value(), 254 | args.at(1).value(), 255 | args.at(2).value(), 256 | args.at(3).value(), 257 | args.at(4).value(), 258 | args.at(5).value(), 259 | args.at(6).value()), 260 | ApplyReturnValue(ret.data()); 261 | } 262 | return ret; 263 | } 264 | protected: 265 | KpfSelf* s; 266 | Func f; 267 | }; 268 | 269 | template 270 | struct EventHelper 271 | { 272 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8); 273 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 274 | QVariant invoke(const QVariantList& args) { 275 | QVariant ret = resultGenerator(); 276 | if (args.count() >= 8) { 277 | emit (s->*f)(args.at(0).value(), 278 | args.at(1).value(), 279 | args.at(2).value(), 280 | args.at(3).value(), 281 | args.at(4).value(), 282 | args.at(5).value(), 283 | args.at(6).value(), 284 | args.at(7).value()), 285 | ApplyReturnValue(ret.data()); 286 | } 287 | return ret; 288 | } 289 | protected: 290 | KpfSelf* s; 291 | Func f; 292 | }; 293 | 294 | template 295 | struct EventHelper 296 | { 297 | using Func = Result(KpfSelf::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9); 298 | EventHelper(KpfSelf* self, Func func) : s(self), f(func) {} 299 | QVariant invoke(const QVariantList& args) { 300 | QVariant ret = resultGenerator(); 301 | if (args.count() >= 9) { 302 | emit (s->*f)(args.at(0).value(), 303 | args.at(1).value(), 304 | args.at(2).value(), 305 | args.at(3).value(), 306 | args.at(4).value(), 307 | args.at(5).value(), 308 | args.at(6).value(), 309 | args.at(7).value(), 310 | args.at(8).value()), 311 | ApplyReturnValue(ret.data()); 312 | } 313 | return ret; 314 | } 315 | protected: 316 | KpfSelf* s; 317 | Func f; 318 | }; 319 | } // namespace Kpf 320 | -------------------------------------------------------------------------------- /include/Kpf/InvokeHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // ======== API声明 ======== 5 | namespace Kpf { 6 | // 变参模板函数,将任意多个输入值打包为QVariantList 7 | template 8 | QVariantList packParams(Args&&... args); 9 | 10 | /** 11 | * @brief InvokeMethodSyncHelper类,用于在目标对象线程中执行回调函数,等待并获取返回值 12 | */ 13 | class InvokeMethodSyncHelperPrivate; 14 | class KPFSHARED_EXPORT InvokeMethodSyncHelper : public QObject 15 | { 16 | Q_OBJECT 17 | public: 18 | // function为反射执行的函数,该函数会在context所在线程中执行 19 | InvokeMethodSyncHelper(QObject* context, const std::function& function); 20 | // function为反射执行的函数,该函数会在context所在线程中执行 21 | InvokeMethodSyncHelper(QObject* context, const std::function& function); 22 | // method为object对象中的的函数,该函数会在object所在线程中执行,arguments为参数列表 23 | InvokeMethodSyncHelper(QObject* object, const QMetaMethod& method); 24 | 25 | // 在目标对象所属线程中执行构造函数中的回调函数,阻塞等待函数执行完毕,返回执行结果 26 | QVariant invoke(bool* ok = nullptr); 27 | QVariant invoke(const QVariantList& args, bool* ok = nullptr); 28 | 29 | private: 30 | Q_DECLARE_PRIVATE(InvokeMethodSyncHelper) 31 | InvokeMethodSyncHelperPrivate* d_ptr; 32 | }; 33 | } // namespace Kpf 34 | // ======== API声明 ======== 35 | 36 | namespace Kpf { 37 | inline void packParamsHelper(QVariantList& ret) 38 | { 39 | Q_UNUSED(ret); 40 | } 41 | template 42 | void packParamsHelper(QVariantList& ret, Arg&& arg) 43 | { 44 | ret << QVariant::fromValue(arg); 45 | } 46 | // QVariant::fromValue compile failes with [ Arg = char* ] 47 | inline void packParamsHelper(QVariantList& ret, char* arg) 48 | { 49 | ret << QVariant::fromValue(QString::fromUtf8(arg)); 50 | } 51 | inline void packParamsHelper(QVariantList& ret, const char* arg) 52 | { 53 | ret << QVariant::fromValue(QString::fromUtf8(arg)); 54 | } 55 | 56 | template 57 | void packParamsHelper(QVariantList& ret, Arg&& arg, Args&&... args) 58 | { 59 | ret << QVariant::fromValue(arg); 60 | packParamsHelper(ret, std::forward(args)...); 61 | } 62 | // QVariant::fromValue compile failes with [ Arg = char* ] 63 | template 64 | void packParamsHelper(QVariantList& ret, char* arg, Args&&... args) 65 | { 66 | ret << QVariant::fromValue(QString::fromUtf8(arg)); 67 | packParamsHelper(ret, std::forward(args)...); 68 | } 69 | template 70 | void packParamsHelper(QVariantList& ret, const char* arg, Args&&... args) 71 | { 72 | ret << QVariant::fromValue(QString::fromUtf8(arg)); 73 | packParamsHelper(ret, std::forward(args)...); 74 | } 75 | 76 | template 77 | QVariantList packParams(Args&&... args) 78 | { 79 | QVariantList ret; 80 | packParamsHelper(ret, std::forward(args)...); 81 | return ret; 82 | } 83 | } // namespace Kpf 84 | -------------------------------------------------------------------------------- /include/Kpf/Kpf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | -------------------------------------------------------------------------------- /include/Kpf/KpfCore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // ======== API声明 ======== 11 | 12 | // 获取框架内核对象,等同于Kpf::KpfCore::instance() 13 | #define kpfCore 14 | 15 | namespace Kpf { 16 | struct ICoreNotifier 17 | { 18 | virtual ~ICoreNotifier() = default; 19 | 20 | virtual void beginInitialization() {} 21 | virtual void initializationFinished() {} 22 | 23 | virtual void loggerInitialized() {} 24 | 25 | // Plugins initialization 26 | virtual void beginLoadLibrary(const QFileInfo& library) { Q_UNUSED(library) } 27 | virtual void libraryLoaded(const QFileInfo& library) { Q_UNUSED(library) } 28 | virtual void libraryUnloaded(const QFileInfo& library) { Q_UNUSED(library) } 29 | 30 | // Config initialization 31 | virtual void componentLoaded(const QFileInfo& componentFile) { Q_UNUSED(componentFile) } 32 | virtual void appConfigLoaded() {} 33 | virtual void componentsExpanded() {} 34 | 35 | virtual void aboutToQuit() {} 36 | virtual void connectionManagerDestroyed() {} 37 | virtual void topicManagerDestroyed() {} 38 | virtual void eventManagerDestroyed() {} 39 | virtual void objectManagerDestroyed() {} 40 | virtual void threadManagerDestroyed() {} 41 | virtual void classManagerDestroyed() {} 42 | virtual void allLibraryUnloaded() {} 43 | virtual void quitFinished() {} 44 | }; 45 | 46 | /** 47 | * @brief KpfCore类,KPF框架内核API声明 48 | */ 49 | class KPFSHARED_EXPORT KpfCore : virtual public INotifyManager 50 | { 51 | public: 52 | virtual ~KpfCore() = default; 53 | 54 | // 获取内核对象 55 | static KpfCore& instance(); 56 | 57 | // 初始化内核,加载配置文件,需要在main函数中调用 58 | virtual bool init(int argc, char *argv[]) = 0; 59 | }; 60 | } // namespace Kpf 61 | // ======== API声明 ======== 62 | 63 | #undef kpfCore 64 | #define kpfCore ::Kpf::KpfCore::instance() 65 | -------------------------------------------------------------------------------- /include/Kpf/Object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // ======== API声明 ======== 6 | 7 | // 获取ObjectManager对象,等同于Kpf::ObjectManager::instance() 8 | #define kpfObject 9 | 10 | namespace Kpf { 11 | struct MetaClass; 12 | struct Thread; 13 | struct Object; 14 | 15 | // 当需要使用接口类时,接口类需继承自QObject或Kpf::Base 16 | // Kpf::Base可作为多继承环境下的替代品(因为QObject不允许多继承) 17 | struct KPFSHARED_EXPORT Base 18 | { 19 | explicit Base(QObject* self); 20 | virtual ~Base(); 21 | 22 | QSharedPointer getObject() const; 23 | QObject* getQObject() const; 24 | 25 | private: 26 | QObject* self = nullptr; 27 | }; 28 | 29 | struct KPFSHARED_EXPORT Object 30 | { 31 | virtual ~Object(); 32 | 33 | QSharedPointer objectClass; 34 | QString name; 35 | QDomElement config; 36 | QPointer object; 37 | Base* base; 38 | QSharedPointer thread; 39 | 40 | static QSharedPointer getObject(QObject* object); 41 | }; 42 | 43 | struct IObjectNotifier 44 | { 45 | virtual ~IObjectNotifier() = default; 46 | 47 | // Object initialization 48 | virtual void aboutToCreateObject(const QString& className, const QString& objectName) { Q_UNUSED(className) Q_UNUSED(objectName) } 49 | virtual void objectCreated(const QString& className, const QString& objectName) { Q_UNUSED(className) Q_UNUSED(objectName) } 50 | virtual void objectDestroyed(const QString& className, const QString& objectName) { Q_UNUSED(className) Q_UNUSED(objectName) } 51 | }; 52 | 53 | class KPFSHARED_EXPORT ObjectManager : public QObject, virtual public INotifyManager 54 | { 55 | Q_OBJECT 56 | public: 57 | virtual ~ObjectManager() = default; 58 | 59 | static ObjectManager& instance(); 60 | 61 | // 获取当前已创建的所有对象名 62 | virtual QStringList objectNames() const = 0; 63 | 64 | // 提供对象名,寻找对应的对象 65 | virtual QWeakPointer findObject(const QString& name) const = 0; 66 | template 67 | T* findObject(const QString& name) const; 68 | 69 | /** 70 | * @brief createObject 构造新对象 71 | * @param className 对象类名,也可配置于config的Class属性,非空时会覆盖config中配置 72 | * @param name 对象名称,也可配置于config的Name属性,非空时会覆盖config中配置 73 | * @param config 对象配置节点 74 | * @param parent 对象的父对象 75 | * @return 构造的新对象,若构造失败,返回nullptr 76 | */ 77 | virtual QWeakPointer createObject(QString name, QString className, QDomElement config = QDomElement(), QObject* parent = qApp) = 0; 78 | QWeakPointer createObject(QString className, const QDomElement& config = QDomElement(), QObject* parent = qApp); 79 | QWeakPointer createObject(const QDomElement& config, QObject* parent = qApp); 80 | template 81 | T* createObject(QString name, QString className, const QDomElement& config = QDomElement(), QObject* parent = qApp); 82 | template 83 | T* createObject(QString className, const QDomElement& config = QDomElement(), QObject* parent = qApp); 84 | template 85 | T* createObject(const QDomElement& config, QObject* parent = qApp); 86 | 87 | // 销毁对应名称的对象 88 | virtual void destroyObject(const QString& name) = 0; 89 | }; 90 | } // namespace Kpf 91 | // ======== API声明 ======== 92 | 93 | #undef kpfObject 94 | #define kpfObject Kpf::ObjectManager::instance() 95 | 96 | namespace Kpf { 97 | inline QObject* Base::getQObject() const 98 | { 99 | return const_cast(self); 100 | } 101 | 102 | template 103 | inline T* ObjectManager::findObject(const QString& name) const 104 | { 105 | QSharedPointer object = findObject(name).toStrongRef(); 106 | if (!object) return nullptr; 107 | T* ptr = toDelivered(object->base); 108 | if (!ptr) { 109 | ptr = toDelivered(object->object.data()); 110 | } 111 | return ptr; 112 | } 113 | 114 | inline QWeakPointer ObjectManager::createObject(QString className, const QDomElement& config, QObject* parent) 115 | { 116 | return createObject(config.attribute(KEY_NAME), className, config, parent); 117 | } 118 | 119 | inline QWeakPointer ObjectManager::createObject(const QDomElement& config, QObject* parent) 120 | { 121 | return createObject(config.attribute(KEY_NAME), config.attribute(KEY_CLASS), config, parent); 122 | } 123 | 124 | template 125 | T* ObjectManager::createObject(QString name, QString className, const QDomElement& config, QObject* parent) 126 | { 127 | QSharedPointer object = createObject(name, className, config, parent) 128 | .toStrongRef(); 129 | if (!object) 130 | { 131 | return nullptr; 132 | } 133 | else 134 | { 135 | T* ptr = toDelivered(object->base); 136 | if (!ptr) { 137 | ptr = toDelivered(object->object.data()); 138 | } 139 | if (!ptr) { 140 | destroyObject(object->name); 141 | } 142 | return ptr; 143 | } 144 | } 145 | 146 | template 147 | T* ObjectManager::createObject(QString className, const QDomElement& config, QObject* parent) 148 | { 149 | return createObject(config.attribute(KEY_NAME), className, config, parent); 150 | } 151 | 152 | template 153 | T* ObjectManager::createObject(const QDomElement& config, QObject* parent) 154 | { 155 | return createObject(config.attribute(KEY_NAME), config.attribute(KEY_CLASS), config, parent); 156 | } 157 | } // namespace Kpf 158 | -------------------------------------------------------------------------------- /include/Kpf/Thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // ======== API声明 ======== 5 | 6 | // 获取ThreadManager对象,等同于Kpf::ThreadManager::instance() 7 | #define kpfThread 8 | 9 | namespace Kpf { 10 | struct Object; 11 | 12 | struct KPFSHARED_EXPORT Thread 13 | { 14 | virtual ~Thread(); 15 | 16 | QThread* thread; 17 | QString name; 18 | 19 | QObject* eventBus; 20 | QSet objects; 21 | 22 | protected: 23 | Thread(); 24 | }; 25 | 26 | struct IThreadNotifier 27 | { 28 | virtual ~IThreadNotifier() = default; 29 | 30 | virtual void threadStarted(const QString& threadName) { Q_UNUSED(threadName) } 31 | virtual void threadStopped(const QString& threadName) { Q_UNUSED(threadName) } 32 | }; 33 | 34 | class KPFSHARED_EXPORT ThreadManager : public QObject, virtual public INotifyManager 35 | { 36 | Q_OBJECT 37 | public: 38 | virtual ~ThreadManager() = default; 39 | 40 | static ThreadManager& instance(); 41 | 42 | virtual QStringList threadNames() const = 0; 43 | virtual QWeakPointer findThread(const QString& threadName) const = 0; 44 | virtual QWeakPointer defaultThread() const = 0; 45 | virtual void removeThread(const QWeakPointer& thread) = 0; 46 | }; 47 | } // namesapace Kpf 48 | // ======== API声明 ======== 49 | 50 | #undef kpfThread 51 | #define kpfThread Kpf::ThreadManager::instance() 52 | 53 | -------------------------------------------------------------------------------- /include/Kpf/Topic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // ======== API声明 ======== 5 | 6 | // 获取TopicManager对象,等同于Kpf::TopicManager::instance() 7 | #define kpfTopic 8 | 9 | namespace Kpf { 10 | struct ObjectEvent; 11 | 12 | struct KPFSHARED_EXPORT Topic 13 | { 14 | virtual ~Topic(); 15 | 16 | QString name; 17 | QSet publishedEvents; 18 | QSet subscribedEvents; 19 | QMap> threadEvents; 20 | 21 | protected: 22 | Topic(); 23 | }; 24 | 25 | class KPFSHARED_EXPORT TopicManager : public QObject 26 | { 27 | Q_OBJECT 28 | public: 29 | virtual ~TopicManager() = default; 30 | 31 | static TopicManager& instance(); 32 | 33 | virtual QStringList topicNames() const = 0; 34 | virtual QWeakPointer findTopic(const QString& name) const = 0; 35 | }; 36 | } // namespace Kpf 37 | // ======== API声明 ======== 38 | 39 | #undef kpfTopic 40 | #define kpfTopic Kpf::TopicManager::instance() 41 | -------------------------------------------------------------------------------- /src/app/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include "ui_MainWindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | MainWindow::~MainWindow() 12 | { 13 | delete ui; 14 | } 15 | 16 | bool MainWindow::init(const QDomElement& config) 17 | { 18 | qInfo() << "MainWindow: initialized at thread" << QThread::currentThread() 19 | << ",it's belonging thread is" << thread() 20 | << ", main thread is" << qApp->thread(); 21 | 22 | QDomElement centralWidgetConfig = config.firstChildElement(QStringLiteral("CentralWidget")); 23 | QWidget* centralWidget = kpfObject.createObject(centralWidgetConfig, this); 24 | if (centralWidget) { 25 | setCentralWidget(centralWidget); 26 | } 27 | 28 | return true; 29 | } 30 | 31 | QString MainWindow::testEvent(QString text) 32 | { 33 | qInfo() << "MainWindow: receive testEvent with arg =" << text 34 | << "invoke thread is" << QThread::currentThread() 35 | << "it's belonging thread is" << thread() 36 | << ", main thread is" << qApp->thread(); 37 | return text; 38 | } 39 | 40 | void MainWindow::changeEvent(QEvent *e) 41 | { 42 | QMainWindow::changeEvent(e); 43 | switch (e->type()) { 44 | case QEvent::LanguageChange: 45 | ui->retranslateUi(this); 46 | break; 47 | default: 48 | break; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | class MainWindow : public QMainWindow 12 | { 13 | Q_OBJECT 14 | KPF_SUBEVENT(TestEvent, testEvent) 15 | 16 | public: 17 | explicit MainWindow(QWidget* parent = nullptr); 18 | virtual ~MainWindow(); 19 | 20 | Q_SLOT bool init(const QDomElement& config); 21 | 22 | Q_SLOT QString testEvent(QString text); 23 | 24 | protected: 25 | virtual void changeEvent(QEvent* event) override; 26 | 27 | private: 28 | Ui::MainWindow* ui; 29 | }; 30 | KPF_REGISTER(MainWindow) 31 | 32 | #endif // MAINWINDOW_H 33 | -------------------------------------------------------------------------------- /src/app/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 0 22 | 400 23 | 22 24 | 25 | 26 | 27 | 28 | 29 | TopToolBarArea 30 | 31 | 32 | false 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/app/app.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-06-01T20:31:10 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui xml 8 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 9 | 10 | TEMPLATE = app 11 | CONFIG += c++11 12 | 13 | win32:CONFIG(release, debug|release): TARGET = app 14 | else:win32:CONFIG(debug, debug|release): TARGET = appd 15 | else:unix:!macx: TARGET = app 16 | DESTDIR = $$PWD/../../bin 17 | 18 | # The following define makes your compiler emit warnings if you use 19 | # any feature of Qt which has been marked as deprecated (the exact warnings 20 | # depend on your compiler). Please consult the documentation of the 21 | # deprecated API in order to know how to port your code away from it. 22 | DEFINES += QT_DEPRECATED_WARNINGS 23 | 24 | # You can also make your code fail to compile if you use deprecated APIs. 25 | # In order to do so, uncomment the following line. 26 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 27 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 28 | 29 | SOURCES += \ 30 | main.cpp \ 31 | MainWindow.cpp 32 | 33 | HEADERS += \ 34 | MainWindow.h 35 | 36 | FORMS += \ 37 | MainWindow.ui 38 | 39 | DISTFILES += \ 40 | $$PWD/../../bin/config/app.json \ 41 | $$PWD/../../bin/components/test.json \ 42 | $$PWD/../../bin/config/app.xml \ 43 | $$PWD/../../bin/components/test.xml 44 | 45 | include($$PWD/../../Kpf.pri) 46 | -------------------------------------------------------------------------------- /src/app/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication app(argc, argv); 8 | 9 | if (!kpfCore.init(argc, argv)) { 10 | return -1; 11 | } 12 | 13 | return app.exec(); 14 | } 15 | -------------------------------------------------------------------------------- /src/core/Class.cpp: -------------------------------------------------------------------------------- 1 | #include "ClassImpl.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::MetaClass::~MetaClass() 5 | { 6 | } 7 | 8 | Kpf::MetaClass::MetaClass() 9 | { 10 | } 11 | 12 | Kpf::MetaClassImpl::~MetaClassImpl() 13 | { 14 | } 15 | 16 | QSharedPointer Kpf::MetaClassImpl::create(QSharedPointer library, const QString& name, QMetaObject metaObject, const std::function& constructor) 17 | { 18 | QSharedPointer ret(new MetaClassImpl); 19 | ret->library = library; 20 | ret->name = name; 21 | ret->metaObject = metaObject; 22 | ret->constructor = constructor; 23 | return ret; 24 | } 25 | 26 | Kpf::MetaClassImpl::MetaClassImpl() 27 | { 28 | } 29 | 30 | Kpf::ClassManager& Kpf::ClassManager::instance() 31 | { 32 | return kpfCoreImpl.classManager(); 33 | } 34 | 35 | Kpf::ClassManagerImpl::ClassManagerImpl() 36 | { 37 | } 38 | 39 | Kpf::ClassManagerImpl::~ClassManagerImpl() 40 | { 41 | QMutexLocker locker(kpfMutex()); 42 | while (!classNames.isEmpty()) { 43 | classes.remove(classNames.pop()); 44 | } 45 | } 46 | 47 | Kpf::ClassManagerImpl& Kpf::ClassManagerImpl::instance() 48 | { 49 | return kpfCoreImpl.classManager(); 50 | } 51 | 52 | QStringList Kpf::ClassManagerImpl::availableClassNames() const 53 | { 54 | QMutexLocker locker(kpfMutex()); 55 | return classes.keys(); 56 | } 57 | 58 | QWeakPointer Kpf::ClassManagerImpl::findClass(const QString& className) const 59 | { 60 | QMutexLocker locker(kpfMutex()); 61 | return classes.value(className); 62 | } 63 | 64 | void Kpf::ClassManagerImpl::registerClass(const QString& className, QMetaObject metaObject, const std::function& constructor) 65 | { 66 | QMutexLocker locker(kpfMutex()); 67 | QSharedPointer classImpl = MetaClassImpl::create(kpfCoreImpl.currentLibrary().toStrongRef(), 68 | className, 69 | metaObject, 70 | constructor); 71 | classNames.push(className); 72 | classes.insert(className, classImpl); 73 | notify(&N::classRegistered, className); 74 | } 75 | -------------------------------------------------------------------------------- /src/core/ClassImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "CommonPrivate.h" 5 | #include "Library.h" 6 | #include "EventImpl.h" 7 | 8 | #ifdef Q_CC_MSVC 9 | #pragma warning(push) 10 | #pragma warning(disable:4250) 11 | #endif 12 | 13 | namespace Kpf { 14 | struct MetaClassImpl : public MetaClass 15 | { 16 | virtual ~MetaClassImpl() override; 17 | 18 | static QSharedPointer create(QSharedPointer library, 19 | const QString& name, 20 | QMetaObject metaObject, 21 | const std::function& constructor); 22 | 23 | QSharedPointer library; 24 | 25 | std::function constructor; 26 | 27 | QMap> publishedEvents; 28 | QMap> subscribedEvents; 29 | 30 | private: 31 | MetaClassImpl(); 32 | }; 33 | 34 | class ClassManagerImpl : public ClassManager, public NotifyManager 35 | { 36 | Q_OBJECT 37 | public: 38 | ClassManagerImpl(); 39 | virtual ~ClassManagerImpl() override; 40 | 41 | static ClassManagerImpl& instance(); 42 | 43 | // ClassManager interface 44 | virtual QStringList availableClassNames() const override; 45 | virtual QWeakPointer findClass(const QString& className) const override; 46 | 47 | protected: 48 | virtual void registerClass(const QString& className, QMetaObject metaObject, const std::function& constructor) override; 49 | 50 | QStack classNames; 51 | QMap> classes; 52 | }; 53 | } // namespace Kpf 54 | #define kpfClassImpl Kpf::ClassManagerImpl::instance() 55 | 56 | #ifdef Q_CC_MSVC 57 | #pragma warning(pop) 58 | #endif 59 | -------------------------------------------------------------------------------- /src/core/CommonPrivate.cpp: -------------------------------------------------------------------------------- 1 | #include "CommonPrivate.h" 2 | #include "KpfPrivate.h" 3 | #include "KpfCoreImpl.h" 4 | #include "RegisterQtClasses.h" 5 | 6 | const QLoggingCategory& kpf() 7 | { 8 | static const QLoggingCategory category("kpf", QtWarningMsg); 9 | return category; 10 | } 11 | 12 | QString normalizedSignature(QString signature) 13 | { 14 | if (signature.isEmpty()) { 15 | return {}; 16 | } 17 | 18 | signature = QMetaObject::normalizedSignature(signature.toUtf8().constData()); 19 | int index = signature.indexOf(QLatin1Char('(')); 20 | QString ret = signature.left(index + 1); 21 | 22 | signature = signature.mid(index + 1); 23 | signature.chop(1); 24 | 25 | std::function appendNormalizeType = 26 | [](QString& ret, QByteArray& typeName){ 27 | int typeId = QMetaType::type(typeName.constData()); 28 | typeName = QMetaType::typeName(typeId); 29 | ret += QString::fromUtf8(typeName); 30 | ret += ','; 31 | typeName.clear(); 32 | }; 33 | 34 | int brackets = 0; 35 | int parentheses = 0; 36 | int pointyBrackets = 0; 37 | QByteArray typeName; 38 | for (QChar ch : signature) 39 | { 40 | char c = ch.toLatin1(); 41 | switch (c) 42 | { 43 | case '[': 44 | brackets += 1; 45 | break; 46 | 47 | case ']': 48 | brackets -= 1; 49 | break; 50 | 51 | case '(': 52 | parentheses += 1; 53 | break; 54 | 55 | case ')': 56 | parentheses -= 1; 57 | break; 58 | 59 | case '<': 60 | pointyBrackets += 1; 61 | break; 62 | 63 | case '>': 64 | pointyBrackets -= 1; 65 | break; 66 | 67 | case ',': 68 | { 69 | if ((brackets != 0) 70 | || (parentheses != 0) 71 | || (pointyBrackets != 0)) 72 | { 73 | break; 74 | } 75 | 76 | appendNormalizeType(ret, typeName); 77 | continue; 78 | } 79 | 80 | default: 81 | break; 82 | } 83 | 84 | typeName += c; 85 | } 86 | appendNormalizeType(ret, typeName); 87 | 88 | if (ret.endsWith(',')) { 89 | ret.chop(1); 90 | } 91 | ret += ')'; 92 | ret = QMetaObject::normalizedSignature(ret.toUtf8().constData()); 93 | return ret; 94 | } 95 | 96 | QByteArray convertSignalName(QByteArray signal) 97 | { 98 | signal.prepend(QByteArray::number(QSIGNAL_CODE)); 99 | #ifndef QT_NO_DEBUG 100 | const char* location = QLOCATION; 101 | size_t locationLen = 1 + strlen(&(location[1])); 102 | QByteArray l(location, int(locationLen)); 103 | signal += l; 104 | #endif 105 | return signal; 106 | } 107 | 108 | QByteArray convertSlotName(QByteArray slot) 109 | { 110 | const char* location = 111 | #ifdef QT_NO_DEBUG 112 | nullptr; 113 | #else 114 | QLOCATION; 115 | #endif 116 | size_t locationLen = 1 + strlen(&(location[1])); 117 | QByteArray l(location, int(locationLen)); 118 | slot.prepend(QByteArray::number(QSLOT_CODE)); 119 | slot += l; 120 | return slot; 121 | } 122 | 123 | QMutex* kpfMutex() 124 | { 125 | return kpfCoreImpl.mutex(); 126 | } 127 | -------------------------------------------------------------------------------- /src/core/CommonPrivate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | const QLoggingCategory& kpf(); 6 | 7 | QString normalizedSignature(QString signature); 8 | QByteArray convertSignalName(QByteArray signal); 9 | QByteArray convertSlotName(QByteArray slot); 10 | 11 | QMutex* kpfMutex(); 12 | 13 | template 14 | using Ptr = T*; 15 | template 16 | using Ref = T&; 17 | 18 | class Defer 19 | { 20 | public: 21 | Defer() = default; 22 | Defer(std::function onDelete) : onDel(onDelete) {} 23 | ~Defer() { if (onDel) { onDel(); } } 24 | 25 | Defer(Defer&& other) : onDel(other.onDel) {} 26 | Defer& operator=(Defer&& other) { onDel = other.onDel; return *this; } 27 | Defer& operator=(std::function onDelete) { onDel = onDelete; return *this; } 28 | void reset() { onDel = {}; } 29 | 30 | private: 31 | Defer(const Defer&) = delete; 32 | Defer& operator=(const Defer&) = delete; 33 | std::function onDel; 34 | }; 35 | #define DEFER_STRCAT_2(A, B) A ## B 36 | #define DEFER_STRCAT(A, B) DEFER_STRCAT_2(A, B) 37 | #define DEFER_TEMPNAME DEFER_STRCAT(__defer, __LINE__) 38 | #define defer Defer DEFER_TEMPNAME; DEFER_TEMPNAME = 39 | 40 | template 41 | class NotifyManager : virtual public Kpf::INotifyManager 42 | { 43 | public: 44 | virtual ~NotifyManager(); 45 | 46 | virtual void registerNotifier(T* notifier) final; 47 | virtual void unregisterNotifier(T* notifier) final; 48 | 49 | template 50 | void notify(Func func, Args... args); 51 | 52 | protected: 53 | QSet notifiers; 54 | }; 55 | 56 | template 57 | NotifyManager::~NotifyManager() 58 | { 59 | qDeleteAll(notifiers); 60 | } 61 | 62 | template 63 | void NotifyManager::registerNotifier(T* notifier) 64 | { 65 | QMutexLocker locker(kpfMutex()); 66 | notifiers.insert(notifier); 67 | } 68 | 69 | template 70 | void NotifyManager::unregisterNotifier(T* notifier) 71 | { 72 | QMutexLocker locker(kpfMutex()); 73 | notifiers.remove(notifier); 74 | } 75 | 76 | template 77 | template 78 | void NotifyManager::notify(Func func, Args... args) 79 | { 80 | for(T* notifier : notifiers) 81 | { 82 | (notifier->*func)(std::forward(args)...); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/core/Connection.cpp: -------------------------------------------------------------------------------- 1 | #include "ConnectionImpl.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::ConnectionImpl::~ConnectionImpl() 5 | { 6 | } 7 | 8 | QSharedPointer Kpf::ConnectionImpl::create(QString sender, QByteArray signalName, QString receiver, QByteArray slotName, Qt::ConnectionType type, QWeakPointer senderPtr, QWeakPointer receiverPtr) 9 | { 10 | QSharedPointer ret(new ConnectionImpl); 11 | ret->sender = sender; 12 | ret->signalName = signalName; 13 | ret->receiver = receiver; 14 | ret->slotName = slotName; 15 | ret->type = type; 16 | ret->senderPtr = senderPtr; 17 | ret->receiverPtr = receiverPtr; 18 | return ret; 19 | } 20 | 21 | Kpf::ConnectionImpl::ConnectionImpl() 22 | { 23 | } 24 | 25 | Kpf::ConnectionManagerImpl::ConnectionManagerImpl() 26 | { 27 | } 28 | 29 | Kpf::ConnectionManagerImpl::~ConnectionManagerImpl() 30 | { 31 | } 32 | 33 | Kpf::ConnectionManagerImpl& Kpf::ConnectionManagerImpl::instance() 34 | { 35 | return kpfCoreImpl.connectionManager(); 36 | } 37 | 38 | const QWeakPointer Kpf::ConnectionManagerImpl::createConnection(const QString& senderName, const QString& signalName, const QString& receiverName, const QString& slotName, Qt::ConnectionType type) 39 | { 40 | QMutexLocker locker(kpfMutex()); 41 | QSharedPointer sender = kpfObject.findObject(senderName) 42 | .toStrongRef() 43 | .staticCast(); 44 | if (!sender) 45 | { 46 | qCWarning(kpf) << "Create connection failed" 47 | << "from sender" << senderName 48 | << "of signal" << signalName 49 | << "to receiver" << receiverName 50 | << "of method" << slotName 51 | << "with type" << type 52 | << ": cannot find sender"<< senderName; 53 | return {}; 54 | } 55 | 56 | QSharedPointer receiver = kpfObject.findObject(receiverName) 57 | .toStrongRef() 58 | .staticCast(); 59 | if(!receiver) 60 | { 61 | qCWarning(kpf) << "Create connection failed" 62 | << "from sender" << senderName 63 | << "of signal" << signalName 64 | << "to receiver" << receiverName 65 | << "of method" << slotName 66 | << "with type" << type 67 | << ": cannot find receiver"<< receiverName; 68 | return {}; 69 | } 70 | 71 | QObject* senderPtr = sender->object; 72 | QObject* receiverPtr = receiver->object; 73 | 74 | QMetaObject::Connection connection; 75 | QSharedPointer c = ConnectionImpl::create(senderName, 76 | signalName.toUtf8(), 77 | receiverName, 78 | slotName.toUtf8(), 79 | type, 80 | sender, 81 | receiver); 82 | c->sender = senderName; 83 | c->signalName = signalName.toUtf8(); 84 | c->receiver = receiverName; 85 | c->slotName = slotName.toUtf8(); 86 | c->type = type; 87 | c->senderPtr = sender; 88 | c->receiverPtr = receiver; 89 | 90 | connection = createConnection(senderName, senderPtr, signalName, 91 | receiverName, receiverPtr, slotName, 92 | type); 93 | c->connection = connection; 94 | if (connection) 95 | { 96 | sender->connections.append(c); 97 | receiver->connections.append(c); 98 | return c.staticCast(); 99 | } 100 | else 101 | { 102 | return {}; 103 | } 104 | } 105 | 106 | const QWeakPointer Kpf::ConnectionManagerImpl::createConnection(const QDomElement& config) 107 | { 108 | QMutexLocker locker(kpfMutex()); 109 | 110 | QString sender = config.attribute(KEY_SENDER); 111 | QString signal = config.attribute(KEY_SIGNAL); 112 | QString receiver = config.attribute(KEY_RECEIVER); 113 | QString slot = config.attribute(KEY_SLOT); 114 | QString type = config.attribute(KEY_TYPE, ConnectionTypes.key(Qt::AutoConnection)); 115 | if(!ConnectionTypes.contains(type)) { 116 | qCWarning(kpf) << "Invalid connection type" << type; 117 | } 118 | 119 | return createConnection(sender, signal, receiver, slot, ConnectionTypes.value(type)); 120 | } 121 | 122 | void Kpf::ConnectionManagerImpl::removeConnection(QWeakPointer connection) 123 | { 124 | QMutexLocker locker(kpfMutex()); 125 | 126 | QSharedPointer c = connection.toStrongRef().staticCast(); 127 | 128 | auto compareFunc = [c](const QSharedPointer& obj)->bool 129 | { return obj == c; }; 130 | 131 | QSharedPointer sender = kpfObject.findObject(c->sender) 132 | .toStrongRef() 133 | .staticCast(); 134 | auto it = std::find_if(sender->connections.begin(), 135 | sender->connections.end(), 136 | compareFunc); 137 | while (it != sender->connections.end()) 138 | { 139 | sender->connections.erase(it); 140 | it = std::find_if(sender->connections.begin(), 141 | sender->connections.end(), 142 | compareFunc); 143 | } 144 | 145 | QSharedPointer receiver = kpfObject.findObject(c->receiver) 146 | .toStrongRef() 147 | .staticCast(); 148 | it = std::find_if(receiver->connections.begin(), 149 | receiver->connections.end(), 150 | compareFunc); 151 | while (it != receiver->connections.end()) 152 | { 153 | receiver->connections.erase(it); 154 | it = std::find_if(receiver->connections.begin(), 155 | receiver->connections.end(), 156 | compareFunc); 157 | } 158 | 159 | if (!sender && !receiver) { 160 | return; 161 | } 162 | 163 | disconnect(c->connection); 164 | 165 | qCDebug(kpf) << "Remove connection" 166 | << "from sender" << c->sender 167 | << "of signal" << c->signalName 168 | << "to receiver" << c->receiver 169 | << "of method" << c->slotName 170 | << "with type" << c->type; 171 | notify(&N::connectionRemoved, c->sender, c->signalName, c->receiver, c->slotName, c->type); 172 | } 173 | 174 | QList> Kpf::ConnectionManagerImpl::connections(const QString& name) const 175 | { 176 | QMutexLocker locker(kpfMutex()); 177 | 178 | QList> ret; 179 | QSharedPointer object = kpfObject.findObject(name) 180 | .toStrongRef() 181 | .staticCast(); 182 | if (!object) { 183 | return ret; 184 | } 185 | for (QSharedPointer connection : object->connections) 186 | { 187 | ret.append(connection.staticCast()); 188 | } 189 | return ret; 190 | } 191 | 192 | QMetaObject::Connection Kpf::ConnectionManagerImpl::createConnection(const QString& senderName, QObject* senderPtr, QString signalName, const QString& receiverName, QObject* receiverPtr, QString slotName, Qt::ConnectionType type) 193 | { 194 | QMutexLocker locker(kpfMutex()); 195 | 196 | if (!senderPtr) 197 | { 198 | qCWarning(kpf) << "Create connection failed" 199 | << "from sender" << senderName 200 | << "of signal" << signalName 201 | << "to receiver" << receiverName 202 | << "of method" << slotName 203 | << "with type" << type 204 | << ": sender is nullptr"; 205 | return {}; 206 | } 207 | if(!receiverPtr) 208 | { 209 | qCWarning(kpf) << "Create connection failed" 210 | << "from sender" << senderName 211 | << "of signal" << signalName 212 | << "to receiver" << receiverName 213 | << "of method" << slotName 214 | << "with type" << type 215 | << ": receiver is nullptr"; 216 | return {}; 217 | } 218 | 219 | const QMetaObject* senderClass = senderPtr->metaObject(); 220 | const QMetaObject* receiverClass = receiverPtr->metaObject(); 221 | 222 | signalName = normalizedSignature(signalName); 223 | slotName = normalizedSignature(slotName); 224 | 225 | QMetaMethod signal; 226 | bool find = false; 227 | int index = senderClass->indexOfMethod(signalName.toUtf8().constData()); 228 | if (index >= 0) 229 | { 230 | signal = senderClass->method(index); 231 | find = (signal.methodType() == QMetaMethod::Signal); 232 | } 233 | if (!find) 234 | { 235 | qCWarning(kpf) << "Create connection failed" 236 | << "from sender" << senderName 237 | << "of signal" << signalName 238 | << "to receiver" << receiverName 239 | << "of method" << slotName 240 | << "with type" << type 241 | << ": cannot find given signal in sender"; 242 | return {}; 243 | } 244 | 245 | QMetaMethod slot; 246 | find = false; 247 | index = receiverClass->indexOfMethod(slotName.toUtf8().constData()); 248 | if (index >= 0) 249 | { 250 | slot = receiverClass->method(index); 251 | find = ((slot.methodType() != QMetaMethod::Constructor) 252 | && (slot.methodType() != QMetaMethod::Method)); 253 | } 254 | if (!find) 255 | { 256 | qCWarning(kpf) << "Create connection failed" 257 | << "from sender" << senderName 258 | << "of signal" << signalName 259 | << "to receiver" << receiverName 260 | << "of method" << slotName 261 | << "with type" << type 262 | << ": cannot find given method in receiver"; 263 | return {}; 264 | } 265 | 266 | QMetaObject::Connection connection = connect(senderPtr, 267 | signal, 268 | receiverPtr, 269 | slot, 270 | type); 271 | if (!connection) 272 | { 273 | qCWarning(kpf) << "Create connection failed" 274 | << "from sender" << senderName 275 | << "of signal" << signalName 276 | << "to receiver" << receiverName 277 | << "of method" << slotName 278 | << "with type" << type 279 | << ": signal and method are not compatible"; 280 | } 281 | 282 | notify(&N::connectionCreated, senderName, signalName.toUtf8(), receiverName, slotName.toUtf8(), type); 283 | 284 | return connection; 285 | } 286 | 287 | Kpf::Connection::~Connection() 288 | { 289 | } 290 | 291 | Kpf::ConnectionManager& Kpf::ConnectionManager::instance() 292 | { 293 | return kpfCoreImpl.connectionManager(); 294 | } 295 | -------------------------------------------------------------------------------- /src/core/ConnectionImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "CommonPrivate.h" 5 | #include "ObjectImpl.h" 6 | 7 | #ifdef Q_CC_MSVC 8 | #pragma warning(push) 9 | #pragma warning(disable:4250) 10 | #endif 11 | 12 | namespace Kpf { 13 | struct ConnectionImpl : public Connection 14 | { 15 | virtual ~ConnectionImpl() override; 16 | 17 | static QSharedPointer create(QString sender, 18 | QByteArray signalName, 19 | QString receiver, 20 | QByteArray slotName, 21 | Qt::ConnectionType type, 22 | QWeakPointer senderPtr, 23 | QWeakPointer receiverPtr); 24 | 25 | QMetaObject::Connection connection; 26 | QWeakPointer senderPtr; 27 | QWeakPointer receiverPtr; 28 | 29 | private: 30 | ConnectionImpl(); 31 | }; 32 | 33 | class ConnectionManagerImpl : public ConnectionManager, public NotifyManager 34 | { 35 | Q_OBJECT 36 | public: 37 | ConnectionManagerImpl(); 38 | virtual ~ConnectionManagerImpl() override; 39 | 40 | static ConnectionManagerImpl& instance(); 41 | 42 | // ConnectionManager interface 43 | virtual const QWeakPointer createConnection(const QString& sender, const QString& signal, const QString& receiver, const QString& slot, Qt::ConnectionType type = Qt::AutoConnection) override; 44 | virtual const QWeakPointer createConnection(const QDomElement& config) override; 45 | virtual void removeConnection(QWeakPointer connection) override; 46 | virtual QList > connections(const QString& name) const override; 47 | 48 | private: 49 | QMetaObject::Connection createConnection(const QString& senderName, QObject* senderPtr, QString signalName, const QString& receiverName, QObject* receiverPtr, QString slotName, Qt::ConnectionType type); 50 | }; 51 | } // namespace Kpf 52 | #define kpfConnectionImpl Kpf::ConnectionManagerImpl::instance() 53 | 54 | #ifdef Q_CC_MSVC 55 | #pragma warning(pop) 56 | #endif 57 | -------------------------------------------------------------------------------- /src/core/CoreDump/CoreDump.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef Q_OS_WIN 3 | #include 4 | #endif 5 | #include "CoreDump.h" 6 | #include 7 | #include "Dump.h" 8 | #include "SystemInfo.h" 9 | 10 | static QDir dir; 11 | static std::function callback; 12 | 13 | QStringList dumpSystemInfo() 14 | { 15 | SystemInfo info; 16 | 17 | QStringList ret; 18 | 19 | QLocale locale = QLocale::system(); 20 | 21 | auto CpuState = [&locale](const CPUState& cpuState) 22 | { 23 | QStringList ret; 24 | ret << QStringLiteral(" Used Rate: %1%").arg(cpuState.userate, 0, 'f', 2, QLatin1Char('0')); 25 | ret << QStringLiteral(" System Time: %1").arg(locale.toString(cpuState.system, 'f')); 26 | ret << QStringLiteral(" User Time: %1").arg(locale.toString(cpuState.user, 'f')); 27 | ret << QStringLiteral(" Nice Time: %1").arg(locale.toString(cpuState.nice, 'f')); 28 | ret << QStringLiteral(" Idle Time: %1").arg(locale.toString(cpuState.idle, 'f')); 29 | return ret; 30 | }; 31 | CompleteCPUState cpuState = info.cpuState(); 32 | ret << QStringLiteral("Cpu State"); 33 | ret << QStringLiteral(" Total State:"); 34 | ret << CpuState(cpuState.total); 35 | for (int i = 0; i < cpuState.childCore.count(); ++i) 36 | { 37 | CPUState coreState = cpuState.childCore.at(i); 38 | ret << QStringLiteral(" Core %1 State:").arg(i); 39 | ret << CpuState(coreState); 40 | } 41 | ret[ret.count() - 1] += QLatin1Char('\n'); 42 | 43 | MemoryState memoryState = info.memoryState(); 44 | ret << QStringLiteral("Memory State"); 45 | ret << QStringLiteral(" Used Rate: %1%").arg(memoryState.userate, 0, 'f', 2, QLatin1Char('0')); 46 | ret << QStringLiteral(" Total Physics Memory: %1").arg(locale.toString(memoryState.totalPhys.convertToB().value(), 'f', 0)); 47 | ret << QStringLiteral(" Free Pyhsics Memory: %1").arg(locale.toString(memoryState.freePhys.convertToB().value(), 'f', 0)); 48 | ret << QStringLiteral(" Total Virtual Memory: %1").arg(locale.toString(memoryState.totalVirtual.convertToB().value(), 'f', 0)); 49 | ret << QStringLiteral(" Total Page: %1").arg(locale.toString(memoryState.totalPage, 'f', 0)); 50 | ret << QStringLiteral(" Free Page: %1\n").arg(locale.toString(memoryState.freePage, 'f', 0)); 51 | 52 | ret << QStringLiteral("Disk State"); 53 | for (const QFileInfo& drive : QDir::drives()) 54 | { 55 | DiskState diskState = info.diskState(drive.absoluteFilePath()); 56 | ret << QStringLiteral(" Drive %1").arg(drive.absoluteFilePath()); 57 | ret << QStringLiteral(" Used Rate: %1%").arg(diskState.userate, 0, 'f', 2, QLatin1Char('0')); 58 | ret << QStringLiteral(" Block Size: %1").arg(locale.toString(diskState.blockSize, 'f', 0)); 59 | ret << QStringLiteral(" Free Size: %1").arg(locale.toString(diskState.freeSize.convertToB().value(), 'f', 0)); 60 | ret << QStringLiteral(" Available Size: %1").arg(locale.toString(diskState.availableSize.convertToB().value(), 'f', 0)); 61 | } 62 | 63 | return ret; 64 | } 65 | 66 | [[noreturn]] void signalHandler(int sig) 67 | { 68 | if (callback) { 69 | callback(sig); 70 | } 71 | 72 | QString dumpProcessOutput = ::dump(dir); 73 | 74 | QString dateTime = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh_mm_ss")); 75 | 76 | QByteArray signal; 77 | switch(sig) 78 | { 79 | case SIGINT: 80 | signal = "SIGINT"; 81 | break; 82 | case SIGILL: 83 | signal = "SIGILL"; 84 | break; 85 | case SIGFPE: 86 | signal = "SIGFPE"; 87 | break; 88 | case SIGSEGV: 89 | signal = "SIGSEGV"; 90 | break; 91 | case SIGTERM: 92 | signal = "SIGTERM"; 93 | break; 94 | case SIGABRT: 95 | signal = "SIGABRT"; 96 | break; 97 | default: 98 | signal = QByteArray::number(sig); 99 | break; 100 | }; 101 | 102 | QFile file(dir.absoluteFilePath(dateTime + QStringLiteral(".txt"))); 103 | file.open(QFile::WriteOnly | QFile::Truncate | QFile::Text); 104 | 105 | QTextStream ts(&file); 106 | ts.setCodec(QTextCodec::codecForName("UTF-8")); 107 | 108 | qDebug() << "Signal" << signal.constData(); 109 | ts << "Signal " << signal << endl; 110 | qDebug() << "========"; 111 | ts << "======== " << endl; 112 | 113 | qDebug(); 114 | ts << endl; 115 | qDebug() << "Generating core dump ..."; 116 | ts << "Generating core dump ..." << endl; 117 | qDebug() << dumpProcessOutput.toUtf8().constData(); 118 | ts << dumpProcessOutput.toUtf8().constData(); 119 | qDebug() << "Core dump generated"; 120 | ts << "Core dump generated" << endl; 121 | 122 | qDebug(); 123 | ts << endl; 124 | qDebug() << "Current Call Stack:"; 125 | ts << "Current Call Stack:" << endl; 126 | for (const QString& stack : ::stackWalk()) 127 | { 128 | qDebug() << stack.toUtf8().constData(); 129 | ts << stack.toUtf8().constData() << endl; 130 | } 131 | 132 | qDebug(); 133 | ts << endl; 134 | for (const QString& str : ::dumpSystemInfo()) 135 | { 136 | qDebug() << str.toUtf8().constData(); 137 | ts << str.toUtf8().constData() << endl; 138 | } 139 | 140 | file.flush(); 141 | while(file.waitForBytesWritten(100)) {} 142 | file.close(); 143 | 144 | QThread::currentThread()->terminate(); 145 | #ifdef Q_OS_WIN 146 | ::TerminateProcess(::GetCurrentProcess(), UINT(-sig)); 147 | #elif defined(Q_OS_LINUX) 148 | QProcess::execute(QStringLiteral("kill"), 149 | { QStringLiteral("-9"), 150 | QString::number(qApp->applicationPid()) }); 151 | #endif 152 | std::exit(-sig); 153 | } 154 | 155 | [[noreturn]] void terminateHandler() 156 | { 157 | signalHandler(SIGTERM); 158 | } 159 | 160 | CoreDump::CoreDump(QObject* parent) 161 | : QObject(parent) 162 | { 163 | dir = QDir(qApp->applicationDirPath() 164 | + QDir::separator() 165 | + QStringLiteral("Dump")); 166 | 167 | if (!dir.exists()) { 168 | dir.mkpath(dir.absolutePath()); 169 | } 170 | 171 | std::signal(SIGINT, &signalHandler); 172 | std::signal(SIGILL, &signalHandler); 173 | std::signal(SIGFPE, &signalHandler); 174 | std::signal(SIGSEGV, &signalHandler); 175 | std::signal(SIGTERM, &signalHandler); 176 | std::signal(SIGABRT, &signalHandler); 177 | std::set_terminate(&terminateHandler); 178 | } 179 | 180 | CoreDump::~CoreDump() 181 | { 182 | } 183 | 184 | QStringList CoreDump::stackWalk() 185 | { 186 | return ::stackWalk(); 187 | } 188 | 189 | QStringList CoreDump::dumpSystemInfo() 190 | { 191 | return ::dumpSystemInfo(); 192 | } 193 | 194 | void CoreDump::dump(const QString& dir) 195 | { 196 | ::dump(QDir(dir)); 197 | } 198 | 199 | void CoreDump::registerCallback(std::function cb) 200 | { 201 | callback = cb; 202 | } 203 | -------------------------------------------------------------------------------- /src/core/CoreDump/CoreDump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | class CoreDump : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit CoreDump(QObject* parent = nullptr); 11 | virtual ~CoreDump(); 12 | 13 | QStringList stackWalk(); 14 | QStringList dumpSystemInfo(); 15 | void dump(const QString& dir); 16 | void registerCallback(std::function callback); 17 | }; 18 | KPF_REGISTER(CoreDump) 19 | -------------------------------------------------------------------------------- /src/core/CoreDump/CoreDump.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/SystemInfoInterface.h \ 3 | $$PWD/SystemInfoPrivate.h \ 4 | $$PWD/SystemInfoType.h \ 5 | $$PWD/CoreDump.h \ 6 | $$PWD/DataSizeHelper.h \ 7 | $$PWD/Dump.h \ 8 | $$PWD/SystemInfo.h 9 | 10 | SOURCES += \ 11 | $$PWD/CoreDump.cpp \ 12 | $$PWD/SystemInfo.cpp \ 13 | 14 | win32 { 15 | SOURCES += \ 16 | $$PWD/SystemInfo_Windows.cpp \ 17 | $$PWD/Dump_Windows.cpp 18 | 19 | LIBS += -ldbghelp 20 | LIBS += -lntdll 21 | } 22 | 23 | unix { 24 | SOURCES += \ 25 | $$PWD/SystemInfo_Unix.cpp \ 26 | $$PWD/Dump_Unix.cpp 27 | } 28 | -------------------------------------------------------------------------------- /src/core/CoreDump/DataSizeHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | // 数据大小的单位 6 | enum class DataSizeUnit 7 | { 8 | B = 1, //< 字节 9 | 10 | KB = 1000, //< 10^3 字节 11 | MB = 1000 * 1000, //< 10^6 字节 12 | GB = 1000 * 1000 * 1000, //< 10^9 字节 13 | 14 | KiB = 1024, //< 2^10 字节 15 | MiB = 1024 * 1024, //< 2^20 字节 16 | GiB = 1024 * 1024 * 1024, //< 2^30 字节 17 | }; 18 | 19 | class DataSize : public QPair 20 | { 21 | public: 22 | inline DataSize(); 23 | inline explicit DataSize(double value); 24 | inline DataSize(double value, DataSizeUnit unit); 25 | inline DataSize(const DataSize& other); 26 | inline DataSize& operator=(const DataSize& ); 27 | 28 | // 创建一个空的 DataSize 29 | inline static DataSize null(); 30 | 31 | // 是否为空 32 | inline bool isNull() const; 33 | 34 | // 解析数据大小的字符串 35 | static inline DataSize fromString(const QString& data); 36 | 37 | // 加\减运算 38 | inline friend DataSize operator+(const DataSize& arg1, const DataSize& arg2); 39 | inline friend DataSize operator-(const DataSize& arg1, const DataSize& arg2); 40 | 41 | // 转换数据大小的单位 42 | inline DataSize convertTo(DataSizeUnit targetUnit) const; 43 | inline DataSize convertToB() const; 44 | inline DataSize convertToKB() const; 45 | inline DataSize convertToMB() const; 46 | inline DataSize convertToGB() const; 47 | inline DataSize convertToKiB() const; 48 | inline DataSize convertToMiB() const; 49 | inline DataSize convertToGiB() const; 50 | 51 | public: 52 | inline double value() const; 53 | inline DataSizeUnit unit() const; 54 | 55 | private: 56 | double& _value; 57 | DataSizeUnit& _unit; 58 | }; 59 | 60 | DataSize::DataSize() 61 | : DataSize(-1, DataSizeUnit::B) 62 | { 63 | } 64 | 65 | DataSize::DataSize(double value) 66 | : DataSize(value, DataSizeUnit::B) 67 | { 68 | } 69 | 70 | DataSize::DataSize(double value, DataSizeUnit unit) 71 | : QPair(value, unit) 72 | , _value(this->first) 73 | , _unit(this->second) 74 | { 75 | } 76 | 77 | DataSize::DataSize(const DataSize& other) 78 | : DataSize(other._value, other._unit) 79 | { 80 | } 81 | 82 | DataSize& DataSize::operator=(const DataSize& other) 83 | { 84 | if (this == &other) 85 | { 86 | return *this; 87 | } 88 | this->_value = other._value; 89 | this->_unit = other._unit; 90 | return *this; 91 | } 92 | 93 | DataSize DataSize::null() 94 | { 95 | return DataSize(); 96 | } 97 | 98 | bool DataSize::isNull() const 99 | { 100 | // 如果值小于0则认为为空 101 | return (_value < 0); 102 | } 103 | 104 | DataSize DataSize::fromString(const QString& data) 105 | { 106 | //< 如果小于两个字符,则返回 107 | if (data.size() < 2) 108 | { 109 | return DataSize::null(); 110 | } 111 | //< 检测最后为字符 112 | if (!data.endsWith('B', Qt::CaseInsensitive)) 113 | { 114 | return DataSize::null(); 115 | } 116 | //< 检测倒数第2、3个字符 117 | int penultLetter = data.at(data.size() - 2).toUpper().digitValue(); 118 | DataSizeUnit unit = DataSizeUnit::B; 119 | QString valueStr = data.left(data.size() - 2); //< 值的字符串 120 | switch (penultLetter) 121 | { 122 | case 'K': 123 | unit = DataSizeUnit::KB; 124 | break; 125 | case 'M': 126 | unit = DataSizeUnit::MB; 127 | break; 128 | case 'G': 129 | unit = DataSizeUnit::GB; 130 | break; 131 | case 'I': 132 | { 133 | if (data.size() < 3) 134 | { 135 | return DataSize::null(); 136 | } 137 | int antepenultLetter = data.at(data.size() - 3).toUpper().digitValue(); 138 | valueStr = data.left(data.size() - 3); //< 值的字符串 139 | switch (antepenultLetter) 140 | { 141 | case 'K': 142 | unit = DataSizeUnit::KiB; 143 | break; 144 | case 'M': 145 | unit = DataSizeUnit::MiB; 146 | break; 147 | case 'G': 148 | unit = DataSizeUnit::GiB; 149 | break; 150 | default: 151 | return DataSize::null(); 152 | } 153 | break; 154 | } 155 | default: 156 | break; 157 | } 158 | bool convertResult = false;; 159 | double value = valueStr.toDouble(&convertResult); 160 | if (!convertResult) 161 | { 162 | return DataSize::null(); 163 | } 164 | return DataSize(value, unit); 165 | } 166 | 167 | DataSize operator+(const DataSize& arg1, const DataSize& arg2) 168 | { 169 | // 检测是否为空 170 | if (arg1.isNull() || arg2.isNull()) 171 | { 172 | return DataSize::null(); 173 | } 174 | // 统一单位 175 | DataSize result = arg2; 176 | if (arg1._unit != arg2._unit) 177 | { 178 | result = arg2.convertTo(arg1._unit); 179 | } 180 | result._value = arg1._value + result._value; 181 | return result; 182 | } 183 | 184 | DataSize operator-(const DataSize& arg1, const DataSize& arg2) 185 | { 186 | // 检测是否为空 187 | if (arg1.isNull() || arg2.isNull()) 188 | { 189 | return DataSize::null(); 190 | } 191 | // 统一单位 192 | DataSize result = arg2; 193 | if (arg1._unit != arg2._unit) 194 | { 195 | result = arg2.convertTo(arg1._unit); 196 | } 197 | result._value = arg1._value - result._value; 198 | return result; 199 | } 200 | 201 | DataSize DataSize::convertTo(DataSizeUnit targetUnit) const 202 | { 203 | // 如果单位与目标单位一致,则直接返回当前值 204 | if (this->_unit == targetUnit) 205 | { 206 | return *this; 207 | } 208 | if (this->_value < 0) 209 | { 210 | return DataSize::null(); 211 | } 212 | double valueOfByte = this->_value * static_cast(this->_unit); 213 | double valueOfTarget = valueOfByte / static_cast(targetUnit); 214 | return DataSize(valueOfTarget, targetUnit); 215 | } 216 | 217 | DataSize DataSize::convertToB() const 218 | { 219 | return convertTo(DataSizeUnit::B); 220 | } 221 | 222 | DataSize DataSize::convertToKB() const 223 | { 224 | return convertTo(DataSizeUnit::KB); 225 | } 226 | 227 | DataSize DataSize::convertToMB() const 228 | { 229 | return convertTo(DataSizeUnit::MB); 230 | } 231 | 232 | DataSize DataSize::convertToGB() const 233 | { 234 | return convertTo(DataSizeUnit::GB); 235 | } 236 | 237 | DataSize DataSize::convertToKiB() const 238 | { 239 | return convertTo(DataSizeUnit::KiB); 240 | } 241 | 242 | DataSize DataSize::convertToMiB() const 243 | { 244 | return convertTo(DataSizeUnit::MiB); 245 | } 246 | 247 | DataSize DataSize::convertToGiB() const 248 | { 249 | return convertTo(DataSizeUnit::GiB); 250 | } 251 | 252 | double DataSize::value() const 253 | { 254 | return _value; 255 | } 256 | 257 | DataSizeUnit DataSize::unit() const 258 | { 259 | return _unit; 260 | } 261 | -------------------------------------------------------------------------------- /src/core/CoreDump/Dump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | QString dump(const QDir& dir); 5 | QStringList stackWalk(); 6 | -------------------------------------------------------------------------------- /src/core/CoreDump/Dump_Unix.cpp: -------------------------------------------------------------------------------- 1 | #include "Dump.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | QString dump(const QDir& dir) 8 | { 9 | QProcess process; 10 | process.setProgram(QStringLiteral("procdump")); 11 | process.setArguments({ 12 | QStringLiteral("-p"), 13 | QString::number(qApp->applicationPid()) 14 | }); 15 | process.setWorkingDirectory(dir.absolutePath()); 16 | process.setProcessChannelMode(QProcess::ForwardedChannels); 17 | process.start(); 18 | process.waitForFinished(-1); 19 | return QString::fromUtf8(process.readAll()); 20 | } 21 | 22 | QStringList stackWalk() 23 | { 24 | QStringList ret; 25 | 26 | void* callStack[256]; 27 | size_t size; 28 | char** strings; 29 | 30 | size = backtrace(callStack, 256); 31 | strings = backtrace_symbols(callStack, size); 32 | 33 | for(size_t i=0;i 2 | #include 3 | #include 4 | #include 5 | #ifdef Q_CC_MINGW 6 | # include 7 | #endif 8 | #include "Dump.h" 9 | 10 | inline void displayError() 11 | { 12 | DWORD dwErrorCode = GetLastError(); 13 | LPTSTR lpMsgBuf = NULL; 14 | QString msg = QStringLiteral("Error code: %1").arg(dwErrorCode); 15 | if(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 16 | NULL, 17 | dwErrorCode, 18 | 0, 19 | LPTSTR(&lpMsgBuf), 20 | 0, 21 | NULL) != 0) 22 | { 23 | msg += QStringLiteral(" - "); 24 | msg += QString::fromWCharArray(lpMsgBuf).remove('\r').remove('\n'); 25 | } 26 | qDebug() << msg; 27 | } 28 | 29 | char* unDecorate(const char* symbol) 30 | { 31 | #ifdef Q_CC_MINGW // demangle by MinGW 32 | int status = 0; 33 | QString gccSymbol = QStringLiteral("_%1").arg(symbol); 34 | char* demangled = ::abi::__cxa_demangle(gccSymbol.toUtf8().constData(), 35 | nullptr, nullptr, &status); 36 | if (status == 0) { 37 | return demangled; 38 | } else { 39 | return nullptr; 40 | } 41 | #elif defined(Q_CC_MSVC) // undecorate by MSVC 42 | PCHAR strName = new CHAR[65536]; 43 | memset(strName, 0, 65536); 44 | DWORD dwNameLen = ::UnDecorateSymbolName(symbol, 45 | strName, 46 | 65536, 47 | UNDNAME_COMPLETE); 48 | if((dwNameLen == 0) || (strncmp(symbol, strName, dwNameLen) == 0)) { 49 | return nullptr; 50 | } else { 51 | return strName; 52 | } 53 | #else 54 | return nullptr; 55 | #endif 56 | } 57 | 58 | QStringList stackWalk(HANDLE hProcess, HANDLE hThread, DWORD dwThreadId, HANDLE hCurrentThread) 59 | { 60 | static const quint32 MaxRecursionCount = 256; 61 | 62 | QStringList ret; 63 | 64 | CONTEXT Context; 65 | memset(&Context, 0, sizeof(Context)); 66 | Context.ContextFlags = CONTEXT_FULL; 67 | 68 | if(hThread == hCurrentThread) 69 | RtlCaptureContext(&Context); 70 | else 71 | { 72 | SuspendThread(hThread); 73 | if (GetThreadContext(hThread, &Context) == FALSE) 74 | { 75 | qDebug() << "Cannot get context for thread" << dwThreadId; 76 | displayError(); 77 | ResumeThread(hThread); 78 | return ret; 79 | } 80 | } 81 | 82 | STACKFRAME StackFrame; 83 | memset(&StackFrame, 0, sizeof(STACKFRAME)); 84 | 85 | DWORD MachineType; 86 | #if defined(Q_PROCESSOR_X86_32) 87 | MachineType = IMAGE_FILE_MACHINE_I386; 88 | StackFrame.AddrPC.Offset = Context.Eip; 89 | StackFrame.AddrPC.Mode = AddrModeFlat; 90 | StackFrame.AddrFrame.Offset = Context.Ebp; 91 | StackFrame.AddrFrame.Mode = AddrModeFlat; 92 | StackFrame.AddrStack.Offset = Context.Esp; 93 | StackFrame.AddrStack.Mode = AddrModeFlat; 94 | #elif defined(Q_PROCESSOR_X86_64) 95 | MachineType = IMAGE_FILE_MACHINE_AMD64; 96 | StackFrame.AddrPC.Offset = Context.Rip; 97 | StackFrame.AddrPC.Mode = AddrModeFlat; 98 | StackFrame.AddrFrame.Offset = Context.Rsp; 99 | StackFrame.AddrFrame.Mode = AddrModeFlat; 100 | StackFrame.AddrStack.Offset = Context.Rsp; 101 | StackFrame.AddrStack.Mode = AddrModeFlat; 102 | #elif defined(Q_PROCESSOR_IA64) 103 | MachineType = IMAGE_FILE_MACHINE_IA64; 104 | StackFrame.AddrPC.Offset = Context.StIIP; 105 | StackFrame.AddrPC.Mode = AddrModeFlat; 106 | StackFrame.AddrFrame.Offset = Context.IntSp; 107 | StackFrame.AddrFrame.Mode = AddrModeFlat; 108 | StackFrame.AddrBStore.Offset = Context.RsBSP; 109 | StackFrame.AddrBStore.Mode = AddrModeFlat; 110 | StackFrame.AddrStack.Offset = Context.IntSp; 111 | StackFrame.AddrStack.Mode = AddrModeFlat; 112 | #else 113 | ret << "Platform not supported!"; 114 | return ret; 115 | #endif 116 | 117 | quint32 curRecursionCount = 0; 118 | bool recursion = false; 119 | while(StackWalk(MachineType, 120 | hProcess, 121 | hThread, 122 | &StackFrame, 123 | &Context, 124 | PREAD_PROCESS_MEMORY_ROUTINE(ReadProcessMemory), 125 | SymFunctionTableAccess, 126 | SymGetModuleBase, 127 | NULL) == TRUE) 128 | { 129 | if(StackFrame.AddrFrame.Offset == 0) 130 | break; 131 | 132 | if(StackFrame.AddrPC.Offset == StackFrame.AddrReturn.Offset) 133 | { 134 | if(recursion && (curRecursionCount > MaxRecursionCount)) 135 | { 136 | recursion = false; 137 | qDebug() << QStringLiteral("Endless callstack at 0x%1!") 138 | .arg(StackFrame.AddrPC.Offset, 0, 16, QLatin1Char('0')); 139 | break; 140 | } 141 | recursion = true; 142 | curRecursionCount++; 143 | } 144 | 145 | BYTE Symbol[sizeof(IMAGEHLP_SYMBOL) + 1024]; 146 | memset(Symbol, 0, sizeof(Symbol)); 147 | PIMAGEHLP_SYMBOL pSymbol = reinterpret_cast(Symbol); 148 | pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); 149 | pSymbol->MaxNameLength = 1024; 150 | 151 | #ifdef Q_OS_WIN64 152 | DWORD64 dwOffsetFromSymbol = 0; 153 | #else 154 | DWORD dwOffsetFromSymbol = 0; 155 | #endif 156 | if(SymGetSymFromAddr(hProcess, 157 | StackFrame.AddrPC.Offset, 158 | &dwOffsetFromSymbol, 159 | pSymbol) == FALSE) { 160 | ret << QStringLiteral("Cannot get function symbol from AddrPC 0x%1") 161 | .arg(StackFrame.AddrPC.Offset, 0, 16, QLatin1Char('0')); 162 | displayError(); 163 | continue; 164 | } 165 | 166 | char* symbolName = unDecorate(pSymbol->Name); 167 | 168 | IMAGEHLP_LINE Line; 169 | memset(&Line, 0, sizeof(Line)); 170 | Line.SizeOfStruct = sizeof(IMAGEHLP_LINE); 171 | DWORD dwOffsetFromLine = 0; 172 | 173 | bool bLine = true; 174 | if(SymGetLineFromAddr(hProcess, 175 | StackFrame.AddrPC.Offset, 176 | &dwOffsetFromLine, 177 | &Line) == FALSE) { 178 | // qDebug("Cannot get line info from addr 0x%lX", StackFrame.AddrPC.Offset); 179 | // ts << QStringLiteral("Cannot get line info from addr 0x%1") 180 | // .arg(StackFrame.AddrPC.Offset, 0, 16, QLatin1Char('0')) 181 | // << endl; 182 | // displayError(); 183 | bLine = false; 184 | } 185 | 186 | if(bLine) 187 | { 188 | ret << QStringLiteral("%1:%2 - %3") 189 | .arg(Line.FileName) 190 | .arg(Line.LineNumber) 191 | .arg(symbolName?symbolName:pSymbol->Name); 192 | } 193 | else 194 | { 195 | ret << QString(symbolName?symbolName:pSymbol->Name); 196 | } 197 | free(symbolName); 198 | } 199 | 200 | if(hThread != hCurrentThread) 201 | ResumeThread(hThread); 202 | 203 | return ret; 204 | } 205 | 206 | QString dump(const QDir& dir) 207 | { 208 | QProcess process ; 209 | process.setProgram(QStringLiteral("procdump.exe")); 210 | process.setArguments({ 211 | QStringLiteral("-ma"), 212 | QString::number(qApp->applicationPid()), 213 | QStringLiteral("-accepteula") 214 | }); 215 | process.setWorkingDirectory(dir.absolutePath()); 216 | process.start(); 217 | process.waitForFinished(-1); 218 | return QString::fromUtf8(process.readAll()); 219 | } 220 | 221 | QStringList stackWalk() 222 | { 223 | QStringList ret; 224 | 225 | HANDLE hProcess = GetCurrentProcess(); 226 | HANDLE hCurrentThread = GetCurrentThread(); 227 | 228 | if(SymInitialize(hProcess, 229 | NULL, 230 | TRUE) == FALSE) 231 | { 232 | ret << "Cannot initialize symbol"; 233 | displayError(); 234 | return ret; 235 | } 236 | 237 | ret += stackWalk(hProcess, 238 | hCurrentThread, 239 | GetCurrentThreadId(), 240 | hCurrentThread); 241 | 242 | if(SymCleanup(hProcess) == FALSE) 243 | { 244 | qDebug() << "SymCleanup failed symbol"; 245 | displayError(); 246 | return ret; 247 | } 248 | return ret; 249 | } 250 | -------------------------------------------------------------------------------- /src/core/CoreDump/Library.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | DESTDIR = $$PWD/../../../../../bin 3 | CONFIG(release, debug | release) : TARGET = Debugging 4 | CONFIG(debug, debug | release) : TARGET = Debuggingd 5 | 6 | DEFINES += DEBUGGING_LIBRARY 7 | 8 | include(Debugging.pri) 9 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "SystemInfoType.h" 3 | #include 4 | 5 | class SystemInfoPrivate; 6 | class SystemInfo : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | Q_ENUMS(AutoPushFlag) 11 | 12 | public: 13 | // 自动推送标记 14 | Q_PROPERTY(AutoPush::Flag autoPushFlag READ autoPushFlag WRITE setAutoPushFlag) 15 | // 自动推送间隔时间 16 | Q_PROPERTY(int timeInterval READ timeInterval WRITE setTimeInterval) 17 | 18 | public: 19 | SystemInfo(QObject* parent = nullptr); 20 | ~SystemInfo(); 21 | 22 | public: 23 | /****************************************************** 24 | * 属性值的 getter and setter 接口 25 | ******************************************************/ 26 | 27 | /** 28 | * @brief autoPushFlag 29 | * @return 30 | */ 31 | AutoPush::Flag autoPushFlag() const; 32 | 33 | /** 34 | * @brief timeInterval 35 | * @return 36 | */ 37 | int timeInterval() const; 38 | 39 | /** 40 | * @brief setAutoPushFlag 41 | * @param value 42 | */ 43 | void setAutoPushFlag(AutoPush::Flag value); 44 | 45 | /** 46 | * @brief setTimeInterval 47 | * @param value 48 | */ 49 | void setTimeInterval(int value); 50 | 51 | public: 52 | /****************************************************** 53 | * 公开的其他接口 54 | ******************************************************/ 55 | 56 | /** 57 | * @brief 获取CPU的的状态信息 58 | * @return 59 | */ 60 | CompleteCPUState cpuState() const; 61 | 62 | /** 63 | * @brief 获取内存的状态 64 | * @return 65 | */ 66 | MemoryState memoryState() const; 67 | 68 | /** 69 | * @brief 获取磁盘指定目录的状态 70 | * @return 71 | */ 72 | DiskState diskState(const QString& dir) const; 73 | 74 | /** 75 | * @brief 清除推送的磁盘目录 76 | */ 77 | void clearPushDiskDir(); 78 | 79 | /** 80 | * @brief 增加推送的磁盘目录 81 | * @param dir 82 | */ 83 | void addPushDiskDir(const QString& dir); 84 | 85 | /** 86 | * @brief 增加cpu检测阈值 87 | * @param rate 使用率 88 | */ 89 | void addCPUAlterRate(double rate); 90 | 91 | /** 92 | * @brief 增加内存检测阈值(使用率) 93 | * @param rate 使用率 94 | */ 95 | void addMemoryAlterRate(double rate); 96 | 97 | /** 98 | * @brief 增加内存检测阈值(使用量) 99 | * @param usage 使用量 100 | */ 101 | void addMemoryAlterUsage(double usage); 102 | 103 | /** 104 | * @brief 增加磁盘检测阈值(使用率) 105 | * @param dir 106 | * @param threshold 107 | */ 108 | void addDiskAlterRate(const QString& dir, double rate); 109 | 110 | /** 111 | * @brief 增加磁盘检测阈值(使用量) 112 | * @param dir 113 | * @param usage 114 | */ 115 | void addDiskAlterUsage(const QString& dir, double usage); 116 | 117 | /** 118 | * @brief 删除cpu检测阈值 119 | * @param rate 120 | */ 121 | void removeCPUAlterRate(double rate); 122 | 123 | /** 124 | * @brief 删除内存检测阈值(使用率) 125 | * @param rate 126 | */ 127 | void removeMemoryAlterRate(double rate); 128 | 129 | /** 130 | * @brief 删除内存检测阈值(使用量) 131 | * @param usage 132 | */ 133 | void removeMemoryAlterUsage(double usage); 134 | 135 | /** 136 | * @brief 删除磁盘检测阈值(使用量) 137 | * @param dir 138 | * @param usage 139 | */ 140 | void removeDiskAlterUsage(const QString& dir, double usage); 141 | 142 | /** 143 | * @brief 删除磁盘检测阈值(使用率) 144 | * @param dir 145 | * @param rate 146 | */ 147 | void removeDiskAlterRate(const QString& dir, double rate); 148 | 149 | /** 150 | * @brief 清空cpu检测阈值 151 | * @param rate 152 | */ 153 | void clearCPUAlterRate(); 154 | 155 | /** 156 | * @brief 清空内存检测阈值(使用率) 157 | */ 158 | void clearMemoryAlterRate(); 159 | 160 | /** 161 | * @brief 清空内存检测阈值(使用量) 162 | */ 163 | void clearMemoryAlterUsage(); 164 | 165 | /** 166 | * @brief 清空磁盘检测阈值(使用率) 167 | * @param dir 168 | */ 169 | void clearDiskAlterRate(const QString& dir); 170 | 171 | /** 172 | * @brief 清空磁盘检测阈值(使用量) 173 | * @param dir 174 | */ 175 | void clearDiskAlterUsage(const QString& dir); 176 | 177 | signals: 178 | /** 179 | * @brief pushCPUUsageRate 推送CPU的使用率 180 | * @param coreId 181 | * @param ratio 182 | */ 183 | void pushCPUUsageRate(int coreId, double ratio); 184 | 185 | /** 186 | * @brief 推送内存的使用量 187 | * @param remain 单位为 GB 188 | */ 189 | void pushMemoryUsage(double usage); 190 | 191 | /** 192 | * @brief 推送内存的使用率 193 | * @param rate 194 | */ 195 | void pushMemoryUsageRate(double rate); 196 | 197 | /** 198 | * @brief 推送内存的剩余量 199 | * @param rate 单位为 GB 200 | */ 201 | void pushMemoryRemain(double remain); 202 | 203 | /** 204 | * @brief 推送内存的剩余率 205 | * @param rate 206 | */ 207 | void pushMemoryRemainRate(double rate); 208 | 209 | /** 210 | * @brief 推送磁盘的使用量 211 | * @param remain 单位为 GB 212 | */ 213 | void pushDiskUsage(const QString& dir, double usage); 214 | 215 | /** 216 | * @brief 推送磁盘的使用率 217 | * @param rate 218 | */ 219 | void pushDiskUsageRate(const QString& dir, double rate); 220 | 221 | /** 222 | * @brief 推送磁盘的剩余量 223 | * @param rate 单位为 GB 224 | */ 225 | void pushDiskRemain(const QString& dir, double remain); 226 | 227 | /** 228 | * @brief 推送磁盘的剩余率 229 | * @param rate 230 | */ 231 | void pushDiskRemainRate(const QString& dir, double rate); 232 | 233 | /** 234 | * @brief 推送CPU使用率报警 235 | * @param rate 236 | */ 237 | void pushCPURateAlter(double rate); 238 | 239 | /** 240 | * @brief 推送CPU使用率报警清除 241 | * @param rate 242 | */ 243 | void pushCPURateAlterClear(double rate); 244 | 245 | /** 246 | * @brief 推送内存使用率报警 247 | * @param rate 248 | */ 249 | void pushMemoryRateAlter(double rate); 250 | 251 | /** 252 | * @brief 推送内存使用率报警清除 253 | * @param rate 254 | */ 255 | void pushMemoryRateAlterClear(double rate); 256 | 257 | /** 258 | * @brief 推送内存使用量报警 259 | * @param rate 260 | */ 261 | void pushMemoryUsageAlter(double usage); 262 | 263 | /** 264 | * @brief 推送内存使用量报警清除 265 | * @param rate 266 | */ 267 | void pushMemoryUsageAlterClear(double usage); 268 | 269 | /** 270 | * @brief 推送磁盘使用率报警 271 | * @param dir 272 | * @param rate 273 | */ 274 | void pushDiskRateAlter(const QString& dir, double rate); 275 | 276 | /** 277 | * @brief 推送磁盘使用率报警清除 278 | * @param dir 279 | * @param rate 280 | */ 281 | void pushDiskRateAlterClear(const QString& dir, double rate); 282 | 283 | /** 284 | * @brief 推送磁盘使用量报警 285 | * @param dir 286 | * @param rate 287 | */ 288 | void pushDiskUsageAlter(const QString& dir, double usage); 289 | 290 | /** 291 | * @brief 推送磁盘使用量报警清除 292 | * @param dir 293 | * @param rate 294 | */ 295 | void pushDiskUsageAlterClear(const QString& dir, double usage); 296 | 297 | private: 298 | Q_DISABLE_COPY(SystemInfo) 299 | Q_DECLARE_PRIVATE(SystemInfo) 300 | QScopedPointer d_ptr; 301 | }; 302 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfo.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/../../../../../include/generic/SystemInfo/SystemInfo_global.h \ 3 | $$PWD/../../../../../include/generic/SystemInfo/SystemInfoType.h \ 4 | $$PWD/../../../../../include/generic/SystemInfo/SystemInfo.h \ 5 | $$PWD/SystemInfoInterface.h \ 6 | $$PWD/SystemInfoPrivate.h 7 | 8 | SOURCES += \ 9 | $$PWD/SystemInfo4Windows.cpp \ 10 | $$PWD/SystemInfo4Unix.cpp \ 11 | $$PWD/SystemInfo.cpp 12 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfoInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "SystemInfoType.h" 3 | 4 | class SystemInfoInterface 5 | { 6 | public: 7 | CompleteCPUState cpuState() const; 8 | MemoryState memoryState() const; 9 | DiskState diskState(const QString& dir) const; 10 | DiskStateList allDiskState() const; 11 | 12 | private: 13 | static void calcCPUUseRate(CPUState& st); 14 | static void calcMemoryUseRate(MemoryState& st); 15 | static void calcDiskUseRate(DiskState& st); 16 | }; 17 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfoPrivate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "SystemInfoInterface.h" 3 | #include 4 | #include 5 | #include 6 | 7 | class ThresholdType 8 | { 9 | public: 10 | #define DeclareIns(Type) \ 11 | static ThresholdType Type##Ins() \ 12 | { \ 13 | return ThresholdType(Type); \ 14 | } 15 | 16 | DeclareIns(CPURate) 17 | DeclareIns(MemoryRate) 18 | DeclareIns(MemoryUsage) 19 | DeclareIns(DiskRate) 20 | DeclareIns(DiskUsage) 21 | 22 | // 只有针对磁盘的类型信息,data才有效 23 | QString str(const QString& data = QString()) const 24 | { 25 | switch (t) 26 | { 27 | case CPURate: 28 | return QString("^CPURate^"); 29 | case MemoryRate: 30 | return QString("^MemoryRate^"); 31 | case MemoryUsage: 32 | return QString("^MemoryUsage^"); 33 | case DiskRate: 34 | return QString("^DiskRate^%1").arg(data); 35 | case DiskUsage: 36 | return QString("^DiskUsage^%1").arg(data); 37 | default: 38 | break; 39 | } 40 | return data; 41 | } 42 | 43 | private: 44 | enum T 45 | { 46 | CPURate, 47 | MemoryRate, 48 | MemoryUsage, 49 | DiskRate, 50 | DiskUsage, 51 | }t; 52 | 53 | ThresholdType(T _t) 54 | : t(_t) 55 | { 56 | } 57 | }; 58 | 59 | class QTimer; 60 | class SystemInfo; 61 | class SystemInfoPrivate 62 | { 63 | public: 64 | explicit SystemInfoPrivate(SystemInfo* pthis); 65 | ~SystemInfoPrivate(); 66 | 67 | public: 68 | SystemInfo* q_ptr; 69 | Q_DECLARE_PUBLIC(SystemInfo) 70 | 71 | public: 72 | SystemInfoInterface* _interface; //< 接口的实例 73 | 74 | AutoPush::Flag _autoPush = AutoPush::None; //< 状态定时推送标记 75 | int _timeInterval = -1; //< 推送状态的时间间隔 76 | 77 | QVector _pushDiskDirList; //< 推送状态的磁盘目录 78 | 79 | QTimer* _timer = nullptr; //< 状态推送的定时器 80 | 81 | QMap> _alterThresholdMap; //< 报警阈值Map 82 | QMap _lastValue; //< 最后一次的值 83 | 84 | public: 85 | /** 86 | * @brief 推送系统信息 87 | */ 88 | void pushSystemInfo(); 89 | 90 | /** 91 | * @brief 推送CPU使用率的阈值 92 | * @param rate 93 | */ 94 | void pushCPURateThreshol(double rate); 95 | 96 | /** 97 | * @brief 推送内存使用率的阈值 98 | */ 99 | void pushMemoryRateThreshol(double rate); 100 | 101 | /** 102 | * @brief 推送内存使用量的阈值 103 | */ 104 | void pushMemoryUsageThreshol(double usage); 105 | 106 | /** 107 | * @brief 推送磁盘使用率的阈值 108 | */ 109 | void pushDiskRateThreshol(const QString& dir, double rate); 110 | 111 | /** 112 | * @brief 推送磁盘使用量的阈值 113 | */ 114 | void pushDiskUsageThreshol(const QString& dir, double usage); 115 | 116 | /** 117 | * @brief 检测新的需要推送的阈值 118 | * @param newValue 119 | * @param threshols 120 | * @return 是警告还是警告清除 121 | */ 122 | bool checkPushThreshol(const QString& key, double newValue, 123 | QVector& threshols); 124 | }; 125 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfoType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "DataSizeHelper.h" 6 | 7 | // 自动推送标记 8 | class AutoPush 9 | { 10 | Q_GADGET 11 | public: 12 | enum T 13 | { 14 | None = 0x0000, 15 | CPUState = 0x0001, 16 | MemoryState = 0x0002, 17 | DiskState = 0x0004, 18 | All = None | CPUState | MemoryState | DiskState, 19 | }; 20 | Q_DECLARE_FLAGS(Flag, T) 21 | Q_FLAGS(Flag) 22 | }; 23 | Q_DECLARE_METATYPE(AutoPush::Flag) 24 | 25 | //< CPU,子核心ID从0开始 26 | enum class CPUCoreId 27 | { 28 | ID_total = -1, //< 总的核心ID 29 | }; 30 | 31 | // CPU状态 32 | struct CPUState 33 | { 34 | double userate = 0.0; //< CPU 使用率,范围[0~100] 35 | double system = 0.0; //< 内核使用时间 36 | double user = 0.0; //< 用户使用时间 37 | double nice = 0.0; //< 优先使用时间 38 | double idle = 0.0; //< 空闲时间 39 | 40 | CPUState& operator+=(const CPUState& other) 41 | { 42 | system += other.system; 43 | user += other.user; 44 | idle += other.idle; 45 | nice += other.nice; 46 | userate = 0.0; //< 使用率更新为0 47 | return *this; 48 | } 49 | 50 | friend CPUState operator-(const CPUState& arg1, const CPUState& arg2) 51 | { 52 | CPUState value; 53 | value.system = arg1.system - arg2.system; 54 | value.user = arg1.user - arg2.user; 55 | value.idle = arg1.idle - arg2.idle; 56 | value.nice = arg1.nice - arg2.nice; 57 | value.userate = 0.0; //< 使用率更新为0 58 | return value; 59 | } 60 | }; 61 | Q_DECLARE_METATYPE(CPUState) 62 | using CPUStateList = QVector; 63 | 64 | struct CompleteCPUState 65 | { 66 | CPUState total; //< 总共的CPU状态 67 | CPUStateList childCore; //< 子核心的CPU状态 68 | }; 69 | Q_DECLARE_METATYPE(CompleteCPUState) 70 | 71 | // 内存状态 72 | struct MemoryState 73 | { 74 | double userate = 0.0; //< 内存使用率,范围[0~100] 75 | DataSize totalPhys; // 总物理内存 76 | DataSize freePhys; // 空闲物理内存 77 | DataSize totalVirtual; // 总虚拟内存 78 | DataSize freeVirtual; // 空闲虚拟内存 79 | double totalPage = 0.0; // 总页面 80 | double freePage = 0.0; // 空闲页面 81 | }; 82 | Q_DECLARE_METATYPE(MemoryState) 83 | 84 | // 磁盘状态 85 | struct DiskState 86 | { 87 | double userate = 0.0; //< 磁盘使用率,范围[0~100] 88 | double blockSize; //< 块大小 89 | DataSize totalSize; //< 总空间 90 | DataSize freeSize; //< 空闲空间 91 | DataSize availableSize; //< 可用空间 92 | }; 93 | Q_DECLARE_METATYPE(DiskState) 94 | typedef QVector DiskStateList; 95 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfo_Unix.cpp: -------------------------------------------------------------------------------- 1 | #include "SystemInfoInterface.h" 2 | 3 | #ifdef Q_OS_UNIX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum MemInfoFlag 11 | { 12 | None = 0x0000, 13 | MemTotal = 0x0001, 14 | MemFree = 0x0002, 15 | SwapTotal = 0x0004, 16 | SwapFree = 0x0008, 17 | All = MemTotal | MemFree | SwapTotal | SwapFree, 18 | }; 19 | 20 | CompleteCPUState SystemInfoInterface::cpuState() const 21 | { 22 | static CPUStateList lastCpuStatuList; 23 | CPUStateList cpuDiffStatuList; 24 | CPUStateList cpuTempStatuList; 25 | // linux 下通过读取系统保存的状态文件中的数据来获取CPU使用率 26 | QFile file(QStringLiteral("/proc/stat")); 27 | if (!file.open(QFile::ReadOnly)) 28 | { 29 | return CompleteCPUState(); 30 | } 31 | for (int coreIndex = 0; ; ++coreIndex) 32 | { 33 | QByteArray dataArray = file.readLine(); 34 | if (!dataArray.startsWith(QByteArrayLiteral("cpu"))) 35 | { 36 | break; 37 | } 38 | qlonglong user = 0L; 39 | qlonglong nice = 0L; 40 | qlonglong system = 0L; 41 | qlonglong idle = 0L; 42 | char name[20]; 43 | QTextStream stream(&dataArray); 44 | stream >>name >>user >>system >>idle; 45 | CPUState cpuState; 46 | cpuState.user = user; 47 | cpuState.nice = nice; 48 | cpuState.system = system; 49 | cpuState.idle = idle; 50 | cpuTempStatuList.push_back(cpuState); 51 | CPUState diffCpuState = cpuState - lastCpuStatuList.value(coreIndex); 52 | cpuDiffStatuList.push_back(diffCpuState); 53 | } 54 | file.close(); 55 | lastCpuStatuList = cpuTempStatuList; 56 | for (CPUState& state : cpuDiffStatuList) 57 | { 58 | calcCPUUseRate(state); 59 | } 60 | CompleteCPUState stateReturn; 61 | stateReturn.total = cpuDiffStatuList.last(); 62 | cpuDiffStatuList.removeFirst(); 63 | stateReturn.childCore = cpuDiffStatuList; 64 | return stateReturn; 65 | } 66 | 67 | MemoryState SystemInfoInterface::memoryState() const 68 | { 69 | // linux 下通过读取系统保存的状态文件中的数据来获取内存使用信息 70 | MemoryState memoryStatus; 71 | QFile file(QStringLiteral("/proc/meminfo")); 72 | if (!file.open(QFile::ReadOnly)) 73 | { 74 | return memoryStatus; 75 | } 76 | int flag = None; 77 | char name[30]; 78 | char type[30]; 79 | qlonglong value; 80 | while (flag != All) 81 | { 82 | QByteArray dataArray = file.readLine(); 83 | if (dataArray.isEmpty()) 84 | { 85 | break; 86 | } 87 | QTextStream stream(&dataArray); 88 | stream >>name >>value >>type; 89 | value <<= 10; 90 | if (strcmp(name, "MemTotal:") == 0) { 91 | memoryStatus.totalPhys = DataSize(value, DataSizeUnit::B); 92 | flag |= MemTotal; 93 | } else if (strcmp(name, "MemFree:") == 0) { 94 | memoryStatus.freePhys = DataSize(value, DataSizeUnit::B); 95 | flag |= MemFree; 96 | } else if (strcmp(name, "SwapTotal:") == 0) { 97 | memoryStatus.totalPage = value; 98 | flag |= SwapTotal; 99 | } else if (strcmp(name, "SwapFree:") == 0) { 100 | memoryStatus.freePage = value; 101 | flag |= SwapFree; 102 | } 103 | } 104 | file.close(); 105 | // 计算使用率 106 | calcMemoryUseRate(memoryStatus); 107 | return memoryStatus; 108 | } 109 | 110 | DiskState SystemInfoInterface::diskState(const QString& dir) const 111 | { 112 | /** 113 | * @brief windows 下通过调用 statfs 来获取磁盘的使用情况 114 | */ 115 | struct statfs diskInfo; 116 | 117 | statfs(dir.toStdString().data(), &diskInfo); 118 | 119 | DiskState diskStatus; 120 | diskStatus.blockSize = diskInfo.f_bsize; 121 | diskStatus.totalSize = DataSize(diskInfo.f_blocks * diskStatus.blockSize, DataSizeUnit::B); 122 | 123 | diskStatus.freeSize = DataSize(diskInfo.f_bfree * diskStatus.blockSize, DataSizeUnit::B); 124 | diskStatus.availableSize = DataSize(diskInfo.f_bavail * diskStatus.blockSize, DataSizeUnit::B); 125 | // 计算使用率 126 | calcDiskUseRate(diskStatus); 127 | return diskStatus; 128 | } 129 | 130 | DiskStateList SystemInfoInterface::allDiskState() const 131 | { 132 | DiskStateList stList; 133 | // linux 下通过读取系统保存的状态文件获取所有的磁盘分区 134 | QFile file(QStringLiteral("/proc/mounts")); 135 | if (!file.open(QFile::ReadOnly)) 136 | { 137 | return stList; 138 | } 139 | QByteArray dataArray; 140 | 141 | char dev[30]; 142 | char mount[30]; 143 | char type[30]; 144 | 145 | while (!file.atEnd()) 146 | { 147 | dataArray = file.readLine(); 148 | QTextStream stream(&dataArray); 149 | stream >>dev >>mount >>type; 150 | if (strcmp(type, "devtmpfs") == 0 151 | || strcmp(type, "tmpfs") == 0 152 | || strcmp(type, "ext2") == 0 153 | || strcmp(type, "ext3") == 0 154 | || strcmp(type, "ext4") == 0) 155 | { 156 | DiskState diskst = diskState(mount); 157 | stList.push_back(diskst); 158 | } 159 | } 160 | file.close(); 161 | return stList; 162 | } 163 | 164 | void SystemInfoInterface::calcCPUUseRate(CPUState& st) 165 | { 166 | double usage = st.system + st.user; 167 | double total = st.system + st.user + st.idle + st.nice; 168 | if (qFuzzyIsNull(total)) 169 | { 170 | st.userate = 0; 171 | } 172 | st.userate = 100.0 * usage / total; 173 | } 174 | 175 | void SystemInfoInterface::calcMemoryUseRate(MemoryState& st) 176 | { 177 | double total = st.totalPhys.value(); 178 | double usage = total - st.freePhys.value(); 179 | if (qFuzzyIsNull(total)) 180 | { 181 | st.userate = 0; 182 | } 183 | st.userate = 100.0 * usage / total; 184 | } 185 | 186 | void SystemInfoInterface::calcDiskUseRate(DiskState& st) 187 | { 188 | double total = st.totalSize.value(); 189 | double usage = total - st.availableSize.value(); 190 | if (qFuzzyIsNull(total)) 191 | { 192 | st.userate = 0; 193 | } 194 | st.userate = 100.0 * usage / total; 195 | } 196 | 197 | #endif // Q_OS_UNIX 198 | -------------------------------------------------------------------------------- /src/core/CoreDump/SystemInfo_Windows.cpp: -------------------------------------------------------------------------------- 1 | #include "SystemInfoInterface.h" 2 | 3 | #ifdef Q_OS_WIN 4 | 5 | #include 6 | #include 7 | 8 | using CPUInfo4Win = SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; 9 | using CPUInfo4WinList = QVector; 10 | using SystemInfo4Win = SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; 11 | 12 | CompleteCPUState SystemInfoInterface::cpuState() const 13 | { 14 | static CompleteCPUState lastCompleteCPUState; //< 最后一次的CPU状态 15 | static int coreNumber = 0; //< CPU核心数不可能为 0,如果为 0 则表示未初始化 16 | if (coreNumber == 0) 17 | { 18 | // 获取核心数,并填充子核心状态Vector 19 | SYSTEM_INFO sys_info; 20 | GetSystemInfo(&sys_info); 21 | coreNumber = static_cast(sys_info.dwNumberOfProcessors); 22 | lastCompleteCPUState.childCore.resize(coreNumber); 23 | } 24 | // 获取信息 25 | SystemInfo4Win systemInfo[1024]; 26 | NtQuerySystemInformation(SystemProcessorPerformanceInformation, 27 | &systemInfo, 28 | sizeof(SystemInfo4Win) * static_cast(coreNumber), 29 | nullptr); 30 | CompleteCPUState currentCompleteCPUState; //< 当前完整的CPU状态 31 | CompleteCPUState diffCompleteCPUState; //< 相差的CPU状态 32 | // 遍历每个核的信息,并计算总的信息 33 | for (int corIndex = 0; corIndex != coreNumber; corIndex++) 34 | { 35 | SystemInfo4Win& cpuInfo = systemInfo[corIndex]; 36 | 37 | // 构建当前单个核心的状态 38 | CPUState singleCoreState; 39 | singleCoreState.system = cpuInfo.KernelTime.QuadPart; 40 | singleCoreState.idle = cpuInfo.IdleTime.QuadPart; 41 | singleCoreState.user = cpuInfo.UserTime.QuadPart; 42 | 43 | // 添加到子核心状态列表中,并更新总的CPU信息 44 | currentCompleteCPUState.total += singleCoreState; 45 | currentCompleteCPUState.childCore.push_back(singleCoreState); 46 | 47 | // 计算与最后一次核心数据的偏差,并保存 48 | CPUState diffToLastState = singleCoreState 49 | - lastCompleteCPUState.childCore.value(corIndex); 50 | // 计算使用率 51 | calcCPUUseRate(diffToLastState); 52 | // 保存 53 | diffCompleteCPUState.childCore.push_back(diffToLastState); 54 | diffCompleteCPUState.total += diffToLastState; 55 | } 56 | // 计算使用率 57 | calcCPUUseRate(diffCompleteCPUState.total); 58 | // 更新最后一次的CPU状态信息 59 | lastCompleteCPUState = currentCompleteCPUState; 60 | return diffCompleteCPUState; 61 | } 62 | 63 | MemoryState SystemInfoInterface::memoryState() const 64 | { 65 | MEMORYSTATUSEX memory; 66 | memory.dwLength = sizeof(MEMORYSTATUSEX); 67 | GlobalMemoryStatusEx(&memory); 68 | 69 | // 构建内存状态 70 | MemoryState state; 71 | state.totalPhys = DataSize(memory.ullTotalPhys, DataSizeUnit::B); 72 | state.freePhys = DataSize(memory.ullAvailPhys, DataSizeUnit::B); 73 | state.totalVirtual = DataSize(memory.ullTotalVirtual, DataSizeUnit::B); 74 | state.freeVirtual = DataSize(memory.ullAvailVirtual, DataSizeUnit::B); 75 | state.totalPage = memory.ullTotalPageFile; 76 | state.freePage = memory.ullAvailPageFile; 77 | // 计算使用率 78 | calcMemoryUseRate(state); 79 | return state; 80 | } 81 | 82 | DiskState SystemInfoInterface::diskState(const QString& dir) const 83 | { 84 | _ULARGE_INTEGER availableSize; 85 | _ULARGE_INTEGER totalSize; 86 | _ULARGE_INTEGER freeSize; 87 | GetDiskFreeSpaceExW(dir.toStdWString().data(), 88 | &availableSize, 89 | &totalSize, 90 | &freeSize); 91 | // 构建磁盘状态 92 | DiskState state; 93 | state.blockSize = 0.0; 94 | state.availableSize = DataSize(static_cast(availableSize.QuadPart), 95 | DataSizeUnit::B); 96 | state.totalSize = DataSize(static_cast(totalSize.QuadPart), 97 | DataSizeUnit::B); 98 | state.freeSize = DataSize(static_cast(freeSize.QuadPart), 99 | DataSizeUnit::B); 100 | // 计算使用率 101 | calcDiskUseRate(state); 102 | return state; 103 | } 104 | 105 | DiskStateList SystemInfoInterface::allDiskState() const 106 | { 107 | DiskStateList stateList; 108 | char drives[MAX_PATH]; 109 | DWORD dwLen = GetLogicalDriveStringsA(MAX_PATH, drives); 110 | for (DWORD pos = 0; pos < dwLen;) { 111 | if (drives[pos] != 0) { 112 | const char *drive = drives + pos; 113 | DiskState state = diskState(QString(drive)); 114 | stateList.push_back(state); 115 | pos += DWORD(strlen(drive)) + 1; 116 | } 117 | } 118 | return stateList; 119 | } 120 | 121 | void SystemInfoInterface::calcCPUUseRate(CPUState& st) 122 | { 123 | double usage = st.system + st.user - st.idle; 124 | double total = st.system + st.user; 125 | if (qFuzzyIsNull(total)) { 126 | st.userate = 0; 127 | } else { 128 | st.userate = 100.0 * usage / total; 129 | } 130 | } 131 | 132 | void SystemInfoInterface::calcMemoryUseRate(MemoryState& st) 133 | { 134 | double total = st.totalPhys.value(); 135 | double usage = total - st.freePhys.value(); 136 | if (qFuzzyIsNull(total)) 137 | { 138 | st.userate = 0; 139 | } 140 | st.userate = 100.0 * usage / total; 141 | } 142 | 143 | void SystemInfoInterface::calcDiskUseRate(DiskState& st) 144 | { 145 | double total = st.totalSize.value(); 146 | double usage = total - st.availableSize.value(); 147 | if (qFuzzyIsNull(total)) 148 | { 149 | st.userate = 0; 150 | } 151 | st.userate = 100.0 * usage / total; 152 | } 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /src/core/Event.cpp: -------------------------------------------------------------------------------- 1 | #include "EventImpl.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::MetaEvent::~MetaEvent() 5 | { 6 | } 7 | 8 | Kpf::MetaEvent::MetaEvent() 9 | { 10 | } 11 | 12 | Kpf::ObjectEvent::~ObjectEvent() 13 | { 14 | QSharedPointer e = event.toStrongRef(); 15 | if (e) { 16 | e->eventObjects.remove(this); 17 | } 18 | 19 | for (auto it = topics.begin(); it != topics.end(); ++it) 20 | { 21 | QSharedPointer topic = it->toStrongRef(); 22 | if (!topic) { 23 | continue; 24 | } 25 | 26 | topic->publishedEvents.remove(this); 27 | topic->subscribedEvents.remove(this); 28 | 29 | for (auto threadEvents = topic->threadEvents.begin(); 30 | threadEvents != topic->threadEvents.end(); 31 | ++threadEvents) 32 | { 33 | threadEvents->removeAll(this); 34 | } 35 | } 36 | } 37 | 38 | QMap Kpf::ObjectEvent::send(const QVariantList& args) 39 | { 40 | QMap ret; 41 | if (kpfCoreImpl.closingDown()) return ret; 42 | 43 | for (auto it = topics.begin(); it != topics.end(); ++it) 44 | { 45 | QSharedPointer topic = it.value().toStrongRef(); 46 | if (!topic) { 47 | continue; 48 | } 49 | 50 | for (ObjectEvent* subscribedEvent : topic->subscribedEvents) 51 | { 52 | ret[subscribedEvent->object.toStrongRef()->name] 53 | = subscribedEvent->func(args); 54 | } 55 | } 56 | 57 | kpfEventImpl.notify(&IEventNotifier::sendEvent, *this, args); 58 | return ret; 59 | } 60 | 61 | void Kpf::ObjectEvent::post(const QVariantList& args) 62 | { 63 | QMap ret; 64 | if (kpfCoreImpl.closingDown()) { 65 | return; 66 | } 67 | 68 | for (auto it = topics.begin(); it != topics.end(); ++it) 69 | { 70 | QSharedPointer topic = it.value().toStrongRef(); 71 | if (!topic) { 72 | continue; 73 | } 74 | 75 | for (auto it = topic->threadEvents.begin(); 76 | it != topic->threadEvents.end(); 77 | ++it) 78 | { 79 | ThreadImpl* thread; 80 | thread = static_cast(reinterpret_cast(it.key())); 81 | PostEvent* event = new PostEvent(args); 82 | event->eventObjects = it.value(); 83 | qApp->postEvent(thread->eventBus, 84 | event, 85 | Qt::HighEventPriority); 86 | } 87 | } 88 | 89 | kpfEventImpl.notify(&IEventNotifier::postEvent, *this, args); 90 | } 91 | 92 | Kpf::MetaEventImpl::~MetaEventImpl() 93 | { 94 | } 95 | 96 | QSharedPointer Kpf::MetaEventImpl::create(Type type, const QString& name, const QString& className) 97 | { 98 | QSharedPointer ret(new MetaEventImpl); 99 | ret->type = type; 100 | ret->name = name; 101 | ret->className = className; 102 | return ret; 103 | } 104 | 105 | Kpf::MetaEventImpl::MetaEventImpl() 106 | { 107 | } 108 | 109 | Kpf::EventManager& Kpf::EventManager::instance() 110 | { 111 | return kpfCoreImpl.eventManager(); 112 | } 113 | 114 | Kpf::EventManagerImpl::EventManagerImpl() 115 | { 116 | } 117 | 118 | Kpf::EventManagerImpl::~EventManagerImpl() 119 | { 120 | QMutexLocker locker(kpfMutex()); 121 | } 122 | 123 | Kpf::EventManagerImpl& Kpf::EventManagerImpl::instance() 124 | { 125 | return kpfCoreImpl.eventManager(); 126 | } 127 | 128 | void Kpf::EventManagerImpl::addPubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignal) 129 | { 130 | QMutexLocker locker(kpfMutex()); 131 | 132 | QSharedPointer object = kpfObject.findObject(objectName) 133 | .toStrongRef() 134 | .staticCast(); 135 | if (!object) { 136 | return; 137 | } 138 | 139 | QString name = eventName; 140 | if (isSignal) 141 | { 142 | name = normalizedSignature(name); 143 | registerPubSignalEvent(object, name); 144 | } 145 | ObjectEvent* eventObject = object->publishedEvents.value(name); 146 | if (!eventObject) 147 | { 148 | qCWarning(kpf) << "Add published event for object" << object->name 149 | << "wtih event signature" << name 150 | << "to topic" << topicName 151 | << "failed : cannot find corresponding event"; 152 | return; 153 | } 154 | 155 | qCDebug(kpf) << "Add published event for object" << object->name 156 | << "wtih event signature" << name 157 | << "to topic" << topicName; 158 | 159 | QSharedPointer topic = kpfTopicImpl.addTopic(topicName); 160 | topic->publishedEvents.insert(eventObject); 161 | eventObject->topics.insert(topic->name, topic); 162 | notify(&N::pubEventAdded, object->name, name, topicName, isSignal); 163 | } 164 | 165 | void Kpf::EventManagerImpl::addSubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignalOrSlot) 166 | { 167 | QMutexLocker locker(kpfMutex()); 168 | 169 | QSharedPointer object = kpfObject.findObject(objectName) 170 | .toStrongRef() 171 | .staticCast(); 172 | if (!object) { 173 | return; 174 | } 175 | 176 | QString name = eventName; 177 | if (isSignalOrSlot) 178 | { 179 | name = normalizedSignature(name); 180 | registerSubSignalSlotEvent(object, name); 181 | } 182 | 183 | ObjectEvent* eventObject = object->subscribedEvents.value(name); 184 | if (!eventObject) 185 | { 186 | qCWarning(kpf) << "Add subscribed event for object" << object->name 187 | << "wtih event signature" << name 188 | << "to topic" << topicName 189 | << "failed : cannot find corresponding event"; 190 | return; 191 | } 192 | 193 | qCDebug(kpf) << "Add subscribed event for object" << object->name 194 | << "wtih event signature" << name 195 | << "to topic" << topicName; 196 | 197 | QSharedPointer topic = kpfTopicImpl.addTopic(topicName); 198 | topic->subscribedEvents.insert(eventObject); 199 | topic->threadEvents[reinterpret_cast(object->thread.data())].append(eventObject); 200 | 201 | eventObject->topics.insert(topic->name, topic); 202 | 203 | notify(&N::subEventAdded, object->name, name, topicName, isSignalOrSlot); 204 | } 205 | 206 | void Kpf::EventManagerImpl::registerPubEvent(const QString& eventName, ObjectEvent* eventObject) 207 | { 208 | QMutexLocker locker(kpfMutex()); 209 | registerEvent(eventName, eventObject, MetaEvent::Publish); 210 | } 211 | 212 | void Kpf::EventManagerImpl::registerSubEvent(const QString& eventName, ObjectEvent* eventObject) 213 | { 214 | QMutexLocker locker(kpfMutex()); 215 | registerEvent(eventName, eventObject, MetaEvent::Subscribe); 216 | } 217 | 218 | void Kpf::EventManagerImpl::setupObjectEvents(QSharedPointer& object) 219 | { 220 | QMutexLocker locker(kpfMutex()); 221 | for (QDomElement config = object->config.firstChildElement(TAG_PUBEVENT); 222 | !config.isNull(); 223 | config = config.nextSiblingElement(TAG_PUBEVENT)) 224 | { 225 | QString eventName = config.attribute(KEY_EVENTID); 226 | QString signal = normalizedSignature(config.attribute(KEY_SIGNAL)); 227 | QString topic = config.attribute(KEY_TOPIC); 228 | if ((eventName.isEmpty() && signal.isEmpty()) || topic.isEmpty()) { 229 | continue; 230 | } 231 | 232 | if (!eventName.isEmpty()) 233 | { 234 | addPubEvent(object->name, eventName, topic, false); 235 | } 236 | else // !signal.isEmpty() 237 | { 238 | addPubEvent(object->name, signal, topic, true); 239 | } 240 | } 241 | 242 | for (QDomElement config = object->config.firstChildElement(TAG_SUBEVENT); 243 | !config.isNull(); 244 | config = config.nextSiblingElement(TAG_SUBEVENT)) 245 | { 246 | QString eventId = config.attribute(KEY_EVENTID); 247 | QString signal = normalizedSignature(config.attribute(KEY_SIGNAL)); 248 | QString slot = normalizedSignature(config.attribute(KEY_SLOT)); 249 | QString topic = config.attribute(KEY_TOPIC); 250 | if ((eventId.isEmpty() && slot.isEmpty() && signal.isEmpty()) 251 | || topic.isEmpty()) { 252 | continue; 253 | } 254 | 255 | if (!eventId.isEmpty()) 256 | { 257 | addSubEvent(object->name, eventId, topic, false); 258 | } 259 | else if(!slot.isEmpty()) 260 | { 261 | addSubEvent(object->name, slot, topic, true); 262 | } 263 | else // !signal.isEmpty() 264 | { 265 | addSubEvent(object->name, signal, topic, true); 266 | } 267 | } 268 | } 269 | 270 | void Kpf::EventManagerImpl::registerPubSignalEvent(QSharedPointer& object, const QString& eventName) 271 | { 272 | QMutexLocker locker(kpfMutex()); 273 | 274 | SignalSpy* signalSpy = new SignalSpy(object, eventName.toUtf8()); 275 | connect(object->object.data(), &QObject::destroyed, 276 | [signalSpy]{ delete signalSpy; }); 277 | 278 | registerEvent(eventName, &(signalSpy->eventObject), MetaEvent::Publish, object); 279 | } 280 | 281 | void Kpf::EventManagerImpl::registerSubSignalSlotEvent(QSharedPointer& object, const QString& eventName) 282 | { 283 | QMutexLocker locker(kpfMutex()); 284 | 285 | const QMetaObject* metaObject = object->object->metaObject(); 286 | int index = metaObject->indexOfMethod(eventName.toUtf8().constData()); 287 | if (index < 0) { 288 | return; 289 | } 290 | QMetaMethod method = metaObject->method(index); 291 | 292 | ObjectEvent* eventObject = new ObjectEvent; 293 | InvokeMethodSyncHelper* invokeHelper; 294 | invokeHelper = new InvokeMethodSyncHelper(object->object, method); 295 | eventObject->func = [invokeHelper](const QVariantList& args)->QVariant{ 296 | return invokeHelper->invoke(args); 297 | }; 298 | 299 | connect(object->object.data(), &QObject::destroyed, 300 | [eventObject, invokeHelper]{ 301 | delete invokeHelper; 302 | delete eventObject; 303 | }); 304 | 305 | registerEvent(eventName, eventObject, MetaEvent::Subscribe, object); 306 | } 307 | 308 | void Kpf::EventManagerImpl::registerEvent(const QString& eventName, ObjectEvent* eventObject, MetaEvent::Type type, QSharedPointer object) 309 | { 310 | QMutexLocker locker(kpfMutex()); 311 | 312 | QSharedPointer currentObj; 313 | if (object) { 314 | currentObj = object; 315 | } else { 316 | currentObj = kpfObjectImpl.currentObject().toStrongRef(); 317 | } 318 | if (!currentObj) { 319 | return; 320 | } 321 | eventObject->object = currentObj; 322 | 323 | QSharedPointer classImpl = currentObj->objectClass 324 | .staticCast(); 325 | if (!classImpl) { 326 | return; 327 | } 328 | 329 | QSharedPointer event; 330 | if (type == MetaEvent::Publish) { 331 | event = classImpl->publishedEvents.value(eventName); 332 | } else { 333 | event = classImpl->publishedEvents.value(eventName); 334 | } 335 | 336 | if (!event) 337 | { 338 | event = MetaEventImpl::create(MetaEvent::Publish, 339 | eventName, 340 | classImpl->name); 341 | if (type == MetaEvent::Publish) { 342 | classImpl->publishedEvents.insert(eventName, event); 343 | } else { 344 | classImpl->subscribedEvents.insert(eventName, event); 345 | } 346 | } 347 | event->eventObjects.insert(eventObject); 348 | 349 | eventObject->event = event; 350 | 351 | if (type == MetaEvent::Publish) 352 | { 353 | currentObj->publishedEvents.insert(eventName, eventObject); 354 | notify(&N::pubEventRegistered, eventName); 355 | } 356 | else 357 | { 358 | currentObj->subscribedEvents.insert(eventName, eventObject); 359 | notify(&N::subEventRegistered, eventName); 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/core/EventBus.cpp: -------------------------------------------------------------------------------- 1 | #include "EventBus.h" 2 | #include "KpfPrivate.h" 3 | 4 | const int Kpf::PostEvent::typeValue = QEvent::User + 'K' + 'p' + 'f'; 5 | 6 | Kpf::PostEvent::PostEvent(const QVariantList& arguments) 7 | : QEvent(QEvent::Type(typeValue)), 8 | args(arguments) 9 | { 10 | } 11 | 12 | Kpf::PostEvent::~PostEvent() 13 | { 14 | } 15 | 16 | Kpf::EventBus::EventBus() 17 | { 18 | } 19 | 20 | bool Kpf::EventBus::event(QEvent* e) 21 | { 22 | if (e->type() != PostEvent::typeValue) { 23 | return QObject::event(e); 24 | } 25 | 26 | PostEvent* event = static_cast(e); 27 | for (ObjectEvent* eventObject : event->eventObjects) 28 | { 29 | eventObject->func(event->args); 30 | } 31 | event->accept(); 32 | return true; 33 | } 34 | 35 | Kpf::EventBus::~EventBus() 36 | { 37 | } 38 | -------------------------------------------------------------------------------- /src/core/EventBus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "EventImpl.h" 4 | 5 | namespace Kpf { 6 | struct PostEvent : public QEvent 7 | { 8 | PostEvent(const QVariantList& args); 9 | virtual ~PostEvent(); 10 | 11 | static const int typeValue; 12 | 13 | QList eventObjects; 14 | QVariantList args; 15 | }; 16 | 17 | class EventBus : public QObject 18 | { 19 | Q_OBJECT 20 | public: 21 | EventBus(); 22 | virtual ~EventBus(); 23 | 24 | protected: 25 | virtual bool event(QEvent* e); 26 | }; 27 | } // namespace Kpf 28 | -------------------------------------------------------------------------------- /src/core/EventImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommonPrivate.h" 4 | #include "ObjectImpl.h" 5 | 6 | #ifdef Q_CC_MSVC 7 | #pragma warning(push) 8 | #pragma warning(disable:4250) 9 | #endif 10 | 11 | namespace Kpf { 12 | struct MetaEventImpl : public MetaEvent 13 | { 14 | ~MetaEventImpl() override; 15 | 16 | static QSharedPointer create(Type type, 17 | const QString& name, 18 | const QString& className); 19 | private: 20 | MetaEventImpl(); 21 | }; 22 | 23 | class EventManagerImpl : public EventManager, public NotifyManager 24 | { 25 | Q_OBJECT 26 | public: 27 | EventManagerImpl(); 28 | virtual ~EventManagerImpl() override; 29 | 30 | static EventManagerImpl& instance(); 31 | 32 | // EventManager interface 33 | virtual void addPubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignal = false) override; 34 | virtual void addSubEvent(const QString& objectName, const QString& eventName, const QString& topicName, bool isSignalOrSlot = false) override; 35 | virtual void registerPubEvent(const QString& eventName, ObjectEvent* eventObject) override; 36 | virtual void registerSubEvent(const QString& eventName, ObjectEvent* eventObject) override; 37 | 38 | void setupObjectEvents(QSharedPointer& object); 39 | void registerPubSignalEvent(QSharedPointer& object, const QString& eventName); 40 | void registerSubSignalSlotEvent(QSharedPointer& object, const QString& eventName); 41 | void registerEvent(const QString& eventName, ObjectEvent* eventObject, MetaEvent::Type type, QSharedPointer object = {}); 42 | }; 43 | } // namespace Kpf 44 | #define kpfEventImpl Kpf::EventManagerImpl::instance() 45 | 46 | #ifdef Q_CC_MSVC 47 | #pragma warning(pop) 48 | #endif 49 | -------------------------------------------------------------------------------- /src/core/InvokeHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "InvokeHelperPrivate.h" 2 | #include "KpfPrivate.h" 3 | #include 4 | 5 | Kpf::InvokeMethodSyncHelper::InvokeMethodSyncHelper(QObject* context, const std::function& function) 6 | : d_ptr(new InvokeMethodSyncHelperPrivate(this, context, function)) 7 | { 8 | } 9 | 10 | Kpf::InvokeMethodSyncHelper::InvokeMethodSyncHelper(QObject* context, const std::function& function) 11 | : d_ptr(new InvokeMethodSyncHelperPrivate(this, context, function)) 12 | { 13 | } 14 | 15 | Kpf::InvokeMethodSyncHelper::InvokeMethodSyncHelper(QObject* object, const QMetaMethod& method) 16 | : d_ptr(new InvokeMethodSyncHelperPrivate(this, object, method)) 17 | { 18 | } 19 | 20 | QVariant Kpf::InvokeMethodSyncHelper::invoke(bool* ok) 21 | { 22 | Q_D(InvokeMethodSyncHelper); 23 | return d->invoke(QVariantList(), ok); 24 | } 25 | 26 | QVariant Kpf::InvokeMethodSyncHelper::invoke(const QVariantList& args, bool* ok) 27 | { 28 | Q_D(InvokeMethodSyncHelper); 29 | return d->invoke(args, ok); 30 | } 31 | 32 | Kpf::InvokeMethodSyncHelperPrivate::InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context) 33 | : QObject(parent), q_ptr(parent), object(context) 34 | { 35 | Q_Q(InvokeMethodSyncHelper); 36 | q->moveToThread(object->thread()); 37 | } 38 | 39 | Kpf::InvokeMethodSyncHelperPrivate::InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context, const std::function& function) 40 | : InvokeMethodSyncHelperPrivate(parent, context) 41 | { 42 | if (object->thread() == QThread::currentThread()) 43 | { 44 | invokeFunction = [this, function](const QVariantList&) 45 | { 46 | invoked = true; 47 | function(); 48 | qCDebug(kpf) << "Invoke object" << object->objectName() 49 | << "for function" << function.target_type().name() 50 | << "finished"; 51 | }; 52 | } 53 | else 54 | { 55 | connect(this, &InvokeMethodSyncHelperPrivate::invokeSignal, 56 | this, [function]{ function(); }, 57 | Qt::BlockingQueuedConnection); 58 | invokeFunction = [this, function](const QVariantList& args) 59 | { 60 | invoked = true; 61 | emit invokeSignal(args); 62 | qCDebug(kpf) << "Invoke object" << object->objectName() 63 | << "for function" << function.target_type().name() 64 | << "finished"; 65 | }; 66 | } 67 | } 68 | 69 | Kpf::InvokeMethodSyncHelperPrivate::InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context, const std::function& function) 70 | : InvokeMethodSyncHelperPrivate(parent, context) 71 | { 72 | if (object->thread() == QThread::currentThread()) 73 | { 74 | invokeFunction = [this, function](const QVariantList&) 75 | { 76 | ret = function(); 77 | invoked = true; 78 | qCDebug(kpf) << "Invoke object" << object->objectName() 79 | << "for function" << function.target_type().name() 80 | << "finished with return value" 81 | << ret; 82 | }; 83 | } 84 | else 85 | { 86 | connect(this, &InvokeMethodSyncHelperPrivate::invokeSignal, 87 | this, [this, function]{ ret = function(); }, 88 | Qt::BlockingQueuedConnection); 89 | invokeFunction = [this, function](const QVariantList& args) 90 | { 91 | emit invokeSignal(args); 92 | invoked = true; 93 | qCDebug(kpf) << "Invoke object" << object->objectName() 94 | << "for function" << function.target_type().name() 95 | << "finished with return value" 96 | << ret; 97 | }; 98 | } 99 | } 100 | 101 | Kpf::InvokeMethodSyncHelperPrivate::InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* o, const QMetaMethod& m) 102 | : InvokeMethodSyncHelperPrivate(parent, o) 103 | { 104 | method = m; 105 | 106 | if (object->thread() == QThread::currentThread()) 107 | { 108 | invokeFunction = [this](const QVariantList& args) 109 | { 110 | invokeMethod(args); 111 | }; 112 | } 113 | else 114 | { 115 | connect(this, &InvokeMethodSyncHelperPrivate::invokeSignal, 116 | this, &InvokeMethodSyncHelperPrivate::invokeMethod, 117 | Qt::BlockingQueuedConnection); 118 | invokeFunction = [this](const QVariantList& args) 119 | { 120 | emit invokeSignal(args); 121 | }; 122 | } 123 | } 124 | 125 | QVariant Kpf::InvokeMethodSyncHelperPrivate::invoke(const QVariantList& args, bool* ok) 126 | { 127 | if (!object) { 128 | return false; 129 | } 130 | 131 | invokeFunction(args); 132 | 133 | if (ok) { 134 | *ok = invoked; 135 | } 136 | 137 | return ret; 138 | } 139 | 140 | void Kpf::InvokeMethodSyncHelperPrivate::invokeMethod(QVariantList args) 141 | { 142 | QGenericArgument arguments[10]; 143 | for (int i = 0; i < method.parameterCount(); ++i) 144 | { 145 | args[i].convert(method.parameterType(i)); 146 | arguments[i] = QGenericArgument(args[i].typeName(), args[i].data()); 147 | } 148 | 149 | if (method.returnType() == QMetaType::Void) 150 | { 151 | invoked = method.invoke(object, 152 | Qt::DirectConnection, 153 | arguments[0], 154 | arguments[1], 155 | arguments[2], 156 | arguments[3], 157 | arguments[4], 158 | arguments[5], 159 | arguments[6], 160 | arguments[7], 161 | arguments[8], 162 | arguments[9]); 163 | if (invoked) 164 | { 165 | qCDebug(kpf) << "Invoke object" << object->objectName() 166 | << "for method" << method.methodSignature() 167 | << "with params" << args 168 | << "successed"; 169 | } 170 | else 171 | { 172 | qCDebug(kpf) << "Invoke object" << object->objectName() 173 | << "for method" << method.methodSignature() 174 | << "with params" << args 175 | << "failed"; 176 | } 177 | } 178 | else 179 | { 180 | ret = QVariant(QVariant::Type(method.returnType())); 181 | QGenericReturnArgument retValue(ret.typeName(), ret.data()); 182 | invoked = method.invoke(object, 183 | Qt::DirectConnection, 184 | retValue, 185 | arguments[0], 186 | arguments[1], 187 | arguments[2], 188 | arguments[3], 189 | arguments[4], 190 | arguments[5], 191 | arguments[6], 192 | arguments[7], 193 | arguments[8], 194 | arguments[9]); 195 | if (invoked) 196 | { 197 | qCDebug(kpf) << "Invoke object" << object->objectName() 198 | << "for method" << method.methodSignature() 199 | << "with params" << args 200 | << "successed with return value" 201 | << QVariant(QMetaType::type(retValue.name()), retValue.data()); 202 | } 203 | else 204 | { 205 | qCDebug(kpf) << "Invoke object" << object->objectName() 206 | << "for method" << method.methodSignature() 207 | << "with params" << args 208 | << "failed"; 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/core/InvokeHelperPrivate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Kpf { 5 | struct ObjectImpl; 6 | class InvokeMethodSyncHelperPrivate : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context); 12 | InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context, const std::function& function); 13 | InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* context, const std::function& function); 14 | InvokeMethodSyncHelperPrivate(InvokeMethodSyncHelper* parent, QObject* object, const QMetaMethod& method); 15 | 16 | QVariant invoke(const QVariantList& args, bool* ok); 17 | 18 | private: 19 | Q_SIGNAL void invokeSignal(const QVariantList& args); 20 | void invokeMethod(QVariantList args); 21 | 22 | Q_DECLARE_PUBLIC(InvokeMethodSyncHelper) 23 | InvokeMethodSyncHelper* q_ptr; 24 | 25 | QObject* object = nullptr; 26 | QMetaMethod method; 27 | 28 | bool invoked = false; 29 | QVariant ret; 30 | 31 | std::function invokeFunction; 32 | }; 33 | } //namespace Kpf 34 | -------------------------------------------------------------------------------- /src/core/KLayout.cpp: -------------------------------------------------------------------------------- 1 | #include "KLayout.h" 2 | 3 | QList initObjects(const QJsonObject& config) 4 | { 5 | QList objects; 6 | if (!config.contains(TAG_ITEMS)) { 7 | return objects; 8 | } 9 | QJsonArray array = config.value(TAG_ITEMS).toArray(); 10 | for (auto it = array.begin(); it != array.end(); ++it) 11 | { 12 | if (!(*it).isObject()) { 13 | continue; 14 | } 15 | QJsonObject objectConfig = (*it).toObject(); 16 | 17 | QObject* object = kpfCore.createObject(QString(), 18 | objectConfig.value(Kpf::TAG_CLASS).toString(), 19 | objectConfig); 20 | if (!object->inherits("QWidget") || !object->inherits("QLayout")) 21 | { 22 | kpfCore.destroyObject(object->objectName()); 23 | continue; 24 | } 25 | 26 | objects << object; 27 | } 28 | return objects; 29 | } 30 | 31 | bool initBoxLayout(QBoxLayout* layout, const QJsonObject& config) 32 | { 33 | QList objects = initObjects(config); 34 | 35 | for (QObject* object : objects) 36 | { 37 | QWidget* widget = qobject_cast(object); 38 | QLayout* subLayout = qobject_cast(object); 39 | 40 | bool ok = false; 41 | int stretch = object->property(TAG_STRETCH.toUtf8().constData()).toInt(&ok); 42 | if (!ok) { 43 | continue; 44 | } 45 | if (widget) { 46 | layout->addWidget(widget, stretch); 47 | } else if (subLayout) { 48 | layout->addLayout(subLayout, stretch); 49 | } 50 | } 51 | 52 | return true; 53 | } 54 | 55 | KHBoxLayout::KHBoxLayout(QWidget* parent) 56 | : QHBoxLayout(parent) 57 | { 58 | } 59 | 60 | bool KHBoxLayout::init(const QJsonObject& config) 61 | { 62 | return initBoxLayout(this, config); 63 | } 64 | 65 | KVBoxLayout::KVBoxLayout(QWidget* parent) 66 | : QVBoxLayout(parent) 67 | { 68 | } 69 | 70 | bool KVBoxLayout::init(const QJsonObject& config) 71 | { 72 | return initBoxLayout(this, config); 73 | } 74 | 75 | KFormLayout::KFormLayout(QWidget* parent) 76 | : QFormLayout(parent) 77 | { 78 | } 79 | 80 | bool KFormLayout::init(const QJsonObject& config) 81 | { 82 | struct Object 83 | { 84 | struct Label 85 | { 86 | QString text; 87 | QWidget* widget = nullptr; 88 | }; 89 | Label label; 90 | QWidget* widget = nullptr; 91 | QLayout* layout = nullptr; 92 | }; 93 | 94 | QList objects; 95 | if (!config.contains(TAG_ITEMS)) { 96 | return true; 97 | } 98 | 99 | QJsonArray array = config.value(TAG_ITEMS).toArray(); 100 | for (auto it = array.begin(); it != array.end(); ++it) 101 | { 102 | if (!(*it).isObject()) { 103 | continue; 104 | } 105 | QJsonObject child = (*it).toObject(); 106 | 107 | if (!child.contains(TAG_FIELD)) { 108 | continue; 109 | } 110 | QJsonObject fieldConfig = child.value(TAG_FIELD).toObject(); 111 | QObject* object = kpfCore.createObject(QString(), 112 | fieldConfig.value(Kpf::TAG_CLASS).toString(), 113 | fieldConfig); 114 | Object obj; 115 | obj.widget = qobject_cast(object); 116 | obj.layout = qobject_cast(object); 117 | if (!obj.widget || !obj.layout) 118 | { 119 | if (object) { 120 | kpfCore.destroyObject(object->objectName()); 121 | } 122 | continue; 123 | } 124 | 125 | if (child.contains(TAG_LABEL)) 126 | { 127 | QJsonValue labelValue = child.value(TAG_FIELD); 128 | switch (labelValue.type()) 129 | { 130 | case QJsonValue::String: 131 | obj.label.text = labelValue.toString(); 132 | break; 133 | 134 | case QJsonValue::Object: 135 | { 136 | QJsonObject labelObject = labelValue.toObject(); 137 | QObject* labelObj = kpfCore.createObject(QString(), 138 | fieldConfig.value(Kpf::TAG_CLASS).toString(), 139 | fieldConfig); 140 | obj.label.widget = qobject_cast(labelObj); 141 | if (!obj.label.widget) 142 | { 143 | if (labelObj) { 144 | kpfCore.destroyObject(labelObj->objectName()); 145 | } 146 | break; 147 | } 148 | } 149 | break; 150 | 151 | default: 152 | break; 153 | } 154 | } 155 | 156 | objects.append(obj); 157 | } 158 | 159 | for (Object object : objects) 160 | { 161 | if (object.label.widget) 162 | { 163 | if (object.widget) { 164 | addRow(object.label.widget, object.widget); 165 | } else { 166 | addRow(object.label.widget, object.layout); 167 | } 168 | } 169 | else 170 | { 171 | if (object.widget) { 172 | addRow(object.label.text, object.widget); 173 | } else { 174 | addRow(object.label.text, object.layout); 175 | } 176 | } 177 | } 178 | 179 | return true; 180 | } 181 | 182 | KGridLayout::KGridLayout(QWidget* parent) 183 | : QGridLayout(parent) 184 | { 185 | } 186 | 187 | bool KGridLayout::init(const QJsonObject& config) 188 | { 189 | QList objects = initObjects(config); 190 | 191 | for (QObject* object : objects) 192 | { 193 | QWidget* widget = qobject_cast(object); 194 | QLayout* layout = qobject_cast(object); 195 | 196 | int row = object->property(TAG_ROW.toUtf8().constData()).toInt(); 197 | int column = object->property(TAG_COLUMN.toUtf8().constData()).toInt(); 198 | int rowSpan = object->property(TAG_ROWSPAN.toUtf8().constData()).toInt(); 199 | rowSpan = std::max(1, rowSpan); 200 | int columnSpan = object->property(TAG_ROWSPAN.toUtf8().constData()).toInt(); 201 | columnSpan = std::max(1, columnSpan); 202 | 203 | if (widget) { 204 | addWidget(widget, row, column, rowSpan, columnSpan); 205 | } else if (layout) { 206 | addLayout(layout, row, column, rowSpan, columnSpan); 207 | } 208 | } 209 | 210 | return true; 211 | } 212 | -------------------------------------------------------------------------------- /src/core/KLayout.h: -------------------------------------------------------------------------------- 1 | #ifndef KLAYOUT_H 2 | #define KLAYOUT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static const QString TAG_ITEMS = QStringLiteral("Items"); 9 | static const QString TAG_STRETCH = QStringLiteral("Stretch"); 10 | static const QString TAG_LABEL = QStringLiteral("Label"); 11 | static const QString TAG_FIELD = QStringLiteral("Field"); 12 | static const QString TAG_ROW = QStringLiteral("Row"); 13 | static const QString TAG_COLUMN = QStringLiteral("Column"); 14 | static const QString TAG_ROWSPAN = QStringLiteral("RowSpan"); 15 | static const QString TAG_COLUMNSPAN = QStringLiteral("ColumnSpan"); 16 | 17 | /* 18 | { 19 | "Class": "QHBoxLayout", 20 | "Items": [ 21 | { 22 | "Class": "MainWindow", 23 | "Stretch": 1 24 | } 25 | ] 26 | }, 27 | { 28 | "Class": "QFormLayout", 29 | "Items": [ 30 | { 31 | "Stretch": 1, 32 | "Field": { "Class": "MainWindow" }, 33 | "Label": "Test" 34 | } 35 | ] 36 | }, 37 | { 38 | "Class": "QGridLayout", 39 | "Items": [ 40 | { 41 | "Row": 0, 42 | "Column": 0, 43 | "Class": "MainWindow" 44 | } 45 | ] 46 | }*/ 47 | 48 | class KHBoxLayout : public QHBoxLayout 49 | { 50 | Q_OBJECT 51 | public: 52 | explicit KHBoxLayout(QWidget* parent = nullptr); 53 | Q_SLOT bool init(const QJsonObject& config); 54 | }; 55 | KPF_REGISTER_CLASS(KHBoxLayout, "QHBoxLayout") 56 | 57 | class KVBoxLayout : public QVBoxLayout 58 | { 59 | Q_OBJECT 60 | public: 61 | explicit KVBoxLayout(QWidget* parent = nullptr); 62 | Q_SLOT bool init(const QJsonObject& config); 63 | }; 64 | KPF_REGISTER_CLASS(KVBoxLayout, "QVBoxLayout") 65 | 66 | class KFormLayout : public QFormLayout 67 | { 68 | Q_OBJECT 69 | public: 70 | explicit KFormLayout(QWidget* parent = nullptr); 71 | Q_SLOT bool init(const QJsonObject& config); 72 | }; 73 | KPF_REGISTER_CLASS(KFormLayout, "QFormLayout") 74 | 75 | class KGridLayout : public QGridLayout 76 | { 77 | Q_OBJECT 78 | public: 79 | explicit KGridLayout(QWidget* parent = nullptr); 80 | Q_SLOT bool init(const QJsonObject& config); 81 | }; 82 | KPF_REGISTER_CLASS(KGridLayout, "QGridLayout") 83 | 84 | #endif // KLAYOUT_H 85 | -------------------------------------------------------------------------------- /src/core/KWidgets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | static const QString TAG_ITEMS = QStringLiteral("Items"); 7 | static const QString TAG_MARGINS = QStringLiteral("Margins"); 8 | static const QString TAG_STRETCH = QStringLiteral("Stretch"); 9 | static const QString TAG_LABEL = QStringLiteral("Label"); 10 | static const QString TAG_FIELD = QStringLiteral("Field"); 11 | static const QString TAG_ROW = QStringLiteral("Row"); 12 | static const QString TAG_COLUMN = QStringLiteral("Column"); 13 | static const QString TAG_ROWSPAN = QStringLiteral("RowSpan"); 14 | static const QString TAG_COLUMNSPAN = QStringLiteral("ColumnSpan"); 15 | static const QString TAG_TAB = QStringLiteral("Tab"); 16 | static const QString TAG_MENU = QStringLiteral("Menu"); 17 | static const QString TAG_ACTION = QStringLiteral("Action"); 18 | static const QString TAG_SEPARATOR = QStringLiteral("Separator"); 19 | static const QString TAG_WIDGET = QStringLiteral("Widget"); 20 | static const QString TAG_MENUBAR = QStringLiteral("MenuBar"); 21 | static const QString TAG_TOOLBARS = QStringLiteral("ToolBars"); 22 | static const QString TAG_CENTRALWIDGET = QStringLiteral("CentralWidget"); 23 | static const QString TAG_STATUSBAR = QStringLiteral("StatusBar"); 24 | static const QString TAG_INDEX = QStringLiteral("Index"); 25 | static const QString TAG_ICON = QStringLiteral("Icon"); 26 | 27 | class KHBoxLayout : public QHBoxLayout 28 | { 29 | Q_OBJECT 30 | public: 31 | explicit KHBoxLayout(QWidget* parent = nullptr); 32 | Q_SLOT bool init(const QDomElement& config); 33 | }; 34 | KPF_REGISTER_CLASS(KHBoxLayout, QHBoxLayout) 35 | 36 | class KVBoxLayout : public QVBoxLayout 37 | { 38 | Q_OBJECT 39 | public: 40 | explicit KVBoxLayout(QWidget* parent = nullptr); 41 | Q_SLOT bool init(const QDomElement& config); 42 | }; 43 | KPF_REGISTER_CLASS(KVBoxLayout, QVBoxLayout) 44 | 45 | class KFormLayout : public QFormLayout 46 | { 47 | Q_OBJECT 48 | public: 49 | explicit KFormLayout(QWidget* parent = nullptr); 50 | Q_SLOT bool init(QDomElement config); 51 | }; 52 | KPF_REGISTER_CLASS(KFormLayout, QFormLayout) 53 | 54 | class KGridLayout : public QGridLayout 55 | { 56 | Q_OBJECT 57 | public: 58 | explicit KGridLayout(QWidget* parent = nullptr); 59 | Q_SLOT bool init(const QDomElement& config); 60 | }; 61 | KPF_REGISTER_CLASS(KGridLayout, QGridLayout) 62 | 63 | class KStackedLayout : public QStackedLayout 64 | { 65 | Q_OBJECT 66 | public: 67 | explicit KStackedLayout(QWidget* parent = nullptr); 68 | Q_SLOT bool init(const QDomElement& config); 69 | }; 70 | KPF_REGISTER_CLASS(KStackedLayout, QStackedLayout) 71 | 72 | class KStackedWidget : public QStackedWidget 73 | { 74 | Q_OBJECT 75 | public: 76 | explicit KStackedWidget(QWidget* parent = nullptr); 77 | Q_SLOT bool init(const QDomElement& config); 78 | }; 79 | KPF_REGISTER_CLASS(KStackedWidget, QStackedWidget) 80 | 81 | class KTabWidget : public QTabWidget 82 | { 83 | Q_OBJECT 84 | public: 85 | explicit KTabWidget(QWidget* parent = nullptr); 86 | Q_SLOT bool init(const QDomElement& config); 87 | }; 88 | KPF_REGISTER_CLASS(KTabWidget, QTabWidget) 89 | 90 | class KListWidget : public QListWidget 91 | { 92 | Q_OBJECT 93 | public: 94 | explicit KListWidget(QWidget* parent = nullptr); 95 | Q_SLOT bool init(const QDomElement& config); 96 | }; 97 | KPF_REGISTER_CLASS(KListWidget, QListWidget) 98 | 99 | class KTableWidget : public QTableWidget 100 | { 101 | Q_OBJECT 102 | public: 103 | explicit KTableWidget(QWidget* parent = nullptr); 104 | Q_SLOT bool init(const QDomElement& config); 105 | }; 106 | KPF_REGISTER_CLASS(KTableWidget, QTableWidget) 107 | 108 | class KAction : public QAction 109 | { 110 | Q_OBJECT 111 | public: 112 | explicit KAction(QObject* parent = nullptr); 113 | Q_SLOT bool init(const QDomElement& config); 114 | }; 115 | KPF_REGISTER_CLASS(KAction, QAction) 116 | 117 | class KWidgetAction : public QWidgetAction 118 | { 119 | Q_OBJECT 120 | public: 121 | explicit KWidgetAction(QObject* parent = nullptr); 122 | Q_SLOT bool init(QDomElement config); 123 | }; 124 | KPF_REGISTER_CLASS(KWidgetAction, QWidgetAction) 125 | 126 | class KMenuBar : public QMenuBar 127 | { 128 | Q_OBJECT 129 | public: 130 | explicit KMenuBar(QWidget* parent = nullptr); 131 | Q_SLOT bool init(const QDomElement& config); 132 | }; 133 | KPF_REGISTER_CLASS(KMenuBar, QMenuBar) 134 | 135 | class KToolBar : public QToolBar 136 | { 137 | Q_OBJECT 138 | public: 139 | explicit KToolBar(QWidget* parent = nullptr); 140 | Q_SLOT bool init(const QDomElement& config); 141 | }; 142 | KPF_REGISTER_CLASS(KToolBar, QToolBar) 143 | 144 | class KToolButton : public QToolButton 145 | { 146 | Q_OBJECT 147 | public: 148 | explicit KToolButton(QWidget* parent = nullptr); 149 | Q_SLOT bool init(const QDomElement& config); 150 | }; 151 | KPF_REGISTER_CLASS(KToolButton, QToolButton) 152 | 153 | class KMainWindow : public QMainWindow 154 | { 155 | Q_OBJECT 156 | public: 157 | explicit KMainWindow(QWidget* parent = nullptr, Qt::WindowFlags flags = nullptr); 158 | Q_SLOT bool init(QDomElement config); 159 | Q_SIGNAL void closed(); 160 | // QWidget interface 161 | protected: 162 | void closeEvent(QCloseEvent*event); 163 | }; 164 | KPF_REGISTER_CLASS(KMainWindow, QMainWindow) 165 | -------------------------------------------------------------------------------- /src/core/KpfCoreImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommonPrivate.h" 4 | #include "ConnectionImpl.h" 5 | #include "ClassImpl.h" 6 | #include "ThreadImpl.h" 7 | #include "ObjectImpl.h" 8 | #include "Library.h" 9 | #include "EventImpl.h" 10 | #include "TopicImpl.h" 11 | #include "ConnectionImpl.h" 12 | #include "KpfLogPrivate.h" 13 | 14 | #ifdef Q_CC_MSVC 15 | #pragma warning(push) 16 | #pragma warning(disable:4250) 17 | #endif 18 | 19 | namespace Kpf { 20 | class KpfCoreImpl : public KpfCore, public NotifyManager 21 | { 22 | public: 23 | struct SignalEvent 24 | { 25 | QString className; 26 | QString eventId; 27 | QMetaMethod slot; 28 | }; 29 | 30 | virtual ~KpfCoreImpl() override; 31 | 32 | static KpfCoreImpl& instance(); 33 | ClassManagerImpl& classManager(); 34 | ThreadManagerImpl& threadManager(); 35 | ObjectManagerImpl& objectManager(); 36 | EventManagerImpl& eventManager(); 37 | TopicManagerImpl& topicManager(); 38 | ConnectionManagerImpl& connectionManager(); 39 | QMutex* mutex(); 40 | 41 | bool closingDown() const; 42 | 43 | QWeakPointer currentLibrary() const; 44 | void removeLibrary(QSharedPointer library); 45 | 46 | // KpfCore interface 47 | virtual bool init(int argc, char *argv[]) override; 48 | 49 | private: 50 | KpfCoreImpl(); 51 | 52 | bool loadPlugins(); 53 | bool loadAppConfig(const QString& appFile); 54 | bool loadComponents(const QDir& dir); 55 | void expandComponents(); 56 | void expandComponent(QDomElement& node, QMap& map); 57 | bool initConnections(); 58 | bool processInitializations(); 59 | 60 | void atExit(); 61 | 62 | QMutex mtx; 63 | 64 | QDomDocument appConfig; 65 | QDomElement rootNode; 66 | QDomElement objectsNode; 67 | QDomElement connectionsNode; 68 | QDomElement initializationsNode; 69 | QMap componentsConfig; 70 | QMap objectsComponentsNode; 71 | QMap connectionsComponentsNode; 72 | QMap initializationsComponentsNode; 73 | 74 | QScopedPointer classManagerImpl; 75 | QScopedPointer threadManagerImpl; 76 | QScopedPointer objectManagerImpl; 77 | QScopedPointer eventManagerImpl; 78 | QScopedPointer topicManagerImpl; 79 | QScopedPointer connectionManagerImpl; 80 | 81 | bool isClosingDown; 82 | QWeakPointer currentLib; 83 | QList> libraries; 84 | }; 85 | } // namespace Kpf 86 | #define kpfCoreImpl Kpf::KpfCoreImpl::instance() 87 | 88 | #ifdef Q_CC_MSVC 89 | #pragma warning(pop) 90 | #endif 91 | -------------------------------------------------------------------------------- /src/core/KpfLog.cpp: -------------------------------------------------------------------------------- 1 | #include "KpfLogPrivate.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::LogDisplayPage::LogDisplayPage() 5 | { 6 | auto buffer = kpfObject.findObject( 7 | QStringLiteral("LogDisplayBuffer")); 8 | if (buffer) { 9 | setBuffer(buffer); 10 | } 11 | } 12 | 13 | Kpf::LogDisplayWidget::LogDisplayWidget() 14 | { 15 | auto buffer = kpfObject.findObject( 16 | QStringLiteral("LogDisplayBuffer")); 17 | if (buffer) { 18 | setBuffer(buffer); 19 | } 20 | } 21 | 22 | void Kpf::initLogger(int argc, char* argv[]) 23 | { 24 | Q_UNUSED(argc) 25 | Q_UNUSED(argv) 26 | 27 | log4qt::LogDebugOutput* logDebugOutput; 28 | logDebugOutput = kpfObject.createObject( 29 | QStringLiteral("logDebugOutput"), 30 | QStringLiteral("LogDebugOutput")); 31 | if (logDebugOutput) { 32 | logDebugOutput->start(); 33 | } 34 | 35 | log4qt::LogFileMmapSaver* logFileMmapSaver; 36 | logFileMmapSaver = kpfObject.createObject( 37 | QStringLiteral("logFileMmapSaver"), 38 | QStringLiteral("LogFileMmapSaver")); 39 | if (logFileMmapSaver) 40 | { 41 | QDir dir(qApp->applicationDirPath() 42 | + QDir::separator() 43 | + QStringLiteral("Log_Critical")); 44 | if (!dir.exists()) { 45 | dir.mkpath(dir.absolutePath()); 46 | } 47 | logFileMmapSaver->setDir(dir.absolutePath()); 48 | logFileMmapSaver->setFilter(QtCriticalMsg); 49 | logFileMmapSaver->start(); 50 | } 51 | 52 | log4qt::LogFileNormalSaver* logFileNormalSaver; 53 | logFileNormalSaver = kpfObject.createObject( 54 | QStringLiteral("logFileNormalSaver"), 55 | QStringLiteral("LogFileNormalSaver")); 56 | if (logFileNormalSaver) { 57 | logFileNormalSaver->start(); 58 | } 59 | 60 | qCInfo(kpf) << "Log engine initialized"; 61 | } 62 | -------------------------------------------------------------------------------- /src/core/KpfLogPrivate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace Kpf { 8 | class LogDisplayPage : public log4qt::LogDisplayPage 9 | { 10 | Q_OBJECT 11 | public: 12 | LogDisplayPage(); 13 | }; 14 | 15 | class LogDisplayWidget : public log4qt::LogDisplayWidget 16 | { 17 | Q_OBJECT 18 | public: 19 | LogDisplayWidget(); 20 | }; 21 | 22 | void initLogger(int argc, char* argv[]); 23 | } // namespace Kpf 24 | 25 | KPF_REGISTER_CLASS(log4qt::LogDebugOutput, LogDebugOutput) 26 | KPF_REGISTER_CLASS(log4qt::LogFileNormalSaver, LogFileNormalSaver) 27 | KPF_REGISTER_CLASS(log4qt::LogFileMmapSaver, LogFileMmapSaver) 28 | KPF_REGISTER_CLASS(log4qt::LogDisplayBuffer, LogDisplayBuffer) 29 | KPF_REGISTER_CLASS(Kpf::LogDisplayPage, LogDisplayPage) 30 | KPF_REGISTER_CLASS(Kpf::LogDisplayWidget, LogDisplayWidget) 31 | -------------------------------------------------------------------------------- /src/core/KpfPrivate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommonPrivate.h" 4 | #include "InvokeHelperPrivate.h" 5 | #include "SignalSpy.h" 6 | #include "ClassImpl.h" 7 | #include "ThreadImpl.h" 8 | #include "ObjectImpl.h" 9 | #include "Library.h" 10 | #include "EventImpl.h" 11 | #include "TopicImpl.h" 12 | #include "EventBus.h" 13 | #include "ConnectionImpl.h" 14 | #include "KpfCoreImpl.h" 15 | #include "KpfLogPrivate.h" 16 | #include "KWidgets.h" 17 | -------------------------------------------------------------------------------- /src/core/Library.cpp: -------------------------------------------------------------------------------- 1 | #include "Library.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::Library::Library(const QFileInfo& info) 5 | : fileInfo(info), 6 | library(info.absoluteFilePath()) 7 | { 8 | library.setLoadHints(QLibrary::ResolveAllSymbolsHint 9 | | QLibrary::ExportExternalSymbolsHint); 10 | } 11 | 12 | Kpf::Library::~Library() 13 | { 14 | library.unload(); 15 | qCInfo(kpf) << "Library" 16 | << fileInfo.absoluteFilePath() 17 | << "unloaded"; 18 | } 19 | -------------------------------------------------------------------------------- /src/core/Library.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Kpf { 5 | struct MetaClassImpl; 6 | struct ObjectImpl; 7 | struct Library 8 | { 9 | explicit Library(const QFileInfo& fileInfo); 10 | virtual ~Library(); 11 | 12 | QFileInfo fileInfo; 13 | QLibrary library; 14 | QMap> classes; 15 | QMap> objects; 16 | }; 17 | } // namespace Kpf 18 | -------------------------------------------------------------------------------- /src/core/ObjectImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommonPrivate.h" 4 | #include "Library.h" 5 | #include "TopicImpl.h" 6 | #include "Library.h" 7 | 8 | #ifdef Q_CC_MSVC 9 | #pragma warning(push) 10 | #pragma warning(disable:4250) 11 | #endif 12 | 13 | namespace Kpf { 14 | struct ConnectionImpl; 15 | 16 | struct ObjectImpl : public Object 17 | { 18 | virtual ~ObjectImpl() override; 19 | 20 | static QSharedPointer create(QSharedPointer objectClass, 21 | const QString& name, 22 | const QDomElement& config); 23 | 24 | QSharedPointer library; 25 | 26 | QList> connections; 27 | 28 | QMap publishedEvents; 29 | QMap subscribedEvents; 30 | 31 | private: 32 | ObjectImpl(); 33 | }; 34 | 35 | class ObjectManagerImpl : public ObjectManager, public NotifyManager 36 | { 37 | Q_OBJECT 38 | public: 39 | ObjectManagerImpl(); 40 | virtual ~ObjectManagerImpl() override; 41 | 42 | static ObjectManagerImpl& instance(); 43 | 44 | // ObjectManager interface 45 | virtual QStringList objectNames() const override; 46 | virtual QWeakPointer findObject(const QString& name) const override; 47 | virtual QWeakPointer createObject(QString name, QString className, QDomElement config = QDomElement(), QObject* parent = qApp) override; 48 | virtual void destroyObject(const QString& name) override; 49 | 50 | QWeakPointer currentObject(); 51 | 52 | QWeakPointer createObject(QString name, QString className, const QDomElement& objectConfig, Ref> oParent = defaultObjectParent, Ref> wParent = defaultWidgetParent); 53 | QWeakPointer createObject(const QDomElement& objectConfig, Ref> oParent = defaultObjectParent, Ref> wParent = defaultWidgetParent); 54 | bool createChildren(const QDomElement& config, QObject* oParent = defaultObjectParent, QWidget* wParent = defaultWidgetParent); 55 | bool createChildren_withoutObject(const QDomElement& config, QObject* oParent = defaultObjectParent, QWidget* wParent = defaultWidgetParent); 56 | 57 | void setObjectParent(QObject* object, const QString& parent, QObject* oParent, QWidget* wParent); 58 | bool setObjectProperty(QSharedPointer& object); 59 | bool initObject(QSharedPointer& object); 60 | 61 | private: 62 | QStringList names; 63 | QMap> objects; 64 | QWeakPointer currentObj; 65 | 66 | static QObject* defaultObjectParent; 67 | static QWidget* defaultWidgetParent; 68 | }; 69 | } // namespace Kpf 70 | #define kpfObjectImpl Kpf::ObjectManagerImpl::instance() 71 | 72 | #ifdef Q_CC_MSVC 73 | #pragma warning(pop) 74 | #endif 75 | -------------------------------------------------------------------------------- /src/core/RegisterQtClasses.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | KPF_REGISTER(QPauseAnimation) 7 | KPF_REGISTER(QPropertyAnimation) 8 | KPF_REGISTER(QVariantAnimation) 9 | KPF_REGISTER(QFile) 10 | KPF_REGISTER(QFileSelector) 11 | KPF_REGISTER(QFileSystemWatcher) 12 | KPF_REGISTER(QProcess) 13 | KPF_REGISTER(QSaveFile) 14 | KPF_REGISTER(QIdentityProxyModel) 15 | KPF_REGISTER(QSortFilterProxyModel) 16 | KPF_REGISTER(QStringListModel) 17 | KPF_REGISTER(QEventLoop) 18 | KPF_REGISTER(QObject) 19 | KPF_REGISTER(QSharedMemory) 20 | KPF_REGISTER(QTimer) 21 | KPF_REGISTER(QTranslator) 22 | KPF_REGISTER(QLibrary) 23 | KPF_REGISTER(QPluginLoader) 24 | KPF_REGISTER(QEventTransition) 25 | KPF_REGISTER(QFinalState) 26 | KPF_REGISTER(QHistoryState) 27 | KPF_REGISTER(QSignalTransition) 28 | KPF_REGISTER(QState) 29 | KPF_REGISTER(QStateMachine) 30 | KPF_REGISTER(QThread) 31 | KPF_REGISTER(QThreadPool) 32 | KPF_REGISTER(QTimeLine) 33 | 34 | KPF_REGISTER(QStandardItemModel) 35 | KPF_REGISTER(QOffscreenSurface) 36 | KPF_REGISTER(QTextDocument) 37 | KPF_REGISTER(QDoubleValidator) 38 | KPF_REGISTER(QIntValidator) 39 | KPF_REGISTER(QRegExpValidator) 40 | 41 | KPF_REGISTER(QFileSystemModel) 42 | KPF_REGISTER(QGraphicsBlurEffect) 43 | KPF_REGISTER(QGraphicsColorizeEffect) 44 | KPF_REGISTER(QGraphicsDropShadowEffect) 45 | KPF_REGISTER(QGraphicsOpacityEffect) 46 | KPF_REGISTER(QGraphicsTextItem) 47 | KPF_REGISTER(QGraphicsProxyWidget) 48 | KPF_REGISTER(QGraphicsScene) 49 | KPF_REGISTER(QGraphicsRotation) 50 | KPF_REGISTER(QGraphicsScale) 51 | KPF_REGISTER(QGraphicsView) 52 | KPF_REGISTER(QGraphicsWidget) 53 | KPF_REGISTER(QColumnView) 54 | KPF_REGISTER(QDataWidgetMapper) 55 | KPF_REGISTER(QItemDelegate) 56 | KPF_REGISTER(QListView) 57 | KPF_REGISTER(QStyledItemDelegate) 58 | KPF_REGISTER(QTableView) 59 | KPF_REGISTER(QTreeView) 60 | KPF_REGISTER(QTreeWidget) 61 | KPF_REGISTER(QGesture) 62 | KPF_REGISTER(QPanGesture) 63 | KPF_REGISTER(QPinchGesture) 64 | KPF_REGISTER(QSwipeGesture) 65 | KPF_REGISTER(QTapAndHoldGesture) 66 | KPF_REGISTER(QTapGesture) 67 | KPF_REGISTER(QWidget) 68 | KPF_REGISTER(QKeyEventTransition) 69 | KPF_REGISTER(QMouseEventTransition) 70 | KPF_REGISTER(QCommonStyle) 71 | KPF_REGISTER(QProxyStyle) 72 | KPF_REGISTER(QCompleter) 73 | KPF_REGISTER(QSystemTrayIcon) 74 | KPF_REGISTER(QUndoGroup) 75 | KPF_REGISTER(QUndoStack) 76 | KPF_REGISTER(QUndoView) 77 | KPF_REGISTER(QAbstractScrollArea) 78 | KPF_REGISTER(QAbstractSlider) 79 | KPF_REGISTER(QAbstractSpinBox) 80 | KPF_REGISTER(QButtonGroup) 81 | KPF_REGISTER(QCalendarWidget) 82 | KPF_REGISTER(QCheckBox) 83 | KPF_REGISTER(QComboBox) 84 | KPF_REGISTER(QCommandLinkButton) 85 | KPF_REGISTER(QDateEdit) 86 | KPF_REGISTER(QDateTimeEdit) 87 | KPF_REGISTER(QTimeEdit) 88 | KPF_REGISTER(QDial) 89 | KPF_REGISTER(QDialogButtonBox) 90 | KPF_REGISTER(QDockWidget) 91 | KPF_REGISTER(QFocusFrame) 92 | KPF_REGISTER(QFontComboBox) 93 | KPF_REGISTER(QFrame) 94 | KPF_REGISTER(QGroupBox) 95 | KPF_REGISTER(QKeySequenceEdit) 96 | KPF_REGISTER(QLabel) 97 | KPF_REGISTER(QLCDNumber) 98 | KPF_REGISTER(QLineEdit) 99 | KPF_REGISTER(QMdiArea) 100 | KPF_REGISTER(QMdiSubWindow) 101 | KPF_REGISTER(QMenu) 102 | KPF_REGISTER(QPlainTextEdit) 103 | KPF_REGISTER(QProgressBar) 104 | KPF_REGISTER(QPushButton) 105 | KPF_REGISTER(QRadioButton) 106 | KPF_REGISTER(QScrollArea) 107 | KPF_REGISTER(QScrollBar) 108 | KPF_REGISTER(QSlider) 109 | KPF_REGISTER(QDoubleSpinBox) 110 | KPF_REGISTER(QSpinBox) 111 | KPF_REGISTER(QSplashScreen) 112 | KPF_REGISTER(QSplitter) 113 | KPF_REGISTER(QStatusBar) 114 | KPF_REGISTER(QTabBar) 115 | KPF_REGISTER(QTextBrowser) 116 | KPF_REGISTER(QTextEdit) 117 | KPF_REGISTER(QToolBox) 118 | KPF_REGISTER(QColorDialog) 119 | KPF_REGISTER(QDialog) 120 | KPF_REGISTER(QErrorMessage) 121 | KPF_REGISTER(QFileDialog) 122 | KPF_REGISTER(QFontDialog) 123 | KPF_REGISTER(QInputDialog) 124 | KPF_REGISTER(QMessageBox) 125 | KPF_REGISTER(QProgressDialog) 126 | KPF_REGISTER(QWizard) 127 | KPF_REGISTER(QWizardPage) 128 | -------------------------------------------------------------------------------- /src/core/SignalSpy.cpp: -------------------------------------------------------------------------------- 1 | #include "SignalSpy.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::SignalSpy::SignalSpy(QSharedPointer& object, const QByteArray& eventName) 5 | : signal(convertSignalName(eventName)) 6 | { 7 | qCDebug(kpf) << "Create signal spy for object" << object->name 8 | << ", observing signal event" << eventName; 9 | 10 | const int memberOffset = QObject::staticMetaObject.methodCount(); 11 | 12 | const QMetaObject* metaObject = object->object->metaObject(); 13 | const int signalIndex = metaObject->indexOfMethod(eventName.constData()); 14 | if (signalIndex < 0) 15 | { 16 | qCWarning(kpf) << "Create signal spy for object" << object->name 17 | << "failed: no such signal" << eventName; 18 | return; 19 | } 20 | 21 | if (!QMetaObject::connect(object->object, 22 | signalIndex, 23 | this, 24 | memberOffset, 25 | Qt::AutoConnection, 26 | nullptr)) 27 | { 28 | qCWarning(kpf) << "Create signal spy for object" << object->name 29 | << "failed: QMetaObject::connect returned false"; 30 | return; 31 | } 32 | 33 | QMetaMethod signalMethod = metaObject->method(signalIndex); 34 | for (int i = 0; i < signalMethod.parameterCount(); ++i) 35 | { 36 | int type = signalMethod.parameterType(i); 37 | args << QVariant(QVariant::Type(type)); 38 | } 39 | } 40 | 41 | int Kpf::SignalSpy::qt_metacall(QMetaObject::Call call, int methodId, void** a) 42 | { 43 | methodId = QObject::qt_metacall(call, methodId, a); 44 | if (methodId < 0) 45 | return methodId; 46 | 47 | if (call != QMetaObject::InvokeMetaMethod) { 48 | return methodId; 49 | } 50 | 51 | if (methodId == 0) 52 | { 53 | for (int i = 0; i < args.count(); ++i) 54 | { 55 | QVariant& arg = args[i]; 56 | QMetaType::Type type = QMetaType::Type(arg.type()); 57 | if (type == QMetaType::QVariant) 58 | arg = *reinterpret_cast(a[i + 1]); 59 | else 60 | arg = QVariant(type, a[i + 1]); 61 | } 62 | } 63 | --methodId; 64 | 65 | eventObject.post(args); 66 | 67 | return methodId; 68 | } 69 | -------------------------------------------------------------------------------- /src/core/SignalSpy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Kpf { 5 | struct ObjectImpl; 6 | class SignalSpy : public QObject 7 | { 8 | public: 9 | SignalSpy(QSharedPointer& object, const QByteArray& eventName); 10 | 11 | ObjectEvent eventObject; 12 | 13 | protected: 14 | virtual int qt_metacall(QMetaObject::Call call, int methodId, void **a) override; 15 | 16 | private: 17 | QByteArray signal; 18 | QVariantList args; 19 | }; 20 | } // namespace Kpf 21 | -------------------------------------------------------------------------------- /src/core/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadImpl.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::Thread::~Thread() 5 | { 6 | } 7 | 8 | Kpf::Thread::Thread() 9 | { 10 | } 11 | 12 | Kpf::ThreadImpl::~ThreadImpl() 13 | { 14 | if (kpfCoreImpl.closingDown()) { 15 | delete eventBus; 16 | } else { 17 | eventBus->deleteLater(); 18 | } 19 | 20 | if (externalThread) { 21 | return; 22 | } 23 | thread->requestInterruption(); 24 | thread->quit(); 25 | thread->wait(); 26 | if (kpfCoreImpl.closingDown()) { 27 | delete thread; 28 | } else { 29 | thread->deleteLater(); 30 | } 31 | kpfThreadImpl.notify(&IThreadNotifier::threadStopped, name); 32 | } 33 | 34 | QSharedPointer Kpf::ThreadImpl::create(const QString& name, bool externalThread) 35 | { 36 | QSharedPointer ret(new ThreadImpl(externalThread)); 37 | ret->name = name; 38 | return ret; 39 | } 40 | 41 | Kpf::ThreadImpl::ThreadImpl(bool external) 42 | { 43 | eventBus = new EventBus; 44 | 45 | if (external) 46 | { 47 | externalThread = true; 48 | } 49 | else 50 | { 51 | thread = new QThread; 52 | thread->setObjectName(name); 53 | thread->start(); 54 | eventBus->moveToThread(thread); 55 | kpfThreadImpl.notify(&IThreadNotifier::threadStarted, name); 56 | } 57 | } 58 | 59 | Kpf::ThreadManager& Kpf::ThreadManager::instance() 60 | { 61 | return kpfCoreImpl.threadManager(); 62 | } 63 | 64 | Kpf::ThreadManagerImpl::ThreadManagerImpl() 65 | : mainThread(ThreadImpl::create("", true)) 66 | { 67 | } 68 | 69 | Kpf::ThreadManagerImpl::~ThreadManagerImpl() 70 | { 71 | QMutexLocker locker(kpfMutex()); 72 | while (!names.isEmpty()) { 73 | threads.remove(names.pop()); 74 | } 75 | } 76 | 77 | Kpf::ThreadManagerImpl &Kpf::ThreadManagerImpl::instance() 78 | { 79 | return kpfCoreImpl.threadManager(); 80 | } 81 | 82 | QStringList Kpf::ThreadManagerImpl::threadNames() const 83 | { 84 | QMutexLocker locker(kpfMutex()); 85 | return threads.keys(); 86 | } 87 | 88 | QWeakPointer Kpf::ThreadManagerImpl::findThread(const QString& threadName) const 89 | { 90 | QMutexLocker locker(kpfMutex()); 91 | return threads.value(threadName).staticCast(); 92 | } 93 | 94 | QWeakPointer Kpf::ThreadManagerImpl::defaultThread() const 95 | { 96 | return mainThread; 97 | } 98 | 99 | void Kpf::ThreadManagerImpl::removeThread(const QWeakPointer& t) 100 | { 101 | QMutexLocker locker(kpfMutex()); 102 | QSharedPointer thread = t.toStrongRef(); 103 | if (thread) { 104 | threads.remove(thread->name); 105 | } 106 | } 107 | 108 | void Kpf::ThreadManagerImpl::setObjectThread(QSharedPointer& object) 109 | { 110 | QMutexLocker locker(kpfMutex()); 111 | 112 | QSharedPointer thread = mainThread; 113 | 114 | bool subThread = object->config.attribute(KEY_SUBTHREAD).toLower() == "true"; 115 | if (subThread) 116 | { 117 | QString threadName = object->config.attribute(KEY_THREADNAME); 118 | thread = kpfThread.findThread(threadName) 119 | .toStrongRef().staticCast(); 120 | if (!thread) 121 | { 122 | thread = ThreadImpl::create(threadName); 123 | names.push(threadName); 124 | threads.insert(threadName, thread); 125 | } 126 | 127 | object->object->setParent(nullptr); 128 | object->object->moveToThread(thread->thread); 129 | 130 | qCDebug(kpf) << "Move object" << object->name 131 | << "to thread" << threadName; 132 | } 133 | 134 | object->thread = thread; 135 | thread->objects << object.data(); 136 | } 137 | -------------------------------------------------------------------------------- /src/core/ThreadImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommonPrivate.h" 4 | 5 | #ifdef Q_CC_MSVC 6 | #pragma warning(push) 7 | #pragma warning(disable:4250) 8 | #endif 9 | 10 | namespace Kpf { 11 | struct ObjectImpl; 12 | class EventBus; 13 | 14 | struct ThreadImpl : public Thread 15 | { 16 | virtual ~ThreadImpl() override; 17 | 18 | static QSharedPointer create(const QString& name, bool externalThread = false); 19 | 20 | bool externalThread = false; 21 | 22 | private: 23 | ThreadImpl(bool externalThread); 24 | }; 25 | 26 | class ThreadManagerImpl : public ThreadManager, public NotifyManager 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | ThreadManagerImpl(); 32 | virtual ~ThreadManagerImpl() override; 33 | 34 | static ThreadManagerImpl& instance(); 35 | 36 | // ThreadManager interface 37 | virtual QStringList threadNames() const override; 38 | virtual QWeakPointer findThread(const QString& threadName) const override; 39 | virtual QWeakPointer defaultThread() const override; 40 | virtual void removeThread(const QWeakPointer& thread) override; 41 | 42 | void setObjectThread(QSharedPointer& object); 43 | 44 | private: 45 | QStack names; 46 | QMap> threads; 47 | QSharedPointer mainThread; 48 | }; 49 | } // namespace Kpf 50 | #define kpfThreadImpl Kpf::ThreadManagerImpl::instance() 51 | 52 | #ifdef Q_CC_MSVC 53 | #pragma warning(pop) 54 | #endif 55 | -------------------------------------------------------------------------------- /src/core/Topic.cpp: -------------------------------------------------------------------------------- 1 | #include "TopicImpl.h" 2 | #include "KpfPrivate.h" 3 | 4 | Kpf::Topic::~Topic() 5 | { 6 | } 7 | 8 | Kpf::Topic::Topic() 9 | { 10 | } 11 | 12 | Kpf::TopicImpl::TopicImpl() 13 | { 14 | } 15 | 16 | Kpf::TopicImpl::~TopicImpl() 17 | { 18 | } 19 | 20 | QSharedPointer Kpf::TopicImpl::create(const QString& name) 21 | { 22 | QSharedPointer ret = QSharedPointer::create(); 23 | ret->name = name; 24 | return ret; 25 | } 26 | 27 | Kpf::TopicManager& Kpf::TopicManager::instance() 28 | { 29 | return kpfCoreImpl.topicManager(); 30 | } 31 | 32 | Kpf::TopicManagerImpl::TopicManagerImpl() 33 | { 34 | } 35 | 36 | Kpf::TopicManagerImpl::~TopicManagerImpl() 37 | { 38 | QMutexLocker locker(kpfMutex()); 39 | while (!names.isEmpty()) { 40 | topics.remove(names.pop()); 41 | } 42 | } 43 | 44 | Kpf::TopicManagerImpl& Kpf::TopicManagerImpl::instance() 45 | { 46 | return kpfCoreImpl.topicManager(); 47 | } 48 | 49 | QStringList Kpf::TopicManagerImpl::topicNames() const 50 | { 51 | QMutexLocker locker(kpfMutex()); 52 | return topics.keys(); 53 | } 54 | 55 | QWeakPointer Kpf::TopicManagerImpl::findTopic(const QString& name) const 56 | { 57 | QMutexLocker locker(kpfMutex()); 58 | return topics.value(name).staticCast(); 59 | } 60 | 61 | QSharedPointer Kpf::TopicManagerImpl::addTopic(const QString& name) 62 | { 63 | QMutexLocker locker(kpfMutex()); 64 | QSharedPointer topic = findTopic(name) 65 | .toStrongRef() 66 | .staticCast(); 67 | if (topic) { 68 | return topic; 69 | } 70 | 71 | topic = TopicImpl::create(name); 72 | names.push(name); 73 | topics.insert(name, topic); 74 | return topic; 75 | } 76 | -------------------------------------------------------------------------------- /src/core/TopicImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "EventImpl.h" 4 | 5 | namespace Kpf { 6 | struct TopicImpl : public Topic 7 | { 8 | TopicImpl(); 9 | virtual ~TopicImpl(); 10 | 11 | static QSharedPointer create(const QString& name); 12 | }; 13 | 14 | class TopicManagerImpl : public TopicManager 15 | { 16 | Q_OBJECT 17 | public: 18 | TopicManagerImpl(); 19 | virtual ~TopicManagerImpl(); 20 | 21 | static TopicManagerImpl& instance(); 22 | 23 | // TopicManager interface 24 | virtual QStringList topicNames() const override; 25 | virtual QWeakPointer findTopic(const QString& name) const override; 26 | 27 | QSharedPointer addTopic(const QString& name); 28 | 29 | private: 30 | QStack names; 31 | QMap> topics; 32 | }; 33 | 34 | } // namespace Kpf 35 | #define kpfTopicImpl Kpf::TopicManagerImpl::instance() 36 | -------------------------------------------------------------------------------- /src/core/core.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-06-01T12:38:36 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui xml 8 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 9 | 10 | CONFIG(release, debug|release): TARGET = KPF 11 | else:CONFIG(debug, debug|release): TARGET = KPFd 12 | 13 | TEMPLATE = lib 14 | CONFIG += c++11 15 | 16 | DESTDIR = $$PWD/../../bin 17 | 18 | DEFINES += KPF_LIBRARY 19 | 20 | # The following define makes your compiler emit warnings if you use 21 | # any feature of Qt which has been marked as deprecated (the exact warnings 22 | # depend on your compiler). Please consult the documentation of the 23 | # deprecated API in order to know how to port your code away from it. 24 | DEFINES += QT_DEPRECATED_WARNINGS 25 | 26 | # You can also make your code fail to compile if you use deprecated APIs. 27 | # In order to do so, uncomment the following line. 28 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 29 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 30 | 31 | INCLUDEPATH += $$PWD/../../include 32 | 33 | HEADERS += \ 34 | $$PWD/../../include/Kpf/Common.h \ 35 | $$PWD/../../include/Kpf/Constants.h \ 36 | $$PWD/../../include/Kpf/InvokeHelper.h \ 37 | $$PWD/../../include/Kpf/Connection.h \ 38 | $$PWD/../../include/Kpf/Event.h \ 39 | $$PWD/../../include/Kpf/Topic.h \ 40 | $$PWD/../../include/Kpf/Thread.h \ 41 | $$PWD/../../include/Kpf/Object.h \ 42 | $$PWD/../../include/Kpf/Class.h \ 43 | $$PWD/../../include/Kpf/KpfCore.h \ 44 | $$PWD/../../include/Kpf/EventHelper.h \ 45 | $$PWD/../../include/Kpf/Kpf.h \ 46 | SignalSpy.h \ 47 | ClassImpl.h \ 48 | ThreadImpl.h \ 49 | ObjectImpl.h \ 50 | EventImpl.h \ 51 | TopicImpl.h \ 52 | EventBus.h \ 53 | KpfCoreImpl.h \ 54 | KpfLogPrivate.h \ 55 | KWidgets.h \ 56 | KpfPrivate.h \ 57 | InvokeHelperPrivate.h \ 58 | CommonPrivate.h \ 59 | ConnectionImpl.h \ 60 | Library.h \ 61 | RegisterQtClasses.h 62 | 63 | SOURCES += \ 64 | CommonPrivate.cpp \ 65 | InvokeHelper.cpp \ 66 | SignalSpy.cpp \ 67 | Class.cpp \ 68 | Thread.cpp \ 69 | Object.cpp \ 70 | Event.cpp \ 71 | Topic.cpp \ 72 | EventBus.cpp \ 73 | Connection.cpp \ 74 | KpfCore.cpp \ 75 | KpfLog.cpp \ 76 | KWidgets.cpp \ 77 | Library.cpp 78 | 79 | DISTFILES += \ 80 | $$PWD/../../bin/components/KWidgets.json 81 | 82 | include(CoreDump/CoreDump.pri) 83 | 84 | DEFINES += LOG4QT_STATIC 85 | include(../../log4qt/src/log4qt.pri) 86 | -------------------------------------------------------------------------------- /src/plugins/plugins.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | CONFIG += ordered 3 | SUBDIRS += \ 4 | test 5 | -------------------------------------------------------------------------------- /src/plugins/test/Test.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_H 2 | #define TEST_H 3 | 4 | #include 5 | 6 | #if defined(TEST_LIBRARY) 7 | # define TEST_EXPORT Q_DECL_EXPORT 8 | #else 9 | # define TEST_EXPORT Q_DECL_IMPORT 10 | #endif 11 | 12 | class TEST_EXPORT Test : public QObject 13 | { 14 | Q_OBJECT 15 | KPF_PUBEVENT(TestEvent) 16 | KPF_SUBEVENT(TestSlot, testSlot) 17 | 18 | public: 19 | explicit Test(QObject *parent = nullptr); 20 | ~Test(); 21 | 22 | Q_SLOT bool init(const QDomElement& config); 23 | 24 | Q_SLOT void start(); 25 | 26 | Q_SIGNAL void testSignal(quint32 value); 27 | Q_SLOT void testSlot(quint32 value); 28 | }; 29 | KPF_REGISTER(Test) 30 | 31 | #endif // TEST_H 32 | -------------------------------------------------------------------------------- /src/plugins/test/test.cpp: -------------------------------------------------------------------------------- 1 | #include "Test.h" 2 | #include 3 | 4 | Test::Test(QObject *parent) : QObject(parent) 5 | { 6 | } 7 | 8 | Test::~Test() 9 | { 10 | QThread::sleep(5); 11 | } 12 | 13 | bool Test::init(const QDomElement&) 14 | { 15 | qInfo() << "Test: initialized at thread" << QThread::currentThread() 16 | << ", it's belonging thread is" << thread() 17 | << ", main thread is" << qApp->thread(); 18 | 19 | return true; 20 | } 21 | 22 | void Test::start() 23 | { 24 | qInfo() << "Test: start() called at thread" << QThread::currentThread() 25 | << ", it's belonging thread is" << thread() 26 | << ", main thread is" << qApp->thread(); 27 | 28 | qInfo() << "Test: emit testSignal at initialization with arg=32"; 29 | emit testSignal(32); 30 | 31 | qInfo() << "Test: send TestEvent at initialization with arg=64"; 32 | kSendEvent(TestEvent, 64); 33 | 34 | qInfo() << "Test: post TestEvent at initialization with arg=128"; 35 | kPostEvent(TestEvent, 128); 36 | } 37 | 38 | void Test::testSlot(quint32 value) 39 | { 40 | qInfo() << "Test: testSlot() received with arg =" << value 41 | << ", at thread" << QThread::currentThread() 42 | << ", it's belonging thread is" << thread() 43 | << ", main thread is" << qApp->thread(); 44 | } 45 | -------------------------------------------------------------------------------- /src/plugins/test/test.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-06-01T15:45:14 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui xml 8 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 9 | 10 | TEMPLATE = lib 11 | CONFIG += c++11 12 | 13 | DEFINES += TEST_LIBRARY 14 | 15 | win32:CONFIG(release, debug|release): TARGET = Test 16 | else:win32:CONFIG(debug, debug|release): TARGET = Testd 17 | else:unix:!macx: TARGET = Test 18 | 19 | DESTDIR = $$_PRO_FILE_PWD_/../../../bin/plugins 20 | 21 | # The following define makes your compiler emit warnings if you use 22 | # any feature of Qt which has been marked as deprecated (the exact warnings 23 | # depend on your compiler). Please consult the documentation of the 24 | # deprecated API in order to know how to port your code away from it. 25 | DEFINES += QT_DEPRECATED_WARNINGS 26 | 27 | # You can also make your code fail to compile if you use deprecated APIs. 28 | # In order to do so, uncomment the following line. 29 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 30 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 31 | 32 | 33 | SOURCES += \ 34 | Test.cpp 35 | 36 | HEADERS += \ 37 | Test.h 38 | 39 | DISTFILES += \ 40 | $$PWD/../../../bin/components/test.json 41 | 42 | include($$PWD/../../../Kpf.pri) 43 | -------------------------------------------------------------------------------- /src/src.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | CONFIG += ordered 3 | SUBDIRS += \ 4 | core \ 5 | app \ 6 | plugins 7 | --------------------------------------------------------------------------------