mainwindow.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. #include "mainwindow.h"
  2. #include "database_manager/databasemodule.h"
  3. #include "daemon/daemon_client.h"
  4. #include "daemon/daemon_connection_dialog.h"
  5. #include "daemon/daemon_message_flow_widget.h"
  6. #include "api/SoftBusAPI.h"
  7. #include "settings/settings_dialog.h"
  8. #include "toolbar/toolbar.h"
  9. #include "view_serial/serialmodule.h"
  10. #include "view_serial/serialdockpage.h"
  11. #include "view_network/networkmodule.h"
  12. #include "view_network/networkdockpage.h"
  13. #include "view_task/TaskManagementPage.h"
  14. #include "connect_signal/view_instance_manager.h"
  15. #include "view_device_config/device_tree_widget.h"
  16. #include "utils/logging.h"
  17. #include <QAction>
  18. #include <QApplication>
  19. #include <QCloseEvent>
  20. #include <QDockWidget>
  21. #include <QHBoxLayout>
  22. #include <QJsonDocument>
  23. #include <QJsonObject>
  24. #include <QLabel>
  25. #include <QMenu>
  26. #include <QMenuBar>
  27. #include <QMessageBox>
  28. #include <QSettings>
  29. #include <QShortcut>
  30. #include <QStackedWidget>
  31. #include <QStatusBar>
  32. #include <QToolBar>
  33. #include <QVBoxLayout>
  34. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { createUI(); }
  35. void MainWindow::createUI() {
  36. // 创建菜单栏
  37. createMenuBar();
  38. // 创建主布局
  39. QWidget *centralWidget = new QWidget(this);
  40. QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
  41. // 界面设置
  42. setWindowTitle("软件总线");
  43. setWindowIcon(QIcon(":/qrc/icons/ads_icon.svg"));
  44. setUnifiedTitleAndToolBarOnMac(true);
  45. setDockNestingEnabled(true);
  46. setAnimated(true);
  47. setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
  48. setDockOptions(QMainWindow::AllowTabbedDocks | QMainWindow::AnimatedDocks |
  49. QMainWindow::VerticalTabs);
  50. setStatusBar(new QStatusBar(this));
  51. setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
  52. setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
  53. setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
  54. setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
  55. setMinimumSize(800, 600);
  56. setMaximumSize(1600, 1200);
  57. // 创建页面堆栈
  58. m_pageStack = new QStackedWidget(this);
  59. mainLayout->addWidget(m_pageStack);
  60. centralWidget->setLayout(mainLayout);
  61. setCentralWidget(centralWidget);
  62. // 先设置守护进程状态(必须在创建模块之前,因为模块可能会初始化 API)
  63. setupDaemonStatus();
  64. // 创建工具栏和页面(在守护进程设置之后)
  65. createHomeToolbar();
  66. createSerialToolbar();
  67. createNetworkToolbar();
  68. createDatabaseToolbar();
  69. createTaskToolbar();
  70. createSettingsToolbar();
  71. createHelpToolbar();
  72. // 默认显示主界面
  73. switchToPage(1);
  74. // 设置快捷键
  75. setupShortcuts();
  76. // 链接信号槽
  77. connectSignals();
  78. // 创建状态栏
  79. this->statusBar()->showMessage("就绪");
  80. }
  81. void MainWindow::createMenuBar() {
  82. // 创建菜单栏
  83. QMenuBar *menuBar = new QMenuBar(this);
  84. setMenuBar(menuBar);
  85. // 视图菜单
  86. QMenu *viewMenu = menuBar->addMenu("视图");
  87. QAction *homeAction =
  88. viewMenu->addAction(QIcon(":/qrc/icons/home.png"), "主界面");
  89. QAction *serialAction =
  90. viewMenu->addAction(QIcon(":/qrc/icons/serial.png"), "串口");
  91. QAction *networkAction =
  92. viewMenu->addAction(QIcon(":/qrc/icons/network.png"), "网络");
  93. QAction *databaseAction =
  94. viewMenu->addAction(QIcon(":/qrc/icons/grid_on.svg"), "数据库");
  95. QAction *taskAction =
  96. viewMenu->addAction(QIcon(":/qrc/icons/task.png"), "任务管理");
  97. QAction *settingsAction =
  98. viewMenu->addAction(QIcon(":/qrc/icons/settings.png"), "设置");
  99. QAction *helpAction =
  100. viewMenu->addAction(QIcon(":/qrc/icons/help.png"), "帮助");
  101. // 连接视图菜单的切换功能
  102. connect(homeAction, &QAction::triggered, this, [this]() { switchToPage(0); });
  103. connect(serialAction, &QAction::triggered, this,
  104. [this]() { switchToPage(1); });
  105. connect(networkAction, &QAction::triggered, this,
  106. [this]() { switchToPage(2); });
  107. connect(databaseAction, &QAction::triggered, this,
  108. [this]() { switchToPage(3); });
  109. connect(taskAction, &QAction::triggered, this,
  110. [this]() {
  111. if (m_taskPageIndex >= 0) {
  112. switchToPage(m_taskPageIndex);
  113. }
  114. });
  115. connect(settingsAction, &QAction::triggered, this,
  116. [this]() { switchToPage(5); });
  117. connect(helpAction, &QAction::triggered, this, [this]() { switchToPage(6); });
  118. // 文件菜单
  119. QMenu *fileMenu = menuBar->addMenu("文件");
  120. QAction *newAction =
  121. fileMenu->addAction(QIcon(":/qrc/icons/new.png"), "新建");
  122. QAction *openAction =
  123. fileMenu->addAction(QIcon(":/qrc/icons/open.png"), "打开");
  124. QAction *saveAction =
  125. fileMenu->addAction(QIcon(":/qrc/icons/save.png"), "保存");
  126. fileMenu->addSeparator();
  127. QAction *exitAction =
  128. fileMenu->addAction(QIcon(":/qrc/icons/exit.png"), "退出");
  129. // 编辑菜单
  130. QMenu *editMenu = menuBar->addMenu("编辑");
  131. QAction *undoAction =
  132. editMenu->addAction(QIcon(":/qrc/icons/undo.png"), "撤销");
  133. QAction *redoAction =
  134. editMenu->addAction(QIcon(":/qrc/icons/redo.png"), "重做");
  135. editMenu->addSeparator();
  136. QAction *cutAction =
  137. editMenu->addAction(QIcon(":/qrc/icons/cut.png"), "剪切");
  138. QAction *copyAction =
  139. editMenu->addAction(QIcon(":/qrc/icons/copy.png"), "复制");
  140. QAction *pasteAction =
  141. editMenu->addAction(QIcon(":/qrc/icons/paste.png"), "粘贴");
  142. // 帮助菜单
  143. QMenu *helpMenu = menuBar->addMenu("帮助");
  144. QAction *helpDocAction =
  145. helpMenu->addAction(QIcon(":/qrc/icons/help.png"), "帮助文档");
  146. QAction *aboutAction =
  147. helpMenu->addAction(QIcon(":/qrc/icons/about.png"), "关于");
  148. QAction *updateAction =
  149. helpMenu->addAction(QIcon(":/qrc/icons/update.png"), "检查更新");
  150. connect(aboutAction, &QAction::triggered, this, &MainWindow::showAbout);
  151. // 连接退出菜单项,真正退出应用
  152. connect(exitAction, &QAction::triggered, qApp, &QApplication::quit);
  153. }
  154. void MainWindow::createHomeToolbar() {
  155. // 创建主界面工具栏
  156. Toolbar *homeToolbar = new Toolbar("主工具栏", this);
  157. addToolBar(Qt::TopToolBarArea, homeToolbar);
  158. homeToolbar->hide();
  159. // 添加按钮
  160. homeToolbar->addAction(QIcon(":/qrc/icons/new.png"), "新建");
  161. homeToolbar->addAction(QIcon(":/qrc/icons/open.png"), "打开");
  162. homeToolbar->addAction(QIcon(":/qrc/icons/save.png"), "保存");
  163. homeToolbar->addAction(QIcon(":/qrc/icons/print.png"), "打印");
  164. // 创建主界面页面
  165. QLabel *homePage = new QLabel("<center><h1>主界面</h1></center>", this);
  166. homePage->setAlignment(Qt::AlignCenter);
  167. // 添加到堆栈
  168. m_toolbars.append(homeToolbar);
  169. m_pageStack->addWidget(homePage);
  170. }
  171. void MainWindow::createSerialToolbar() {
  172. if (!m_serialModule) {
  173. m_serialModule = new SerialModule(this, this);
  174. }
  175. if (Toolbar *serialToolbar = m_serialModule->toolbar()) {
  176. addToolBar(Qt::TopToolBarArea, serialToolbar);
  177. serialToolbar->hide();
  178. m_toolbars.append(serialToolbar);
  179. }
  180. if (QWidget *serialPage = m_serialModule->pageWidget()) {
  181. m_serialPageIndex = m_pageStack->addWidget(serialPage);
  182. }
  183. }
  184. void MainWindow::createNetworkToolbar() {
  185. if (!m_networkModule) {
  186. m_networkModule = new NetworkModule(this, this);
  187. }
  188. if (Toolbar *networkToolbar = m_networkModule->toolbar()) {
  189. addToolBar(Qt::TopToolBarArea, networkToolbar);
  190. networkToolbar->hide();
  191. m_toolbars.append(networkToolbar);
  192. }
  193. if (QWidget *networkPage = m_networkModule->pageWidget()) {
  194. m_networkPageIndex = m_pageStack->addWidget(networkPage);
  195. }
  196. }
  197. void MainWindow::createDatabaseToolbar() {
  198. if (!m_databaseModule) {
  199. m_databaseModule = new DatabaseModule(this, this);
  200. }
  201. if (Toolbar *databaseToolbar = m_databaseModule->toolbar()) {
  202. addToolBar(Qt::TopToolBarArea, databaseToolbar);
  203. databaseToolbar->hide();
  204. m_toolbars.append(databaseToolbar);
  205. }
  206. if (QWidget *databasePage = m_databaseModule->pageWidget()) {
  207. m_databasePageIndex = m_pageStack->addWidget(databasePage);
  208. }
  209. }
  210. void MainWindow::createTaskToolbar() {
  211. // 创建任务管理页面
  212. if (!m_taskPage) {
  213. m_taskPage = new TaskManagementPage(this);
  214. }
  215. // 创建空工具栏以保持索引一致性(任务页面的工具栏已内置在页面中)
  216. Toolbar *taskToolbar = new Toolbar("任务管理工具栏", this);
  217. addToolBar(Qt::TopToolBarArea, taskToolbar);
  218. taskToolbar->hide();
  219. m_toolbars.append(taskToolbar);
  220. // 添加任务页面到堆栈
  221. m_taskPageIndex = m_pageStack->addWidget(m_taskPage);
  222. }
  223. void MainWindow::createSettingsToolbar() {
  224. // 创建设置界面工具栏
  225. Toolbar *settingsToolbar = new Toolbar("设置工具栏", this);
  226. addToolBar(Qt::TopToolBarArea, settingsToolbar);
  227. settingsToolbar->hide();
  228. // 添加按钮
  229. QAction *preferencesAction = settingsToolbar->addAction(QIcon(":/qrc/icons/preferences.png"), "首选项");
  230. connect(preferencesAction, &QAction::triggered, this, &MainWindow::showSettingsDialog);
  231. settingsToolbar->addAction(QIcon(":/qrc/icons/theme.png"), "主题");
  232. settingsToolbar->addAction(QIcon(":/qrc/icons/keyboard.png"), "快捷键");
  233. settingsToolbar->addAction(QIcon(":/qrc/icons/plugins.png"), "插件");
  234. // 创建设置界面页面
  235. QLabel *settingsPage = new QLabel("<center><h1>设置界面</h1><p>点击工具栏中的\"首选项\"按钮打开设置对话框</p></center>", this);
  236. settingsPage->setAlignment(Qt::AlignCenter);
  237. // 添加到堆栈
  238. m_toolbars.append(settingsToolbar);
  239. m_pageStack->addWidget(settingsPage);
  240. }
  241. void MainWindow::createHelpToolbar() {
  242. // 创建帮助界面工具栏
  243. Toolbar *helpToolbar = new Toolbar("帮助工具栏", this);
  244. addToolBar(Qt::TopToolBarArea, helpToolbar);
  245. helpToolbar->hide();
  246. // 添加按钮
  247. helpToolbar->addAction(QIcon(":/qrc/icons/help.png"), "帮助文档");
  248. helpToolbar->addAction(QIcon(":/qrc/icons/about.png"), "关于");
  249. helpToolbar->addAction(QIcon(":/qrc/icons/update.png"), "检查更新");
  250. // 创建帮助界面页面
  251. QLabel *helpPage = new QLabel("<center><h1>帮助界面</h1></center>", this);
  252. helpPage->setAlignment(Qt::AlignCenter);
  253. // 添加到堆栈
  254. m_toolbars.append(helpToolbar);
  255. m_pageStack->addWidget(helpPage);
  256. }
  257. /*
  258. function: 返回指定索引的页面
  259. @author: flower
  260. @date: 2025-10-23
  261. @param index 页面索引
  262. @return 无
  263. */
  264. void MainWindow::switchToPage(int index) {
  265. // 隐藏所有工具栏
  266. for (Toolbar *toolbar : m_toolbars) {
  267. toolbar->hide();
  268. }
  269. // 显示当前工具栏
  270. if (index >= 0 && index < m_toolbars.size()) {
  271. m_toolbars[index]->show();
  272. m_pageStack->setCurrentIndex(index);
  273. }
  274. }
  275. /*
  276. function: 设置快捷键
  277. @author: flower
  278. @date: 2025-10-23
  279. @param
  280. @return 无
  281. */
  282. void MainWindow::setupShortcuts() {
  283. // 创建快捷键
  284. QShortcut *homeShortcut = new QShortcut(QKeySequence("Ctrl+1"), this);
  285. QShortcut *serialShortcut = new QShortcut(QKeySequence("Ctrl+2"), this);
  286. QShortcut *networkShortcut = new QShortcut(QKeySequence("Ctrl+3"), this);
  287. QShortcut *databaseShortcut = new QShortcut(QKeySequence("Ctrl+4"), this);
  288. QShortcut *taskShortcut = new QShortcut(QKeySequence("Ctrl+5"), this);
  289. QShortcut *settingsShortcut = new QShortcut(QKeySequence("Ctrl+6"), this);
  290. QShortcut *helpShortcut = new QShortcut(QKeySequence("Ctrl+7"), this);
  291. // 连接快捷键信号
  292. connect(homeShortcut, &QShortcut::activated, this,
  293. [this]() { switchToPage(0); });
  294. connect(serialShortcut, &QShortcut::activated, this,
  295. [this]() { switchToPage(1); });
  296. connect(networkShortcut, &QShortcut::activated, this,
  297. [this]() { switchToPage(2); });
  298. connect(databaseShortcut, &QShortcut::activated, this,
  299. [this]() { switchToPage(3); });
  300. connect(taskShortcut, &QShortcut::activated, this,
  301. [this]() {
  302. if (m_taskPageIndex >= 0) {
  303. switchToPage(m_taskPageIndex);
  304. }
  305. });
  306. connect(settingsShortcut, &QShortcut::activated, this,
  307. [this]() { switchToPage(5); });
  308. connect(helpShortcut, &QShortcut::activated, this,
  309. [this]() { switchToPage(6); });
  310. }
  311. /*
  312. function: 链接信号槽
  313. @author: flower
  314. @date: 2021-10-23
  315. @param
  316. @return 无
  317. */
  318. void MainWindow::connectSignals() {
  319. // 连接设备树选择信号到自动跳转槽函数
  320. // 现在有两个独立的设备树实例(串口页面和网络页面),都需要连接
  321. ViewInstanceManager* viewMgr = ViewInstanceManager::instance();
  322. if (viewMgr) {
  323. // 连接串口页面的设备树
  324. DeviceTreeWidget* serialDeviceTree = viewMgr->getSerialDeviceTreeWidget();
  325. if (serialDeviceTree) {
  326. connect(serialDeviceTree, &DeviceTreeWidget::deviceSelected,
  327. this, &MainWindow::onDeviceSelectedForAutoSwitch);
  328. LOG_INFO() << "MainWindow: 串口页面设备树自动跳转信号已连接";
  329. }
  330. // 连接网络页面的设备树
  331. DeviceTreeWidget* networkDeviceTree = viewMgr->getNetworkDeviceTreeWidget();
  332. if (networkDeviceTree) {
  333. connect(networkDeviceTree, &DeviceTreeWidget::deviceSelected,
  334. this, &MainWindow::onDeviceSelectedForAutoSwitch);
  335. LOG_INFO() << "MainWindow: 网络页面设备树自动跳转信号已连接";
  336. }
  337. }
  338. }
  339. void MainWindow::onDeviceSelectedForAutoSwitch(const QString &deviceType, const QString &deviceId) {
  340. // 根据设备类型自动跳转到相应页面
  341. if (deviceType == QStringLiteral("network")) {
  342. // 如果是网络设备,跳转到网络页面
  343. if (m_networkPageIndex >= 0) {
  344. switchToPage(m_networkPageIndex);
  345. LOG_INFO() << "MainWindow: 自动跳转到网络页面 - 设备=" << deviceId;
  346. }
  347. } else if (deviceType == QStringLiteral("serial")) {
  348. // 如果是串口设备,跳转到串口页面
  349. if (m_serialPageIndex >= 0) {
  350. switchToPage(m_serialPageIndex);
  351. LOG_INFO() << "MainWindow: 自动跳转到串口页面 - 设备=" << deviceId;
  352. }
  353. }
  354. // 其他设备类型(如CAN)可以在这里添加
  355. }
  356. void MainWindow::showAbout() {
  357. QMessageBox::about(this, "关于",
  358. "<h2>基于DoDAF的多源数据融合系统总线</h2>"
  359. "<p> </p>"
  360. "<p>版本: 1.0.0</p>"
  361. "<p>© flower </p>");
  362. }
  363. void MainWindow::setupDaemonStatus()
  364. {
  365. // 创建守护进程客户端
  366. m_daemonClient = new DaemonClient(this);
  367. // 连接信号
  368. connect(m_daemonClient, &DaemonClient::daemonStatusChanged,
  369. this, &MainWindow::onDaemonStatusChanged);
  370. connect(m_daemonClient, &DaemonClient::loadInfoUpdated,
  371. this, &MainWindow::onLoadInfoUpdated);
  372. // 强制使用守护进程模式,先尝试连接守护进程(如果已存在则直接连接)
  373. LOG_INFO() << "强制使用守护进程模式,正在尝试连接守护进程服务...";
  374. bool connected = m_daemonClient->connectToDaemon();
  375. // 如果连接失败,再尝试启动守护进程
  376. if (!connected) {
  377. LOG_INFO() << "守护进程未运行,正在启动守护进程...";
  378. // 尝试启动守护进程(可能已经存在)
  379. m_daemonClient->startDaemon();
  380. // 无论启动是否成功,都尝试连接(守护进程可能已经通过其他方式启动)
  381. LOG_INFO() << "正在尝试连接守护进程...";
  382. connected = m_daemonClient->connectToDaemon();
  383. if (connected) {
  384. LOG_INFO() << "守护进程启动并连接成功";
  385. } else {
  386. LOG_WARNING() << "守护进程启动或连接失败";
  387. }
  388. } else {
  389. LOG_INFO() << "守护进程已存在,连接成功";
  390. }
  391. if (!connected) {
  392. LOG_WARNING() << "守护进程连接失败,弹出对话框询问用户";
  393. // 连接失败,弹出对话框询问是否重试
  394. DaemonConnectionDialog dialog(this);
  395. dialog.setErrorMessage(tr("守护进程服务未运行或无法访问。"));
  396. int result = dialog.exec();
  397. if (result == QDialog::Accepted) {
  398. if (dialog.switchToLocalMode()) {
  399. // 用户选择切换到本地模式(已废弃,但保留兼容性)
  400. QMessageBox::warning(this,
  401. tr("本地模式已移除"),
  402. tr("本地模式已移除,所有硬件操作必须通过守护进程进行。\n"
  403. "请确保守护进程服务正常运行。"));
  404. // 尝试启动守护进程(可能已经存在)
  405. m_daemonClient->startDaemon();
  406. // 无论启动是否成功,都尝试连接(守护进程可能已经通过其他方式启动)
  407. connected = m_daemonClient->connectToDaemon();
  408. } else {
  409. // 用户选择重试,再次尝试启动和连接
  410. LOG_INFO() << "用户选择重试,正在重新启动守护进程...";
  411. // 尝试启动守护进程(可能已经存在)
  412. m_daemonClient->startDaemon();
  413. // 无论启动是否成功,都尝试连接(守护进程可能已经通过其他方式启动)
  414. connected = m_daemonClient->connectToDaemon();
  415. if (!connected) {
  416. // 重试仍然失败
  417. QMessageBox::critical(this,
  418. tr("连接失败"),
  419. tr("重试启动和连接守护进程仍然失败。\n"
  420. "请检查守护进程服务是否正常运行。"));
  421. LOG_CRITICAL() << "重试仍然失败,无法连接守护进程";
  422. } else {
  423. // 重试成功
  424. LOG_INFO() << "重试启动和连接守护进程成功";
  425. }
  426. }
  427. } else {
  428. // 用户取消
  429. QMessageBox::warning(this,
  430. tr("警告"),
  431. tr("未连接到守护进程,硬件操作将无法使用。"));
  432. LOG_WARNING() << "用户取消对话框,守护进程未连接";
  433. }
  434. } else {
  435. // 连接成功
  436. LOG_INFO() << "守护进程启动并连接成功";
  437. }
  438. // 初始化 API(现在强制使用守护进程模式)
  439. SoftBusAPI* api = SoftBusAPI::instance();
  440. if (!api) {
  441. LOG_CRITICAL() << "无法获取 SoftBusAPI 实例";
  442. return;
  443. }
  444. LOG_INFO() << "设置API模式: 守护进程模式(强制)";
  445. api->setUseDaemonMode(true); // 强制使用守护进程模式
  446. // 初始化 API(会根据模式创建相应的 Manager)
  447. LOG_INFO() << "正在初始化 SoftBusAPI...";
  448. if (!api->initialize()) {
  449. LOG_WARNING() << "Failed to initialize SoftBusAPI";
  450. return;
  451. }
  452. LOG_INFO() << "SoftBusAPI 初始化成功";
  453. // 设置 DaemonClient 到 SoftBusAPI,让硬件操作通过守护进程
  454. LOG_INFO() << "设置 DaemonClient 到 SoftBusAPI";
  455. api->setDaemonClient(m_daemonClient);
  456. // 守护进程连接成功后,启动设备扫描(由守护进程负责扫描)
  457. // 注意:在守护进程模式下,设备扫描由守护进程负责,这里只是通知可以开始查询设备列表
  458. LOG_INFO() << "启动设备扫描(守护进程模式)";
  459. api->startDeviceDiscovery(5000);
  460. // 在状态栏添加状态标签
  461. QStatusBar* statusBar = this->statusBar();
  462. if (statusBar) {
  463. m_statusLabel = new QLabel("核心服务: 未连接", this);
  464. m_loadLabel = new QLabel("负载: --", this);
  465. statusBar->addPermanentWidget(m_statusLabel);
  466. statusBar->addPermanentWidget(m_loadLabel);
  467. // 初始更新
  468. updateDaemonStatus(false, QString());
  469. }
  470. // 创建信息流列表停靠窗口(在守护进程客户端创建之后)
  471. createMessageFlowDock();
  472. // 设置守护进程客户端到信息流组件
  473. if (m_daemonClient && m_messageFlowWidget) {
  474. m_messageFlowWidget->setDaemonClient(m_daemonClient);
  475. }
  476. }
  477. void MainWindow::onDaemonStatusChanged(bool running, const QString& statusJson)
  478. {
  479. updateDaemonStatus(running, statusJson);
  480. // 信息流组件会自动处理状态更新(通过信号连接)
  481. }
  482. void MainWindow::onLoadInfoUpdated(const QString& loadInfoJson)
  483. {
  484. updateLoadInfo(loadInfoJson);
  485. // 信息流组件会自动处理负载信息更新(通过信号连接)
  486. }
  487. void MainWindow::updateDaemonStatus(bool running, const QString& statusJson)
  488. {
  489. if (!m_statusLabel) return;
  490. QString statusText;
  491. QString style;
  492. if (running) {
  493. statusText = "核心服务: 运行中";
  494. style = "color: green; font-weight: bold;";
  495. // 获取进程ID
  496. if (m_daemonClient) {
  497. qint64 pid = m_daemonClient->getPid();
  498. if (pid > 0) {
  499. statusText += QString(" (PID: %1)").arg(pid);
  500. }
  501. }
  502. // 解析状态 JSON 获取详细信息
  503. if (!statusJson.isEmpty()) {
  504. QJsonDocument doc = QJsonDocument::fromJson(statusJson.toUtf8());
  505. if (doc.isObject()) {
  506. QJsonObject obj = doc.object();
  507. int deviceCount = obj["deviceCount"].toInt(0);
  508. int onlineCount = obj["onlineDeviceCount"].toInt(0);
  509. statusText += QString(" | 设备: %1/%2").arg(onlineCount).arg(deviceCount);
  510. }
  511. }
  512. } else {
  513. statusText = "核心服务: 未运行";
  514. style = "color: red; font-weight: bold;";
  515. }
  516. m_statusLabel->setText(statusText);
  517. m_statusLabel->setStyleSheet(style);
  518. }
  519. void MainWindow::updateLoadInfo(const QString& loadInfoJson)
  520. {
  521. if (!m_loadLabel) return;
  522. if (loadInfoJson.isEmpty()) {
  523. m_loadLabel->setText("负载: --");
  524. return;
  525. }
  526. QJsonDocument doc = QJsonDocument::fromJson(loadInfoJson.toUtf8());
  527. if (!doc.isObject()) {
  528. m_loadLabel->setText("负载: --");
  529. return;
  530. }
  531. QJsonObject obj = doc.object();
  532. double messageRate = obj["messageRate"].toDouble(0.0);
  533. qint64 totalMessages = obj["totalMessages"].toVariant().toLongLong();
  534. QString loadText = QString("消息速率: %1 msg/s | 总计: %2")
  535. .arg(messageRate, 0, 'f', 1)
  536. .arg(totalMessages);
  537. m_loadLabel->setText(loadText);
  538. }
  539. void MainWindow::createMessageFlowDock()
  540. {
  541. // 创建信息流列表组件
  542. m_messageFlowWidget = new DaemonMessageFlowWidget(this);
  543. // 创建停靠窗口
  544. QDockWidget* dockWidget = new QDockWidget("守护进程信息流", this);
  545. dockWidget->setWidget(m_messageFlowWidget);
  546. dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
  547. dockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
  548. // 添加到主窗口
  549. addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
  550. // 设置守护进程客户端
  551. if (m_daemonClient) {
  552. m_messageFlowWidget->setDaemonClient(m_daemonClient);
  553. }
  554. // 默认隐藏,可以通过视图菜单显示
  555. dockWidget->hide();
  556. // 添加到视图菜单
  557. QMenuBar* menuBar = this->menuBar();
  558. if (menuBar) {
  559. QMenu* viewMenu = nullptr;
  560. QList<QAction*> actions = menuBar->actions();
  561. for (QAction* action : actions) {
  562. if (action->text() == "视图") {
  563. viewMenu = qobject_cast<QMenu*>(action->menu());
  564. break;
  565. }
  566. }
  567. if (viewMenu) {
  568. QAction* flowAction = viewMenu->addAction("守护进程信息流");
  569. flowAction->setCheckable(true);
  570. flowAction->setChecked(false);
  571. connect(flowAction, &QAction::toggled, dockWidget, &QDockWidget::setVisible);
  572. }
  573. }
  574. }
  575. void MainWindow::loadSettings() {
  576. // 现在强制使用守护进程模式,不再从设置中读取
  577. // 保留此方法以保持接口兼容性
  578. SoftBusAPI* api = SoftBusAPI::instance();
  579. if (api) {
  580. api->setUseDaemonMode(true); // 强制使用守护进程模式
  581. LOG_DEBUG() << "加载设置 - 守护进程模式: 启用(强制)";
  582. }
  583. }
  584. void MainWindow::showSettingsDialog() {
  585. if (!m_settingsDialog) {
  586. m_settingsDialog = new SettingsDialog(this);
  587. // 设置守护进程客户端,让设置对话框能检查守护进程状态
  588. m_settingsDialog->setDaemonClient(m_daemonClient);
  589. }
  590. // 加载当前设置
  591. m_settingsDialog->loadSettings();
  592. // 显示对话框
  593. if (m_settingsDialog->exec() == QDialog::Accepted) {
  594. // 用户点击了"确定",应用设置
  595. // 注意:现在强制使用守护进程模式,设置对话框中的模式选项已无效
  596. SoftBusAPI* api = SoftBusAPI::instance();
  597. if (api) {
  598. api->setUseDaemonMode(true); // 强制使用守护进程模式
  599. LOG_DEBUG() << "设置已更新 - 守护进程模式: 启用(强制)";
  600. }
  601. }
  602. }
  603. void MainWindow::closeEvent(QCloseEvent *event) {
  604. // 关闭窗口时清理 soft_bus 相关资源并退出应用程序
  605. LOG_INFO() << "主界面关闭,正在清理 soft_bus 相关资源并退出应用程序...";
  606. SoftBusAPI* api = SoftBusAPI::instance();
  607. if (api && api->isInitialized()) {
  608. // 关闭所有设备(串口、CAN设备等)并清理资源
  609. // shutdown() 会调用 cleanupManagers() 来关闭所有设备
  610. api->shutdown();
  611. LOG_INFO() << "soft_bus 资源清理完成";
  612. }
  613. // 断开 daemon 连接(删除对象会触发析构函数,自动注销客户端)
  614. if (m_daemonClient) {
  615. delete m_daemonClient;
  616. m_daemonClient = nullptr;
  617. LOG_INFO() << "已断开 daemon 连接";
  618. }
  619. // 接受关闭事件,退出应用程序
  620. // 应用程序退出时,main.cpp 中的 CoreService::shutdown() 会被调用
  621. event->accept();
  622. // 退出应用程序(这会触发 main.cpp 中的 CoreService::shutdown())
  623. QApplication::quit();
  624. }